Files
cmshoppe/progress.md
T

160 KiB
Raw Blame History

执行进度记录

本文件是只追加的历史流水,记录任务执行过程、验证命令、阻塞点和关键决策。 当前目录、当前命令、下一个可领取任务等可覆盖快照,写入 docs/current-state.md。 历史条目里的“下一步”只代表当时判断,不作为当前任务领取依据;当前任务必须按 docs/06-tasks.md 的顺序与 docs/current-state.md 的快照执行。

职责边界

  • docs/06-tasks.md:任务看板,维护任务状态、依赖和验收要点。
  • progress.md:历史流水,只追加记录每轮执行发生了什么。
  • docs/current-state.md:当前快照,可覆盖更新仓库现实、可运行命令和下一步。

记录格式

## 【YYYY-MM-DD】T-【编号】 【任务名】

- 状态:【DONE / BLOCKED / PARTIAL】
- 变更:【修改了哪些文件或模块】
- 验证:【运行的真实命令和结果】
- 阻塞:【如有,写明原因和需要谁决策】
- 决策:【如有,记录本轮确定的关键取舍】
- 下一步:【建议下一个任务 ID 或待确认事项】

执行记录

【2026-06-25】Phase -1 单账号流程验证(建文档前)

  • 状态:DONE
  • 变更:新增 cdp.py、demo.py、set_title.py、set_cover.py、get_title.py、cookies.py、inspect_images.py、grab.py;本轮建立 docs/ 全套 harness coding 文档与 progress.md、AGENTS.md、CLAUDE.md。
  • 验证:
    • CDP 连接 Chrome(开发期经 WSL→Windows portproxy 192.168.0.224:9333→127.0.0.1:9222)成功。
    • cookies.py:读到 shopee.tw 标签页 50 个 Cookie(含 csrftoken)。
    • get_title.py:读到测试商品(ITEM_ID 51100639510)标题。
    • set_title.py:改标题后 value==modelvalue==新值。
    • set_cover.py:setFileInputFiles 上传成功(张数 5→6),拖拽落点 first.left-0.30*w 后新图到第一位。
    • demo.py:在 Windows 端跑通改标题 + 换封面(未提交)。
    • 文档:python -m py_compile *.py 通过;demo.py 增加 UPDATE=1 提交开关并语法校验通过。
  • 决策:
    • 浏览器自动化用自研 cdp.py(websocket-client + requests),不引入 playwright/selenium。
    • 必须清代理环境变量 + suppress_origin=True + --remote-allow-origins=*,否则连不上 CDP。
    • SPA 就绪用“标题框+图片 itembox+上传框”三元素存在判断,不用 load 事件。
    • 封面由位置决定,用模拟鼠标拖拽到第一位;「更新」默认不点,UPDATE=1 才提交。
    • 下一阶段做多账号管理 + GUI,GUI 暂定 Tkinter(待维护者确认)。
  • 下一步:从 docs/06-tasks.md 领取 T-001(抽 editor.py)或 T-002(accounts.json + config.py)。

【2026-06-25】决策 · 多账号隔离方案

  • 状态:DONE(仅文档决策,未涉及代码)
  • 变更:更新 docs/04-architecture.md(新增 3.0 多账号隔离方案决策表)、docs/02-requirements.md(功能加“生成快捷方式 P1”、决策表加“多账号隔离方式”)、docs/03-tech-stack.md(决策记录)、docs/api.md(chrome 模块加 create_shortcut)、docs/06-tasks.md(新增 T-105 生成快捷方式)。
  • 决策:
    • 多账号隔离采用方案 B:每账号独立 user-data-dir,否决方案 A(Chrome profile)。理由:--remote-debugging-port 绑在 user-data-dir/进程上而非 profile,方案 A 无法每账号独立 CDP 端点、无法并行、串号风险高。
    • 启动主路径用程序 subprocess 直接带参数启动;快捷方式为可选便利,用 PowerShell WScript.Shell.CreateShortcut 生成,参数须写在快捷方式「目标」字段而非「起始位置」。
  • 下一步:实现 chrome.py(T-102 启动器 + T-105 快捷方式),或先做 T-001/T-002 地基。

【2026-06-25】决策 · 双 Tab + 配置文件 + SQLite + Excel 批量 + 登录检测 + 导出

  • 状态:DONE(仅文档决策,未涉及代码)
  • 变更:系统性更新 docs/02-requirements.md(第二版功能/决策表/风险)、docs/03-tech-stack.md(config.json+SQLite+openpyxl)、docs/04-architecture.md(双 Tab 结构、4.1 config.json、4.2 SQLite schema、4.3 Excel 模板、5.x 批量与登录检测流程、第六节加登录检测事实)、docs/api.md(拆 appconfig/db/excel 模块、editor 加登录检测与 run_task)、docs/06-tasks.md(重排 Phase 0-4)、docs/routes.md(重写为双 Tab 线框)、docs/00-ai-start-here.md、docs/current-state.md。
  • 决策:
    • 存储拆两层:应用设置 config.json + 业务数据 SQLite cmshopee.db,取代早期 accounts.json。
    • GUI 双 Tab:Tab1 Excel 批量(导入/列表/执行/导出),Tab2 账号管理(密码加密仅参考、登录检测)。
    • 账号↔任务绑定以 Excel“别名”列为权威(弃文件名);未匹配略过,结束弹窗汇总。
    • Excel 模板列:别名/商品id/新标题/新封面图片路径/旧标题(留档)/旧封面图片路径(留档)/更新状态(输出结果)。
    • 是否提交更新由 Tab1 批次级开关控制,默认关;多账号串行、单条失败继续。
    • 密码不自动登录、仅参考、加密存;人工登录 + 程序检测登录态。
    • 引入 openpyxl;DB/config/用户数据目录均 gitignore。
  • 下一步:从 Phase 0 起步(T-001 editor.py / T-002 appconfig / T-003 db.py,任选其一)。

【2026-06-25】修正 · 旧数据为程序输出 + 回写时机 + 文件锁

  • 状态:DONE(仅文档修正)
  • 变更:docs/04-architecture.md(4.2 schema 注释、4.3 列性质、3.x 关键事实、5.1 流程)、docs/api.md(run_task 抓旧值、update_task_result 加旧数据参数、export_results→write_back 回写原文件 + export_copy 退路)、docs/06-tasks.md(T-303/304/305)、docs/02-requirements.md(功能行 + 决策表)。
  • 决策修正:
    • 「旧标题/旧封面」由“运营输入/留档”改为 程序改动前抓取的快照(输出列),用于审计/回滚。
    • SQLite 逐条实时写回(每条任务处理完立即写状态+旧数据),不是批末统一写。
    • Excel 回写到原文件:该 Excel 全部任务完成后,批量把旧数据+更新状态写回原 .xlsx;原文件被锁则提示关闭重试或 export_copy 另存副本。SQLite 为事实来源。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】扩展 · 5 Tab 流水线 + AI 生成 + 采集回写 + 首次引导

  • 状态:DONE(仅文档)
  • 变更:重写 docs/routes.md(5 Tab + AI生成界面)、docs/04-architecture.md(流水线/ai 模块/采集/本地图片目录/扩展 tasks schema)、docs/api.md(新增 ai 模块、editor 加采集 read_cover/download_cover/collect、db 拆 set_collected/generated/confirmed/applied)、docs/06-tasks.md(Phase 0-5 按 5 Tab 重排);增量更新 docs/02-requirements.md、docs/03-tech-stack.md(AI 依赖待定)、docs/00-ai-start-here.md、docs/current-state.md。
  • 决策:
    • GUI 定为 5 Tab,工作流优先顺序:① 导入采集 ② AI生成 ③ 更新shopee ④ 账号管理 ⑤ 设置。
    • 流水线五阶段:imported→collected→generated→confirmed→applied,stage 字段贯穿。
    • 「采集」只读抓旧标题+下载旧封面到本地并回写 Excel;「旧数据」为程序输出(已确认)。
    • 新增 AI:提示词+旧标题→新标题、提示词+旧封面→新封面(image-to-image);服务商/模型待定;产出必须人工确认才进更新。
    • Excel 增 账号名 输入列;输出列扩为 旧标题/旧封面/新标题/新封面/更新状态。
    • 本地 images/<slug>/<item_id>_old|_new 存图,路径记 DB;images/ 加 gitignore。
    • 首次未配账号/未登录:① ③ 执行按钮禁用并提示去④。
  • 待确认:AI 服务商/模型/计费/合规;密码与 AI Key 加密密钥来源。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】增补 · Tab① 导入汇总栏

  • 状态:DONE(文档 + 效果图)
  • 变更:docs/routes.md(Tab① 加导入汇总栏 + 说明)、docs/02-requirements.md(功能加“导入校验汇总”)、docs/api.md(import_tasks 返回 stats、新增 match_summary)、docs/06-tasks.md(新增 T-202b)、docs/ui/tab1-import-collect.svg(加汇总栏)。
  • 决策:导入多个 Excel 后即时展示 文件数/解析行数/有效/无效/匹配(按账号细分)/未匹配,作为跑采集前的校验关口;未匹配/无效可点击在列表筛出。与执行后的“结束弹窗汇总”互补。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】简化 · 去掉人工确认 + 去掉提交开关 + Tab② 左右布局

  • 状态:DONE(文档;SVG 同步)
  • 变更:docs/04-architecture.md(流水线去 confirmed、schema 删 confirmed 列、config 删 commit_update_default、5.x/6.x 流程、第七/十节)、docs/api.md(删 set_confirmed、apply_task 去 commit 参数恒提交、ai 说明)、docs/routes.md(Tab② 左右布局无确认、Tab③ 去开关/改“已生成”、流程/组件)、docs/06-tasks.md(T-302/303/401/402、里程碑)、docs/02-requirements.md、docs/03-tech-stack.md、docs/00-ai-start-here.md、docs/current-state.md;SVG tab2/tab3/overview。
  • 决策(用户拍板):
    • 去掉人工确认:流水线 imported→collected→generated→applied(删 confirmed 阶段)。
    • 去掉提交开关:③ 执行即点「更新」总是提交线上。
    • Tab② 改左右布局:左 ~1/4 提示词(标题/封面),右 筛选(批次/店铺)+任务列表(店铺/商品id/旧标题/新标题),双击弹窗看新旧封面(纯查看);底部「开始生成」。
    • 新标题不可编辑,直接用 AI 输出。
    • 已知并接受风险:AI 标题/封面经 ③ 直接上线无核对,本地留档+回写 Excel 为唯一追溯。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】AI 生成 · 并发参数 + 单按钮两段式

  • 状态:DONE(文档 + SVG)
  • 变更:docs/04-architecture.md(config.json ai 段加 title_concurrency/image_concurrency/retry/resolution/jpg_quality;6.2 两段式并发流程)、docs/api.md(gen_title/gen_cover 加重试/分辨率/质量、新增 generate_batch 并发编排、ai_config 字段)、docs/routes.md(Tab② 单按钮+停止+进度、参数移⑤、⑤ 设置补参数)、docs/06-tasks.md(T-301/303/501)、docs/03-tech-stack.md(concurrent.futures 并发、Pillow 存盘);SVG tab2(单按钮+停止+进度、参数移⑤)、tab5(AI 段加 5 参数)。
  • 决策(用户):
    • 配置(⑤)新增:标题并发数、图片并发数、失败重试次数、分辨率、jpg 质量。
    • Tab② 单个「开始生成」+「停止」;点击后先按 title_concurrency 并发生成标题,接着按 image_concurrency 并发生成图片;进度显示 标题/封面/失败。
    • 每条/每张完成即写库;停止取消未开始项,可继续。并发用 concurrent.futures.ThreadPoolExecutor。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】AI 生成 · 提示词管理

  • 状态:DONE(文档 + SVG)
  • 变更:docs/04-architecture.md(存储加 title_prompt.txt + prompts/cover/、6.2 提示词管理与变量、目录结构)、docs/api.md(新增 prompts 模块:标题存取、封面模板 CRUD、render_prompt)、docs/routes.md(Tab② 左侧提示词管理说明)、docs/02-requirements.md(提示词管理功能行)、docs/06-tasks.md(T-302p)、SVG tab2(标题加保存、封面加模板下拉+图标工具栏+插入标题/预览)。
  • 决策(用户):
    • 标题提示词:单文件 title_prompt.txt +「保存」;启动回显。
    • 封面提示词:多模板,存 prompts/cover/<名>.txt;下拉 + 图标工具栏(新建/保存/另存为/重命名/删除)+「插入标题」(=插 {新标题})+「预览」。
    • 变量 {旧标题}/{新标题}/{商品id}/{店铺},生成前 render_prompt 替换;预览=替换后查看。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-25】更新shopee · 加批次/店铺/状态筛选

  • 状态:DONE(文档 + SVG)
  • 变更:docs/routes.md(Tab③ 加筛选栏 + 「开始更新」作用于当前筛选 + 状态=失败重试说明)、docs/02-requirements.md(③ 功能行)、docs/06-tasks.md(T-401)、SVG tab3(顶部加批次/店铺/状态筛选行,表与按钮下移避让)。
  • 决策(用户):③ 与 ①② 一致加筛选;店铺筛选利于逐店铺更新,状态筛选用于失败重试;「开始更新」仅作用于当前筛选结果(兼作范围控制/安全)。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-26】AI 模型配置 · 模型清单 + 角色分配 + 分辨率/超时

  • 状态:DONE(文档 + SVG)
  • 变更:docs/04-architecture.md(config.json ai 段改为 default_text/image_model + resolution + resolution_timeouts;新增 5.1b config/ai_models.json schema 含 category/api_type/connect_timeout;存储/目录/gitignore;6.2 模型选择与超时派生)、docs/api.md(appconfig 加 response_timeout、模型 CRUD/测试连接、get_model;ai 模块超时来源)、docs/02-requirements.md(⑤ 功能)、docs/03-tech-stack.md(AI 多模型行)、docs/06-tasks.md(T-501 模型管理 + T-501b 角色与参数);SVG tab5 重画为模型管理(master-detail)+角色下拉+分辨率/超时+路径。
  • 决策(用户 + 分析):
    • 模型清单 config/ai_models.json:每模型加 category(text/image)、唯一 name、api_type、connect_timeout_seconds(默认30,每模型)。
    • ⑤ 设置:模型下拉 + 新增/删除/测试连接 + 详情(服务商名/类别/api_type/模型ID/网址/密钥打码);至少各一个 text+image。
    • 角色:标题大模型/图片大模型下拉(按 category 过滤)→ config.json default_text/image_model。
    • 分辨率下拉 512/1k/2k/4k;返回超时由 resolution_timeouts 映射自动(180/240/360/600),不单独填。
    • 安全:密钥加密、打码、不入日志;config/ 必须 gitignore;提醒轮换已暴露的 Key。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-26】整理 · 测试脚本迁入 prototypes/

  • 状态:DONE
  • 变更:git mv 把 demo.py/set_title.py/set_cover.py/get_title.py/cookies.py/inspect_images.py/grab.py/1.py 移入 prototypes/;cdp.py 留根目录(正式模块);新增 prototypes/README.md;批量把文档里的脚本引用改为 prototypes/ 路径(含 04/00/03/05/06/api/AGENTS、current-state);修掉 config.json 里残留的 api_key_enc 描述(密钥已移至 ai_models.json)。
  • 决策:这些是已验证原型/探查脚本,逻辑待 editor.py(T-001) 移植并实测后清理;现保留为唯一已验证参照。1.py 作为 ai.py 调用方式参考。
  • 注意:prototypes/demo.py 依赖根目录 cdp.py,需从项目根运行或设 PYTHONPATH。
  • 下一步:Phase 0 起步(T-001/T-002/T-003)。

【2026-06-26】修正 · V1 提交策略 + 入口引用 + 版本边界

  • 状态:DONE(仅文档)
  • 变更:更新 AGENTS.md、CLAUDE.md、docs/00-ai-start-here.md、docs/01-vision.md、docs/02-requirements.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/05-coding-rules.md、docs/06-tasks.md、docs/routes.md、docs/current-state.md、docs/README.md、docs/api.md 与 UI 线框说明。
  • 决策:
    • ③ 更新 shopee 的提交策略统一为:点击「开始更新」后弹窗确认当前筛选范围和任务数量,用户确认后才批量更新并逐条点「更新」提交线上;取消则不执行、不改库。
    • V1 不设逐条人工审核阶段,也无常驻提交开关;批量确认弹窗是提交线上前的确认边界。
    • V0 = 已验证单账号原型;V1 = 当前 5 Tab + Excel + AI + SQLite 流水线;V2 = 多账号并行 / dry-run / 完整运行日志等后续能力。
    • CDP 已验证事实统一引用 docs/04-architecture.md 第七节。
  • 下一步:继续处理剩余全栈落地缺口,如 SQLite/Excel schema、GUI 线程模型、AI 接入任务依赖。

【2026-06-26】决策 · GUI 框架改为 PySide6

  • 状态:DONE(仅文档)
  • 变更:更新 docs/03-tech-stack.md、docs/04-architecture.md、docs/routes.md、docs/06-tasks.md、docs/api.md、docs/00-ai-start-here.md、docs/02-requirements.md、docs/05-coding-rules.md、docs/current-state.md、docs/README.md。
  • 决策:
    • V1 GUI 框架固定为 PySide6(Qt for Python),不再使用 Tkinter。
    • 理由:当前环境已安装 PySide6,Tkinter 不可导入;V1 需要表格、图片预览、后台任务进度、停止按钮、确认弹窗,Qt 的 QThread + signal/slot 更适合。
    • GUI 线程模型:主线程只操作 Qt widget;采集/生成/更新/回写使用 QObject worker + QThread;worker 通过 signal 回传 progress/log/row_updated/failed/finished/cancelled;worker 不直接操作 QWidget,不跨线程共享 SQLite connection。
    • 新增 workers.py 作为可选模块承载 PySide6 worker/QThread 编排。
  • 下一步:继续处理 SQLite/Excel schema 与 AI 接入任务依赖。

【2026-06-26】补强 · 数据模型 / AI 顺序 / 测试 / SQLite 并发 / 明文敏感信息

  • 状态:DONE(仅文档)
  • 变更:更新 docs/04-architecture.md、docs/api.md、docs/06-tasks.md、docs/03-tech-stack.md、docs/05-coding-rules.md、docs/00-ai-start-here.md、docs/02-requirements.md、docs/current-state.md、docs/routes.md、AGENTS.md、CLAUDE.md 与 UI 线框。
  • 决策:
    • 数据模型补强:新增 batches 表;tasks 增加 source_file_abs/source_sheet/source_row/row_key、stage/status 分离、时间戳、attempts、last_error,用于可靠回写、重试与断点续跑。
    • SQLite 并发:每个 worker 独立 connection;统一 foreign_keys=ON、journal_mode=WAL、busy_timeout=5000、synchronous=NORMAL;短事务单条提交。
    • AI 顺序:先做 T-005 AI 模型清单后端,再做 T-301 真实 AI 接入;T-501 只做设置页 UI。
    • 测试策略:引入 tests/ + stdlib unittest 基座,优先覆盖 appconfig/db/excel/prompts 纯逻辑;CDP/Shopee/真实 AI 作为集成或手动验证。
    • 不做加密:密码与 AI Key 本地明文保存,文件必须 gitignore;UI 打码,日志/导出脱敏,不自动登录。
  • 下一步:继续按任务看板从 Phase 0 开始实现,建议优先 T-003/T-006 或 T-001。

【2026-06-26】修正 · 任务领取规则与 tests 命令时机

  • 状态:DONE(仅文档)
  • 变更:更新 docs/current-state.md、docs/00-ai-start-here.md、docs/05-coding-rules.md、docs/03-tech-stack.md、docs/06-tasks.md、AGENTS.md。
  • 决策:
    • 任务领取规则统一为:每轮只取 docs/06-tasks.md 中第一个 TODO 且依赖均 DONE 的任务;current-state.md 只能展示按该规则计算出的当前任务,不能写“任选”。
    • 当前下一个可领取任务修正为 T-001;T-002/T-003 虽无依赖,但排在 T-001 后,不能跳过。
    • tests/ 与 python -m unittest discover -s tests 由 T-006 建立;T-006 前缺少 tests/ 不算验证失败,T-006 后纯逻辑改动必须补测并运行该命令。
  • 下一步:按任务看板领取 T-001。

【2026-06-26】修正 · 敏感文件清单与 Excel 容错策略

  • 状态:DONE(仅文档)
  • 变更:更新 AGENTS.md、CLAUDE.md、docs/05-coding-rules.md、docs/06-tasks.md、docs/current-state.md、docs/api.md、docs/02-requirements.md、docs/04-architecture.md。
  • 决策:
    • gitignore/禁止提交清单统一为:config.json、config/ai_models.json、cmshopee.db、chrome_user_data_dir/、images/。
    • current-state.md 的待建数据路径补齐 config/ai_models.json 与 images/。
    • Excel 导入容错定稿:必需列缺失(别名/商品id)时拒绝整个文件;单行缺值或商品id格式错误等脏数据逐行跳过,计入 invalid,不阻塞同文件其他有效行。
  • 下一步:按任务看板领取 T-001。

【2026-06-26】决策 · 正式代码迁入 app 包

  • 状态:DONE(仅文档)
  • 变更:更新 AGENTS.md、docs/00-ai-start-here.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/05-coding-rules.md、docs/06-tasks.md、docs/current-state.md、docs/api.md、prototypes/README.md。
  • 决策:
    • 正式代码统一放入 app/ 包,根目录只保留 main.py、配置/数据目录、文档和原型目录。
    • cdp.py 由根目录迁入 app/cdp.py;包内模块优先使用相对导入,根入口使用 from app.gui import main。
    • 新增 T-000 作为首个任务:创建 app/、迁移 CDP、补 app/__main__.py 和 main.py,并修正 prototypes/demo.py 导入。
    • 正式启动入口为 python main.py,开发/包入口为 python -m app。
  • 下一步:按任务看板领取 T-000。

【2026-06-26】T-000 正式代码包结构

  • 状态:DONE
  • 变更:创建 app/ 包;将根目录 cdp.py 迁入 app/cdp.py;新增 app/__init__.py、app/__main__.py、app/gui.py 占位入口、根目录 main.py;修改 prototypes/demo.py 改为从项目根导入 app.cdp;同步 docs/06-tasks.md 与 docs/current-state.md。
  • 验证:py -3 -m compileall app main.py 通过;python main.py 输出 GUI 未实现提示并退出;py -3 main.py 输出同样提示并退出;py -3 -m app 输出同样提示并退出;py -3 -c "import prototypes.demo" 通过。
  • 决策:app/gui.py 只保留最小入口占位,不提前实现 PySide6 主窗口,完整 GUI 留给 T-104;app/cdp.py 对 requests / websocket-client 改为按需导入,使包导入不依赖外部库,真正连接 CDP 时仍要求安装依赖。
  • 注意:本机 python 指向 Python 3.7.9 isolated,不符合项目 Python 3.10+ 要求,且 python -m app 不搜索当前目录;本轮用 py -3(Python 3.14.4)完成包入口验证。
  • 下一步:按任务看板领取 T-001。

【2026-06-26】T-001 editor 模块化

  • 状态:DONE
  • 变更:新增 app/editor.py,封装 is_logged_in/open_product/read_title/read_cover_src/download_cover/collect/change_title/replace_cover/click_update/apply_task;app/cdp.py 增加 host 参数,支持后续按账号端口连接;更新 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 验证:
    • py -3 -m compileall app main.py 通过。
    • python main.py 输出 GUI 未实现提示并退出。
    • py -3 -c "import app.editor as e; ..." 导入通过,apply_task 可调用。
    • 测试商品 51100639510:open_product + read_title 读到标题;change_title 写回原标题后 value == modelvalue == 原标题。
    • 测试商品 51100639510:read_cover_src 读到第一张封面 CDN 链接。
    • 测试商品 51100639510:使用 1_TY030.jpg 执行 replace_cover,上传成功并拖到第 0 位,返回 ok=True;全程未点击「更新」。
  • 决策:满 9 张封面的删除确认框仍未实测,replace_cover 当前返回 FULL_IMAGE_SLOTS,实际删第一张流程留给 T-502。
  • 注意:本轮真实页面验证使用本机 python(3.7.9,已装 requests/websocket-client)连接 CDP;项目版本要求仍为 Python 3.10+,后续开发优先用 py -3 并补齐依赖。
  • 下一步:按任务看板领取 T-002。

【2026-06-27】T-002 appconfig 应用配置

  • 状态:DONE
  • 变更:新增 app/appconfig.py,实现 config.json 默认配置、缺失时写默认、读取/保存/合并更新、路径/端口/CDP 等待时间/AI 参数读取、按分辨率派生返回超时;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 配置边界:config.json 只保存应用路径、端口、AI 角色选择与生成参数;api_key / *_key / token / password 等敏感字段写入时抛 ConfigError,AI Key 仍留给 T-005 的 config/ai_models.json。
  • 验证:py -3 -m compileall app main.py 通过;临时 config.json 的 load_config / update_config / response_timeout 验证通过;尝试写入 api_key 返回 ConfigError: config.json 不允许保存敏感字段: api_key。
  • 注意:python -m unittest discover -s tests 仍等 T-006 建立测试基座后再运行。
  • 下一步:按任务看板领取 T-003。

【2026-06-27】T-003 SQLite 持久化地基

  • 状态:DONE
  • 变更:新增 app/db.py,按架构 5.2 建立 batches、accounts、tasks 三张表和索引;实现 connect/init_db、批次、账号、任务导入、任务筛选,以及 mark_running/mark_failed/mark_skipped/set_collected/set_generated/set_applied;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 连接规则:connect() 设置 foreign_keys=ON、journal_mode=WAL、busy_timeout=5000、synchronous=NORMAL、row_factory=sqlite3.Row;每个函数默认短事务写入并提交,worker 后续可按线程自建 connection。
  • 阶段规则:失败和跳过只更新 status/last_error/attempts,stage 保持最后成功阶段;成功采集/生成/应用分别推进到 collected/generated/applied。
  • 验证:py -3 -m compileall app main.py 通过;临时 SQLite 文件中重复 init_db 通过;PRAGMA 输出 (1, 'wal', 5000);批次/账号/任务写入、失败状态、采集/生成/应用阶段推进验证通过。
  • 注意:python -m unittest discover -s tests 仍等 T-006 建立测试基座后再运行。
  • 下一步:按任务看板领取 T-004。

【2026-06-27】T-004 本地数据 gitignore

  • 状态:DONE
  • 变更:校准 .gitignore,明确排除 config.json、config/ai_models.json、cmshopee.db、chrome_user_data_dir/、images/;保留本地测试图片与临时启动脚本忽略项;同步 docs/06-tasks.md、docs/current-state.md。
  • 决策:将原来的 config/ 整目录忽略收窄为 config/ai_models.json,与文档安全红线保持一致,避免后续非敏感模板或说明文件被误隐藏。
  • 验证:git check-ignore -v -- config.json config/ai_models.json cmshopee.db chrome_user_data_dir/ images/ 五个路径均命中仓库 .gitignore;命令同时提示全局 ignore 文件权限不可读,但不影响仓库规则生效。
  • 下一步:按任务看板领取 T-005。

【2026-06-27】T-005 AI 模型清单后端

  • 状态:DONE
  • 变更:扩展 app/appconfig.py,实现 config/ai_models.json 默认清单、读写、增删改、category 过滤、展示打码、get_model 明文返回、最小请求测试连接;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 安全边界:list_ai_models() 默认只返回打码 api_key 和 api_key_set;只有 get_model() 返回明文 key 给实际调用层;所有 key 只写入 gitignored 的 config/ai_models.json。
  • 约束:模型 name 唯一;category 只允许 text/image;api_type 只允许 chat/images_edits/auto;保存后必须至少有一个启用的 text 和一个启用的 image 模型。
  • 验证:py -3 -m compileall app main.py 通过;临时 ai_models.json 默认写入、分类过滤、key 打码、get_model 明文 key、重命名/禁用、缺少 url/model/key 的测试连接错误返回均通过;重复 name 与删除最后 image 模型均返回 ConfigError。
  • 注意:本轮未使用真实 API Key 发外部网络请求;真实「测试连接」需用户在本地 config/ai_models.json 填入有效 url/model/api_key 后由 UI 或函数触发。
  • 下一步:按任务看板领取 T-006。

【2026-06-27】T-006 单元测试基座

  • 状态:DONE
  • 变更:新增 tests/ 基座,包含 _helpers.py、test_appconfig.py、test_db.py、test_module_contracts.py;覆盖 config.json 默认/更新/敏感字段拦截、config/ai_models.json CRUD/过滤/打码/约束、SQLite 初始化/PRAGMA/账号批次任务生命周期/失败状态;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 补强:config.json 敏感字段拦截从 exact token/password 扩展到 *_token、*_password,测试覆盖 provider_token。
  • 说明:app.excel 与 app.prompts 尚未实现,test_module_contracts.py 对这两个模块做契约占位测试;当前表现为 2 个 skip,后续模块文件出现后会检查公开函数是否齐全。
  • 验证:py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(9 tests,skipped=2);python -m unittest discover -s tests 通过(9 tests,skipped=2);测试临时目录位于 tests/ 下并已清理。
  • 下一步:按任务看板领取 T-101。

【2026-06-27】T-101 账号 slug 与 user-data-dir

  • 状态:DONE
  • 变更:新增 app/config.py,实现 make_slug(alias) 与 ensure_user_data_dir(slug, root=None, config=None);app/db.py 改为复用同一 slug 生成规则;新增 tests/test_config.py 覆盖 slug 稳定性、非 ASCII 别名、非法 slug 拒绝、目录创建与绝对路径;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 规则:slug = 可读 ASCII 前缀 + 8 位 SHA1 后缀;非 ASCII 别名使用 account_<hash>;ensure_user_data_dir 只接受 [a-z0-9_],防止路径穿越。
  • 验证:py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(12 tests,skipped=2);python -m unittest discover -s tests 通过(12 tests,skipped=2);测试临时目录已清理。
  • 下一步:按任务看板领取 T-102。

【2026-06-27】T-102 Chrome 启动器

  • 状态:DONE
  • 变更:新增 app/chrome.py,实现 build_launch_args、launch_chrome、is_running、wait_debug_ready;启动参数包含 --remote-debugging-port、--remote-allow-origins=*、--user-data-dir;新增 tests/test_chrome.py 覆盖参数拼装、Popen 调用模拟、本地 /json/version 端口探测;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:端口探测使用 stdlib urllib 访问 127.0.0.1:<port>/json/version,显式禁用环境代理,避免 localhost/CDP 被代理干扰。
  • 范围:本轮不实现 .lnk 快捷方式,留给 T-106。
  • 验证:py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(17 tests,skipped=2);python -m unittest discover -s tests 通过(17 tests,skipped=2)。
  • 下一步:按任务看板领取 T-103。

【2026-06-27】T-103 登录保活与检测

  • 状态:DONE
  • 变更:增强 app/editor.py 登录检测,新增 login_status(account, timeout=8) 返回 logged_in/reason/url/host/cookie_names,is_logged_in() 保持 bool 包装;无 Shopee tab 时打开卖家中心用于检测/人工登录;新增 tests/test_editor_login.py 覆盖登录页、会话 Cookie、缺 Cookie、无 Shopee tab 创建检测页;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 规则:不自动登录、不填密码;登录态依赖 T-101/T-102 的稳定 user-data-dir 保留;URL 命中登录页返回 LOGIN_PAGE,缺 SPC_ST/SPC_U 返回 NO_SESSION_COOKIE。
  • 验证:py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(22 tests,skipped=2);python -m unittest discover -s tests 通过(22 tests,skipped=2)。
  • 下一步:按任务看板领取 T-104。

【2026-06-27】T-104 PySide6 五 Tab 主窗口骨架

  • 状态:DONE
  • 变更:将 app/gui.py 从占位入口升级为 PySide6 MainWindow(QMainWindow),内含固定顺序 QTabWidget 五 Tab:①导入采集、②AI生成、③更新shopee、④账号管理、⑤设置;实现基础状态栏与 Tab 切换状态提示;新增 tests/test_gui.py 覆盖 Tab 顺序与状态栏;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:Tab 内容保持空壳容器,不提前实现后续业务 UI;缺 PySide6 时 main() 返回 1 并输出明确提示,便于依赖诊断。
  • 验证:py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(23 tests,skipped=3,其中 GUI 因 py -3 缺 PySide6 跳过);python -m unittest discover -s tests 通过(24 tests,skipped=2,实际 offscreen 创建 MainWindow);默认 python 的 PySide6 版本为 6.5.3。
  • 下一步:按任务看板领取 T-104b。

【2026-06-27】审查 · T-001~T-103(含 T-000/T-004/T-005/T-006)

  • 状态:DONE(审查通过)
  • 结论:按文档完成、忠实于已验证 CDP 事实、文档↔代码一致、22 测试通过;未臆造未验证内容(满 9 张删除留 T-502)。
  • 待办:app/editor.py 接 GUI(T-104+)前,建议用 prototypes 同款环境做一次真机冒烟(本轮测试均为 mock CDP,未连真实 Shopee)。
  • 完整报告:docs/reviews/2026-06-27-T001-T103-acceptance.md

【2026-06-27】T-104b PySide6 worker 基座

  • 状态:DONE
  • 变更:新增 app/workers.py,实现 BaseWorker(QObject)、progress/log/row_updated/failed/finished/cancelled 通用 signals、协作式取消标记 cancel()/should_cancel()、统一 run() 执行入口与 run_worker() QThread 包装;新增 tests/test_workers.py 覆盖 signal 回传、取消、异常转失败、普通对象拒绝;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md、docs/04-architecture.md。
  • 细节:workers.py 不导入 QtWidgets,业务 worker 子类只能通过 signal 回传 UI 所需数据;run_worker() 默认启动线程,也支持 start=False 便于测试或调用方先连接额外信号;缺 PySide6 时抛明确 WorkerError,测试自动 skip。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(28 tests,skipped=2);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(24 tests,skipped=4,其中 GUI/worker 因 py -3 缺 PySide6 跳过)。
  • 下一步:按任务看板领取 T-105。

【2026-06-27】T-105 Tab④ 账号管理

  • 状态:DONE
  • 变更:新增 app/accounts.py 账号管理服务层,封装账号新增/编辑/删除、slug 与 user-data-dir 创建、端口默认分配、启动登录、登录检测与 last_login_at 更新;app/db.py 支持账号别名更新并把唯一约束错误转为 DbError;app/gui.py 将 ④ Tab 替换为账号表格、账号编辑弹窗、启动登录与检测登录按钮,检测登录通过 BaseWorker 后台执行;新增/更新 tests/test_accounts.py、tests/test_gui.py;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md、docs/04-architecture.md。
  • 细节:密码只在 DB 本地明文保存与弹窗密码框中打码显示,账号表格不展示密码;账号服务层校验调试端口不重复;「启动登录」只启动对应 user-data-dir 的 Chrome,人工登录,不读取/填写/提交密码;删除账号只删 DB 记录,不删除本地 user-data-dir。
  • 追加收尾:运行最新 GUI 后发现顶部 5 个 Tab 间距偏紧,容易误点;已在 MainWindow 应用全局 TAB_STYLE,包含 Tab 最小宽度、padding、间距、hover 与当前态高亮,并补测试防止后续误删。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过;py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过;本轮未连接真实 Shopee/CDP 做登录检测实跑,登录检测路径由 mock 覆盖。
  • 下一步:按任务看板领取 T-106(可选)。

【2026-06-27】T-106 账号桌面快捷方式

  • 状态:DONE
  • 变更:app/chrome.py 新增 create_shortcut(),复用 build_launch_args() 生成 Chrome 目标与参数,并通过 PowerShell WScript.Shell.CreateShortcut 写 .lnk;app/accounts.py 新增 create_shortcut() 服务包装;app/gui.py 在 ④ 账号管理增加「快捷方式」按钮,选中账号后生成默认桌面快捷方式并提示路径;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md、docs/routes.md。
  • 细节:快捷方式参数包含 --remote-debugging-port、--remote-allow-origins=*、--user-data-dir=<该账号目录>;不包含账号密码/API Key;测试 mock PowerShell 调用,不在测试环境真实写桌面。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过;py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过。
  • 下一步:按任务看板领取 T-201。

【2026-06-27】审查 · T-104~T-106(含 T-104b)

  • 状态:DONE(审查通过)
  • 结论:按文档完成;5 Tab 顺序/降级、worker 6 信号与线程纪律、账号④增删改/打码/不自动登录、.lnk 含账号参数均对上;33 测试通过(skipped=4 为 excel/prompts 契约测试)。
  • 待办:账号启动登录、快捷方式、登录检测本轮均为 mock;接 Phase 2(T-201/T-203 真连 CDP)前,建议 editor.py 真机冒烟 + 账号④走一遍(新增→启动→人工登录→检测→生成快捷方式)一起验。
  • 完整报告:docs/reviews/2026-06-27-T104-T106-acceptance.md

【2026-06-27】T-201 Excel 导入入库

  • 状态:DONE
  • 变更:新增 app/excel.py,实现多 Excel 文件导入、输入列解析、必需列校验、脏行跳过、batches/tasks 入库、导入统计与 match_summary();新增 tests/test_excel.py 覆盖有效/无效行、缺必需列整文件拒绝、DB 写入和别名匹配统计;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:输入列只解析 账号名(可选)、别名、商品id;有效行记录 source_file/source_file_abs/source_sheet/source_row/row_key;缺 别名 或 商品id 的非空工作表会拒绝整个文件并写入 file_errors;单行缺别名、缺商品 id 或商品 id 非数字会跳过并计入 invalid/row_errors。write_back() 与 export_copy() 本轮只保留可调用占位,实际回写留给 T-204/T-403。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(45 tests,skipped=1,默认 python 环境已安装 openpyxl 并执行真实 Excel 解析测试);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过,app.excel 契约测试通过)。
  • 注意:本轮不涉及 Shopee/CDP 页面改动,无需测试商品实跑。目录中未跟踪的本地 Excel 文件未处理、未纳入本次变更。
  • 下一步:按任务看板领取 T-202(Tab① 任务列表 + 导入按钮 + 别名匹配标记)。

【2026-06-27】T-202 Tab① 任务列表 + 导入按钮 + 别名匹配标记

  • 状态:DONE
  • 变更:app/gui.py 新增 CollectTab 与 TaskTableModel(QAbstractTableModel);① 导入采集 Tab 接入「导入 Excel...」按钮、QTableView 任务列表和刷新按钮;导入时调用 excel.import_tasks(file_paths, path=db_path) 并展示当前批次任务;任务表列为账号、别名、商品ID、阶段,别名未匹配账号时阶段显示“略过”。更新 tests/test_gui.py 覆盖 Tab① 接入、任务展示、未匹配略过和导入按钮刷新;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:账号列优先显示匹配到的 accounts.account_name,未匹配时保留 Excel 输入账号名;T-202 只做 UI 标记,不把未匹配任务立即写库为 skipped,实际跳过与原因入库留给 T-203 采集执行阶段。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(8 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(47 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 注意:本轮只改 GUI/DB 展示与 Excel 导入入口,不涉及 Shopee/CDP 页面操作,无需测试商品实跑。
  • 下一步:按任务看板领取 T-202b(Tab① 导入汇总栏)。

【2026-06-27】补充 · 标准 Excel 模板入库规则

  • 状态:DONE(文档/忽略规则补充)
  • 变更:将根目录 shopee待处理任务模板.xlsx 整理为可提交的标准空模板(单工作表 待处理任务,含输入列与后续输出列);更新 .gitignore,默认忽略运营填写后的 *.xlsx/*.xlsm 业务文件与 Excel 临时锁文件,但放行该标准模板;同步 AGENTS.md、docs/04-architecture.md、docs/api.md、docs/current-state.md、docs/05-coding-rules.md。
  • 决策:标准模板推荐表头固定为 账号名 | 别名 | 商品id;别名 必须与 ④ 账号管理中的别名一致;运营实际填写时复制模板另存,填写后的副本不进版本库。
  • 验证:只读检查 shopee待处理任务模板.xlsx 可被当前 app.excel 识别核心列(账号名/别名/商品id),file_errors=[]、row_errors=[];本轮未导入数据库。

【2026-06-27】T-202b Tab① 导入汇总栏

  • 状态:DONE
  • 变更:app/gui.py 的 CollectTab 增加导入汇总栏,展示文件数、解析行数、有效/无效、匹配、未匹配;增加按账号的匹配明细;TaskTableModel 支持 all/unmatched 过滤,「未匹配(n)」按钮可筛出别名未匹配账号的任务,「全部」恢复完整列表。更新 tests/test_gui.py 覆盖汇总文本、匹配明细和未匹配筛选;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:汇总栏的无效行数量来自本次 excel.import_tasks() 返回的 stats;未匹配数量基于当前批次任务与 ④ 账号管理中的 accounts.alias 实时计算。未匹配在本阶段仍只做 UI 标记,不写库为 skipped,实际跳过留给 T-203 采集执行阶段。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(9 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(48 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 注意:本轮只改 GUI 汇总与过滤,不涉及 Shopee/CDP 页面操作,无需测试商品实跑。
  • 下一步:按任务看板领取 T-203(采集旧标题+旧封面,只读下载并立即写库)。

【2026-06-27】T-203 采集旧标题+旧封面

  • 状态:DONE
  • 变更:app/gui.py 新增 CollectWorker,Tab① 增加「采集旧标题/旧封面」与「停止」按钮;worker 逐条处理 stage=imported 任务,别名未匹配写 db.mark_skipped(..., "别名未匹配账号"),已登录则调用 editor.collect() 下载旧封面到 image_dir/<slug>/<item_id>_old.jpg 并 db.set_collected();单条失败 mark_failed(..., "collect", error) 后继续。T-203 当时覆盖了未登录逐条兼容分支;最终 Phase 2 语义已在 T-205 调整为匹配账号未登录由采集前预检阻断,不进入逐条采集。更新 tests/test_gui.py 覆盖成功采集、preflight=False 兼容分支、未匹配略过;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:采集通过 BaseWorker/QThread 后台执行,使用 signal 回传进度、行更新、失败和完成;GUI 线程只刷新表格与状态栏。停止使用协作式 cancel,正在执行的单条跑到安全边界后结束。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(10 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(49 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 注意:本轮未连接真实 Shopee/CDP 实跑采集,accounts.detect_login() 与 editor.collect() 路径由 mock 覆盖;接 T-204 前建议用测试商品和已登录账号做一次 Tab① 真机采集冒烟。
  • 下一步:按任务看板领取 T-204(回写旧字段到原 Excel,含文件锁处理)。

【2026-06-27】修正 · 登录检测入口 URL

  • 状态:DONE
  • 变更:app/editor.py 将无 Shopee tab 时的登录检测入口从 https://<region_host>/portal/ 改为 https://<region_host>/,默认即 https://seller.shopee.tw/;更新 tests/test_editor_login.py、docs/api.md、docs/04-architecture.md、docs/current-state.md。
  • 决策:商品编辑页 URL 仍保持 /portal/product/<item_id>?pageEntry=product_list&ignore-html-cache=1,本轮只改登录检测/人工登录入口。
  • 验证:python -m unittest discover -s tests -p "test_editor_login.py" 通过(5 tests);python -m unittest discover -s tests -p "test_accounts.py" 通过(8 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(49 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4)。

【2026-06-27】T-204 回写旧字段到原 Excel

  • 状态:DONE
  • 变更:app/excel.py 实现 write_back() 与 export_copy():按 tasks.source_file_abs/source_sheet/source_row 定位原 Excel 行,回写 旧标题 与 旧封面图片路径;输出列缺失时自动追加;.xlsm 写入时保留 VBA;原文件被占用或无权限时抛中文 ExcelError,SQLite 采集结果不回滚。app/gui.py 在 Tab① 增加「回写旧数据到 Excel」按钮与 WriteBackWorker,后台调用 excel.write_back(),锁文件时弹窗提示关闭后重试或另存副本。更新 tests/test_excel.py、tests/test_gui.py、docs/06-tasks.md、docs/current-state.md、docs/api.md。
  • 细节:write_back(batch_id, excel_path=None, path=None) 默认按批次涉及的源文件分组回写;只写已到 collected/generated/applied 阶段或已有旧字段值的任务;无可写行时返回 rows=0。export_copy(batch_id, out_dir_or_path, path=None) 不修改原文件,目录输出时生成 *_cmshopee回写.xlsx,同名自动加序号。
  • 验证:python -m unittest discover -s tests -p "test_excel.py" 通过(7 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(11 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(53 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 注意:本轮只做 Excel 回写与 GUI 后台接入,不涉及 Shopee/CDP 页面操作,无需测试商品实跑。export_copy() 已有后端能力,Tab① 当前只在锁文件提示中说明可另存副本,尚未提供另存按钮。
  • 下一步:按任务看板领取 T-205(首次未配账号/未登录的引导保护)。

【2026-06-27】文档补充 · 采集自动回写与 Chrome 未启动引导

  • 状态:DONE(文档调整)
  • 背景:运行最新代码后发现两个体验缺口:① 采集旧标题/旧封面后仍需手动点「回写旧数据到 Excel」;② 未在④账号管理启动对应账号 Chrome 时无法采集。
  • 变更:docs/06-tasks.md 新增 T-204b(采集完成后自动回写旧字段到 Excel),并把 T-205 扩展为“未配账号 / Chrome 未启动 / 未登录”的引导保护;同步 docs/current-state.md 下一个可领取任务为 T-204b,并补充当前已发现待修体验问题;同步 docs/routes.md、docs/api.md、docs/04-architecture.md、docs/02-requirements.md。
  • 决策:T-204b 先解决采集闭环自动回写,保留手动回写作为锁文件失败后的重试入口;T-205 解决 Chrome 未启动/未登录的禁用、提示和跳转④,不做无提示批量启动所有账号 Chrome。
  • 验证:文档-only 更新,未运行单元测试。

【2026-06-27】T-204b 采集完成自动回写旧字段

  • 状态:DONE
  • 变更:app/gui.py 将 Tab① 手动回写启动逻辑抽为 _start_write_back(),CollectTab._on_collect_finished() 在本轮成功采集数量大于 0 时自动启动 WriteBackWorker 回写当前批次旧标题/旧封面路径;自动回写成功时状态栏显示“Excel 自动回写完成”;自动回写遇到原 Excel 被占用时弹窗提示关闭文件后点击「回写旧数据到 Excel」手动重试,SQLite 采集结果不回滚。更新 tests/test_gui.py 覆盖自动触发、无成功采集不触发、锁文件提示手动重试;同步 docs/06-tasks.md、docs/current-state.md、docs/api.md、docs/04-architecture.md。
  • 细节:手动「回写旧数据到 Excel」按钮保留,主要作为自动回写失败后的重试入口;若回写 worker 已在运行,会提示“Excel 回写正在进行”,避免重复启动。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(14 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(56 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 下一步:按任务看板领取 T-205(首次未配账号 / Chrome 未启动 / 未登录的引导保护)。

【2026-06-27】T-205 首次未配账号 / Chrome 未启动 / 未登录引导保护

  • 状态:DONE
  • 变更:app/gui.py 的 CollectWorker 增加采集前账号就绪预检:无账号、当前批次匹配账号 CDP 端口未响应、账号未登录时返回 blocked=True,不进入逐条采集、不写 skipped/failed;CollectTab 收到 blocked 后弹窗汇总原因,并跳转/引导用户去④账号管理配置账号、启动对应 Chrome、人工登录。MainWindow 为①传入打开④的回调;GUI 测试增加无账号、Chrome 未启动、未登录、弹窗引导覆盖。
  • 细节:预检只检查当前批次中别名能匹配到账号的任务;别名未匹配的任务仍按既有逻辑在采集 worker 中略过。设计上不无提示批量启动所有账号 Chrome,避免开错账号或启动过多浏览器进程。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(18 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(60 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(34 tests,skipped=4,py -3 环境缺 openpyxl/PySide6,相关测试按设计跳过)。
  • 下一步:按任务看板领取 T-301(确定 AI 服务商/模型并接入 app/ai.py)。

【2026-06-27】审查 · T-201~T-205(含 T-204b)

  • 状态:DONE(审查通过)
  • 验证:本机(WSL)临时装 openpyxl 后 test_excel 7/7 实跑通过、compileall 通过;GUI/worker 测试因本机无 PySide6 按测试清单+源码核对(以 Codex Windows 运行为准)。
  • 结论:T-201 导入(行定位/缺列拒文件/脏行跳过/row_key 唯一)、T-202/202b 列表与汇总栏、T-203 采集 worker、T-204 回写+锁处理+export_copy、T-204b 自动回写、T-205 账号就绪预检拦截 均按当前文档完成。
  • T-205 口径:当前文档已对齐为「预检拦截 + 弹窗说明 + 自动跳④」;实现方案接受,作为最终方案记录。匹配账号未登录由 T-205 预检 blocked=True 拦截,不进入逐条采集、不写 skipped/failed;别名未匹配仍按 T-203 逐条逻辑 mark_skipped。
  • 待办:采集/editor.collect 真连 CDP 仍未冒烟;进 Phase 3 前建议对 Tab① 做一次真机采集冒烟(导入→采集→出图→回写)。
  • 完整报告:docs/reviews/2026-06-27-T201-T205-acceptance.md

【2026-06-27】修复 · T-201~T-205 审查三点

  • 状态:DONE
  • 变更:修正评审报告中的 GUI 用例数量为 18;确认 T-205「预检拦截 + 弹窗说明 + 自动跳④」为最终方案,不再作为待决事项;同步 docs/api.md、docs/06-tasks.md、docs/current-state.md,明确匹配账号未登录由 T-205 预检 blocked=True 阻断,不进入逐条采集、不写 skipped/failed,别名未匹配仍按 T-203 mark_skipped。
  • 测试补强:tests/test_gui.py 为未登录预检分支增加断言,确认任务保持 stage=imported/status=pending/last_error=None,防止后续误写 skipped。

【2026-06-27】冒烟 · Tab① 真实采集回写

  • 状态:DONE
  • 前置:账号 papa 使用专属 Chrome user-data-dir 启动,CDP 端口 9224 就绪,accounts.detect_login() 返回已登录。
  • 验证:因原业务 Excel 正被 Excel 锁定,改用数据库现有 5 条任务生成 gitignore 的临时 Excel;执行 excel.import_tasks() 导入 5 行,CollectWorker 真连 Shopee/CDP 采集 5 条旧标题/旧封面,下载 5 张旧封面到 images/,随后 excel.write_back() 成功回写临时 Excel。
  • 结果:collect_summary {'ok': True, 'total': 5, 'done': 5, 'collected': 5, 'skipped': 0, 'failed': 0};旧标题长度非空,旧封面路径均存在。

【2026-06-27】T-301 AI 生成接口

  • 状态:DONE
  • 变更:新增 app/ai.py,实现 AIError、gen_title()、gen_cover();按 config.json 的默认文本/图片模型名读取 config/ai_models.json 明文模型定义,调用时不记录 Key;支持 retry、模型启用/字段校验、错误脱敏、OpenAI-compatible chat JSON、images_edits multipart、图片 URL/data URL/base64/b64_json 解析、按 resolution resize 并用 jpg_quality 保存 JPEG。
  • 文档:docs/06-tasks.md 将 T-301 标为 DONE;同步 docs/api.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/current-state.md,下一个可领取任务更新为 T-302。
  • 测试:新增 tests/test_ai.py,覆盖文本生成重试与 extra_body、缺字段错误不泄露 Key、图片生成保存 JPEG。
  • 验证:python -m unittest discover -s tests -p "test_ai.py" 通过(3 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(63 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests -p "test_ai.py" 通过(3 tests,skipped=1,py -3 环境缺 Pillow);py -3 -m unittest discover -s tests 通过(37 tests,skipped=5,py -3 环境缺 openpyxl/PySide6/Pillow,相关测试按设计跳过)。
  • 注意:T-301 只做通用 AI 接口与 mock 单测;真实 AI 调用还需要在 config/ai_models.json 填入可用 url/model/api_key 后做一次小样本实测。生成批次编排和 GUI 接入留给 T-303/T-302。

【2026-06-27】T-302 Tab② AI生成布局与任务列表

  • 状态:DONE
  • 变更:app/gui.py 新增 GenerateTab 与 GenerateTaskTableModel;MainWindow 的②从占位页切换为实际 AI 生成页。左侧使用 QSplitter 约 1/4 宽度放标题提示词、封面提示词两个多行输入;右侧提供批次、店铺、状态筛选和任务列表。
  • 细节:任务列表列为店铺、商品ID、旧标题、新标题、状态;店铺优先使用匹配账号名;状态将 stage=collected 显示为“待生成”、stage=generated 显示为“已生成”,并优先显示 failed/skipped/running。筛选只读 SQLite,不调用 AI、不写库。
  • 测试:tests/test_gui.py 增加 MainWindow 挂载②、提示词多行输入、任务列表展示,以及按批次/店铺/状态筛选的覆盖。
  • 文档:docs/06-tasks.md 将 T-302 标为 DONE;同步 docs/api.md、docs/current-state.md,下一个可领取任务更新为 T-302p。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(20 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(65 tests,skipped=1);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(37 tests,skipped=5,py -3 环境缺 openpyxl/PySide6/Pillow,相关测试按设计跳过)。

【2026-06-27】T-302p Tab② 提示词管理

  • 状态:DONE
  • 变更:新增 app/prompts.py,实现标题提示词 title_prompt.txt 读写、封面模板 prompts/cover/*.txt 列表/读取/保存/重命名/删除,以及 {旧标题}、{新标题}、{商品id}、{店铺} 变量替换。模板名做空值、路径分隔符、.. 与 Windows 非法字符校验;列表读取不自动创建文件。
  • GUI:GenerateTab 启动时回显标题提示词;封面提示词增加模板下拉、新建、保存、另存为、重命名、删除、插入 {新标题}、预览。预览使用选中任务渲染变量并弹窗展示;删除模板先二次确认。T-302p 仍不调用 AI、不写 SQLite,生成执行留给 T-303。
  • 测试:新增 tests/test_prompts.py;tests/test_gui.py 覆盖标题回显/保存、封面模板另存/重命名/删除、插入标题与变量预览。
  • 文档:docs/06-tasks.md 将 T-302p 标为 DONE;同步 docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-303。
  • 验证:python -m unittest discover -s tests -p "test_prompts.py" 通过(3 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(21 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(69 tests);py -3 -m compileall app main.py tests 通过;py -3 -m unittest discover -s tests 通过(40 tests,skipped=4,py -3 环境缺 openpyxl/PySide6/Pillow,相关测试按设计跳过)。

【2026-06-27】T-303 Tab② 开始生成 + 停止 + 进度

  • 状态:DONE
  • 变更:app/ai.py 新增 generate_batch() 批量编排,按 title_concurrency 先并发生成标题,再按 image_concurrency 并发生成封面;封面成功后立即 db.set_generated(),标题/封面失败 db.mark_failed(..., "generate", error),失败不阻塞其余任务;should_stop() 为真时取消未开始的 Future,被取消任务不记失败。
  • GUI:GenerateTab 底部接入「开始生成」「停止」和进度标签;开始生成只处理当前筛选结果里 stage=collected 的任务;新增 GenerateWorker 通过 signal 回传进度、行刷新、完成/取消状态;任务表双击弹窗查看旧封面与新封面对照。
  • 测试:tests/test_ai.py 覆盖 generate_batch 正常落库、单条失败不阻塞、停止前取消且任务保持 collected;tests/test_gui.py 覆盖生成控件、双击预览弹窗、GenerateWorker 调用 ai.generate_batch() 并发出 progress/row_updated。
  • 文档:docs/06-tasks.md 将 T-303 标为 DONE;同步 docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-401。
  • 验证:python -m unittest discover -s tests -p "test_ai.py" 通过(6 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(22 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(73 tests)。
  • 注意:本轮仍为 mock AI 单测,未调用真实 AI 服务;真实生成需在 config/ai_models.json 配好可用 text/image 模型后做小样本实测。

【2026-06-27】T-205b 采集后关闭自动新建商品页 tab

  • 状态:DONE
  • 背景:真机采集时发现程序为不同商品新建编辑页 tab,采集标题和封面后只断开 CDP 连接,不会关闭浏览器页面,批量采集后 Chrome 会堆积多个商品页。
  • 方案:区分“复用用户已有 tab”和“本轮程序自动新建 tab”。CDP.close() 仍只断开 WebSocket;新增 close_tab(target_id) 调 Chrome /json/close/<targetId> 关闭浏览器 target;open_product() 给 CDP 对象标记 target_id/created_by_app/cdp_host;collect() finally 中只关闭 created_by_app=True 的商品页,用户原本打开的 tab 不关闭。③ 更新流程暂不自动关页,失败时保留现场便于排查。
  • 变更:更新 app/cdp.py、app/editor.py;同步 docs/06-tasks.md、docs/04-architecture.md、docs/api.md、docs/routes.md、docs/current-state.md。
  • 测试:tests/test_editor_login.py 增加 open_product() 新/旧 tab 标记、collect() 关闭自动新建 tab、不关闭复用 tab 的覆盖。
  • 验证:python -m unittest discover -s tests -p "test_editor_login.py" 通过(9 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(77 tests)。

【2026-06-27】审查 · T-301~T-303(含 T-302p + T-205b 采集关页)

  • 状态:DONE(审查通过)
  • 验证:本机(WSL)临时装 openpyxl+Pillow 后 test_ai 6/6、test_prompts 3/3 实跑通过,全套 53 tests OK(skipped=2 仅 PySide6 的 gui/workers);GUI 测试按源码+清单核对,以 Codex Windows 运行为准。
  • 结论:T-301 ai.py(脱敏/重试/多 API 形态/两段并发/失败隔离)、T-302 Tab② 布局、T-302p prompts.py(防穿越校验+模板 CRUD+render_prompt 接入)、T-303 开始生成(先并发标题再并发封面、逐条 set_generated、停止取消未开始项、双击新旧封面对照)均按文档完成。
  • 小问题(不阻验收):标题提示词不走 render_prompt(与设计自洽,建议 UI 注明“标题提示词不支持变量”);urllib 单一 timeout 取 max(connect,read);_looks_base64 启发式。
  • 待办:gen_title/gen_cover 对真实 AI 仍 mock,未真连;进 Phase 4 前建议端到端真机冒烟(账号④登录→①真机采集出图→②真实模型各生成 1 标题+1 封面→看 images//_new.jpg 落盘与分辨率/质量)。
  • 完整报告:docs/reviews/2026-06-27-T301-T303-acceptance.md

【2026-06-27】T-401 Tab③ 更新列表 + 开始更新确认

  • 状态:DONE
  • 变更:app/gui.py 新增 ApplyTaskTableModel 与 ApplyTab,MainWindow 的③从空壳切换为更新页。③ 顶部提供批次、店铺、状态筛选,默认显示 stage=generated/status=success|pending 的已生成待更新任务;状态筛选支持失败、已更新、略过和全部。
  • 细节:③任务表列为店铺、商品ID、新标题、新封面、阶段、结果;店铺优先显示匹配账号名。候选范围只包含已具备新标题/新封面、可进入更新阶段的任务;导入/采集/生成失败但没有新字段的任务不会进入③。
  • 确认边界:点击「开始更新」只作用于当前筛选结果;弹窗展示批次、店铺、状态、任务数和提交线上风险。用户取消时不执行、不改库;用户确认后当前 T-401 只记录“已确认范围”,实际 apply_task() 串行执行留给 T-402。无常驻提交开关。
  • 测试:tests/test_gui.py 覆盖 MainWindow 挂载③、③筛选列表、失败/已更新状态展示、开始更新确认弹窗,以及确认/取消均不调用 editor.apply_task()、不改 DB。
  • 文档:docs/06-tasks.md 将 T-401 标为 DONE;同步 docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-402。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(24 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(79 tests)。

【2026-06-27】T-402 Tab③ 确认后串行更新

  • 状态:DONE
  • 变更:app/gui.py 新增 ApplyWorker,③点击「开始更新」并确认后才创建后台 worker;worker 只处理当前筛选结果里 stage=generated 且已有新标题或新封面的可执行任务,串行调用 editor.apply_task()。
  • 执行策略:更新前先做账号就绪预检;无账号、对应账号 Chrome 未启动或未登录时整体阻断并弹窗引导去④账号管理,不调用 apply_task()、不写失败状态。预检通过后逐条 mark_running(..., "apply")、执行更新、set_applied() 写库;成功推进 stage=applied/status=success/committed=1,失败保留原 stage 并写 status=failed/last_error,单条失败继续。
  • GUI:③运行中禁用筛选/刷新/开始按钮,启用「停止」;停止使用 worker 协作式 cancel(),已开始单条跑到安全边界后结束。未匹配账号任务逐条 mark_skipped(),原因 别名未匹配账号。结果回写 Excel 和结束弹窗汇总留给 T-403。
  • 测试:tests/test_gui.py 调整 T-401 确认测试为“取消不启动”和“确认启动 ApplyWorker”;新增 ApplyWorker 成功/失败/略过串行写库、Chrome 未启动预检阻断、③阻断弹窗引导④的覆盖。
  • 文档:docs/06-tasks.md 将 T-402 标为 DONE;同步 docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-403。
  • 验证:python -m unittest discover -s tests -p test_gui.py 通过(28 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(83 tests)。

【2026-06-27】T-403 Tab③ 结果回写与结束汇总

  • 状态:DONE
  • 变更:app/excel.py 新增 write_back_results(),按 source_file_abs/source_sheet/source_row 把新标题、新封面图片路径、更新状态写回原 Excel;更新状态输出为“成功 / 失败:原因 / 略过:原因 / 待更新”。write_back() 仍保持旧标题/旧封面回写给①使用。
  • GUI:ApplyTab 在 ApplyWorker 完成后自动启动 WriteBackWorker(mode="results") 回写结果;成功后弹窗汇总成功/失败/略过数量与 Excel 回写文件/行数;文件被占用时提示关闭原 Excel 后点击「回写结果到 Excel」手动重试,SQLite 更新结果不回滚。③的「回写结果到 Excel」按钮作为手动重试入口。
  • Worker:WriteBackWorker 增加 mode,默认 old 兼容①旧字段回写,results 调用 excel.write_back_results();支持单批次或批次列表。
  • 测试:tests/test_excel.py 覆盖结果字段与三种更新状态写回;tests/test_gui.py 覆盖③自动结果回写、结束汇总弹窗、文件锁手动重试提示、WriteBackWorker(mode="results") 调用;模块契约加入 write_back_results。
  • 文档:docs/06-tasks.md 将 T-403 标为 DONE;同步 docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-501。
  • 验证:python -m unittest discover -s tests -p test_excel.py 通过(8 tests);python -m unittest discover -s tests -p test_gui.py 通过(32 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(88 tests)。

【2026-06-27】审查 · T-401~T-403(Phase 4 更新 Shopee)

  • 状态:DONE(代码层面审查通过)
  • 验证:本机(WSL)装 openpyxl+Pillow 后 test_excel 8/8 实跑通过(含 write_back_results),全套 54 tests OK(skipped=2 仅 PySide6);UpdateTab/ApplyWorker 9 个 GUI 用例按源码+清单核对,以 Codex Windows 运行为准。
  • 结论:T-401 三筛选+「开始更新」仅作用当前筛选+确认弹窗(批次/店铺/状态/任务数/线上风险,取消不执行);T-402 确认门控(未确认不调 apply)+串行 apply+单条失败继续+预检引导+逐条 set_applied;T-403 自动 write_back_results 回写新标题/新封面/更新状态(锁处理)+结束弹窗汇总。均按文档完成。失败任务保留 stage=generated 可重试,闭环正确。
  • 小问题:③ 不自动关 tab,批量后堆积编辑页(有意决策,V2 可优化);_is_update_task(显示)⊇ _is_actionable_task(执行),建议加注释防误改。
  • ⚠️ 关键边界:T-402 是唯一不可逆、真提交线上的步骤,但 apply_task→change_title/replace_cover/click_update 全程 mock,真机冒烟为 0。强烈建议真批量前做单条端到端冒烟(④登录→①采集→②生成→③只选1条确认提交→看线上改动+Excel 回写=成功),作为 Phase 4 正式验收门槛。
  • 完整报告:docs/reviews/2026-06-27-T401-T403-acceptance.md

【2026-06-27】复核 · Phase 4 冒烟策略延后

  • 状态:DONE(文档决策更新)
  • 背景:复核 Claude Code 的 Phase 4 验收报告后,确认报告总体正确,但当前不希望马上真实更新 Shopee 商品图片或标题。
  • 决策:真实 Shopee 单条更新冒烟登记为 T-404,但依赖新增的 T-501c “Shopee 更新安全开关”完成后再执行。T-404 默认先只测标题更新,封面更新作为可选子项;未通过前不得扩大真实批量更新。
  • 细化:取消语义明确为协作式取消,只阻止后续未开始任务,不中断当前正在执行的商品;Tab① 旧标题/旧封面采集已有真机冒烟,未真机闭环的是真实 AI 生成与 Tab③ 在线提交更新。
  • 变更:更新 docs/06-tasks.md、docs/current-state.md、docs/reviews/2026-06-27-T401-T403-acceptance.md。
  • 验证:仅文档更新,未运行测试。

【2026-06-27】T-501 Tab⑤ AI 模型管理 UI

  • 状态:DONE
  • 变更:app/gui.py 新增 SettingsTab,将⑤设置从空壳替换为 AI 模型 master-detail 管理界面。左侧为模型下拉、新增、删除;右侧为启用、服务商名、类别、api_type、模型ID、网址、密钥、连接超时、保存、测试连接。
  • 安全:密钥字段使用 QLineEdit.Password 打码;模型清单仍写入 gitignore 的 config/ai_models.json;删除按钮在当前类别只剩一个模型时禁用,后端继续保证至少有 text/image 各一个启用模型。
  • Worker:新增 AIModelTestWorker,通过后台线程调用 appconfig.test_ai_model(),避免在 GUI 主线程发网络请求。
  • 测试:tests/test_gui.py 覆盖 MainWindow 挂载⑤、模型加载与密钥打码、新增/保存/删除、测试连接 worker、AIModelTestWorker.execute()。
  • 文档:docs/06-tasks.md 将 T-501 标为 DONE;同步 docs/routes.md、docs/api.md、docs/current-state.md,下一个可领取任务更新为 T-501b。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests -p test_gui.py 通过(36 tests);python -m unittest discover -s tests 通过(92 tests)。

【2026-06-29】T-501b Tab⑤ 角色与生成参数

  • 状态:DONE
  • 变更:app/gui.py 扩展 SettingsTab,⑤设置页新增角色与生成参数、路径与端口配置区。标题大模型下拉只列 text 类模型,图片大模型下拉只列 image 类模型;支持标题/图片并发、失败重试、分辨率、jpg 质量、Chrome 路径、账号数据根目录、图片目录、DB 路径、默认调试端口、端口范围、CDP 就绪超时。
  • 配置:点击「保存设置」写入 config.json;保留 resolution_timeouts,分辨率切换时只读展示对应返回超时;保存前校验端口范围和默认端口。
  • 细节:SettingsTab 和 MainWindow 支持注入 config_path 便于测试;保存时不会把测试用的 config_path/ai_models_path 写入 config.json。
  • 测试:tests/test_gui.py 覆盖角色下拉类别过滤、分辨率返回超时显示、生成参数/路径/端口保存到临时 config.json、非法端口范围拦截。
  • 文档:docs/06-tasks.md 将 T-501b 标为 DONE;同步 docs/routes.md、docs/api.md、docs/current-state.md,下一个可领取任务更新为 T-501c。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests -p test_gui.py 通过(38 tests);python -m unittest discover -s tests 通过(94 tests)。

【2026-06-29】T-501c Tab⑤ Shopee 更新安全开关

  • 状态:DONE
  • 配置:app/appconfig.py 的 config.json 默认值新增 shopee_update 段:测试商品 ID、允许真实提交、允许更新封面、单次最大更新条数、成功后关闭本次新开编辑页。默认关闭真实提交和封面更新,单次最大更新 1 条。
  • GUI:SettingsTab 新增 Shopee 更新安全表单并持久化;ApplyTab.start_update() 在弹确认前读取安全设置,拦截未开启真实提交、超过最大条数、包含非测试商品 ID、或包含新封面但未允许封面更新的任务。确认弹窗会展示当前安全设置。
  • 执行:ApplyWorker 将 close_success_tab 传给 editor.apply_task();editor.apply_task() 在成功提交、且商品页为本轮程序自动新建时,可按设置关闭该 tab。失败任务和复用的用户已有 tab 保留现场。
  • 测试:tests/test_gui.py 覆盖安全设置默认值、保存到 config.json、⑤保存后③立即读取共享安全配置、③安全拦截、最大条数/测试商品 ID 校验、确认后 worker 接收 close_success_tab;tests/test_editor_login.py 覆盖成功提交后关闭本轮新开 tab、失败时不关闭。
  • 文档:docs/06-tasks.md 将 T-501c 标为 DONE;同步 docs/04-architecture.md、docs/api.md、docs/routes.md、docs/current-state.md,下一个可领取任务更新为 T-404。
  • 验证:python -m unittest discover -s tests -p test_gui.py 通过(42 tests);python -m unittest discover -s tests -p test_editor_login.py 通过(11 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(100 tests)。未执行真实 Shopee 提交,T-404 仍需在测试商品上手动冒烟。

【2026-06-29】T-502 满 9 张封面删除前备份策略

  • 状态:文档决策更新,代码未实现。
  • 决策:满 9 张封面需要删除第一张再上传时,不允许盲删线上图片;删除前必须确认该任务已有本地旧封面备份,即 old_cover_path 非空且文件存在。
  • 失败语义:备份缺失时直接阻断该条封面更新,返回明确错误,要求先回到①采集旧封面或修复本地备份;不进入删除确认框、不删除线上第一张图。
  • 实测边界:删除确认框选择器仍需在真实 Shopee 测试商品页面探查;真实保存线上变更仍需经过 ⑤ 安全开关和 ③ 二次确认。
  • 变更:同步 docs/02-requirements.md、docs/04-architecture.md、docs/05-coding-rules.md、docs/06-tasks.md、docs/api.md、docs/routes.md、docs/current-state.md。
  • 验证:仅文档更新,未运行测试。

【2026-06-29】T-502 满 9 张封面删除代码路径

  • 状态:BLOCKED(代码路径和 mock 单测已完成;真实 Shopee 9 图商品删除确认框仍需实测)。
  • 变更:app/editor.py 的 replace_cover() 支持 old_cover_path,满 9 张时先校验本地旧封面备份存在;缺失时返回 OLD_COVER_BACKUP_MISSING,不点击删除。备份存在时点击第一张图片的删除按钮,在可见 dialog/modal/popover 中点击删除/确认类按钮,确认图片数减少后再上传新图并拖到第一位。
  • 执行链路:apply_task() 会把任务的 old_cover_path 传给 replace_cover(),确保③真实封面更新继承①采集备份保护。
  • 测试:tests/test_editor_login.py 新增满 9 张备份缺失阻断、删除确认后上传并拖首位、删除按钮缺失报错、apply_task() 传递旧封面备份路径的覆盖。
  • 文档:docs/06-tasks.md 将 T-502 标为 BLOCKED;同步 docs/04-architecture.md、docs/api.md、docs/current-state.md。
  • 验证:python -m unittest discover -s tests -p test_editor_login.py 通过(15 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(104 tests)。未执行真实 Shopee 删除/提交。

【2026-06-29】T-502 真实 9 图商品不提交实测

  • 状态:DONE
  • 商品:29671243750,URL https://seller.shopee.tw/portal/product/29671243750?pageEntry=product_list&ignore-html-cache=1,账号别名 papa,CDP 端口 9224。
  • 前置:本地旧封面备份存在:images/papa_f722f20f/29671243750_old.jpg;商品编辑页初始图片数为 9。
  • 删除确认框实测:新开测试 tab,执行 _delete_first_cover(),结果 ok=True,图片数 9 → 8,测试 tab 已关闭,未点击「更新」。
  • 满 9 张完整换封面实测:新开测试 tab,执行 replace_cover(..., image=1_TY030.jpg, old_cover_path=备份路径),结果 ok=True,删除后上传新图,图片数回到 9,新图 index=0 且为第一位,测试 tab 已关闭。
  • 安全边界:全程只操作新开的测试 tab,未点击「更新」保存线上;线上真实保存仍需走 ⑤ 安全开关和 ③ 二次确认。
  • 文档:docs/06-tasks.md 将 T-502 标为 DONE;同步 docs/04-architecture.md、docs/api.md、docs/current-state.md。

【2026-06-29】T-503 敏感信息本地明文保存提示与日志脱敏

  • 状态:DONE
  • 变更:app/gui.py 在④账号管理保存/变更非空密码前弹出“本地明文保存提示”,在⑤设置保存/变更非空 API Key 前弹出同类提示;账号表格仍不展示密码,API Key 字段继续使用 QLineEdit.Password 打码。
  • 脱敏:app/appconfig.py 新增 mask_secret()、sanitize_for_log()、redact_secrets();AIModelTestWorker.execute() 返回 GUI 前对测试连接结果做结构化脱敏;test_ai_model() 的异常文本会用已知 API Key 做替换。
  • 测试:tests/test_appconfig.py 覆盖结构化日志脱敏;tests/test_gui.py 覆盖保存 API Key 提示、账号密码保存提示、表格/状态不泄露明文、AI 测试 worker payload 脱敏。
  • 文档:docs/06-tasks.md 将 T-503 标为 DONE;同步 docs/02-requirements.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/05-coding-rules.md、docs/api.md、docs/routes.md、docs/current-state.md。
  • 验证:python -m unittest discover -s tests -p test_appconfig.py 通过(5 tests);python -m unittest discover -s tests -p test_gui.py 通过(44 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(107 tests)。

【2026-06-29】T-504 多账号并行 / dry-run / 运行日志

  • 状态:DONE
  • 配置:app/appconfig.py 的 shopee_update 新增 dry_run、parallel_accounts、max_parallel_accounts;⑤ 设置页可配置并持久化,默认 dry-run 关闭、多账号并行关闭。
  • 数据:app/db.py 新增 run_logs / run_log_events schema 与创建、结束、逐条事件、查询函数;日志 payload 统一走脱敏工具。
  • 执行:③ ApplyWorker 支持 dry-run 预览、默认串行真实更新、按账号并行真实更新;dry-run 不打开 Shopee、不调用 editor.apply_task()、不改任务状态、不回写 Excel,只写运行日志和汇总;真实更新前检查账号就绪和本轮账号调试端口冲突,不同账号可并行,同一账号内仍串行。
  • UI:③ 增加运行日志视图,确认弹窗展示 dry-run 与多账号并行状态;dry-run 完成只弹预览汇总,不触发结果回写。端口冲突阻断时弹窗列出冲突端口并引导去④。
  • 测试:tests/test_db.py 覆盖运行日志持久化;tests/test_gui.py 覆盖 dry-run 不变更任务、真实更新串行、按账号并行、端口冲突阻断、⑤设置读写与③共享配置。
  • 文档:docs/06-tasks.md 将 T-504 标为 DONE;同步 docs/00-ai-start-here.md、docs/02-requirements.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/05-coding-rules.md、docs/api.md、docs/routes.md、docs/current-state.md 和 UI 草图。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(112 tests);未执行真实 Shopee 提交。

【2026-06-29】AI 模型 category 启动报错排查记录

  • 问题:启动最新代码时报 “AI 模型 category 必须是 text 或 image”。
  • 原因:本地 gitignored 的 config/ai_models.json 来自旧数据或手工维护,模型缺少 category,而当前 schema 要求每个模型必须是 text 或 image。
  • 处理:已在本机只补齐模型 category 和空的 enabled=true,保留原有 url/model/API Key;验证 appconfig.list_ai_models() 可正常加载,且 config/ai_models.json 仍被 gitignore。
  • 文档:新增 docs/troubleshooting.md,并在 docs/README.md、docs/03-tech-stack.md、docs/current-state.md 增加索引和说明。排查命令只输出 name/category/api_type/enabled/has_api_key,不输出 API Key。

【2026-06-29】设置页 AI 模型布局微调

  • 状态:DONE
  • 变更:app/gui.py 将⑤设置页的 AI 模型下拉/新增/删除从左侧分栏移到“模型详情”上方,设置页改为单列滚动布局;模型详情、角色与生成参数、路径与端口、Shopee 更新安全表单尽量两项一行,URL/API Key/Chrome 路径等长字段独占整行。
  • 文档:同步 docs/routes.md、docs/api.md、docs/current-state.md 中的设置页布局描述,并更新 docs/ui/tab5-settings.svg UI 草图。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests -p test_gui.py 通过(48 tests)。

【2026-06-29】T-206 删除指定批次(设计登记)

  • 状态:TODO(设计登记;硬删除语义仍待用户最终确认,排在 T-404 之后实现)
  • 问题:①导入采集仅有批次筛选下拉,没有任何删除入口;db 有 delete_account 但无 delete_batch。导错文件 / 测试导入 / 处理完的历史批次都无法清理,批次下拉只增不减,长期必然劣化使用体验。
  • 数据模型:tasks.batch_id REFERENCES batches(id);每条 task 关联磁盘封面图片 old_cover_path(采集下载的旧封面)、new_cover_path(AI 生成的新封面),均为本工具产出,硬删后会成为孤儿文件。
  • 方案(硬删除):
    • app/db.py 新增 delete_batch(batch_id):单事务内先 DELETE FROM tasks WHERE batch_id=? 再 DELETE FROM batches WHERE id=?;返回 {"tasks": 删除任务数, "committed": 其中已上线数, "images": 关联封面绝对路径列表}。
    • app/gui.py ①导入采集页批次筛选旁加「删除批次」按钮:仅选中具体批次时可用,运行中随其他控件一起禁用。
    • 二次确认弹窗(不可逆动作,符合安全红线):展示批次标签 + 任务数 + 已上线(committed=1)任务数,明确提示「删除本地记录不会回滚 Shopee 线上已提交的修改」;提供「同时删除已下载/生成的封面图片」勾选项,默认不勾。
    • 确认后调用 db.delete_batch,按勾选 os.remove 清理 images 列表中的孤儿图片(容错,缺失/占用不报错只记日志),刷新①与③的批次下拉和任务列表。
  • 安全:删除前显式弹窗确认;提示线上修改不可回滚;图片清理默认不开启需用户主动勾选。
  • 测试计划:tests/test_db.py 覆盖 delete_batch 删任务+批次、返回计数/图片路径、外键不残留;tests/test_gui.py 覆盖未选具体批次时按钮禁用、确认后调用删除并刷新、取消不删除。

【2026-06-29】T-303b ②/③ 商品ID筛选

  • 状态:DONE
  • 文档:先同步 docs/routes.md、docs/api.md、docs/06-tasks.md,明确 ② AI生成与 ③ 更新shopee 的商品ID输入框按包含匹配 item_id,清空表示全部;当前筛选结果约束「开始生成」和「开始更新」范围;③确认弹窗显示商品ID筛选条件。
  • 实现:app/gui.py 在 GenerateTab 和 ApplyTab 增加商品ID输入框,刷新时与批次/店铺/状态共同过滤;运行中禁用该输入框,避免生成/更新过程中改变作用范围。
  • 测试:tests/test_gui.py 覆盖 ② 商品ID筛选、③ 商品ID筛选,以及③确认弹窗显示商品ID。
  • 任务顺序:T-206 删除批次仍为设计登记,依赖 T-404,避免抢在真实 Shopee 单条冒烟前执行。
  • 验证:python -m compileall app main.py tests 通过;python -m unittest discover -s tests -p test_gui.py 通过(48 tests);python -m unittest discover -s tests 通过(112 tests)。

【2026-06-29】文档补充 · 采集失败诊断日志方案

  • 背景:用户本次导入 5 个商品 ID 采集旧标题/旧封面时有 1 条失败;当前实现会把该任务写成 status=failed 并保存 last_error,但不会写 ① 采集的持久运行日志,也没有本地 traceback,因此无法判断卡在打开商品页、页面就绪、读标题、读封面、下载图片、写库还是 Excel 回写。
  • 方案:采用两层日志。SQLite run_logs/run_log_events 保存业务可读事件(run_type、task_id、alias、item_id、step、简短错误);本地 gitignore 的 logs/ 保存脱敏 traceback、异常类型、步骤、耗时和必要上下文。
  • 任务:新增 T-207「① 采集诊断日志(run_logs + 本地 log)」作为下一步可领取任务;新增 T-505「全流程诊断日志扩展」覆盖 ② AI生成、Excel 导入/回写、③ 更新shopee、④ Chrome/登录检测、⑤ AI 模型测试连接。
  • 安全:日志不得记录 Cookie、密码、API Key、token;结构化 payload 过 sanitize_for_log(),自由文本异常按需 redact_secrets()。
  • 文档:同步 docs/04-architecture.md、docs/06-tasks.md、docs/api.md、docs/routes.md、docs/05-coding-rules.md、docs/current-state.md。
  • 验证:仅文档更新,未运行测试。

【2026-06-29】T-207 ①采集诊断日志(run_logs + 本地 log)

  • 状态:DONE
  • 文档:docs/06-tasks.md 将 T-207 标为 DONE;docs/04-architecture.md 更新为 T-207 已接入 ①采集、T-505 待扩展;docs/current-state.md 同步当前快照、目录清单、下一步和已知限制。
  • 实现:新增 app/diagnostics.py,写入 gitignore 的 logs/cmshopee.log,支持大小滚动、异常类型、traceback、step、task_id/alias/item_id、耗时和 payload;结构化 payload 与自由文本统一脱敏。
  • 采集链路:app/editor.py 为采集流程增加 on_step 回调,覆盖 open_product、wait_ready、read_title、read_cover、download_cover;CollectWorker 创建 run_type=collect 的 run_logs,逐任务写 run_log_events,失败时保留最后 step、简短错误并继续后续任务。
  • UI:①导入采集页新增最近一次采集运行日志视图;采集完成自动回写 Excel 时记录 excel_write_back 开始/成功/失败事件。
  • 安全:DB 运行日志、状态栏错误、本地诊断日志均不记录 Cookie、密码、API Key、token;自由文本中的 token/password/cookie/authorization/api_key 形式会写入前脱敏。
  • 测试:tests/test_gui.py 覆盖采集成功/略过写 run log、采集失败写 DB 事件与本地诊断 log、token 脱敏、①日志视图加载最近一次 collect run log。
  • 验证:python -m py_compile app\diagnostics.py app\editor.py app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p test_gui.py 通过(50 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(114 tests);git diff --check 通过(仅 LF/CRLF 提示)。
  • 下一步:按 docs/current-state.md,建议领取 T-404(真实 Shopee 单条更新冒烟)。

【2026-06-29】修复⑤设置测试连接 base URL 返回 HTTP 404

  • 问题:本地文本模型 URL 配置为 OpenAI-compatible base URL(如 https://api.vectorengine.ai/v1)时,⑤「测试连接」原样 POST 到 /v1,服务端返回 HTTP 404;实际 AI 生成请求也存在同类风险。
  • 修复:app/appconfig.py 新增 model_request_url(),当 url 是 /v1、/v1beta、/api/v1、/api/v1beta 这类 base URL 时,按 api_type 自动补 /chat/completions 或 /images/edits;完整 endpoint 和自定义路径保持不变。
  • 接入:appconfig.test_ai_model() 与 app/ai.py 的真实 AI HTTP 调用统一使用解析后的 endpoint。
  • 文档:更新 docs/api.md、docs/routes.md、docs/troubleshooting.md、docs/current-state.md,说明⑤网址可填完整 endpoint 或 OpenAI-compatible base URL,并记录 HTTP 404 排查方法。
  • 测试:tests/test_appconfig.py 覆盖 base URL/full endpoint/custom path 解析和测试连接请求 URL;tests/test_ai.py 覆盖标题生成使用 base URL 自动补 endpoint。
  • 验证:python -m unittest discover -s tests -p test_appconfig.py 通过(7 tests);python -m unittest discover -s tests -p test_ai.py 通过(7 tests);python -m compileall app main.py tests 通过;python -m unittest discover -s tests 通过(117 tests);git diff --check 通过(仅 LF/CRLF 提示)。

【2026-06-29】② AI生成图片失败诊断日志补丁

  • 背景:用户实测 ② AI生成已能按商品 ID 和提示词生成标题,但生成图片失败时页面与本地都找不到可定位原因的日志。
  • 代码:app/ai.py 为标题/封面生成增加 on_step 与 on_event/on_error 回调,覆盖模型加载、请求构建、请求发送、响应解析、图片保存、写库等步骤;失败错误进入任务 last_error 前先脱敏。
  • UI/日志:GenerateWorker 创建 run_type=generate 的 run_logs/run_log_events,② 页面新增「AI生成运行日志」;图片生成异常同时写本地 logs/cmshopee.log 脱敏 traceback。
  • 测试:新增覆盖 GenerateWorker 图片生成失败时 DB 运行日志、本地诊断日志和 token 脱敏,以及 ② 页面加载最近一次 generate 日志。

【2026-06-29】T-404 冒烟发现 · Shopee 更新二次确认框

  • 现象:用户用测试商品走完整流程,③ 更新shopee 已替换标题和封面,并自动点击页面主「更新」按钮;随后 Shopee 弹出站点侧确认框 確定您要更新商品嗎?,底部按钮为 立即優化 和主按钮 更新,当前代码没有点击最终确认,因此未真正提交。
  • 结论:T-404 不能标 DONE;click_update() 的提交成功定义需要扩展为“页面主更新按钮已点击,且 Shopee 站点侧确认框未出现或已点击确认框内主按钮「更新」”。
  • 方案:基于用户提供 HTML,检测可见 .eds-modal__box,标题匹配 確定您要更新商品嗎?/简繁变体;只在该 modal footer 内点击 button.eds-button--primary 且文案为 更新 的按钮;明确不点击 立即優化。弹窗出现但未确认成功时,该任务返回失败、保留现场、不得写 committed=1。
  • 文档:同步 docs/04-architecture.md、docs/api.md、docs/routes.md、docs/06-tasks.md、docs/current-state.md。本轮只更新文档,未改代码。

【2026-06-29】T-404 补丁 · 点击 Shopee 更新确认框主按钮

  • 代码:app/editor.py 新增 JS_FIND_UPDATE_CONFIRM / JS_CLICK_UPDATE_CONFIRM,click_update(cdp, confirm_timeout=3) 点击页面主「更新」后等待 Shopee 站点侧确认框;若可见 .eds-modal__box 标题匹配 確定/确定 + 更新商品,只点击同一 modal 内文案精确为 更新 的按钮,优先 eds-button--primary,不点击 立即優化。
  • 失败语义:确认框出现但未点到主按钮时返回 clicked=False 和 NO_UPDATE_CONFIRM_BUTTON / UPDATE_CONFIRM_NOT_CLICKED,apply_task() 不写 committed 成功,失败商品保留现场。
  • 测试:tests/test_editor_login.py 增加 Shopee 更新确认框成功点击、确认框未确认失败、无确认框保持原成功语义的 mock 覆盖。
  • 文档:同步 docs/api.md、docs/06-tasks.md、docs/current-state.md。T-404 仍为 TODO,下一步需要用户用测试商品复跑真实提交验收。

【2026-06-29】设计登记 · ②/③ 选中记录重置

  • 背景:用户真实联调时,② AI生成和③ 更新shopee列表没有重置选中记录功能;商品一旦生成/上传/提交成功,就不方便用同一商品重复测试图片上传和 Shopee 提交流程。
  • 决策:新增 T-404a「②/③ 选中记录重置(联调重试辅助)」,排在 T-404 真实单条冒烟前。先做单选记录,不做批量重置,避免误操作放大线上风险。
  • ② 方案:增加「重置生成结果」。确认后只改本地 DB,清空 new_title/new_cover_path/last_error,退回 stage=collected/status=success,默认不删除本地新封面文件;若记录已提交过线上,确认框必须提示本地重置不回滚 Shopee。
  • ③ 方案:增加「重置更新状态」。确认后保留 new_title/new_cover_path,本地退回 stage=generated/status=pending,用于重复测试上传/提交;若 committed=1,必须醒目提示线上已提交过、重复更新会再次提交,并保留 committed 历史事实/运行日志。
  • 日志与边界:两类重置都写 run_type=reset 运行日志;运行中禁用;不触碰 Shopee,不自动回写 Excel,后续由用户按需手动回写结果。
  • 文档:同步 docs/06-tasks.md、docs/routes.md、docs/api.md、docs/04-architecture.md、docs/current-state.md。本轮只更新文档,未改代码。

【2026-06-30】T-404a 完成 · ②/③ 选中记录重置

  • 代码:app/db.py 新增 get_task()、reset_generated()、reset_apply_status();app/gui.py 在② AI生成增加「重置生成结果」,在③ 更新shopee增加「重置更新状态」。两者仅作用当前选中单条,运行中禁用,确认后只改本地 SQLite,不触碰 Shopee,不自动回写 Excel。
  • 行为:② 清空 new_title/new_cover_path/last_error 并退回 stage=collected/status=success,默认不删除本地新封面文件;③ 保留 new_title/new_cover_path,退回 stage=generated/status=pending。已 committed=1 的记录会在确认框提示线上已提交过、本地重置不回滚 Shopee、重复更新会再次提交。
  • 日志:两类重置都创建 run_type=reset 的 run_logs/run_log_events,记录 action、task_id、alias、item_id。
  • 测试:新增 tests/test_db.py reset 生命周期覆盖;新增 tests/test_gui.py 覆盖②重置生成结果、③重置更新状态、确认框提示和 reset 运行日志。已运行 python -m py_compile app/db.py app/gui.py tests/test_db.py tests/test_gui.py、python -m unittest discover -s tests -p "test_db.py"、python -m unittest discover -s tests -p "test_gui.py"。
  • 文档:docs/06-tasks.md 将 T-404a 标为 DONE;同步 docs/current-state.md、docs/api.md、docs/04-architecture.md。下一个任务仍是 T-404 真实 Shopee 单条更新冒烟,必须用测试商品复跑站点侧确认框主按钮「更新」路径后才能标 DONE。

【2026-06-30】T-404 补丁 · 兼容 Shopee .eds-modal__content 更新确认框

  • 现象:用户实跑最新代码后仍停在 Shopee 站点侧确认框,真实 DOM 根节点为 .eds-modal__content,标题 確定您要更新商品嗎?,footer 按钮为 立即優化 和主按钮 更新。
  • 原因:确认框检测候选 root 过宽,可能把 .eds-modal__title 等子节点当成最后一个候选,导致点击逻辑在没有 footer 按钮的 root 中查找「更新」失败。
  • 代码:app/editor.py 的 JS_FIND_UPDATE_CONFIRM / JS_CLICK_UPDATE_CONFIRM 改为优先查找 .eds-modal__content,.eds-modal__box,[role=dialog],并要求候选 root 标题匹配更新确认框且包含可点击「更新」按钮;按钮查找优先限定在 .eds-modal__footer 内,仍只点击文案精确为「更新」的主按钮,不点击「立即優化」。
  • 测试:tests/test_editor_login.py 增加 .eds-modal__content 结构覆盖,防止回退到只支持 .eds-modal__box。T-404 仍需用户用测试商品复跑真实提交确认后才能标 DONE。

【2026-06-30】T-404 补丁 · 新封面上传状态诊断

  • 现象:用户实跑最新代码时,新封面上传后页面一直转圈,程序等待一段时间后提示更新失败。
  • 现状确认:旧 replace_cover() 已有上传成功检测,但只判断“图片列表出现新 susercontent CDN 地址”;若页面一直 loading/blob 预览或 Shopee 返回页面错误,最终只给 UPLOAD_TIMEOUT,无法定位是仍在上传、格式/大小错误还是裁剪弹窗。
  • 代码:app/editor.py 新增 JS_UPLOAD_STATE / _upload_state(),上传等待期间采集图片管理器状态:当前 src、blob 数、CDN 数、loading/progress 数、错误文案、裁剪弹窗和 toast;默认上传等待从 90 秒调到 180 秒。
  • 失败语义:replace_cover() 现在区分 UPLOAD_STILL_PROCESSING(仍在转圈或 blob 预览)、UPLOAD_PAGE_ERROR(页面/Toast 出现失败错误)、UPLOAD_CROP_REQUIRED(出现裁剪弹窗)、UPLOAD_TIMEOUT(没有任何新图/CDN/忙碌状态);失败结果包含 upload_state、count_after、blob_seen、file_size。apply_task() 会把封面失败转换成更可读的中文错误。
  • 测试:tests/test_editor_login.py 新增上传仍在处理中、页面上传错误、apply_task 封面失败中文错误的覆盖。T-404 仍需用户用测试商品复跑真实上传和提交路径。

【2026-06-30】T-404 补丁 · 删除旧封面后等待图片管理器稳定

  • 现象:用户实跑最新代码后,新封面上传后仍停在转圈并最终提示更新失败;怀疑满 9 张时删除旧图后立刻上传,Shopee 图片管理组件尚未完成重排。
  • 分析:判断方向成立。旧流程在 _delete_first_cover() 里只等待图片数量减少,随后立刻重新取上传 input 并 DOM.setFileInputFiles;但数量减少不等于 Vue 组件已重渲染完成、上传入口已恢复、loading/blob 已消失。
  • 代码:JS_UPLOAD_STATE 增加上传 input 存在/禁用状态;replace_cover() 上传前先等图片管理器稳定,初始图片稳定后再操作,满 9 张删除确认后等待删除后的数量、无 busy/blob、上传 input 恢复并短暂稳定,再重新获取 input 上传;触发文件选择后等待 2 秒再轮询新图 CDN。新增 IMAGE_MANAGER_BUSY、IMAGE_COUNT_NOT_READY、UPLOAD_INPUT_NOT_READY 等失败语义。
  • 测试:tests/test_editor_login.py 增加“删除后 busy 两轮,必须等稳定后才 setFileInputFiles”的覆盖;python -m unittest discover -s tests -p "test_editor_login.py" 通过(23 tests),python -m compileall app main.py 通过,python -m unittest discover -s tests 通过(130 tests),git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 边界:本轮仍未直接操作真实 Shopee 测试商品,T-404 仍为 TODO,需要用户复跑单条真实上传与提交路径后才能标 DONE。

【2026-06-30】T-404 补丁 · 记录更新成功后跳回商品列表页

  • 现象:用户复跑最新代码后,Shopee 站点侧确认框里的主按钮「更新」已成功点击,提交成功后当前 tab 跳回 https://seller.shopee.tw/portal/product/list/all?operationSortBy=modified_time,但浏览器 tab 没有关闭。
  • 分析:代码已有可选关闭逻辑:只有 ⑤ 开启 close_success_tab 且商品页是 open_product() 本轮自动新建 tab,成功提交后才调用 close_tab();默认不关闭,复用用户已有 tab 也不关闭。旧代码没有把“跳回商品列表页”作为提交后观测结果记录。
  • 代码:click_update() 新增提交后状态探测,点击确认框主按钮后等待并记录 post_update.url、redirected_to_list、toast 结果;若出现失败 toast,则本条视为未提交失败;如果没有可观测跳转/成功 toast,仍沿用点击确认成功的兼容语义。
  • 测试:tests/test_editor_login.py 增加确认后跳回商品列表页的 mock 覆盖;python -m unittest discover -s tests -p "test_editor_login.py" 通过(24 tests),python -m compileall app main.py 通过,python -m unittest discover -s tests 通过(131 tests),git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 边界:是否关闭 tab 仍由 ⑤“成功后关闭本次新开编辑页”和 created_by_app 决定;跳到商品列表页本身不会强制关闭用户原本打开的 tab。

【2026-06-30】T-404 回归分析 · 满 9 张删除前误等上传入口

  • 现象:用户复跑最新代码后,商品详情页加载完成,但没有删除原商品图片第一张图,也没有后续上传和更新确认。
  • 原因:上次为解决“删除后立刻上传导致转圈”新增了 _wait_image_manager_stable(),但在 replace_cover() 开头、删除旧图之前就要求上传 input 存在且未禁用。满 9 张时 Shopee 可能因已满格隐藏或禁用上传入口,所以前置等待返回 UPLOAD_INPUT_NOT_READY,流程在删除前中断。
  • 正确顺序:满 9 张时,删除前只等待现有图片列表稳定(无 loading/blob、src 稳定),不检查上传 input;完成第一张删除并确认图片数量减少后,再等待上传 input 恢复可用并短暂稳定,然后上传新图。
  • 测试缺口:mock 中满 9 张场景默认 upload_input_ready=True,没有覆盖真实页面“满格时上传入口不可用”的状态,导致回归未被单测发现。
  • 修复:_wait_image_manager_stable() 增加 require_upload_input 参数;replace_cover() 初始稳定等待传 False,满 9 张先删除第一张;删除后和未满 9 张上传前再传 True 等上传入口恢复。
  • 测试:tests/test_editor_login.py 新增 test_replace_cover_full_slots_deletes_before_upload_input_is_ready,模拟满 9 张时上传入口初始不可用、删除后恢复;python -m unittest discover -s tests -p "test_editor_login.py" 通过(25 tests),python -m compileall app main.py 通过,python -m unittest discover -s tests 通过(132 tests),git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 下一步:用户用测试商品复跑真实 T-404 封面上传和更新确认链路。

【2026-06-30】T-404 回归分析 · 物流校验被误判为封面上传失败

  • 现象:用户复跑最新代码后,程序能删除第一张图片,但一直没有上传新图片,最后报 新封面上传失败:此物流選項不支援較長備貨商品。
  • 原因:JS_UPLOAD_STATE 在封面上传阶段扫描了全局 toast/message/notice,并把包含 不支援 的文本都归入 error_toasts。此物流選項不支援較長備貨商品 是物流/备货页面级校验,不是图片上传错误;当前代码在删除后等待上传入口恢复时看到该全局错误,提前返回 UPLOAD_PAGE_ERROR,因此没有继续执行 DOM.setFileInputFiles。
  • 正确边界:封面上传阶段只应把图片管理器内错误,或图片/文件/上传相关的全局 toast,当作封面上传失败。物流、备货、价格、库存等页面级校验应保留给点击「更新」提交阶段处理,不能阻断上传新图。
  • 修复:JS_UPLOAD_STATE 新增图片/文件/上传相关 uploadRe 过滤;全局页面错误仍记录在 page_error_toasts,但只有匹配图片上传语义的 toast 才进入 error_toasts 并阻断封面上传。JS_POST_UPDATE_STATE 同步把 不支援/不支持/無法/无法 识别为提交阶段错误,避免真正点击「更新」后误判成功。
  • 测试:tests/test_editor_login.py 新增 test_replace_cover_ignores_unrelated_logistics_page_error_toast 和 test_click_update_reports_logistics_validation_after_confirm;python -m unittest discover -s tests -p "test_editor_login.py" 通过(27 tests),python -m compileall app main.py 通过,python -m unittest discover -s tests 通过(134 tests),git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 下一步:用户复跑真实 T-404 链路。

【2026-06-30】T-404 回归分析 · 成功跳转列表页后 GUI 误报 POST_UPDATE_ERROR

  • 现象:用户复跑最新代码后,浏览器上标题和封面都已成功更新,点击 Shopee 确认框主按钮「更新」后跳转到 https://seller.shopee.tw/portal/product/list/all?operationSortBy=modified_time,但 GUI 仍提示 任务 1 商品 28431952912 更新失败:POST_UPDATE_ERROR。
  • 原因:click_update() 的提交后观测 _wait_post_update() 当前先检查 error_toasts,再检查 redirected_to_list。若页面上存在残留或短暂的物流/备货 error toast,即使 Shopee 已接受提交并跳转到商品列表页,也会先返回 POST_UPDATE_ERROR,导致 GUI 把真实成功误判为失败。
  • 正确判断优先级:跳转到 /portal/product/list/ 是提交成功的强信号,必须优先于残留/短暂 error toast;只有在未跳转商品列表、无成功 toast,且错误 toast 持续存在到观测窗口结束时,才应判 POST_UPDATE_ERROR。
  • 解决方案:调整 _wait_post_update() 顺序与策略:每轮先判断 redirected_to_list 或成功 toast;错误 toast 只记录为诊断,延迟到未见成功信号且持续存在时再判失败。GUI 错误显示应尽量带出 post_update.error_toasts 的具体文案,避免只显示 POST_UPDATE_ERROR。
  • 修复:_wait_post_update() 改为先判断 redirected_to_list 或成功 toast;错误 toast 只记录为 last_error_state,观测窗口结束仍没有成功信号时才返回 POST_UPDATE_ERROR。
  • 测试:tests/test_editor_login.py 新增 test_click_update_treats_list_redirect_as_success_even_with_stale_error_toast,保留 test_click_update_reports_logistics_validation_after_confirm 覆盖未跳转时错误仍失败;python -m unittest discover -s tests -p "test_editor_login.py" 通过(28 tests),python -m compileall app main.py 通过,python -m unittest discover -s tests 通过(135 tests),git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 下一步:用户复跑真实 T-404 链路,确认 GUI 与浏览器成功状态一致。

【2026-06-30】文档补充 · ③ 更新前账号 Chrome 就绪预检

  • 背景:讨论 ③「开始更新」后如果本轮需要的账号 Chrome 未打开,是否应由程序自动打开。产品判断为:真实更新是线上高风险动作,不应静默启动多个账号浏览器并继续提交。
  • 决策:③ 点击「开始更新」并通过安全开关/确认后,真实提交前必须检查当前筛选结果涉及的账号 Chrome/CDP/登录态;若任一账号 Chrome 未启动、CDP 端口不可访问、未登录或端口冲突,弹窗列出账号和原因,整体中止本轮更新,不调用 editor.apply_task(),不写失败状态,不自动打开 Chrome。
  • ④ 边界:④「启动登录」只打开对应账号浏览器供人工登录;④「检测登录」与①/③预检只验证当前环境是否可用,不自动登录、不填密码。
  • 文档:同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/04-architecture.md、docs/06-tasks.md、docs/current-state.md。本轮只更新文档,未改代码。

【2026-06-30】代码补齐 · ③ 账号未就绪时明确中止更新

  • 代码:app/gui.py 的 ③ 更新账号未就绪弹窗新增明确文案:本轮更新已中止,不会自动打开账号 Chrome,也不会提交任何商品;① 采集账号未就绪文案单独保持为“本轮采集已中止”,避免把更新语义带到采集模块。
  • 测试:tests/test_gui.py 覆盖 ③ 账号 Chrome 未启动时 ApplyWorker 不调用 accounts.launch_for_login()、不调用 editor.apply_task()、不写任务失败状态;覆盖弹窗包含“本轮更新已中止 / 不会自动打开账号 Chrome / 不会提交任何商品”。同步修正①采集阻断文案断言。
  • 验证:python -m py_compile app/gui.py tests/test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(54 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(135 tests);git diff --check 无空白错误(仅 LF/CRLF 提示)。

【2026-06-30】文档补充 · 正式使用批量更新与设置页布局

  • 背景:单条真实更新已人工测试通过,正式使用需要支持当前筛选结果无论多少条都能更新到 Shopee,同时降低误筛选风险,并整理⑤设置页视觉密度。
  • 决策:保留预览能力但不再对用户显示 dry-run 技术词,③ 增加「预览本轮更新」按钮;「开始更新」按每批最大更新条数自动分批,确认弹窗显示总数/每批/预计批次;点击停止为协作式停止,当前商品跑到安全边界后不再开始新商品或下一批。
  • 设置页:⑤ 内容区居中并加大左右留白到当前约 250% 的视觉尺度;模型详情、角色与生成参数、路径与端口、Shopee 更新安全均改为响应式三列布局,短字段一格,URL/API Key/路径等长字段跨列;测试商品 ID 后续移入高级/调试区或弱化展示。
  • 文档:同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/04-architecture.md、docs/06-tasks.md、docs/current-state.md。本轮只更新文档,未改代码。

【2026-06-30】代码补齐 · T-506 正式使用批量更新体验

  • 代码:③ 更新shopee新增「预览本轮更新」按钮,预览不再依赖⑤里的 dry-run 开关;正式「开始更新」固定走真实更新安全开关和确认弹窗,弹窗展示任务数、每批最大更新条数和预计批次。
  • 分批:ApplyWorker 新增 batch_size,真实更新按当前筛选全部可更新记录切批执行;每批写运行日志,summary/progress/run_log options 记录 batch_size 和 batch_count;点击停止为协作式停止,不再开始下一条或下一批。
  • 设置页:⑤ 隐藏用户可见 dry-run 开关,保存设置时将 dry_run 固定为 False;模型详情、角色与生成参数、路径与端口、Shopee 更新安全改为三列布局,内容区居中并加大左右留白。
  • 测试:更新 tests/test_gui.py 覆盖预览按钮、不再按总数阻断、Worker 分批日志、设置页 dry-run 隐藏与保存为 False。
  • 文档:docs/00-ai-start-here.md、docs/04-architecture.md、docs/routes.md 同步新语义;docs/06-tasks.md 将 T-506 标记 DONE,docs/current-state.md 更新当前实现快照。
  • 验证:python -m py_compile app/gui.py tests/test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(54 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(135 tests);git diff --check 无空白错误(仅 LF/CRLF 提示)。

【2026-06-30】设置页微调 · 左右留白缩短为约 40%

  • 背景:用户反馈 ⑤ 设置模块两边空白需要缩短为当前约 40%。
  • 代码:app/gui.py 中 SettingsTab 外层 layout.setContentsMargins(45, 18, 45, 18) 调整为 18, 18, 18, 18,中间内容区 panel_layout.setContentsMargins(32, 18, 32, 18) 调整为 13, 18, 13, 18;保留居中内容区和三列表单,当前 panel.setMaximumWidth(1800) 用于减少宽屏下的左右空白。
  • 文档:同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md,将 250% 留白描述改为约 40% / 适度留白。

【2026-06-30】设置页微调 · 保存成功提示框

  • 背景:⑤ 设置点击「保存设置」成功后原来只写状态栏,用户不容易感知保存结果。
  • 文档:先同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/current-state.md,明确保存成功后保留状态栏提示并弹轻量提示框。
  • 代码:SettingsTab.save_app_settings() 在保存、替换配置、回填表单并设置状态栏后,调用 QMessageBox.information(self, "保存设置", "设置已保存")。
  • 测试:更新 tests/test_gui.py 的设置保存用例,mock 成功提示框并断言标题/文案,避免模态框阻塞测试。

【2026-06-30】设置页微调 · 最大并行账号数移到多账号并行后

  • 文档:先同步 docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md,明确 Shopee 更新安全三列布局中「最大并行账号数」必须位于「多账号并行更新」后面同一行。
  • 代码:SettingsTab 的 Shopee 更新安全字段顺序调整为第二行「允许更新封面 / 多账号并行更新 / 最大并行账号数」,「成功后关闭本次新开编辑页」移动到下一行;同时保留 self.shopee_update_form_layout 供测试定位。
  • 测试:tests/test_gui.py 新增布局位置断言,确认 max_parallel_accounts_spin 与 parallel_accounts_checkbox 同行且在其后。

【2026-06-30】设置页微调 · 并行账号数与并行开关合并同一组件

  • 背景:用户确认「最大并行账号数」不是只放到同一网格行,而是必须紧跟「多账号并行更新」后面,不能显示到下面。
  • 文档:先同步 docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md,明确「多账号并行更新」与「最大并行账号数」合并为同一个横向组件,最大并行账号数紧跟其后且不换行。
  • 代码:SettingsTab 新增 parallel_accounts_group,内部用 QHBoxLayout 顺序放置 parallel_accounts_checkbox、max_parallel_accounts_label、max_parallel_accounts_spin;Shopee 更新安全表单支持字段跨 2 个组件位,并把该组合组件放在「允许更新封面」后面。
  • 测试:更新 tests/test_gui.py,断言组合组件与「允许更新封面」同一行,跨 2 个组件位,且内部 widget 顺序为多账号并行开关、最大并行账号数标签、输入框。

【2026-06-30】文档补充 · T-507 移除普通流程测试商品 ID 限制

  • 背景:正式批量更新时,③「开始更新」当前仍因任务包含非测试商品 ID 阻断,只允许更新 ⑤ 配置的测试商品 ID。这适合开发测试阶段,但不适合正式批量更新真实商品。
  • 决策:新增 T-507。普通正式更新不再以 test_item_id 阻断当前筛选结果;当前筛选结果可包含多个真实商品 ID。test_item_id 仅保留为历史/调试兼容字段,后续如需要调试模式再单独启用。
  • 保留安全闸:允许真实提交线上商品、允许更新封面、每批最大更新条数、开始更新二次确认、账号 Chrome/CDP/登录态预检、多账号并行上限、运行日志和 Excel 回写。
  • 文档:同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/04-architecture.md、docs/06-tasks.md、docs/current-state.md。本轮只更新文档,代码尚未改;下一步代码更新前仍会因非测试商品 ID 阻断。

【2026-06-30】代码更新 · T-507 移除普通流程测试商品 ID 限制

  • 代码:ApplyTab._update_safety_error() 移除 test_item_id 非空与商品 ID 比对阻断;普通正式更新只继续检查「允许真实提交线上商品」和「允许更新封面」。
  • 代码:③「开始更新」确认弹窗不再显示测试商品 ID;当前筛选结果可包含多个真实商品 ID,仍按每批最大更新条数分批执行。
  • 代码:⑤ 设置页隐藏普通用户可见的测试商品 ID 输入入口,但保留 test_item_id 字段加载/保存兼容旧配置和后续调试模式。
  • 测试:更新 tests/test_gui.py,覆盖确认弹窗不含测试商品 ID、非测试商品 ID/空测试商品 ID 不再阻断、设置页测试商品 ID 入口隐藏且配置兼容。
  • 验证:python -m py_compile app/gui.py tests/test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(54 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(135 tests)。

【2026-06-30】T-404 补丁 · 上传前点击上传块模拟人工路径

  • 现象:商品 26887160467 更新封面时,代码删除第一张图片后直接 DOM.setFileInputFiles,Shopee 图片组件长期转圈;同一张约 220KB 图片在浏览器手动上传成功。
  • 分析:文件大小和格式不是主因;差异在于人工流程会先点击「新增图片」上传块,Shopee 前端可能在点击时初始化上传队列,而旧代码直接给隐藏 input 注入文件,可能导致队列未完整初始化。
  • 文档:先同步 docs/04-architecture.md、docs/api.md、docs/06-tasks.md、docs/current-state.md,将封面上传策略改为“点击上传块 → 短暂等待 → 重新获取 input → DOM.setFileInputFiles → 派发 input/change”。
  • 代码:app/editor.py 新增 JS_CLICK_UPLOAD_TILE 和 _click_upload_tile();replace_cover() 在上传前先点击 .shopee-image-manager__upload,等待 1 秒后重新获取 input[type=file],再注入本地图片;失败时返回 UPLOAD_TILE_NOT_READY 并带 upload_click 诊断。
  • 测试:tests/test_editor_login.py 扩展 FakeCoverCDP,新增上传块点击成功和上传块不可点击的回归测试,确认执行 DOM.setFileInputFiles 时上传块已先被点击。
  • 验证:python -m py_compile app/editor.py tests/test_editor_login.py 通过;python -m unittest discover -s tests -p "test_editor_login.py" 通过(30 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(137 tests)。T-404 仍需真实商品复跑确认。

【2026-06-30】T-404 补丁 · 返回商品列表后延迟关闭 tab

  • 背景:真实流程为点击页面主「更新」后出现 Shopee 确认弹窗,点击弹窗主按钮「更新」后跳回我的商品列表页;如果此时立即关闭本轮新开的 tab,可能不给页面跳转与状态稳定留时间。
  • 文档:先同步 docs/04-architecture.md、docs/api.md、docs/routes.md、docs/06-tasks.md、docs/current-state.md,明确 close_success_tab=true 且成功提交、tab 为本轮自动新开时,确认后跳回商品列表页场景关闭前等待 2 秒。
  • 代码:app/editor.py 的 _close_applied_product() 在真正调用 close_tab(target_id, host=...) 前执行 time.sleep(2);失败任务、复用的用户已有 tab、未开启 close_success_tab 的任务不等待关闭。
  • 测试:更新 tests/test_editor_login.py,成功提交并关闭自动新开 tab 的路径断言 time.sleep(2);失败提交路径断言不关闭且不等待。
  • 验证:python -m py_compile app/editor.py tests/test_editor_login.py 通过;python -m unittest discover -s tests -p "test_editor_login.py" 通过(30 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(137 tests)。T-404 仍需真实商品复跑确认。

【2026-06-30】T-404/T-502 补丁 · 8张图也先删第一张 + 图片路径按批次细分

  • 第1点文档:同步 docs/04-architecture.md、docs/api.md、docs/routes.md、docs/05-coding-rules.md、docs/06-tasks.md、docs/current-state.md,明确更新封面统一按“替换第一张”执行,不再只在满 9 张时删除;有1張重複的圖片 / 重複 / 重复 / duplicate 作为封面上传错误立即失败。
  • 第1点代码:app/editor.py 的 replace_cover() 改为只要有新封面就先校验 old_cover_path 本地备份,再删除当前第一张、等待稳定、点击上传块并上传新图;上传循环优先处理错误 toast,重复图返回 UPLOAD_DUPLICATE_IMAGE。tests/test_editor_login.py 覆盖 8 张图也删除第一张、重复图片 toast 和旧备份缺失保护。
  • 第2点文档:同步本地图片目录规则,新采集/新生成图片改为 images/<batch_id>/<slug>/<task_id>_<item_id>_old/new.jpg;DB 已存旧路径继续作为权威路径,不迁移、不推断。
  • 第2点代码:新增 app/image_paths.py 统一图片路径 helper;CollectWorker 的旧封面目标路径、ai.generate_batch() 的新封面目标路径、editor.collect() 兜底旧封面路径均接入该规则。历史 old_cover_path/new_cover_path 仍按 DB 记录读取。
  • 测试:新增 tests/test_image_paths.py;更新 tests/test_ai.py、tests/test_gui.py、tests/test_editor_login.py。验证通过:python -m py_compile app/image_paths.py app/ai.py app/gui.py app/editor.py tests/test_image_paths.py tests/test_ai.py tests/test_gui.py tests/test_editor_login.py;python -m unittest discover -s tests -p "test_image_paths.py"(2 tests);python -m unittest discover -s tests -p "test_ai.py"(7 tests);python -m unittest discover -s tests -p "test_gui.py"(54 tests);python -m unittest discover -s tests -p "test_editor_login.py"(32 tests);python -m compileall app main.py;python -m unittest discover -s tests(141 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。
  • 下一步:用户复跑 T-404 真实商品链路,重点确认 8 张图商品先删第一张、重复图片提示不再拖到超时、新图片上传成功后可提交。

【2026-07-01】T-404 完成 · 5 个真实商品更新 Shopee 验收

  • 验收事实:用户手动导入包含 5 个商品 ID 的 Excel,完成 AI 标题和图片生成,并通过 Tab③「开始更新」流程更新到 Shopee。
  • 覆盖链路:Excel 导入 → AI 生成标题/图片 → Tab③ 安全确认与账号预检 → 打开真实商品详情页 → 更新标题/封面 → Shopee 站点侧确认框 → 提交到线上 → 本地更新结果链路。
  • 结论:该实测已超过 T-404 原本“真实 Shopee 单条更新冒烟验收”的范围,T-404 标记为 DONE。
  • 后续:可以开始 T-206「Tab① 删除指定批次」;实现时仍需保留已上线记录提示,默认不删除本地图片,只有用户勾选时才清理关联封面文件。

【2026-07-01】T-206 完成 · Tab① 指定批次软删除

  • 产品决策:删除指定批次改为软删除,不物理删除 batches/tasks,也不删除原 Excel 或本地图片;删除后该批次默认不能在软件页面查看、筛选、采集、生成、更新或回写。
  • 数据库:batches 增加 deleted_at/deleted_reason,init_db() 自动补旧库字段;delete_batch() 只写删除标记并返回任务数、已提交线上数、关联图片路径;list_batches/list_tasks/get_task 默认排除已软删除批次,include_deleted=True 仅供诊断/测试。
  • GUI:① 导入采集页新增批次下拉和「删除批次」按钮;只能删除具体批次,运行中禁用;确认框显示任务数、已提交线上数,并提示不会回滚 Shopee。确认后刷新①自身和②/③批次筛选与任务列表。
  • 测试:新增 DB 软删除默认过滤测试;新增 GUI 软删除回归测试,覆盖删除后①/②/③下拉和任务列表都不再包含该批次,且默认 get_task 也不能绕过软删除。
  • 验证:python -m py_compile app\db.py app\gui.py tests\test_db.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_db.py" 通过(6 tests);python -m unittest discover -s tests -p "test_gui.py" -k soft_deletes 通过(1 test);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(143 tests);git diff --check 无空白错误(仅 LF/CRLF 提示)。
  • 下一步:T-505 全流程诊断日志扩展。

【2026-07-01】T-508/T-509 完成 · 更新区生产化与新标题微调

  • 产品化:③「开始更新」改为主操作视觉;「重置更新状态」从底部批处理区移到任务表右键菜单,保持运行中禁用,避免与批量线上提交放在同一操作组。
  • 安全拦截:③ 更新安全开关阻断弹窗现在写明具体未开启设置,并提供「前往设置」跳到⑤,便于正式使用时快速修正配置。
  • 新标题微调:②「新标题」列允许已生成、未提交线上、非运行中任务双击本地编辑;写回 tasks.new_title,保留 stage=generated,清空 last_error 并回到可更新状态,不触碰 Shopee/CDP/Excel/封面。
  • 测试:新增 DB 与 GUI 回归测试,覆盖本地标题编辑、③ 右键重置入口、开始更新主按钮标识、安全拦截前往设置。
  • 验证:python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(145 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。

【2026-07-01】T-510 完成 · 「预览本轮更新」改名为「检查本轮更新」

  • 文档:先同步 docs/00-ai-start-here.md、docs/02-requirements.md、docs/04-architecture.md、docs/06-tasks.md、docs/api.md、docs/routes.md、docs/current-state.md,新增 T-510,明确用户可见按钮/弹窗/日志统一使用「检查本轮更新」。
  • 代码:app/gui.py 将③按钮、风险提示、确认框标题、取消/开始/完成状态、完成弹窗和 dry-run 运行日志文案从「预览本轮更新」改为「检查本轮更新」;内部 preview_update_button、preview_update() 与 dry_run 字段保留,不改变执行语义。
  • 测试:更新 tests/test_gui.py 的按钮文案、状态栏和 dry-run 日志断言。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(57 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(145 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。

【2026-07-01】T-505 完成 · 全流程诊断日志扩展

  • 范围:在 T-207 采集诊断和②AI生成诊断基础上,补齐 Excel 导入/回写、③更新shopee、④Chrome 启动/登录检测、⑤AI模型测试连接的业务运行日志与本地脱敏诊断日志。
  • 代码:app/gui.py 新增安全 run log helper;CollectTab.import_excel() 写 run_type=import,记录选中文件、缺列、脏行和入库统计;WriteBackWorker 写 run_type=write_back,记录写入文件、行数和文件锁/保存异常;ApplyWorker 的 run_type=apply 改为步骤级事件,覆盖预检、Chrome/CDP 检查、登录检测、打开商品页、改标题、换封面、点更新、写库;④「启动登录」写 run_type=chrome_launch,登录检测 worker 写 run_type=login_check;⑤AI模型测试连接写 run_type=ai_model_test。
  • CDP:app/editor.py 只给 apply_task() 增加可选 on_step 回调,用于上报 open_product/change_title/replace_cover/click_update,不改选择器、上传方式、确认框点击或提交逻辑。
  • 安全:DB 业务日志和本地 logs/cmshopee.log 均通过现有脱敏工具处理,不记录 Cookie、密码、API Key、token;异常路径本地日志保留脱敏 traceback。
  • 测试:新增/更新 tests/test_gui.py 覆盖 import/write_back/apply/chrome_launch/login_check/ai_model_test 运行日志和本地日志脱敏;python -m py_compile app\gui.py app\editor.py tests\test_gui.py 通过;python -m unittest discover -s tests -p test_gui.py 通过(63 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(151 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。

【2026-07-01】T-511 完成 · 语义色板与任务状态列上色

  • 范围:按 docs/ui-color-design.md 落地第一步状态列上色,只改 GUI 展示层,不改 CDP、Shopee 提交流程、DB schema 或业务状态流转。
  • 代码:app/gui.py 顶部新增统一语义色板常量(success/danger/info/pending/muted/warning/danger-bg),TaskTableModel、GenerateTaskTableModel、ApplyTaskTableModel 在状态相关列响应 Qt.ForegroundRole,按内部 stage/status 返回 QColor;完成态用 success、失败用 danger、略过/取消用 muted、待处理用 pending、进行中用 info,不按中文显示文案硬匹配,不给普通行刷底色。
  • 测试:tests/test_gui.py 新增状态列前景色断言,覆盖①待采集/未匹配、②待生成/已生成/失败、③待更新/失败/已更新。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(63 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(151 tests)。测试输出仍有 PySide6 字体目录提示,不影响结果。
  • 下一步:T-512「③高风险按钮上色 + ①导入校验数字标红」。

【2026-07-01】T-512 完成 · 高风险按钮与导入校验数字标红

  • 范围:按 docs/ui-color-design.md 落地第二步颜色优化,只改 GUI 样式层,不改 Tab 名、不改 CDP、Shopee 提交流程、DB schema 或业务状态流转。
  • 代码:③「开始更新」按钮使用 warning #bc4c00 文字和描边,保留「停止」中性;①导入汇总使用 rich text 将无效行数 >0、未匹配数 >0 标为 danger #cf222e;未匹配按钮 >0 时同样使用 danger 描边/文字并保持可点击筛出,=0 时清空样式并禁用;无效行仅标红提示,不新增筛表入口。
  • 测试:tests/test_gui.py 新增开始更新按钮 warning 样式、未匹配按钮 danger 样式、无效行 rich text danger 标记断言。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(63 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(151 tests)。测试输出仍有 PySide6 字体目录提示,不影响结果。
  • 下一步:T-513「登录点 / ③Tab危险标识 / 破坏性按钮上色」。

【2026-07-02】T-513 完成 · 登录点、③Tab风险标识与破坏性按钮上色

  • 文档先行:补充 docs/ui-color-design.md 的 T-513 落地口径,明确④登录状态列显示 ● 状态 并用 QTableWidgetItem.setForeground(QColor(...)) 上色;③更新shopee Tab 用 QTabWidget.setTabIcon(2, ...) 的小 warning 圆点,不改 Tab 文案/文字色;删除类按钮只用 danger 文字/描边,二次确认仍是主防线。
  • 代码:app/gui.py 新增 _login_status_display()、_login_status_color()、_warning_dot_icon();④账号管理登录状态列按状态着色(已登录 success、检测中 info、未登录/检测失败 danger、未知/已启动 muted);③更新shopee Tab 设置 warning 小圆点图标;①「删除批次」和④「删除账号」复用 danger 描边样式。
  • 测试:tests/test_gui.py 补充主窗口 ③Tab icon、账号登录状态文本与颜色、删除账号/删除批次按钮 danger 样式断言。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(63 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(151 tests)。测试输出仍有 PySide6 字体目录提示,不影响结果。
  • 下一步:T-514「①②③ 首次空状态引导卡片」。

【2026-07-02】T-514 完成 · ①②③首次空状态引导卡片

  • 文档先行:扩展 docs/06-tasks.md 的 T-514 口径,明确无账号时①②③均显示「前往账号管理」引导,有账号但无任务时分别提示①导入 Excel、②先完成①采集、③先完成②生成;卡片只做 UI 引导,不替代执行前账号/Chrome/登录态预检。
  • 代码:app/gui.py 新增共享 _build_empty_state_card() / _set_empty_state();①导入采集、②AI生成、③更新shopee在刷新任务时按账号和任务状态显示/隐藏空状态卡片;②新增 open_accounts_callback 并由 MainWindow 传入跳④回调;原有导入、采集、生成、更新和安全拦截流程不变。
  • 测试:tests/test_gui.py 新增①②③空状态断言,覆盖无账号时按钮跳④、有账号但无任务时显示对应下一步提示且隐藏跳④按钮。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(66 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(154 tests)。测试输出仍有 PySide6 字体目录提示,不影响结果。
  • 下一步:T-515「批次阶段进度总览」。

【2026-07-02】T-515 完成 · 批次阶段进度总览

  • 文档先行:docs/06-tasks.md 将 T-515 标记为 DOING 后补充计数口径,明确①②③同显当前批次/全部批次总数、导入、已采集、已生成、已更新、失败、略过,失败/略过按 status 优先统计,不新增表、不改执行流程。
  • 代码:app/gui.py 新增共享批次进度聚合和总览条;①导入采集、②AI生成、③更新shopee在摘要区下方展示同一组计数。③任务列表仍只显示可更新相关记录,但总览使用当前批次全部未软删除任务统计。
  • 测试:tests/test_gui.py 新增①②③批次进度总览覆盖,构造导入/已采集/已生成/已更新/失败/略过各 1 条,并确认软删除批次不出现在筛选和计数中。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py、python -m unittest discover -s tests -p "test_gui.py"(67 tests)、python -m compileall app main.py、python -m unittest discover -s tests(155 tests)均通过;Qt 仍有本机字体目录提示,不影响测试结果。
  • 下一步:T-516「①筛选对齐②③」。

【2026-07-02】T-516 完成 · ①筛选对齐②③

  • 文档先行:docs/06-tasks.md 将 T-516 标记为 DOING 后补充验收口径,明确①新增店铺、商品ID、状态筛选;当前筛选结果用于①表格和采集作用范围,导入汇总栏/批次进度/未匹配数量仍按当前批次全量统计。
  • 代码:app/gui.py 的①导入采集新增 collectShopFilter、collectItemFilter、collectStatusFilter,筛选栏顺序对齐②③;刷新时用全量批次任务更新汇总和进度,用筛选后任务更新表格;「采集旧标题/旧封面」改为只处理当前表格可见任务;采集/回写运行中禁用新增筛选控件。
  • 测试:tests/test_gui.py 新增①筛选覆盖,验证店铺、商品ID、状态筛选、空结果提示、未匹配筛出和采集 worker 接收当前筛选任务。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py、python -m unittest discover -s tests -p "test_gui.py"(68 tests)、python -m compileall app main.py、python -m unittest discover -s tests(156 tests)均通过;Qt 仍有本机字体目录提示,不影响测试结果。
  • 下一步:T-517「⑤设置分区 + 清理兼容字段」。

【2026-07-02】T-517 完成 · ⑤设置分区与兼容字段清理

  • 文档先行:docs/06-tasks.md 将 T-517 标记为 DOING 后明确范围:只改⑤设置页 UI 分区、保存/加载展示和 GUI 测试,不改配置 schema,不改 Shopee/CDP 更新流程。
  • 代码:app/gui.py 将「Shopee 更新安全 / 执行模式」前置为独立分区,将「基础设施(路径与端口)」后置;移除 test_item_id_edit、dry_run_checkbox 这类用户入口,加载时只记录 test_item_id 内部兼容值,保存时保留该值并固定 dry_run=false。
  • 测试:tests/test_gui.py 更新设置页断言,覆盖分区顺序、旧入口不存在、保存设置仍同步 ApplyTab 安全配置且兼容字段不丢。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(68 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(156 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。

【2026-07-02】T-518 文档启动 · ②左栏提示词区组件密度优化

  • 背景:Claude Code review T-511~T-517 未发现问题;下一步从 docs/06-tasks.md Backlog 和 docs/ux-review.md P2 提升②左栏组件密度优化为正式任务。
  • 文档:docs/06-tasks.md 新增 T-518 并标记 DOING,明确只收敛②AI生成左栏封面模板低频操作「另存为/重命名/删除」,第一版不移入⑤,不改 prompts 数据结构、AI生成、DB、Excel、Shopee/CDP 流程;同步 docs/current-state.md 与 docs/ux-review.md。
  • 验证:文档-only 更新,未运行单元测试。
  • 下一步:按 T-518 文档更新 app/gui.py 和 tests/test_gui.py。

【2026-07-02】T-518 完成 · ②左栏提示词区组件密度优化

  • 代码:app/gui.py 将②AI生成左栏封面模板低频操作「另存为 / 重命名 / 删除」从平铺按钮收敛进「模板操作」菜单;「新建」「保存」继续作为可见按钮,菜单 action 仍调用原有模板保存/重命名/删除方法,删除二次确认和错误处理不变。
  • 范围控制:不迁移到⑤设置,不改 prompts 数据结构,不改 AI 生成 HTTP、DB schema、Excel 或 Shopee/CDP 流程。
  • 测试:tests/test_gui.py 覆盖「模板操作」菜单入口、菜单 action 触发原有行为,以及旧低频按钮不再平铺。
  • 验证:python -m py_compile app\gui.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(68 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(156 tests)。Qt 仍有本机字体目录提示,不影响测试结果。

【2026-07-02】T-519 文档启动 · ②AI生成长任务进度条与用户日志

  • 背景:用户反馈批量生成几十/上百个标题或图片超时重试时耗时较长,需要在②AI生成里更清楚地看到剩余量、是否卡住、慢在哪一步。
  • 文档:docs/06-tasks.md 新增 T-519 并标记 DOING,明确②底部增加标题/图片两条独立进度条,现有「AI生成运行日志」增强为用户可读自动滚动日志;日志展示本轮开始、标题/图片开始与成功、商品ID/店铺、图片超时/重试、失败原因、停止请求和完成汇总,同时禁止显示 API Key、密码、Cookie、token、完整请求体、base64 图片或超长 prompt。
  • 范围:只改②生成 UI、GenerateWorker/AI 生成事件文案和测试;不改 AI HTTP 协议、DB schema、Excel、Shopee/CDP 流程。
  • 验证:文档-only 更新,未运行单元测试。
  • 下一步:按 T-519 文档更新 app/gui.py、app/ai.py 和相关测试。

【2026-07-02】T-519 完成 · ②AI生成长任务进度条与用户日志

  • 代码:app/gui.py 在②AI生成底部增加标题/图片两条独立 QProgressBar,分别显示 标题 x/y、图片 x/y 和失败数;保留原进度文本用于状态汇总;现有「AI生成运行日志」追加后自动滚到底部,加载最近一次日志时按时间顺序显示。
  • 日志:GenerateWorker 将生成事件转为用户可读短句,显示本轮开始、标题/图片开始与成功、商品ID/店铺、调用失败重试、失败、停止请求和完成汇总;日志继续通过脱敏工具处理并写入 run_logs/run_log_events。
  • AI事件:app/ai.py 的 _call_with_retry() 支持 on_retry 回调,标题/图片请求失败但仍会重试时上报 retry 事件;不改 AI HTTP 协议、DB schema、Excel 或 Shopee/CDP 流程。
  • 测试:tests/test_gui.py 覆盖双进度条初始状态、用户可读日志、重试日志脱敏和旧日志加载;tests/test_ai.py 覆盖标题生成重试事件上报。
  • 验证:python -m py_compile app\ai.py app\gui.py tests\test_ai.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_ai.py" 通过(7 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(68 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(156 tests)。Qt 仍有本机字体目录提示,不影响测试结果。

【2026-07-02】T-520 文档启动 · ②AI生成封面可选生成开关

  • 背景:②AI生成当前默认标题和图片都生成,图片模型成本明显高于标题;用户只想改标题时也会产生图片生成成本。⑤「允许更新封面」只控制③线上提交阶段,不能替代②生成阶段的成本选择。
  • 决策:新增 T-520。②AI生成页增加「生成封面图片(成本较高)」复选框,默认关闭并持久化到 config.json 的 ai.generate_cover;关闭时只生成标题,标题成功即 db.set_generated(task_id, new_title, NULL),③只更新标题;开启时保持标题后图片两段流程。
  • 文档:同步 docs/02-requirements.md、docs/04-architecture.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md。本轮只更新文档,未改代码。
  • 下一步:按 T-520 文档更新 app/appconfig.py、app/ai.py、app/gui.py 和相关单测。

【2026-07-02】T-520 完成 · ②AI生成封面可选生成开关

  • 配置:app/appconfig.py 新增 ai.generate_cover=false 默认值;②AI生成页复选框状态会持久化到 config.json,设置页保存其他 AI 参数时保留该隐藏成本开关。
  • 代码:app/ai.py 的 generate_batch() 按 generate_cover 分支执行;关闭时只生成标题,标题成功即 db.set_generated(task_id, new_title, None) 并进入 generated,不调用 gen_cover()、不渲染封面提示词、不创建新封面文件;开启时保留标题后图片两段流程。
  • GUI:app/gui.py 在②底部增加「生成封面图片(成本较高)」复选框;开始生成前保存当前开关;标题-only 模式进度显示 图片0/0,运行日志写明“本轮仅生成标题,不生成图片”,完成统计使用 generated_done,避免只看 cover_done。
  • 测试:tests/test_appconfig.py 覆盖默认关闭;tests/test_ai.py 覆盖跳过封面时不调用 gen_cover 且任务进入 generated;tests/test_gui.py 覆盖开关持久化、Worker 标题-only 日志/运行日志统计,以及旧图片路径显式开启开关。
  • 验证:python -m py_compile app\appconfig.py app\ai.py app\gui.py tests\test_appconfig.py tests\test_ai.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_appconfig.py" 通过(7 tests);python -m unittest discover -s tests -p "test_ai.py" 通过(8 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(70 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(159 tests);git diff --check 无空白错误,仅 LF/CRLF 提示。Qt 仍有本机字体目录提示,不影响测试结果。

【2026-07-02】T-521 完成 · 依赖清单(锁版本 requirements)

  • 代码/配置:新增根目录 requirements.txt,锁定当前直接运行依赖:PySide6==6.5.3、openpyxl==3.1.3、requests==2.31.0、websocket-client==1.6.1、Pillow==9.5.0;不新增运行时依赖,不改业务代码。
  • 文档:docs/03-tech-stack.md 的安装命令改为 python -m pip install -r requirements.txt,并补充依赖纪律;docs/README.md 增加运行环境安装命令;docs/06-tasks.md 标记 T-521 DONE;docs/current-state.md 同步当前快照和下一任务 T-522。
  • 验证:python -c "import PySide6, openpyxl, requests, websocket, PIL; ..." 确认当前版本;python -m pip install --no-index -r requirements.txt 确认当前环境已满足锁定依赖且不触网;python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(159 tests)。python -m pip check 在全局环境发现 albumentations/paddleocr/flask-babel 等非本项目包的既有依赖冲突,非 T-521 新增依赖导致;本项目锁定的 5 个直接依赖可正常 import。

【2026-07-02】T-522 完成 · CI 自动跑语法 + 单元 / GUI 测试

  • 配置:新增 .github/workflows/tests.yml,在 push / pull_request 上使用 windows-latest + Python 3.11,安装 requirements.txt,设置 QT_QPA_PLATFORM=offscreen,运行 python -m compileall app main.py 与 python -m unittest discover -s tests。
  • 文档:同步 docs/03-tech-stack.md、docs/README.md、docs/current-state.md;docs/06-tasks.md 将 T-522 标为 DONE,下一个可领取任务更新为 T-523。
  • 验证:python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(159 tests);git diff --check 无空白错误(仅 LF/CRLF 提示)。本地未执行 GitHub Actions 远端 runner,workflow 已按同等命令配置。

【2026-07-02】T-523 完成 · 拆分 app/gui.py 为 app/gui/ 包

  • 代码:删除旧 app/gui.py,新增 app/gui/ 包;__init__.py 保持 from app import gui、from app.gui import MainWindow/各 Tab/各 Worker 等旧导入兼容;main_window.py 放 MainWindow;models.py 放 3 个 TableModel;widgets.py 放 Qt 导入、语义色板、空状态卡、批次总览和日志 helper;workers.py 放 GenerateWorker/ApplyWorker/CollectWorker/WriteBackWorker/AccountLoginCheckWorker/AIModelTestWorker;tabs/ 按 ①~⑤ 拆分各 Tab。
  • 边界:纯结构重构;未改 Shopee/CDP、AI、DB、Excel 行为;PySide6 缺失时仍由 main() 返回 1 并提示,旧公开导入路径继续可用。
  • 文档:同步 docs/04-architecture.md、docs/api.md、docs/current-state.md;docs/06-tasks.md 将 T-523 标为 DONE,下一个可领取任务更新为 T-524。
  • 验证:python -m compileall app main.py 通过;python -m unittest discover -s tests -p "test_gui.py" 通过(70 tests);python -m unittest discover -s tests 通过(159 tests)。

【2026-07-02】文档 · T-523a ②/③ 本轮日志显示重置

  • 需求:②AI生成和③更新shopee启动新一轮运行时,不应继续显示上一轮日志,避免用户把旧失败、旧进度误认为本轮状态。
  • 方案:新增 T-523a;点击②「开始生成」、③「检查本轮更新」或③「开始更新」时,先清空对应界面的可见日志显示区,并写入本轮开始摘要;运行中只追加本轮日志,完成后保留本轮日志。只清空界面文本,不删除 SQLite run_logs/run_log_events 或本地 logs/ 诊断日志。
  • 文档:同步 docs/02-requirements.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md;当前下一个可领取任务改为 T-523a。
  • 验证:文档-only 更新,未运行单元测试。

【2026-07-02】T-523a 完成 · ②/③ 本轮日志显示重置

  • 代码:GenerateTab 和 ApplyTab 进入页面后不再自动加载上一轮历史日志,默认显示“本轮日志会在开始运行后显示”;②点击「开始生成」时清空可见日志并写入本轮 AI 生成摘要;③点击「检查本轮更新」或「开始更新」并确认后清空可见日志并写入本轮检查/更新摘要。
  • 边界:只清空 GUI 文本显示,不删除 SQLite run_logs/run_log_events 或本地 logs/;未改 AI HTTP、DB schema、Excel、Shopee/CDP 更新流程。
  • 测试:更新 tests/test_gui.py,覆盖②/③进入页面不自动混入历史日志,以及②开始生成、③检查/真实更新启动时旧日志被清掉且本轮摘要出现。
  • 文档:docs/06-tasks.md 将 T-523a 标为 DONE;同步 docs/current-state.md,下一个可领取任务更新为 T-524。
  • 验证:python -m unittest discover -s tests -p "test_gui.py" 通过(72 tests)。

【2026-07-02】文档 · T-404b 商品详情页加载失败 toast 自动捕获

  • 需求:商品 ID 失效、无权限或店铺不匹配时,Shopee 商品详情页可能只弹出很快消失的错误 toast,例如 please input correct product id;用户来不及复制 HTML,当前错误也可能只表现为商品详情页等待超时。
  • 方案:新增 T-404b。open_product()/等待商品详情页就绪前安装或启用 .eds-toasts .eds-toast__content 捕获,保存 toast 文本、outerHTML、当前 URL、时间和可见状态;详情页关键元素超时或页面不符合商品编辑页时,把最近错误 toast 上浮到 tasks.last_error、run_logs/run_log_events、③/①可见日志和本地 logs/ 诊断日志。可保存失败现场 HTML/toast JSON,禁止记录 Cookie、密码、token。
  • 文档:同步 docs/02-requirements.md、docs/04-architecture.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md;当前下一个可领取任务改为 T-404b。
  • 验证:文档-only 更新,未运行单元测试。

【2026-07-02】文档补充 · T-404b 商品失效显示边界

  • 需求补充:用户确认①导入采集列表可以在商品 ID 失效时显示更直观的“商品失效”,但必须确认不会影响②AI生成、③更新shopee、进度统计和 Excel 回写。
  • 决策:只做 UI 显示映射,不新增或改写数据库 stage 枚举。捕获到明确商品失效/商品不存在/无权限类 toast 时,任务底层保持 stage=imported/status=failed/last_error=商品失效:<原始toast>,①列表“阶段”列显示“商品失效”;网络、CDP、未登录、页面超时、风控等其他打开失败仍显示“失败”。
  • 文档:同步 docs/02-requirements.md、docs/04-architecture.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md。
  • 验证:文档-only 更新,未运行单元测试。

【2026-07-02】T-404b 完成 · 商品详情页加载失败 toast 自动捕获

  • 代码:app/editor.py 在 open_product() 导航商品详情页前后安装 toast 观察器,缓存最近 toast 的文本、HTML、URL、可见状态和时间;_wait_ready() 超时或检测到失效 toast 时,将商品失效/商品不存在/无权限类文案上浮为 商品失效:<原始toast>,其他打开失败仍保持普通失败原因。
  • GUI:①导入采集任务表只在 last_error 明确包含商品失效类错误时把“阶段”列显示为“商品失效”;底层 DB 不新增 stage 枚举,仍保持 stage=imported/status=failed,其他超时、网络、登录、风控类错误仍显示“失败”。
  • 测试:tests/test_editor_login.py 覆盖隐藏 toast 捕获、失效 toast 错误上浮和 open_product 安装观察器;tests/test_gui.py 覆盖只有明确失效错误才显示“商品失效”。
  • 验证:已通过相关测试;全量验证见本轮最终结果。

【2026-07-02】文档补充 · T-404b 商品失效失败 tab 清理

  • 问题:商品 ID 失效时,_wait_ready() 在 open_product() 内部抛出 商品失效:...,上层 collect() / apply_task() 尚未拿到 cdp,因此上层 finally 无法关闭本轮自动新建的商品 tab。
  • 方案:补充 T-404b 边界。open_product() 如果在返回 cdp 前失败,要自行清理:本轮自动新建 tab 先断开 CDP 再调用 close_tab(target_id, host=...);复用用户原本打开的 tab 只断开 CDP,不关闭页面。进入编辑页后的更新失败仍按原设计保留现场。
  • 文档:同步 docs/02-requirements.md、docs/04-architecture.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md。
  • 验证:文档-only 更新,未运行单元测试。

【2026-07-02】T-404b 补丁完成 · 商品失效失败 tab 自动清理

  • 代码:app/editor.py 新增 open_product() 内部失败清理。若 _wait_ready() 因商品失效 toast 或其他打开页异常在返回 cdp 前抛错,会先断开 CDP;本轮自动新建的商品 tab 继续调用 close_tab(target_id, host=...) 关闭,复用用户已有 tab 不关闭。
  • 边界:只处理 open_product() 内部打开失败导致的残留 tab;进入编辑页后的更新失败仍按原设计保留现场,成功提交后的关闭仍受 ⑤ close_success_tab 控制。
  • 测试:tests/test_editor_login.py 增加自动新建 tab 商品失效时关闭、复用 tab 商品失效时不关闭的覆盖。
  • 验证:python -m unittest discover -s tests -p "test_editor_login.py" 通过(36 tests)。

【2026-07-02】文档 · T-103b 登录检测补充识别 Shopee accounts 登录页

  • 需求:打开商品详情页或卖家中心时,未登录账号可能跳转到 https://accounts.shopee.tw/seller/login...。④「检测登录」以及①/③执行前账号预检应明确把该 URL 判为未登录,不能依赖模糊规则或误判为普通无 Cookie。
  • 方案:新增 T-103b。登录页 URL marker 显式加入 accounts.shopee.tw/seller/login / Shopee accounts 域名下 /seller/login;login_status() 返回 logged_in=false/reason=LOGIN_PAGE/url=<实际URL>;④状态列显示“未登录”,①/③预检继续阻断并引导去④。
  • 边界:不自动登录、不填密码、不绕过验证码;只增强登录页识别和测试覆盖,不改 CDP 商品页、上传、提交逻辑。
  • 文档:同步 docs/02-requirements.md、docs/04-architecture.md、docs/routes.md、docs/api.md、docs/06-tasks.md、docs/current-state.md;当前下一个可领取任务改为 T-103b。
  • 验证:文档-only 更新,未运行单元测试。

【2026-07-02】T-103b 完成 · 登录检测补充识别 Shopee accounts 登录页

  • 代码:app/editor.py 的 LOGIN_PATH_MARKERS 显式加入 accounts.shopee.tw/seller/login,_is_login_url() 增加 accounts.shopee.* 域名且路径以 /seller/login 开头的判断。
  • 行为:login_status() 遇到 https://accounts.shopee.tw/seller/login... 立即返回 logged_in=false/reason=LOGIN_PAGE/url=<实际URL>,④状态列会显示未登录,①/③预检继续阻断并引导去④。
  • 边界:不自动登录、不填密码、不绕过验证码;未改商品页、上传、提交逻辑。
  • 测试:tests/test_editor_login.py 增加真实 accounts 登录 URL 覆盖。
  • 验证:python -m unittest discover -s tests -p "test_editor_login.py" 通过(37 tests)。

【2026-07-03】T-524 完成 · PyInstaller 打包为免安装 exe

  • 代码/配置:新增 cmshopee.spec、scripts/build_exe.ps1、requirements-build.txt;main.py 在 PyInstaller frozen 模式下把工作目录切到 cmshopee.exe 所在目录,确保配置、DB、图片、日志、登录态和提示词在 exe 同级目录生成/读取;.gitignore 新增 build/、dist/、db.sqlite、prompts/、title_prompt.txt。
  • 打包安全:cmshopee.spec 不声明本地数据 datas;构建脚本打包后检查 dist\cmshopee,发现 config.json、config/ai_models.json、cmshopee.db*、db.sqlite、chrome_user_data_dir/、images/、logs/、prompts/、title_prompt.txt 会直接失败;脚本会打印当前 Python 版本,低于项目目标 3.10 时给出警告。
  • 文档:新增 docs/packaging.md,同步 docs/README.md、docs/03-tech-stack.md、docs/06-tasks.md、docs/current-state.md;T-524 标为 DONE,下一个可领取任务更新为 T-525。
  • 测试:新增 tests/test_packaging.py 覆盖 frozen 入口路径、spec 不打包本地数据、构建脚本排除列表。
  • 验证:python -m compileall app main.py 通过;python -m unittest discover -s tests -p "test_packaging.py" 通过(3 tests);python -m unittest discover -s tests 通过(170 tests);git diff --check 无空白错误(仅 LF/CRLF 提示);powershell -ExecutionPolicy Bypass -File scripts\build_exe.ps1 成功产出 dist\cmshopee\cmshopee.exe,脚本确认未混入本地数据。本机当前 python 为 3.7.9,构建脚本已提示低于项目目标;正式发布建议切到 Python 3.10+ 环境后重新打包。

【2026-07-04】文档修正 · cmhub 网关对接任务定义

  • 背景:Claude Code 已新增 docs/cmhub-integration-design.md 与 T-526~T-528;本轮从全栈工程角度评审后修正任务边界,避免未配置 cmhub 时破坏现有 direct 生文/生图流程。
  • 修正:docs/cmhub-integration-design.md 增补 v3 评审结论,明确旧配置缺 backend 时按 direct 迁移、cmhub Key 固定存 config/cmhub.json、新增 CMHubError 结构化错误、点数/余额通过事件回调传播、cmhub HTTP 调用需区分 connect/read timeout、image_url 下载需安全校验。
  • 任务:docs/06-tasks.md 将业务优先级调整为 Phase 7 cmhub,对 T-526/T-527/T-528 验收重写;T-525 ruff 顺延到 Phase 8。docs/current-state.md 下一个可领取任务改为 T-526。
  • 验证:文档-only 更新,未改代码,未运行单元测试。

【2026-07-04】文档修正 · cmhub v3.2 六点一致性收口

  • 修正:docs/cmhub-integration-design.md 将目标接口改为 title/image/balance/models 四类接口;统一 gen_title/gen_cover 为“返回值与现有调用兼容,可新增可选事件回调参数”;把不存在的 default_ai_config() 改为现有 DEFAULT_CONFIG / default_config() 表述;明确 T-526 只发出计费 metadata 事件,T-528 再负责 GUI run_logs 与余额展示;补充 image_url 域名解析后 IP 也要拒绝内网/回环/本机地址。
  • 任务:docs/06-tasks.md 将 T-526/T-527/T-528 引用统一为 docs/cmhub-integration-design.md v3.2,并同步 T-526 的 run_logs 边界与安全下载验收。
  • 验证:文档-only 更新,未改代码,未运行单元测试。

【2026-07-04】T-526 完成 · app/ai.py + appconfig 接入 cmhub backend

  • 状态:DONE
  • 变更:app/appconfig.py 在 config.json 的 ai 段新增 backend=direct/cmhub 和 ai.cmhub 默认配置,新增 config/cmhub.json 的读写/打码 helper;.gitignore 增加 config/cmhub.json。app/ai.py 保留 direct 直连模型清单路径,新增 cmhub 生文、生图和 /models 别名发现 helper;gen_title() / gen_cover() 返回值不变,cmhub 计费 metadata 通过事件回调传出;新增 CMHubError 结构化错误、按 code 的重试策略、tuple timeout、生图读超时不自动重发、image_url http/https + DNS/IP 内网拦截 + 大小上限下载。
  • 文档:同步 docs/03-tech-stack.md、docs/04-architecture.md、docs/api.md、docs/06-tasks.md、docs/current-state.md;T-526 标记 DONE,下一步为 T-527。
  • 测试:python -m py_compile app\appconfig.py app\ai.py tests\test_appconfig.py tests\test_ai.py 通过;python -m unittest discover -s tests -p "test_appconfig.py" 通过(8 tests);python -m unittest discover -s tests -p "test_ai.py" 通过(16 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(179 tests)。全量测试仍有本机 PySide6 字体目录提示,不影响结果。
  • 决策:全新配置和旧配置缺 ai.backend 时都保持 direct,避免升级后未配置 cmhub 就破坏现有生成;cmhub Key 固定只进 config/cmhub.json,不进 config.json;T-526 只传出 metadata,GUI 余额/计费提示留给 T-528。
  • 下一步:T-527 ⑤设置 cmhub 网关面板。

【2026-07-04】T-527 完成 · ⑤设置 cmhub 网关面板

  • 状态:DONE
  • 代码:⑤设置页新增 AI 后端选择,direct 模式保留现有 config/ai_models.json 模型 master-detail 和直连模型测试;cmhub 模式显示网关 Base URL、API Key、生文别名、生图别名、刷新别名、测试连接/查余额和余额结果。cmhub Key 单独保存到 config/cmhub.json,保存新 Key 时沿用本地明文保存提示,config.json 只保存 backend、Base URL、别名、连接超时和余额预检开关。
  • 别名:CMHubSettingsWorker 后台调用 fetch_cmhub_models(),⑤设置页首次显示且已配置 Base URL/Key 时自动刷新一次,也可手动点「刷新别名」;按 operation_type 拆分生文/生图,过滤 pricing_status="unpriced",下拉展示点数价格和 requires_image 提示;网关暂不可达或已存别名不在可用列表时保留已存值,避免保存设置时清空用户配置。
  • 余额:app/ai.py 新增 fetch_cmhub_balance() 调 GET /api/v1/balance,设置页「测试连接/查余额」复用同一个 worker 拉模型和余额;worker 失败会用本地 Key 脱敏后再上浮错误。
  • 边界:未改 Shopee/CDP、Excel、DB schema、账号流程;config/ai_models.json 在切换 cmhub 时不删除,仍供 direct 模式回退使用。
  • 测试:tests/test_ai.py 覆盖 cmhub 余额 helper;tests/test_gui.py 覆盖 CMHubSettingsWorker 成功/失败脱敏、设置页 cmhub backend 切换、保存 config.json + config/cmhub.json、别名过滤与已存值保留。
  • 文档:docs/06-tasks.md 将 T-527 标为 DONE;同步 docs/current-state.md,下一步为 T-528。
  • 验证:python -m py_compile tests\test_ai.py tests\test_gui.py 通过;python -m unittest discover -s tests -p "test_ai.py" 通过(17 tests);python -m unittest discover -s tests -p "test_gui.py" 通过(77 tests);python -m compileall app main.py 通过;python -m unittest discover -s tests 通过(184 tests);git diff --check 无空白错误(仅 LF/CRLF 提示)。全量测试仍有本机 PySide6 字体目录提示,不影响结果。
  • 下一步:T-528 ②计费错误提示 + 余额展示。