Commit Graph

13 Commits

Author SHA1 Message Date
Misaka
96e7018146 定时下载(APScheduler) + 跑比对纯离线 + 偏移拆 expected/actual + 报告下载
定时下载:
- state_store:site_config 加 schedule_enabled/schedule_time(旧库迁移)+ set_schedule/get_all_config
- server:APScheduler BackgroundScheduler,启动按配置注册各站 cron job、改配置重排;job 投 undelivered 任务到队列(错过跳过);/config 扩展 schedule
- runtime:("__compare__","compare") 改纯离线 expected_undelivered.main()(不下载)
- requirements:加 apscheduler

偏移拆分 + 报告下载:
- state_store:date_offset 拆 expected_offset/actual_offset(迁移)+ get_offset(site,kind)/set_offset(site,kind,n)
- 4 站 actual impl 改读 actual 偏移(expected 走默认 kind)
- server:/config 用 expected_offset/actual_offset;新增 GET /report(服务 output/应到未到数据.xlsx)
- paths:加 OUTPUT_DIR

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-18 08:11:18 +08:00
Misaka
26a94999dc 按站点指定下载日期偏移(0=今天…30)+ 修复启动陈旧登录态
偏移量功能(前端/API 可配,服务端持久化、多用户共享):
- state_store:新增 site_config 表 + get_offset / set_offset(0..30 钳制) / get_all_offsets
- server:新增 GET/PUT /config(百世锁定当天,不可配置)
- 顺心/中通/韵达/安能(各 expected+actual):日期逻辑由 query_days 范围改为读 offset
  算单日 target=今天-offset,起止同日;百世仍走当日
- config.example.yaml:query_days 标记为已废弃

修复启动时显示上一会话陈旧登录态:
- state_store:新增 reset_login_states(登录态会话级,启动重置为 unknown;数据态会话无关、保留)
- runtime.launch_and_prepare:启动时对各站重置登录态,心跳就绪后重新探测写真实值

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 21:27:52 +08:00
Misaka
66bd8af421 阶段1:服务化骨架(FastAPI + Playwright worker + 任务队列)
- 新增 runtime.py:抽离共享核心 launch_and_prepare / dispatch_task / run_heartbeat /
  probe_* / launch_anneng / RuntimeContext,常量 SITES_CONFIG 等;main_router 复用
- 新增 server.py:FastAPI(主线程)+ Playwright worker(独立线程)+ 任务队列;
  API:POST/GET /tasks、GET /status、GET /data/{file}(防路径穿越)
- state_store:加 task_history 表 + create/update/get/list 接口
- 5 站点 with_retry 改为返回 True/False,供 dispatch_task 判成败
- main_router:重写为复用 runtime 的交互模式(行为不变)
- requirements:加 fastapi、uvicorn
- CLAUDE.md:补充运行模式与共享核心架构说明

线程模型:主线程 FastAPI 不碰 Playwright,worker 线程独占 page,经 Queue + SQLite 通信。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 00:04:39 +08:00
Misaka
5030e5b89b 统一各站成败反馈信号;修复中通报错卡死与提示框误判
成败信号统一化(顺心/中通/韵达/安能/百世):
- 各站 impl 开头清理上次的最终文件,避免无数据/失败时残留旧数据误导比对
- 轮询下载段加汇总校验:下载数 < 预期则 raise,堵住"零/部分下载被判成功"
- 正常完成统一显式 return True(原中通/韵达/安能靠 None 隐式成功)
- 无数据统一不落文件(安能实到不再落空 xlsx);韵达裸 except 改 except Exception
- 中通"票数0无空提示"分支改判失败

中通 bug 修复(site_zto.py):
- poll 加 stall 快速失败(连续4轮无进展即 raise)+ 刷新短超时 + 双失败 raise,
  避免页面被遮挡时干等 5 分钟才触发重试
- "生成离线导出任务成功"提示所在 iframe 提交后被销毁,wait_for 抛
  "Frame was detached" 属正常(提示已随 iframe 消失=任务已建立),改判成功

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 21:38:56 +08:00
Misaka
a71924ca1a Cap export-task poll loops at 5min to avoid infinite hang
顺心/中通/韵达/安能 的导出任务轮询循环原本只在"本批任务全部完成"时
退出,无任何时间上限:任务卡在生成中、或因时钟偏移没落进 40s 容差窗口
匹配不上时,会无限轮询、流程永不返回,连 with_retry 都没机会触发。

给这 5 处轮询加 300s deadline,超时即 raise → 流程返回 False → 触发
已有的重置重试机制。把"永久挂死"变成"有界失败→自动重试"。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 22:24:41 +08:00
Misaka
2d49c3d6f1 Add per-site exception fallback (reset + retry), router stays pure dispatch
每个站点模块自带"失败→重置回初始态→重试"兜底(最多 3 次,含首次;每次
失败都重置,含最终放弃那次清场),对外只暴露 xxx_download 公开入口,路由
层无感、只负责调度。

- 各站点模块新增:HOME_URL、xxx_reset、内联 with_retry;原流程拆为
  xxx_download(带重试) + xxx_download_impl(单次,供自动化测试探测原始失败)。
- 网页站重置=goto 首页 URL;安能(Electron)重置=关业务 tab+收菜单(实测
  reload 会留下杀不掉的僵尸 webContents,故不用 reload)。
- main_router:SITES_CONFIG 改引用各模块 HOME_URL(单一来源);菜单分派回归
  朴素调用;run_automation_test 改走 _impl 以保留"暴露问题"的测试本意。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-08 22:39:38 +08:00
Misaka
3ae94bef0d Fix ZTO actual-download date-cell click blocked by hover tooltip
中通实到流程选日期时,Playwright 的 .click() 会先 hover 日期格子,
触发“范围长度”提示气泡(.date-range-length-tip)盖住格子,导致点击被
判遮挡而超时(query_days=1 时尤甚,起始日==今日,点的是同一格子两次)。

改为直接在日期格子元素上派发 mousedown+mouseup+click 事件(新增
_dom_click helper),不经过坐标命中测试,气泡根本不会出现、也无法拦截。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 23:26:37 +08:00
Misaka
63ee8bbae1 Unify export-task matching to time tolerance only (≤40s)
去掉顺心/中通/韵达/安能(应到) 导出任务认领时的标题/模块名校验,
统一改为仅按提交时间容差 ≤40 秒匹配本批任务。

理由:单账号无并发,时间窗内的任务必为本批所建;而站点可能调整
任务标题名,写死标题会导致匹配失败、任务已创建却一直查不到。
同步清理因此变成死代码的局部变量与函数形参。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 22:04:22 +08:00
Misaka
229e474b58 Add cross-flow automation test and tone down log/comment wording
- main_router: add run_automation_test that runs each site's download
  flows in a cross sequence (expected/actual) plus a pass/fail report
  with timings; expose it as menu [8]
- Site download functions now return False on their exception paths so
  the test harness can record failures (baishi also flags config-read
  failure)
- Replace overblown log/comment phrasing across all modules with plain
  statements; trim docstrings

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 23:33:22 +08:00
Misaka
ab3f25a10e Centralize paths in paths.py and harden waybill-number handling
- Add paths.py: BASE_DIR/DOWNLOAD_DIR/CONFIG_PATH anchored on __file__
  so paths resolve regardless of the launch cwd
- Route main_router and all site modules through DOWNLOAD_DIR/CONFIG_PATH,
  replacing os.getcwd()-based download dirs and the "config.yaml" literal
- main_router compare engine: read Excel as str with keep_default_na,
  strip/normalize 运单号, drop blanks, and isin against a set so
  int/float-vs-str mismatches no longer produce false "undelivered"
- Shunxin: give downloaded files unique microsecond temp names and read
  Excel as str to preserve long-waybill precision
- Normalize bare except: to except Exception: across affected files

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 22:28:30 +08:00
Misaka
eb9bbe9b70 Harden ZTO export flows and close site tabs after each stage
- Poll #inEwbCount until it updates before reading the result, then
  branch on zero-count (confirm empty-data area vs missing flag)
- Wait for real grid rows to render in the expected-arrival flow
- Close the active site tab (进站交接单查询 / 到件扫描监控 / 导出任务管理)
  after each stage completes to reset the page state
- Tighten export-task time-match window from 60s to 20s
- Trim verbose log messages and stale comments

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 15:24:48 +08:00
Misaka
358b8327b9 Implement ZTO actual-arrival download and extract shared poll engine
- Implement zto_actual_download via the 到件扫描监控 menu with 子单
  number-type filter, reusing the common download flow
- Extract the export-task poll/verify/download/merge steps into
  _zto_poll_and_download_tasks so both ZTO flows share it
- Tighten task time-match window from 120s to 60s and add a
  refresh-and-recheck loop when expected tasks are missing or pending
- Drop unused _ensure_menu_expanded helper
- Update menu [6] label since actual-arrival is now implemented

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 13:48:28 +08:00
Misaka
9375b6efd6 Integrate ZTO site module and add debug/single-site mode
- Add site_zto.py: ZTO expected-arrival data download with menu
  navigation, export polling, and Excel merge
- Wire ZTO into main_router: site URL, login detection, menu items
  [5]/[6], and a global offline Left Anti-Join compare entry [9]
- Read config.yaml debug flags to launch only the target site for
  focused debugging; guard each site init and route handler behind
  site-loaded checks via is_site_ready()
- Expand config.example.yaml with documented debug, baishi, and zto
  config keys

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:46:46 +08:00