feat: 完善RJ数据自动调度

This commit is contained in:
2026-06-01 10:28:36 +08:00
parent 9711aa6270
commit e0056e609e
10 changed files with 328 additions and 113 deletions
+14 -15
View File
@@ -21,25 +21,22 @@
| 格式 | 示例 | 数据日期 |
|------|------|----------|
| `XXX_YYYYMMDDHHMM_YYYYMMDDHHMM` | `CapacityReportData2.6_202605110000_202605120000.zip` | 第一个时间戳 `202605110000` → 2026-05-11 |
| `XXX_YYYYMMDDHHMM` | `CapacityReportData2.6_202605110000.zip` | 时间戳 `202605110000` → 2026-05-11 |
| `XXX_YYYYMMDDHHMM_YYYYMMDDHHMM` | `CapacityReportData2.6_202605110000_202605120000.zip` | 覆盖起止时间范围,结束零点按右开区间处理 → 2026-05-11 |
| `XXX_YYYYMMDDHHMM` | `CapacityReportData2.6_202605110000.zip` | 视为单日文件 → 2026-05-11 |
### 2.2 解析逻辑
复用项目已有的正则 `_ZIP_DATE_RE = re.compile(r"(?<!\d)(20\d{10}(?:\d{2})?)(?!\d)")`,取第一个匹配项作为数据日期。
复用项目已有的正则 `_ZIP_DATE_RE = re.compile(r"(?<!\d)(20\d{10}(?:\d{2})?)(?!\d)")`,优先解析文件覆盖的自然日范围。
```python
def extract_file_date(filename: str) -> date | None:
"""从文件名提取数据日期(取第一个匹配的时间戳)"""
match = _ZIP_DATE_RE.search(filename)
if not match:
return None
timestamp = match.group(1) # 12位: YYYYMMDDHHMM 或 14位: YYYYMMDDHHMMSS
fmt = "%Y%m%d%H%M%S" if len(timestamp) == 14 else "%Y%m%d%H%M"
try:
return datetime.strptime(timestamp, fmt).date()
except ValueError:
def parse_file_date_range(filename: str) -> FileDateRange | None:
"""从文件名提取数据覆盖范围。"""
values = _ZIP_DATE_RE.findall(filename)
if not values:
return None
start = parse_timestamp(values[0])
end = parse_timestamp(values[1]) if len(values) > 1 else start + timedelta(days=1)
return FileDateRange(start=start.date(), end_exclusive=normalize_end(end))
```
---
@@ -130,10 +127,12 @@ def get_target_week_range(week_offset: int = 0) -> tuple[date, date]:
**关键**:
1. 不依赖系统日期,而是从文件名中提取日期
2. 文件名只取**第一个**时间戳作为数据日期
3. 例如文件 `CapacityReportData2.6_202605120000_202605130000.zip` → 数据日期为 2026-05-12
2. 文件名带两个时间戳时按覆盖范围判断;只有一个时间戳时视为单日文件
3. 例如文件 `CapacityReportData2.6_202605120000_202605130000.zip` → 覆盖 2026-05-12
4. 如果某个日期没有对应的 ZIP 文件,该目录判定为未就绪
RJ 目录会额外按最新文件自动判断粒度:最新文件为单日时要求 7 个目标日都齐全;最新文件为多日/周文件时要求存在一个 ZIP 覆盖完整目标自然周。
### 3.4 标识文件
- **位置**:`cache/auto_scheduler/ready.flag`
+10
View File
@@ -1,5 +1,15 @@
# 项目上下文记录
## 2026-06-01:完善 RJ 自动调度日/周粒度识别
- `app/utils/file_dates.py` 新增文件日期范围解析:`XXX_YYYYMMDDHHMM` 视为单日文件,`XXX_YYYYMMDDHHMM_YYYYMMDDHHMM` 按起止时间展开自然日,结束时间为零点时按右开区间处理。
- `app/services/auto_scheduler.py` 的 RJ 检查改为按目录最新 ZIP 自动识别 `daily` 或 `weekly`:日粒度目录要求目标自然周 7 天都存在,周粒度目录要求有一个 ZIP 覆盖目标自然周;空 RJ 目录继续视为停推并跳过。
- 自动调度普通 4G/5G 目录扫描会排除已配置的 RJ 目录,避免 `expected_directories=[]` 时 RJ 周目录被普通 7 天规则误判阻塞。
- `app/services/remote_download.py` 的调度下载筛选改为使用日期覆盖范围:单日文件只要覆盖目标日即下载,多日/周文件必须覆盖完整目标周才下载,避免 ready 后漏下或误下 RJ 周文件。
- `Configure.json` 将 `RJ/700M/700RJGD`、`RJ/700M/700RJYD` 加入 RJ 数据目录,并补充 `700MRJGD`、`700MRJYD` 字段映射;`processor.py` 避免多个源字段别名映射到同一目标字段时生成重复列。
- 配置上传接口现在会导入/保存 `RJData`,前端类型补充 `rj_data` 和调度状态中的 `granularity` 字段。
- 已验证:后端 AST 语法检查、`Configure.json` JSON 解析、`npm run build`、真实 SFTP 清单识别、MySQL 临时导入 700RJYD 样本并清理测试表均通过;前端构建仅保留既有大 chunk 警告。
## 2026-05-29:新增 RJ 周数据处理功能
- 新增 `RJData` 配置块到 `app/config.py`,支持 `enabled`、`weekly_directories` 和 `table_field_mappings` 配置项,用于管理 RJ 周数据目录和字段映射。