Commit Graph

33 Commits

Author SHA1 Message Date
Misaka
75abbdf14c Add websocket-client to requirements; sync docs
site_anneng 的 CDP 驱动用到 websocket-client,此前 requirements.txt 缺漏,
需额外手动安装。补进 requirements.txt,并把 README/CLAUDE 里"暂未列入"的
临时提示改为"已包含"。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 22:48:07 +08:00
Misaka
c6a23febc0 Add README and CLAUDE.md project docs
- README.md:面向使用者的项目说明(站点/流程、环境、配置、运行、架构、输出)。
- CLAUDE.md:面向后续开发的关键命令与非显而易见的跨文件架构与约定。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 22:38:21 +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
d05848ee36 Ignore .playwright-cli/ artifacts directory
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 21:26:12 +08:00
Misaka
d55c460c2d Integrate expected-vs-actual (应到未到) comparison into main_router
- 应到未到比对.py -> expected_undelivered.py(英文名);main() 的 sys.exit 改为
  return,使其可被 main_router 安全调用而不杀进程。
- main_router.py:菜单 [9] 改为调用 expected_undelivered.main()——全站点自动比对,
  输出 output/应到未到数据.xlsx(汇总报表 + 中通/顺心/韵达/安能 各站明细);移除被
  取代的旧 task_process_undelivered_data 及其专属 import pandas。
- .gitignore:忽略 output/(比对输出目录)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 23:39:36 +08:00
Misaka
dea9ad6e07 Add Anneng actual-data (scan) download and wire into automation test
安能站点第二阶段:实到数据下载 + 接入自动化测试。

- site_anneng.py:新增 anneng_actual_download()。网点到件扫描查询页是 Ant Design
  且无导出功能——综合查询→扫描查询→网点到件扫描查询(新)→ 设扫描时间(直接输入
  +回车)→ 选「子单」→ 每页 500(size-changer 用 mousedown 展开)→ 查询 → 直接
  从表格 DOM 抽数、逐页翻页取完 → 存 安能-实到货物数据.xlsx → 关 tab。复用应到的
  CDP/菜单/tab 辅助;扫描专有逻辑单独成段。main() 支持 `actual` 参数独立跑实到。
  修掉复用 tab 时首查读到旧总数的问题(查询后等总数变化再读)。
- main_router.py:菜单加 [11] 实到货物数据下载;run_automation_test 的 flow_table
  加入安能(expected/actual),执行循环对应用类站点(APP_SITES)走无 page 分支。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 22:12:23 +08:00
Misaka
9d3d3cbb78 Add Anneng (Electron) site: expected-data download + main_router integration
安能站点第一阶段:把应到数据(运单信息)下载流程接入主路由。

- site_anneng.py:用页面级 CDP 驱动「安能全网门户」Electron 应用(Playwright
  connect_over_cdp 被 Electron 浏览器域 CDP 拦截,故走页面级)。完整应到流程:
  菜单导航 → 进站交接单查询 → 设日期查询(“带小数点的 0”为加载完成判据)
  → 逐条交接单双击进运单信息并核对单号 → 导出(选中字段+→箭头转移全部列)
  → 关闭查询 tab → 导出下载页轮询 → 免对话框下载(x-auth+TGC 直连 GET)
  → 合并为 安能-应到货物数据.xlsx。CDP 端口可配;anneng_ready() 供路由就绪轮询。
- main_router.py:以调试模式启动安能(动态空闲端口,避免端口冲突),经 CDP
  判断首页就绪,菜单加 [10] 应到下载,退出时关闭应用;网页站点逻辑不变。
- config.example.yaml:补充 anneng.query_days 与 anneng.app_path 说明。
- docs/安能门户CDP连接指南.md:连接方案、独立 webContents/tab 处理、免对话框下载。
- .gitignore:忽略 Archive/(早期探查脚本归档)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 19:38:44 +08:00
Misaka
d4a9fb3b4a Harden Yunda export dialog with two-layer reset and plain wording
- Add a two-layer reset engine to the export dialog (both expected and
  actual arrival): an outer 3x reopen loop with a field-list presence
  check (交接单号 / 扫描类型 as per-page anchor), and an inner 4x
  submit loop that distinguishes a missed field (re-click 全选) from a
  vanished field list (reopen the whole dialog), recovering from
  empty/ghost-cleared export dialogs
- Keep log/comment wording plain and factual (no hyperbole)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 12:19:51 +08:00
Misaka
47d9140dc6 Add Baishi tab cleanup helper and close tab after extraction
- Add _close_tab(page, tab_name) for Baishi's tab close affordance
  (li>span text + i[title='关闭标签页']), matching the other sites
- Close the 扫描综合查询 tab both on the empty-data early return and
  after a successful download; return True on completion

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 10:55:56 +08:00
Misaka
5b7a024fa8 Parameterize Shunxin query window and document it in example config
- site_shunxin: replace the hardcoded 1天 radio with config-driven
  shunxin.query_days, set the date range via the ant-picker, and add a
  two-pass query/retry to clear stale "暂无数据" DOM state; return True
  on completion
- config.example.yaml: add the shunxin section (query_days) so the
  example matches what the code reads

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 10:43:55 +08:00
Misaka
f4f9f520e1 Document yunda config and remove dead main_task.py
- config.example.yaml: add the yunda section (username/password for
  auto-login, query_days) and list 韵达 as a valid debug target_site
- Delete main_task.py: early single-site (顺心-only) prototype whose
  every function is superseded by main_router.py + site_shunxin.py;
  nothing imports it, and it predates paths.py / multi-site / the
  automation test

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 23:35:42 +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
5d13c13f40 Close Shunxin tabs after each stage via shared _close_tab helper
- Add _close_tab(page, tab_name) for closing Ant Design Tabs by label
- Close 运单列表 / 车辆点到 in the expected-arrival flow after export
  submission, and 数据导出 after download/merge
- Close 卸车扫描记录 and 数据导出 likewise in the actual-arrival flow
- Renumber step comments

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 21:47:05 +08:00
Misaka
a67b64f8f8 Auto-login Yunda and switch router to ready-guard polling
- Add yunda_login: probe the login page, fill credentials from
  config.yaml (yunda.username/password), submit; no-op if already
  logged in
- main_router: register per-site READY_SELECTORS and replace the
  blocking input() with a ready-guard poll loop; invoke Yunda
  auto-login up front; simplify site-init cleanup
- site_yunda: drop the custom frame probes in favor of native
  frame_locator("section iframe")
- Skip handover rows already marked 已绑定; abort the export harvest
  when no tasks were submitted
- Fix NameError from undefined username/password fallback

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 21:33:09 +08:00
Misaka
e8b789e906 Add anti-collapse menu nav and fix multi-tab Strict Mode leakage
- Rewrite yunda_smart_menu_click to check each parent submenu's
  is-opened state before clicking (skip if already open), using XPath
  parent-child isolation to avoid collapsing accordion menus
- Scope the expected/actual-arrival loading mask, #sum panel, and
  empty-record hint to #tab-1 and add .first to fix Playwright Strict
  Mode (5 elements found) leaks across multiple open tabs
- Move _yunda_poll_and_download_tasks above yunda_actual_download for
  definition order

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 19:22:01 +08:00
Misaka
604d1822e4 Implement Yunda actual-arrival download and harden query loading
- Implement yunda_actual_download via the 报表管理 -> 扫描记录查询
  menu: set date range, switch scan type to 到件, then reuse the
  shared poll/download/merge engine
- Add a three-stage query buffer (yield, wait for the Bootstrap Table
  loading mask, settle) before the data/empty verdict to avoid stale
  DOM reads in the expected-arrival flow
- Trim the offline-export retry state machine's verbose logs
- Fix a typo (研编 -> 研判) and drop the 待开发 tag on menu [7]

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:59:49 +08:00
Misaka
194fbc7cda Integrate Yunda site module and rewire router menu numbering
- Add site_yunda.py: Yunda expected-arrival download (进站交接单查询)
  with Layui date-range setup, row double-click export, a retry state
  machine for the offline-export dialog, and a shared poll/download/
  merge engine; actual-arrival is a placeholder
- Wire Yunda into main_router: site URL, login detection, menu items,
  and read yunda.query_days from config.yaml
- Rework the hub menu: drop the standalone Shunxin local-compare entry,
  renumber modules (百世 3, 中通 4/5, 韵达 6/7), keep global compare [9]
- Streamline site-init cleanup and log wording

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:20:46 +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
Misaka_Company
7f8d81af21 Add zero-count validation for Baishi undelivered data extraction 2026-06-17 15:27:51 +08:00
Misaka_Company
7cae24fae3 Add PyYAML dependency to fix missing yaml module 2026-06-17 15:11:03 +08:00
Misaka
b127ef6165 Fix Baishi scan-query selector ambiguity and add password guard
- Scope the 扫描综合查询 click to .nav-level2-wrapper to avoid collision with the right-side tab of the same name
- Warn when config.yaml has no baishi.password before attempting export

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 22:32:10 +08:00
Misaka
5c3225388e Add multi-round popup cleanup engine for Baishi site initialization
- Loop up to 5 rounds to dismiss 阅读完毕 / 配置检查 / 通知提示 / 广告 popups until the page is clean
- Revert undelivered-data docstring to dynamic-prefix wording

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 22:20:07 +08:00
Misaka
ec1a9d9fbc Implement Baishi undelivered-data extraction and restructure menu by site
- Replace Baishi placeholders with full download flow (scan-rate query, export modal, password auth via config.yaml)
- Reorganize router menu into 顺心 / 百世 modules; move undelivered-data compare into 顺心 flow
- Add config.example.yaml and ignore config.yaml to keep credentials out of VCS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 21:58:02 +08:00
Misaka
497fd11674 Add per-site file prefix for undelivered-data comparison
- task_process_undelivered_data now accepts site_name (default 顺心)
  and reads/writes {site}-{应到/实到/应到未到}货物数据.xlsx
- Menu option 5 prompts for site name before running reconciliation
- Update 顺心 site outputs to 顺心-应到/实到货物数据.xlsx naming
- Remove redundant inline comments in site_shunxin.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 22:09:12 +08:00
Misaka
411a2487fc Refactor monolithic script into multi-site module architecture
- Introduce main_router.py as multi-site controller with interactive menu
- Extract 顺心 site logic into site_shunxin.py (expected & actual download)
- Add site_baishi.py stub for upcoming 百世 integration
- Add global 应到未到 data reconciliation via Left Anti-Join on 运单号

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 22:02:51 +08:00
Misaka
b0c82bc23d Update selectors and query flow in expected/actual goods tasks
- Use regex-based locator to match 已发/已到 status options robustly
- Switch to role-based selectors for 查询 button and 任务标题 column
- Trigger additional 查询 after entering 数据导出 page to refresh list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 21:29:06 +08:00
Misaka_Company
e5205760a0 Initial commit: InboundVerify automation scripts for logistics data processing 2026-06-15 18:18:51 +08:00