Files
Orbitin/docs/feishu_data_flow.md

180 lines
4.8 KiB
Markdown
Raw Normal View History

# 飞书数据获取流程
## 整体流程
```mermaid
flowchart TD
A[开始: 生成日报] --> B[调用 get_shift_personnel]
B --> C[创建 FeishuScheduleManager]
C --> D[调用 get_schedule_for_date]
D --> E[解析日期: 2025-12-30 → 12/30]
E --> F[检查缓存: data/schedule_cache.json]
F --> G{缓存是否存在?}
G -->|是| H[直接返回缓存数据]
G -->|否| I[调用 API 获取数据]
I --> J[调用 get_sheets_info]
J --> K[GET /spreadsheets/{token}/sheets/query]
K --> L[返回表格列表: 8月, 9月, 10月, 11月, 12月, 2026年...]
L --> M[根据月份选择表格: 12月 → sheet_id='zcYLIk']
M --> N[调用 get_sheet_data]
N --> O[GET /spreadsheets/{token}/values/zcYLIk!A:AF]
O --> P[返回表格数据: 姓名, 12月1日, 12月2日...]
P --> Q[调用 ScheduleDataParser.parse]
Q --> R[解析日期列: 查找12月30日对应的列索引]
R --> S[筛选班次人员: 白班='白', 夜班='夜']
S --> T[返回结果: 白班人员列表, 夜班人员列表]
T --> U[保存到缓存]
U --> V[返回给日报模块]
V --> W[填充到日报中]
```
## API调用详情
### 1. 获取表格列表
**请求**:
```
GET https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/EgNPssi2ghZ7BLtGiTxcIBUmnVh/sheets/query
Authorization: Bearer u-dbctiP9qx1wF.wfoMV2ZHGkh1DNl14oriM8aZMI0026k
```
**响应**:
```json
{
"code": 0,
"data": {
"sheets": [
{"sheet_id": "904236", "title": "8月"},
{"sheet_id": "ATgwLm", "title": "9月"},
{"sheet_id": "2ml4B0", "title": "10月"},
{"sheet_id": "y5xv1D", "title": "11月"},
{"sheet_id": "zcYLIk", "title": "12月"},
{"sheet_id": "R35cIj", "title": "2026年排班表"},
{"sheet_id": "wMXHQg", "title": "12月副本"}
]
}
}
```
### 2. 获取表格数据
**请求**:
```
GET https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/EgNPssi2ghZ7BLtGiTxcIBUmnVh/values/zcYLIk!A:AF
Authorization: Bearer u-dbctiP9qx1wF.wfoMV2ZHGkh1DNl14oriM8aZMI0026k
params: {
valueRenderOption: "ToString",
dateTimeRenderOption: "FormattedString"
}
```
**响应**:
```json
{
"code": 0,
"data": {
"valueRange": {
"range": "zcYLIk!A1:AF11",
"values": [
["姓名", "12月1日", "12月2日", "12月3日", "12月4日", ...],
["张勤", "白", "白", "白", "白", ...],
["刘炜彬", "白", null, "夜", "夜", ...],
["杨俊豪", "白", "白", "白", "白", ...],
["梁启迟", "夜", "夜", "夜", "夜", ...],
...
]
}
}
}
```
## 数据解析流程
### 1. 查找日期列索引
```python
# 查找 "12月30日" 在表头中的位置
headers = ["姓名", "12月1日", "12月2日", ..., "12月30日", ...]
target = "12/30" # 从 "2025-12-30" 转换而来
# 遍历表头找到匹配的日期
for i, header in enumerate(headers):
if header == "12月30日":
column_index = i
break
# 结果: column_index = 31 (第32列)
```
### 2. 筛选班次人员
```python
# 遍历所有人员行
for row in values[1:]: # 跳过表头
name = row[0] # 姓名
shift = row[31] # 12月30日的班次
if shift == "白":
day_shift_list.append(name)
elif shift == "夜":
night_shift_list.append(name)
# 结果
# day_shift_list = ["张勤", "杨俊豪", "冯栋", "汪钦良"]
# night_shift_list = ["刘炜彬", "梁启迟"]
```
### 3. 生成日报输出
```python
day_shift_str = "、".join(day_shift_list) # "张勤、杨俊豪、冯栋、汪钦良"
night_shift_str = "、".join(night_shift_list) # "刘炜彬、梁启迟"
# 日报中的格式
lines.append(f"12/31 白班人员:{day_shift_str}")
lines.append(f"12/31 夜班人员:{night_shift_str}")
```
## 缓存机制
```mermaid
flowchart LR
A[首次请求] --> B[调用API]
B --> C[保存缓存: data/schedule_cache.json]
C --> D{"1小时内再次请求"}
D -->|是| E[直接读取缓存]
D -->|否| F[重新调用API]
```
缓存文件格式:
```json
{
"last_update": "2025-12-30T15:00:00",
"data": {
"2025-12-12/30": {
"day_shift": "张勤、杨俊豪、冯栋、汪钦良",
"night_shift": "刘炜彬、梁启迟",
"day_shift_list": ["张勤", "杨俊豪", "冯栋", "汪钦良"],
"night_shift_list": ["刘炜彬", "梁启迟"]
}
}
}
```
## 关键代码位置
| 功能 | 文件 | 行号 |
|------|------|------|
| 飞书API客户端 | [`src/feishu.py`](src/feishu.py:10) | 10 |
| 获取表格列表 | [`src/feishu.py`](src/feishu.py:28) | 28 |
| 获取表格数据 | [`src/feishu.py`](src/feishu.py:42) | 42 |
| 数据解析器 | [`src/feishu.py`](src/feishu.py:58) | 58 |
| 缓存管理 | [`src/feishu.py`](src/feishu.py:150) | 150 |
| 主管理器 | [`src/feishu.py`](src/feishu.py:190) | 190 |
| 日报集成 | [`src/report.py`](src/report.py:98) | 98 |