Files
cmshoppe/docs/current-state.md
T
2026-07-07 15:11:40 +08:00

212 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 当前实现状态
> 本文是可覆盖的当前快照,记录代码与任务看板的现实状态。
> 历史执行流水追加到 [`../progress.md`](../progress.md),不在本文重复完整日志。
## 当前快照
- 日期:2026-07-07
- 阶段:V0 单账号 CDP 流程已验证;V1 已完成 T-000 正式代码包结构、T-001 `app/editor.py` 模块化、T-002 `app/appconfig.py` 应用配置、T-003 SQLite 持久化地基、T-004 本地数据忽略规则、T-005 AI 模型清单后端、T-006 单元测试基座、T-101 账号 user-data-dir 工具、T-102 Chrome 启动器、T-103 登录保活与检测、T-103b 登录检测补充识别 Shopee accounts 登录页、T-104 PySide6 主窗口骨架、T-104b PySide6 worker 基座、T-105 Tab④ 账号管理、T-105b ④启动登录复用已打开 Chrome、T-106 账号快捷方式、T-201 Excel 导入入库、T-202 Tab① 任务列表与导入按钮、T-202b Tab① 导入汇总栏、T-203 采集旧标题旧封面、T-204 回写旧字段到原 Excel、T-204b 采集完成自动回写、T-205 首次未配账号/Chrome 未启动/未登录引导保护、T-205b 采集后关闭自动新建商品页 tab、T-206 Tab① 删除指定批次软删除、T-301 AI 生成接口、T-302 Tab② AI 生成布局与任务列表、T-302p 提示词管理、T-303 Tab② 开始生成/停止/进度、T-303b ②/③ 商品ID筛选、T-401 Tab③ 更新列表筛选与开始更新确认、T-402 Tab③ 确认后串行更新、T-403 Tab③ 结果回写与结束汇总、T-501 Tab⑤ AI 模型管理 UI、T-501b Tab⑤ 角色与生成参数、T-501c Tab⑤ 蝦皮更新安全开关、T-502 换封面删第一张再上传、T-503 敏感信息本地明文保存提示与日志脱敏、T-504 多账号并行/dry-run/运行日志、T-207 ①采集诊断日志、② AI生成图片失败诊断日志补丁、T-404a ②/③ 选中记录重置、T-404 真实 Shopee 单条更新冒烟验收、T-506 正式使用批量更新体验、T-507 正式批量更新移除普通流程测试商品 ID 限制、T-508 ③ 更新蝦皮生产化操作区、T-509 ② 新标题人工微调、T-510 ③ 检查本轮更新文案统一、T-505 全流程诊断日志扩展、T-511 语义色板与任务状态列上色、T-512 ③高风险按钮上色与①导入校验数字标红、T-513 登录点/③Tab危险标识/破坏性按钮上色、T-514 ①②③ 首次空状态引导卡片、T-515 批次阶段进度总览、T-516 ①筛选对齐②③、T-517 ⑤设置分区与兼容字段清理、T-518 ②左栏提示词区组件密度优化、T-519 ②AI生成长任务进度条与用户可读滚动日志、T-520 ②AI生成封面可选生成开关、T-521 依赖清单(锁版本 requirements)、T-522 CI 自动跑语法 + 单元 / GUI 测试、T-523 拆分 `app/gui.py` 为 `app/gui/` 包、T-523a ②/③ 新一轮运行前清空界面日志显示、T-404b 商品详情页加载失败 toast 自动捕获、T-524 PyInstaller 打包为免安装 exe、T-526 `app/ai.py` + `appconfig` 接入 cmhub backend、T-527 ⑤设置 cmhub 网关面板、T-528 ②计费错误提示与余额展示、T-529 默认 cmhub 网关并隐藏 AI 后端选择、T-530 cmhub Base URL 规整与 404 明确提示、T-531 ⑤设置未保存状态追踪与离开确认、T-532 ⑤cmhub连接成功提示显示账号名、T-533 ②增量生成:按缺失组件补生成、T-534 ②重置增强:多选/筛选范围 + 按组件重置、T-535 ②cmhub生成标题读取等待固定600秒、T-536 GUI按钮圆角全局统一、T-537 品牌名显示为蝦皮圈優化助手、T-538 打包产物用户数据收进 `data/`、T-540 打包版本号与 release 产物命名统一、T-541 打包版主窗口初始位置与小屏适配、T-542 GUI 用户可见 shopee/Shopee 文案统一改为蝦皮。
- T-542 已完成:运行程序后 GUI 用户可见 `shopee/Shopee` 平台名统一显示为「蝦皮」(例如「③ 更新蝦皮」「蝦皮更新安全」);内部标识符、配置键、URL、域名、CDP 选择器和第三方原始错误仍保留原名。
- T-525 已完成:根目录新增 `pyproject.toml` 与 `requirements-dev.txt`,引入 ruff 0.5.7;当前只开启安全类规则(`E4/E7/E9/F`),CI 已在语法检查和 unittest 前运行 `python -m ruff check app tests main.py`;`ruff format` 配置可用,但本轮不做全仓格式化重排。
- 测试卫生修正:`WriteBackWorker` 的 GUI 单测不再使用相对路径 `db.sqlite`,改为临时目录内 SQLite,避免跑测试后在项目根目录重新生成空 `db.sqlite`。
- 技术栈:正式打包固定 Python 3.10(脚本调用 `py -3.10`),CI 使用 Windows + Python 3.11 自动跑 ruff lint、语法和单元/GUI 测试,根目录 `requirements.txt` 锁定运行依赖,`requirements-dev.txt` 锁定开发检查依赖(ruff),PyInstaller onedir 打包为 Windows 免安装 exe;自研 CDP(websocket-client + requests),SQLite(sqlite3)+ `data/config.json` + openpyxl + AI(默认 cmhub: `data/config.json` 网关配置 + `data/config/cmhub.json` Key;direct: `data/config/ai_models.json` 通用 HTTP 内部兼容),GUI PySide6 5 Tab(已定)。
- 生产代码:已建立 `app/` 包 + 根入口 `main.py`;`app/cdp.py` 为已验证 CDP 底座,已区分 `CDP.close()` 断开 WebSocket 与 `close_tab()` 关闭浏览器 target;`app/editor.py` 已封装登录状态检测、标题/封面/采集/更新按钮能力,打开商品详情页时会安装 toast 捕获并在详情页加载失败时上浮商品失效/无权限等错误原因,`open_product()` 内部失败会关闭本轮自动新建的失败 tab,复用用户已有 tab 不关闭,并在采集结束后只关闭本轮自动新建的商品编辑页 tab、保留用户已有 tab,更新提交成功且设置开启时可关闭本轮自动新建商品页,确认后跳回商品列表页时关闭前等待 2 秒;`click_update()` 已补 Shopee 站点侧确认框处理,页面主「更新」后若出现 `確定您要更新商品嗎?` modal(`.eds-modal__content` / `.eds-modal__box`),只点击弹窗主按钮「更新」并避开「立即優化」,且记录确认后是否跳回商品列表页;`replace_cover()` 已实现更新封面统一先校验本地旧封面备份,再点第一张删除、可见确认框、等待图片管理器稳定和上传 input 恢复,随后先点击上传块模拟人工入口、短暂等待、重新获取 input、注入文件上传新图并等待 蝦皮 CDN 后拖到第一位的代码路径;已修正 2026-06-30 稳定等待回归:删除第一张前不要求上传 input 可用,只等图片列表稳定;删除后再等上传入口恢复;`重複/重复/duplicate` 上传 toast 会立即判为新封面重复错误;`app/image_paths.py` 已统一新采集/新生成图片路径为 `images/<batch_id>/<slug>/<task_id>_<item_id>_old/new.jpg`,历史 DB 路径继续按原路径读取;`app/appconfig.py` 已实现 `config.json` 默认值/读写/更新、AI 参数、端口读取、蝦皮更新安全与执行模式默认值,`ai.backend` 默认 `cmhub`,`config/ai_models.json` 模型清单 CRUD/过滤/打码/测试连接与 OpenAI-compatible base URL 自动补 endpoint,`config/cmhub.json` cmhub Key 读写/打码 helper、cmhub Base URL 规整与请求 URL 拼接 helper,以及 `mask_secret()`、`sanitize_for_log()`、`redact_secrets()` 敏感信息脱敏工具;`app/ai.py` 已实现 `gen_title()`/`gen_cover()`/`generate_batch()`,支持 direct 通用 HTTP 和 cmhub 网关 backend,direct 按默认文本/图片模型调用,cmhub 按 Base URL + 生文/生图别名调用 title/image/models/balance 接口,生图 `image_url` 安全下载后转本地 JPEG,计费 metadata 通过事件回调传出,HTTP 404 映射为 `not_found` 并给出中文排障提示,且保留重试、错误脱敏、图片 URL/base64 解析、resolution resize、jpg_quality 保存、按 `ai.generate_cover` 选择只生成标题或先并发标题再并发封面、逐条 `set_generated`、失败 `mark_failed`、步骤级事件/错误回调与停止取消未开始项;`app/prompts.py` 已实现标题提示词读写、封面模板 CRUD 与变量替换;`app/db.py` 已实现 SQLite schema、连接 PRAGMA、批次/账号/任务与阶段写库函数、T-206 批次软删除标记与默认业务查询过滤、T-404a/T-534 本地生成结果/更新状态重置函数(②生成结果可按标题/封面组件重置并保持 generated)、T-509 `update_generated_title()` 本地新标题微调函数,以及 `run_logs/run_log_events` 运行日志函数;`app/diagnostics.py` 已实现 gitignore 本地诊断日志、滚动写入、结构化 payload 和自由文本脱敏;T-505 已把 Excel 导入/回写、③更新蝦皮、④Chrome 启动/登录检测、⑤AI模型测试连接接入 `run_logs/run_log_events` 与本地脱敏诊断日志;`app/excel.py` 已实现多 Excel 输入列解析、整文件列校验、脏行统计跳过、导入批次与任务入库、别名匹配统计、旧标题/旧封面路径回写原 Excel、更新结果回写原 Excel 与另存副本;`app/config.py` 已实现账号 slug 与 user-data-dir 创建;`app/accounts.py` 已实现账号 CRUD 服务、端口默认分配、启动登录幂等复用已打开 Chrome、检测登录、生成快捷方式;`app/chrome.py` 已实现 Chrome 参数拼装、启动、CDP 端口探测、PowerShell `.lnk` 快捷方式生成;`app/gui/` 已由 T-523 拆分为 PySide6 GUI 包,包入口 `__init__.py` 兼容旧导入,`main_window.py` 放 `MainWindow`,`models.py` 放 3 个 TableModel,`widgets.py` 放色板/空状态/批次总览/helper,`workers.py` 放具体 GUI worker,`tabs/` 放 ①~⑤ Tab;整体仍实现 PySide6 `MainWindow`(窗口标题显示「蝦皮圈優化助手」)、五 Tab、顶部 Tab 栏防误点样式、统一语义色板、①②③任务状态列前景色、③「开始更新」warning 描边/文字色和①导入校验数字标红、④登录状态点上色、③更新蝦皮 Tab warning 小圆点和删除类按钮 danger 样式、①②③首次空状态引导卡片、①②③批次阶段进度总览、① 导入采集的 Excel 导入按钮/导入汇总栏/批次筛选与删除批次软删除入口/QTableView 任务列表/未匹配筛选与略过标记/采集旧标题旧封面 worker/采集前账号就绪预检与④引导/采集完成自动回写/旧数据回写重试按钮与 worker/采集运行日志视图、② AI生成左右布局/标题与封面提示词管理/批次/店铺/商品ID/状态筛选/任务列表/新标题列本地微调/变量预览/生成封面图片成本开关/开始生成/停止/标题与图片双进度条/双击新旧封面预览/用户可读自动滚动AI生成运行日志/cmhub余额显示/点数不足弹窗/计费日志/重置生成结果与 `GenerateWorker`,且②重置支持多选/当前筛选结果并可只重置标题、只重置封面或重置全部;③ 更新蝦皮批次/店铺/商品ID/状态筛选栏/任务列表/开始更新主按钮/重置更新状态右键菜单/更新安全开关拦截与「前往设置」跳转/「检查本轮更新」按钮/开始更新确认弹窗/确认后 `ApplyWorker` 按每批最大更新条数分批执行当前筛选全部可更新记录/账号就绪和端口冲突预检/按账号并行可选/逐条 `set_applied`/运行日志/自动回写结果到 Excel/结束汇总弹窗/手动回写重试按钮、④ 账号管理表格/弹窗/按钮/快捷方式与状态栏、密码明文保存提示、⑤ 设置页 T-529 后默认展示 cmhub 网关 Base URL、API Key、动态生文/生图别名下拉、Base URL 网关根提示、刷新别名与测试连接/查余额,不再显示「AI 后端」label/dropdown、direct 模型选择、模型详情或标题/图片模型角色下拉;保存设置固定写 `ai.backend=cmhub`,保存/刷新前会把 Base URL 规整为网关根,允许先保存不完整 cmhub 配置,生成时再提示补齐;direct 模型配置、`AIModelTestWorker` 和 `config/ai_models.json` 仅作内部兼容/手工回滚;通用生成参数、路径/端口、蝦皮更新安全与多账号并行设置继续持久化 `config.json`,cmhub Key 单独写入 `config/cmhub.json`,保存成功后弹轻量提示框;⑤ 设置页已将「蝦皮更新安全 / 执行模式」前置、将「基础设施(路径与端口)」后置,`test_item_id` 与 `dry_run` 不再有用户可操作控件,保存时保留 `test_item_id` 兼容值并固定 `dry_run=false`;③ 普通正式更新不再用 `test_item_id` 阻断非测试商品,确认弹窗不再显示测试商品 ID;`app/workers.py` 已实现 `BaseWorker`、通用 signals、取消标记和 `QThread` 启动包装。
- 测试:`tests/` 已建立;T-522 已新增 GitHub Actions 在 push / pull_request 自动运行语法检查与全量 unittest,T-525 后 CI 先运行 ruff 安全类 lint;T-006 后纯逻辑改动必须运行 `python -m unittest discover -s tests`,当前覆盖 appconfig/db/config/accounts(含 T-105b 启动登录复用已运行 Chrome)/chrome 启动与快捷方式/editor 登录检测(含 Shopee accounts 登录页)与商品 tab 生命周期、商品详情页失效/隐藏 toast 捕获、更新成功后关闭本轮新开 tab、更新封面备份缺失阻断/8张与9张先删第一张/删除确认/上传入口初始不可用/重复图片 toast/物流错误不阻断上传/删图后稳定等待/上传状态诊断/拖首位 mock 路径/Shopee 更新确认框、成功跳回商品列表和残留错误 toast 不覆盖成功 mock 路径/excel 导入/旧字段与更新结果回写/ai 标题与封面 HTTP 解析/`generate_batch` 正常、失败与停止/prompts 读写与渲染/gui ① 导入采集、删除批次软删除与采集诊断日志/gui ② AI生成布局与批次/店铺/商品ID/状态筛选、提示词管理、生成 worker、图片失败诊断日志、双击预览、重置生成结果与新标题本地编辑/gui ③ 更新蝦皮批次/店铺/商品ID/状态筛选列表、确认弹窗、开始更新主按钮、重置更新状态右键菜单、蝦皮更新安全拦截与前往设置、`ApplyWorker` 串行/检查/分批/按账号并行/端口冲突预检、运行日志、结果回写与汇总/gui ④ 账号管理、密码打码与明文保存提示/gui ⑤ AI 模型管理、API Key 打码与明文保存提示、角色/生成参数设置、蝦皮更新安全设置、检查按钮/每批最大更新条数/多账号并行设置、测试商品 ID 限制移除/worker signal 与线程包装、T-505 全流程诊断日志(import/write_back/apply/chrome_launch/login_check/ai_model_test)与本地日志脱敏、gui T-511 语义色板和任务状态列前景色、T-512 高风险按钮与导入校验数字样式、T-513 登录状态/Tab 标识/删除按钮样式、T-514 首次空状态引导卡片、T-515 批次阶段进度总览、T-516 ①筛选对齐②③、T-517 ⑤设置分区与兼容字段清理、T-518 ②左栏提示词区组件密度优化、T-519 ②AI生成长任务进度条与用户可读滚动日志、T-520 ②AI生成封面可选生成开关、T-524 PyInstaller 打包入口/构建脚本/发布目录校验、T-526 cmhub backend mock、T-527 设置页 cmhub backend 切换/别名下拉/worker mock、T-528 ②cmhub余额显示/计费日志/点数不足中止提示、T-529 默认 cmhub/隐藏 AI 后端选择/保存固定 cmhub/direct 兼容、T-530 cmhub Base URL 规整/404 not_found 明确提示、T-531 设置页未保存状态/离开确认/放弃还原、T-532 cmhub连接成功账号名提示、T-533 增量生成组件口径、T-534 ②按标题/封面组件重置与多选/筛选范围重置、T-535 cmhub标题请求读取等待固定600秒、T-536 GUI按钮全局基础样式与语义色按钮叠加样式、T-537 主窗口标题显示中文品牌;2026-07-01 已完成 5 个真实商品的 T-404 更新验收,后续 CDP/Shopee 改动仍需测试商品手动验证。
- 数据:T-538 后默认用户数据根为 `data/`(整体 gitignore);旧布局的 `config.json`、`config/ai_models.json`、`config/cmhub.json`、`cmshopee.db`、`cmshopee.db-*`、`chrome_user_data_dir/`、`images/`、`logs/`、`prompts/`、`title_prompt.txt`、`build/`、`dist/` 仍由 `.gitignore` 排除以支持迁移前安全;密码与 API Key 本地明文保存但保存/变更时提示,UI 打码,日志/导出必须脱敏;运营填写后的 Excel 业务文件默认忽略,标准空模板 `shopee待处理任务模板.xlsx` 可提交;`app/appconfig.py` 首次读取缺失的 `data/config.json` 时会在本地写默认配置,`app/db.py` 调用 `init_db()` 时会在本地创建 SQLite DB。
## 既定设计要点(文档已定)
- 产品显示名:`蝦皮圈優化助手`;`cmshopee` 仅作为仓库、代码、打包产物、数据库、日志和兼容文件名等技术代号保留。
- GUI:**PySide6 5 Tab 流水线**,目标顺序文案为 ① 导入采集 → ② AI生成 → ③ 更新蝦皮 → ④ 账号管理 → ⑤ 设置;后台任务用 worker/QThread/signal。
- 全局用户可见文案规则:弹窗标题/正文/按钮、窗口标题、按钮、菜单、label、placeholder、tooltip、状态栏、空状态、确认框、运行日志、错误提示和成功提示等都必须使用中文。运行程序后 GUI 上的 `shopee/Shopee` 平台名统一显示为「蝦皮」;URL、配置键、API 字段、模型别名、第三方/Shopee 原始错误可保留原文,但必须配中文解释,不得裸露英文技术报错。
- 流水线阶段:imported → collected(采集旧标题/旧封面+下载+回写)→ generated(AI 提示词生成新标题/新封面)→ applied(③ 弹窗批量确认后改 Shopee 并提交)。**无 confirmed、无常驻提交开关。**
- 存储:`data/config.json`(应用设置和 AI backend 内部字段,普通默认 cmhub)+ `data/config/ai_models.json`(direct AI 模型清单与本地明文 Key)+ `data/config/cmhub.json`(cmhub 本地明文 Key)+ SQLite `data/cmshopee.db`(账号/任务/各阶段结果,密码本地明文仅参考)+ openpyxl(Excel)+ 本地 `data/images/`(旧/新封面);密码/API Key 保存或变更时提示,展示和日志/导出必须脱敏。
- 多账号隔离:每账号独立 user-data-dir(非 profile)。
- 账号↔任务绑定:以 Excel“别名”列为权威;未匹配略过,结束弹窗汇总。
- 执行:默认多账号串行、单条失败继续;③ 提供「检查本轮更新」按钮,检查只写运行日志和汇总,不打开 Shopee、不提交线上、不改任务状态;⑤ 可开启多账号并行(不同账号并行、同账号内串行)并设置每批最大更新条数。③ 点击「开始更新」后先按真实更新安全设置弹窗确认当前筛选范围、任务数量、每批大小和预计批次;确认后做本轮账号 Chrome/CDP/登录态预检,未启动或未登录则弹窗列出账号并中止、不自动打开 Chrome;账号就绪后按批逐条点「更新」提交线上,点击停止后不再开始下一条或下一批。
- AI:普通产品默认 `backend=cmhub`,由 `data/config.json` 的 Base URL/别名和 `data/config/cmhub.json` Key 配置,Base URL 会规整为网关根;`app/ai.py` 仍支持 `backend=direct` 作为内部兼容/手工回滚路径,direct 由 `data/config/ai_models.json` 配置服务商/模型/Key。生成返回值保持不变,计费 metadata 通过事件传出。生成内容直接用于更新,本地留档+回写 Excel 供追溯。
- 登录:人工登录 + 程序检测,不自动登录;④「启动登录」会打开或复用对应账号浏览器供人工登录,④「检测登录」和①/③预检只验证登录态;无 Shopee tab 时检测入口为 `https://<region_host>/`(默认 `https://seller.shopee.tw/`);页面跳到 `accounts.shopee.tw/seller/login` 时已明确判为未登录;首次未配账号、对应账号 Chrome 未启动或未登录时,① ③ 应禁用或执行前预检提示,并引导去④,③ 不静默启动缺失账号 Chrome。
## 当前目录要点
| 路径 | 状态 | 说明 |
| --- | --- | --- |
| `docs/` | 已有 | 本 harness coding 文档集合 |
| `docs/packaging.md` | 已有 | T-524/T-538 产出:PyInstaller 打包命令、发布目录排除本地数据规则、首次运行 `data/` 数据位置、旧顶层布局迁移和用户手动覆盖程序文件并保留 `data/` 的更新步骤 |
| `app/cdp.py` | 已有 | CDP 底座:连接/找 tab/开 tab/关闭 target/执行 JS/拖拽;`CDP.close()` 只断开 WebSocket,`close_tab()` 才关闭浏览器页面 |
| `prototypes/` | 已有 | 已验证原型/探查脚本(demo/set_title/set_cover/get_title/cookies/inspect_images/grab/1.py),保留作人工回归与探查参考;见 `prototypes/README.md` |
| `chrome-remote-debug-lan.md` | 已有 | WSL→Windows CDP 转发排查记录 |
| `docs/troubleshooting.md` | 已有 | 常见问题排查;已记录 `data/config/ai_models.json` 缺失 `category`、cmhub 404、②无可生成任务、④启动登录重复开 Chrome,以及打包版窗口左上角显示不全/标题栏不可拖动的原因、临时处理和修复方案 |
| `app/__init__.py` / `app/__main__.py` / `main.py` | 已有 | 正式包与启动入口;`python main.py` / `python -m app` 可运行占位入口 |
| `requirements.txt` | 已有 | T-521 产出:锁定运行时直接依赖 PySide6 6.5.3、openpyxl 3.1.3、requests 2.31.0、websocket-client 1.6.1、Pillow 9.5.0;换机/CI 使用 `python -m pip install -r requirements.txt` |
| `requirements-dev.txt` | 已有 | T-525 产出:锁定开发检查依赖 ruff 0.5.7;不属于运行时或打包依赖 |
| `pyproject.toml` | 已有 | T-525 产出:ruff 配置;当前 lint 只开启 `E4/E7/E9/F` 安全规则,格式化配置可用但不强制全仓重排 |
| `requirements-build.txt` | 已有 | T-524/T-540 产出:打包环境依赖,先安装运行依赖再安装 PyInstaller 6.11.1;不作为运行时依赖文件 |
| `.github/workflows/tests.yml` | 已有 | T-522/T-525 产出:push / pull_request 自动在 `windows-latest` + Python 3.11 安装 `requirements.txt` 与 `requirements-dev.txt`,设置 `QT_QPA_PLATFORM=offscreen`,运行 ruff lint、`python -m compileall app main.py` 与 `python -m unittest discover -s tests` |
| `app/version.py` | 已有 | T-540 产出:统一维护 `APP_NAME`、`APP_CODE_NAME`、`APP_VERSION` 和窗口显示名;GUI 标题、打包脚本、release 目录、portable zip 和 `version.txt` 共用该版本源 |
| `cmshopee.spec` / `scripts/build_exe.ps1` | 已有 | T-524/T-540 产出:PyInstaller onedir 构建配置与发布目录校验脚本;`cmshopee.spec` 不声明本地数据 `datas`,脚本固定使用 `py -3.10`,先检查 `dist\\cmshopee` 不含配置、DB、图片、日志、Chrome 登录态或提示词,再组装 `release\\cmshopee-<APP_VERSION>\\` 与 `release\\cmshopee-<APP_VERSION>-portable.zip` |
| `app/gui/` | 已有 | T-523 产出:由旧 `app/gui.py` 拆分的 PySide6 GUI 包,包入口 `__init__.py` 继续兼容 `from app import gui` / `from app.gui import MainWindow`;`main_window.py` 放 MainWindow,`models.py` 放 3 个 TableModel,`widgets.py` 放色板/空状态/批次总览/helper,`workers.py` 放具体 GUI workers,`tabs/` 放 ①~⑤ Tab; T-104/T-105/T-106/T-202/T-202b/T-203/T-204/T-204b/T-205/T-206/T-207/T-302/T-302p/T-303/T-303b/T-401/T-402/T-403/T-404a/T-501/T-501b/T-501c/T-503/T-504/T-506/T-507/T-508/T-509/T-510/T-505/T-511/T-512/T-513/T-514/T-515/T-516/T-517/T-518/T-519/T-520/T-527/T-528/T-529/T-530/T-531/T-532/T-536/T-537/T-540/T-541/T-542 产出:PySide6 `QMainWindow` + 五 Tab;窗口标题显示「蝦皮圈優化助手 v<APP_VERSION>」,启动时按屏幕可用区域限制尺寸、居中并保证标题栏可见;顶部 Tab 栏防误点样式;全局 `QPushButton` 基础样式统一 4px 圆角、hover/pressed/disabled/focus 状态;统一语义色板、①②③状态列前景色、③开始更新 warning 语义色、①导入校验数字标红、④登录状态点、③Tab warning 小圆点、删除/未匹配按钮 danger 语义色样式、①②③首次空状态引导卡片和批次阶段进度总览;① 导入采集导入按钮、导入汇总栏、批次/店铺/商品ID/状态筛选、删除批次软删除按钮、`QTableView` 任务列表、未匹配筛选与略过标记、采集旧标题旧封面 worker(旧封面路径按批次/店铺/任务细分)、采集前账号就绪预检与④引导、采集完成自动回写与手动重试、采集运行日志视图;② AI生成左右布局、提示词管理、批次/店铺/商品ID/状态筛选栏、任务列表、新标题列本地编辑、开始生成/停止/标题与图片双进度条、双击新旧封面预览、用户可读自动滚动AI生成运行日志、重置生成结果与 `GenerateWorker`;③ 更新蝦皮批次/店铺/商品ID/状态筛选栏、任务列表、开始更新主按钮、重置更新状态右键菜单、蝦皮更新安全拦截与「前往设置」跳转、「检查本轮更新」按钮、开始更新确认弹窗、`ApplyWorker` 检查/分批串行/按账号并行、账号与端口预检、运行日志、逐条 `set_applied`、自动回写结果到 Excel、结束汇总弹窗与手动回写重试;④ 账号管理表格、账号弹窗、密码本地明文保存提示、启动登录、检测登录、快捷方式;⑤ 设置普通默认展示 cmhub 网关 Base URL、API Key、生文/生图动态别名、Base URL 网关根提示、刷新别名、测试连接/查余额并保存 `config/cmhub.json` Key,不再显示 AI 后端选择、direct 模型选择/详情/角色下拉;direct 配置仅内部兼容/手工回滚;通用生成参数、路径端口配置、三列 蝦皮更新安全与执行模式设置仍保留,高频安全/执行模式分区前置、基础设施分区后置,`test_item_id`/`dry_run` 兼容字段无用户入口且普通更新不再阻断正式更新;②封面模板「另存为/重命名/删除」低频操作已收敛进「模板操作」菜单;②AI生成底部已增加标题/图片双进度条,运行日志已改为用户可读、自动滚动、脱敏的长任务日志,且②本轮「生成封面图片(成本较高)」开关默认关闭并持久化到 `ai.generate_cover`,关闭时只生成标题并进入可更新状态;②cmhub模式会显示生成后的剩余点数,记录 points_cost/call_id 计费日志,并在点数不足时弹提示且中止未开始任务;⑤设置页已显示“● 未保存更改”,切 Tab/关闭窗口时拦截保存/放弃/取消,放弃会从 `config.json` 与 `config/cmhub.json` 重新回填,刷新别名/测试连接不自动保存并提醒点保存;cmhub 测试连接/查余额成功时会优先显示 cmhub 账号名或脱敏邮箱,缺账号信息时保留普通成功提示 |
| `app/workers.py` | 已有 | T-104b 产出:`BaseWorker` + 通用 signals + 取消标记 + `run_worker()` QThread 包装 |
| `app/accounts.py` | 已有 | T-105/T-106 产出:账号 CRUD 服务、目录创建、端口分配、启动登录、检测登录、快捷方式 |
| `app/editor.py` | 已有 | T-001/T-103/T-205b/T-207/T-501c/T-502/T-404b + T-404 补丁产出:登录状态检测、打开商品页、详情页加载失败 toast 捕获与商品失效归因、读/写标题、读/下载封面、采集步骤回调、更新步骤回调、采集后关闭自动新建商品页 tab、上传前等待图片管理器稳定、点击上传块后注入文件并检测 CDN 后拖封面、更新封面统一先校验旧封面备份再删线上第一张、重复图片 toast 明确失败、页面主更新按钮、Shopee 站点侧确认框主按钮、apply_task;更新成功后可按设置关闭本轮自动新建商品页 |
| `app/appconfig.py` | 已有 | T-002/T-501c/T-503/T-504/T-520/T-526/T-527/T-538 产出:`data/config.json` 默认值、读写、更新、路径/端口/AI 参数读取、`data_dir` 路径解析、旧顶层用户数据迁移、`data/` 可写性检测、AI `backend=direct/cmhub` 和 `ai.cmhub` 默认值、`data/config/cmhub.json` Key helper、蝦皮更新安全与 dry-run/多账号并行默认值,②生成封面默认关闭的 `ai.generate_cover`;拒绝敏感字段写入;提供敏感值打码、结构化日志脱敏与自由文本替换工具 |
| `app/diagnostics.py` | 已有 | T-207 + AI生成诊断补丁 + T-505 产出:本地 `data/logs/cmshopee.log` 诊断日志、大小滚动、异常类型/traceback/step/耗时记录,结构化 payload 和自由文本脱敏后写入 |
| `app/ai.py` | 已有 | T-301/T-303 + AI生成诊断补丁 + T-519/T-520/T-526/T-528/T-533/T-535 产出:`gen_title()`/`gen_cover()`/`generate_batch()`;支持 direct 默认模型直连和 cmhub 网关 backend;cmhub 使用 `CMHubError` 结构化错误、tuple timeout、非幂等生图读超时不重发、`image_url` 安全下载、`fetch_cmhub_models()` 别名发现、`fetch_cmhub_balance()` 余额查询和 metadata 事件;cmhub 标题请求连接超时取 `ai.cmhub.connect_timeout`、读取等待固定 600 秒;direct 保留通用 HTTP 调用、失败重试、错误脱敏;封面按 resolution/jpg_quality 保存并按批次/店铺/任务路径落盘,封面请求与图片下载仍按分辨率读取等待;批量生成可按 `ai.generate_cover` 跳过封面阶段,开启封面时按缺失组件增量补齐,已有标题不重生、不覆盖手动标题,已有封面不重生;进度回调按标题/封面组件统计,逐条落库、失败标记、事件/错误回调、停止取消未开始项 |
| `app/prompts.py` | 已有 | T-302p 产出:标题提示词读写、封面模板列表/读取/保存/重命名/删除、变量替换 |
| `app/db.py` | 已有 | T-003/T-206/T-404a/T-504/T-509/T-534 产出:batches/accounts/tasks schema;batches 软删除字段与默认业务查询过滤;run_logs/run_log_events;WAL/busy_timeout/foreign_keys;账号/批次/任务与 set_* 阶段写库;生成结果/更新状态本地重置,②生成结果支持按标题/封面组件清空并保持 generated;`update_generated_title()` 本地新标题微调;运行日志写入与查询 |
| `app/config.py` | 已有 | T-101 产出:别名→稳定 slug;创建并返回绝对 user-data-dir |
| `app/image_paths.py` | 已有 | 本地图片路径 helper:T-538 后新采集旧封面和新生成封面默认写入 `data/images/<batch_id>/<slug>/<task_id>_<item_id>_old/new.jpg`;历史 DB 已存路径继续按原路径读取 |
| `app/chrome.py` | 已有 | T-102/T-106 产出:Chrome 启动参数、`subprocess.Popen` 启动、`/json/version` 端口探测、PowerShell `.lnk` 快捷方式 |
| `tests/` | 已有 | T-006/T-201/T-202/T-202b/T-203/T-204/T-204b/T-205/T-206/T-207/T-301/T-302/T-302p/T-303/T-303b/T-401/T-402/T-403/T-501/T-501b/T-501c/T-502/T-503/T-504/T-506/T-507/T-508/T-509/T-510/T-505/T-511/T-512/T-513/T-514/T-515/T-516/T-517/T-518/T-519/T-520/T-523/T-523a/T-404b/T-524/T-526/T-527/T-528/T-538/T-540/T-541/T-542 产出:stdlib unittest 基座;覆盖 appconfig/db/config/accounts/chrome/editor/excel/ai/image_paths/prompts/gui/workers/packaging,含 `data_dir` 路径解析、旧布局迁移、可写性检测、版本源、GUI 标题版本、打包 release 组装脚本校验和主窗口小屏适配 |
| `app/excel.py` | 已有 | T-201/T-204/T-403 产出:多文件 Excel 输入列解析、必需列整文件拒绝、脏行逐行跳过、批次/任务入库、匹配统计;按源文件/工作表/行号回写旧标题与旧封面路径;按源文件/工作表/行号回写新标题、新封面路径、更新状态;支持原文件被占用时另存副本 |
| `shopee待处理任务模板.xlsx` | 已有,已提交 | 标准空 Excel 模板;单工作表 `待处理任务`,表头 `账号名 | 别名 | 商品id | 旧标题 | 旧封面图片路径 | 新标题 | 新封面图片路径 | 更新状态`;运营复制后填写,填写副本不提交 |
| `data/` | 本地存在或按需生成,已忽略 | T-538 后统一用户数据根,包含 `config.json`、`config/ai_models.json`、`config/cmhub.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/`、`logs/`、`prompts/`、`title_prompt.txt` 等配置、密钥、业务、登录态、图片、本地诊断日志和用户提示词;打包更新时保留,不提交版本库 |
| 旧布局本地数据 | 兼容迁移,已忽略 | 顶层 `config.json` / `config/ai_models.json` / `config/cmhub.json` / `cmshopee.db` / `cmshopee.db-*` / `chrome_user_data_dir/` / `images/` / `logs/` / `prompts/` / `title_prompt.txt` 仍保持 gitignore;新版启动时若无冲突会迁移到 `data/` |
## 已验证能力(单账号)
- CDP 连接 Chrome、遍历 tab、读取 shopee.tw Cookie。
- 找到/新建商品详情页 tab,等编辑器就绪。
- 改标题:原生 setter + 派发事件,`value` 与 `modelvalue` 双等于新值。
- 换封面:`setFileInputFiles` 上传(`.shopee-image-manager__upload input[type=file]`)→ 等 CDN 链接 → 等 1 秒 → `Input.dispatchMouseEvent` 拖到第一位(落点 `first.left - 0.30*w`);使用 `1_TY030.jpg` 在测试商品验证通过。
- 「更新」按钮:可点才点,禁用态识别;③ 未批量确认前不提交。2026-06-29 测试商品实测:页面主「更新」后会出现 Shopee 站点侧确认框 `.eds-modal__content` / `.eds-modal__box`,标题 `確定您要更新商品嗎?`,底部 `立即優化` / 主按钮 `更新`;2026-06-30 用户复跑确认点击弹窗主按钮后提交成功,并跳回 `https://seller.shopee.tw/portal/product/list/all?operationSortBy=modified_time`,代码已记录该跳转结果;若设置开启且该 tab 是本轮自动新开,关闭前等待 2 秒。
- Tab① 真机冒烟(2026-06-27):账号 `papa`,导入临时 Excel 5 行,采集 5 条旧标题/旧封面,下载 5 张旧封面并回写临时 Excel 成功。
## 任务看板状态
任务状态以 [`06-tasks.md`](06-tasks.md) 为准,历史记录见 [`../progress.md`](../progress.md)。
- 已完成:T-000(正式代码包结构)、T-001(`app/editor.py` 模块化)、T-002(`app/appconfig.py` + `config.json`)、T-003(SQLite 建表)、T-004(本地数据 gitignore)、T-005(AI 模型清单后端)、T-006(单元测试基座)、T-101(账号 slug/user-data-dir)、T-102(Chrome 启动器)、T-103(登录保活与检测)、T-103b(登录检测补充识别 Shopee accounts 登录页)、T-104(PySide6 五 Tab 主窗口骨架)、T-104b(PySide6 worker 基座)、T-105(Tab④ 账号管理)、T-105b(④启动登录复用已打开 Chrome)、T-106(账号快捷方式)、T-201(Excel 导入:解析多文件输入列入库)、T-202(Tab① 任务列表 + 导入按钮 + 别名匹配标记)、T-202b(Tab① 导入汇总栏)、T-203(采集旧标题+旧封面)、T-204(回写旧字段到原 Excel)、T-204b(采集完成自动回写旧字段)、T-205(首次未配账号 / Chrome 未启动 / 未登录引导保护)、T-205b(采集后关闭自动新建商品页 tab)、T-206(Tab① 删除指定批次软删除)、T-301(AI 生成接口)、T-302(Tab② 左右布局与任务列表)、T-302p(提示词管理)、T-303(Tab② 开始生成 + 停止 + 进度)、T-303b(②/③ 商品ID筛选)、T-401(Tab③ 更新列表筛选 + 开始更新确认弹窗)、T-402(Tab③ 确认后串行更新)、T-403(Tab③ 结果回写与结束汇总)、T-501(Tab⑤ AI 模型管理 UI)、T-501b(Tab⑤ 角色与生成参数)、T-501c(Tab⑤ 蝦皮更新安全开关)、T-502(换封面删第一张再上传)、T-503(敏感信息本地明文保存提示与日志脱敏)、T-504(多账号并行 / dry-run / 运行日志)、T-207(①采集诊断日志)、② AI生成图片失败诊断日志补丁、T-404a(②/③ 选中记录重置)、T-404(真实 Shopee 单条更新冒烟验收)、T-506(正式使用批量更新体验)、T-507(正式批量更新:移除普通流程测试商品 ID 限制)、T-508(③ 更新蝦皮生产化操作区)、T-509(② 新标题人工微调)、T-510(③ 检查本轮更新文案统一)、T-505(全流程诊断日志扩展)、T-511(语义色板 + ①②③任务状态列上色)、T-512(③高风险按钮上色 + ①导入校验数字标红)、T-513(登录点 / ③Tab危险标识 / 破坏性按钮上色)、T-514(①②③ 首次空状态引导卡片)、T-515(批次阶段进度总览)、T-516(①筛选对齐②③)、T-517(⑤设置分区 + 清理兼容字段)、T-518(②左栏提示词区组件密度优化)、T-519(②AI生成长任务进度条 + 用户可读滚动日志)、T-520(②AI生成封面可选生成开关)、T-521(依赖清单:锁版本 requirements)、T-522(CI:自动跑语法 + 单元 / GUI 测试)、T-523(拆分 `app/gui.py` 为 `app/gui/` 包)、T-523a(②/③ 新一轮运行前清空界面日志显示)、T-404b(商品详情页加载失败 toast 自动捕获)、T-524(PyInstaller 打包为免安装 exe)、T-526(`app/ai.py` + `appconfig` 接入 cmhub backend)、T-527(⑤设置 cmhub 网关面板)、T-528(②计费错误提示 + 余额展示)、T-529(默认 cmhub 网关并隐藏 AI 后端选择)、T-530(cmhub Base URL 规整 + 404 明确提示)、T-531(⑤设置未保存状态追踪 + 离开确认)、T-532(⑤cmhub连接成功提示显示账号名)。
- 最近完成补充:T-533(②增量生成:按缺失组件补生成)、T-534(②重置增强:多选/筛选范围 + 按组件重置)、T-535(②cmhub生成标题读取等待固定600秒)、T-536(GUI按钮圆角全局统一)、T-537(品牌名显示为蝦皮圈優化助手)、T-538(打包产物用户数据收进 `data/`)、T-540(打包版本号与 release 产物命名统一)、T-541(打包版主窗口初始位置与小屏适配)、T-542(GUI 用户可见 shopee/Shopee 文案统一改为蝦皮)、T-525(引入 ruff lint/format 工程检查)。
- 下一个可领取任务:T-539(⑤ 隐藏数据路径设置)。
## 当前已知限制
- T-505 已完成:①采集、②AI生成、Excel 导入/回写、③更新蝦皮、④Chrome 启动/登录检测、⑤AI模型测试连接均已接入业务可读 `run_logs/run_log_events`;异常路径写本地 `data/logs/cmshopee.log` 脱敏 traceback,业务日志不记录 Cookie、密码、API Key、token。
- T-105b 已完成:④账号管理「启动登录」改为幂等入口。同一账号再次点击时会先检查 `debug_port` 是否已有 CDP 响应;已运行则复用现有账号 Chrome 并打开/激活卖家中心登录 tab,状态栏提示“该账号 Chrome 已打开,已复用现有窗口”,不会再次 `subprocess.Popen()`;未运行才新启动 Chrome 并等待 CDP 就绪。不自动登录、不填密码、不改变①/③预检不自动启动 Chrome 的规则。
- ① 采集和③真实更新都依赖对应账号 Chrome 已用专属 user-data-dir 和 CDP 端口启动并登录;T-205/T-402 已在执行前拦截未配置账号、Chrome 未启动、CDP 端口不可访问、未登录,并引导去④账号管理。③ 点击「开始更新」后若本轮需要账号未就绪,必须中止本轮更新,不自动打开账号 Chrome、不提交任何商品。
- T-501/T-501b/T-501c 已完成 `data/config/ai_models.json` 模型清单 UI,以及 `data/config.json` 里的标题/图片默认模型角色、并发、重试、分辨率、jpg 质量、路径/端口设置和 蝦皮更新安全开关。
- T-506 已完成:③ 已将用户可见 `dry-run` 改为「检查本轮更新」按钮;真实更新对当前筛选结果按每批最大更新条数自动分批,确认弹窗显示任务数和预计批次,停止为当前商品安全结束后不再开始新任务;⑤ 设置页已改为居中内容区,左右留白已缩短为 T-506 初始实现约 40%,模型详情/角色与生成参数/路径与端口/蝦皮更新安全使用三列布局,长字段跨列;「多账号并行更新」与「最大并行账号数」已合并为同一个横向组件,最大并行账号数紧跟其后且不换行。
- T-507 已完成:普通正式更新移除 `test_item_id` 商品 ID 限制;③ 确认弹窗不再显示测试商品 ID;⑤ 普通设置页隐藏测试商品 ID,只作为历史/调试兼容字段保留;仍保留允许真实提交、允许更新封面、每批最大条数、二次确认、账号就绪预检、多账号并行上限、运行日志和 Excel 回写。
- T-508/T-509/T-510 已完成:③「开始更新」作为主操作视觉强化,「重置更新状态」移到任务表右键菜单,更新安全拦截弹窗写明具体设置并可跳到⑤;②「新标题」列允许已生成、未提交线上、非运行中任务本地微调,写回 `tasks.new_title`,清空 `last_error` 并回到可更新状态,不触碰蝦皮/CDP/Excel/封面;③ 用户可见「预览本轮更新」已统一改名为「检查本轮更新」,内部 `dry_run` 字段保留。
- T-511 已完成:统一语义色板常量已随 T-523 迁入 `app/gui/widgets.py`;①②③任务表状态相关列通过 `Qt.ForegroundRole` 按内部 `stage/status` 返回 `QColor`,完成/失败/略过/待处理/进行中分别使用 success/danger/muted/pending/info,不按中文显示文案硬匹配,不给普通行刷底色。
- T-512 已完成:③「开始更新」使用 warning `#bc4c00` 文字和描边强调写线上风险;①导入汇总中无效行数 >0、未匹配数 >0 以 danger 标红,未匹配按钮仍保持现有点击筛出能力,无效行不新增筛表入口。
- T-513 已完成:④账号管理登录状态列显示 `● 状态` 并按状态着色(已登录 success、检测中 info、未登录/检测失败 danger、未知/已启动 muted);③更新蝦皮 Tab 通过 `setTabIcon(2, ...)` 显示克制 warning 小圆点,不改 Tab 文字色;①「删除批次」和④「删除账号」使用 danger 文字/描边,原有启用/禁用和二次确认逻辑不变。
- 状态栏语义色已记录为后续体验优化建议,尚未落地代码:普通/就绪提示保持 muted 或默认,进行中用 info,成功用 success,需用户处理但可恢复的问题用 warning,失败/阻断用 danger;落地时建议统一 `MainWindow.show_status(message, level)`,逐步替换直接 `statusBar().showMessage(...)`,只改状态栏文字色,不做大面积背景。
- T-514 已完成:①②③增加轻量空状态引导卡片;无账号时显示「前往账号管理」按钮并跳转④,有账号但无任务时分别提示①导入 Excel、②先完成①采集、③先完成②生成;卡片只做 UI 引导,不改执行前账号/Chrome/登录态预检。
- T-515 已完成:①②③在摘要区下方显示批次进度总览,按当前批次/全部批次聚合总数、导入、已采集、已生成、已更新、失败、略过;③进度总览使用当前批次全部任务,不受可更新列表过滤限制;数据来自 `db.list_tasks()`,不新增表,软删除批次默认不计入。
- T-516 已完成:①导入采集补齐店铺、商品ID、状态筛选,筛选栏与②③对齐;当前筛选结果用于①表格显示和「采集旧标题/旧封面」作用范围,导入汇总栏、批次进度总览和未匹配数量仍按当前批次全量任务统计;未匹配按钮继续在当前筛选结果内筛出未匹配任务。
- T-517 已完成:⑤设置页将「蝦皮更新安全 / 执行模式」前置为独立分区,将「基础设施(路径与端口)」后置;`test_item_id`、`dry_run` 不再有用户可操作控件,保存设置仍保留 `test_item_id` 兼容字段并固定 `dry_run=false`,③「检查本轮更新」语义不变。
- T-518 已完成:②AI生成左栏保留模板选择、编辑内容、新建/保存等高频入口,把封面模板「另存为 / 重命名 / 删除」收敛进②本页「模板操作」菜单;动作仍调用原有保存/重命名/删除方法,删除二次确认、错误处理和 prompts 文件结构不变,不涉及 AI/Shopee/CDP。
- T-519 已完成:②AI生成底部增加标题/图片两条独立进度条,现有「AI生成运行日志」改为用户可读、自动滚动、脱敏的长任务日志;日志显示本轮开始、标题/图片开始与成功、商品ID/店铺、调用失败重试、失败、停止请求和完成汇总,不显示 API Key、密码、Cookie、token、完整请求体、base64 图片或超长 prompt,不改变 AI/DB/Excel/Shopee/CDP 核心流程。
- T-520 已完成:②AI生成页增加「生成封面图片(成本较高)」开关,默认关闭以避免无意产生图片模型成本;关闭时标题生成成功即可写库进入 generated,`new_cover_path=NULL`,③只更新标题且不受「允许更新封面」阻断;开启时保持标题后图片两段生成流程。2026-07-06 运行修正:②AI生成页会把失败按阶段显示为“采集失败 / 生成失败 / 更新失败”;「开始生成」只处理已采集待生成或生成失败可重试任务,采集失败会提示先回到①完成旧数据采集,更新失败不会被②误重试。未改 DB schema、AI HTTP 协议、Excel、Shopee/CDP 更新流程。
- T-528 已完成:②AI生成页在 cmhub backend 下显示生成后的剩余点数;GenerateWorker 读取计费 metadata,把 points_cost、points_balance、call_id 写入脱敏运行日志;遇到 CMHubError.code=insufficient_points 时弹出「点数不足,请先充值」并中止本轮未开始任务,不靠中文错误字符串匹配。未改 AI HTTP 协议、DB schema、Excel、Shopee/CDP 流程。
- T-529 已完成:普通默认 `ai.backend=cmhub`;⑤设置页不再显示「AI 后端」label/dropdown、direct 模型选择、模型详情或标题/图片模型角色下拉,直接展示 cmhub 网关配置;保存设置固定写 `ai.backend=cmhub` 且允许先保存不完整 cmhub 配置,②生成时仍由 `app/ai.py` 提示补齐 Base URL/API Key/别名。direct 代码和 `data/config/ai_models.json` 保留为内部兼容/手工回滚,不改 AI HTTP 协议、DB schema、Excel、Shopee/CDP 流程。
- T-530 已完成:`appconfig.normalize_cmhub_base_url()` / `cmhub_request_url()` 会把 cmhub Base URL 规整到 scheme+host(+port),去掉 `/api`、`/api/v1`、其它路径、查询串和片段;⑤设置页输入框提示只填网关根,保存/刷新前同步规整;cmhub HTTP 404 统一映射为 `CMHubError(code="not_found")`,显示“cmhub 接口不存在,请检查 Base URL 或该实例是否已部署 /api/v1/models”。未改 AI HTTP 协议、DB schema、Excel、Shopee/CDP 流程。
- T-531 已完成:⑤设置页增加未保存状态追踪与离开确认。用户修改设置后显示“● 未保存更改”;`save_app_settings()` 成功写入 `data/config.json` + `data/config/cmhub.json` 后清 dirty,失败保留 dirty;切换 Tab/关闭窗口时提供保存、放弃、取消三选一,且使用自定义中文按钮避免系统默认英文按钮;放弃会重新从 `data/config.json` 与 `data/config/cmhub.json` 回填控件;程序化回填和刷新别名写入下拉不置脏;`currentChanged` 回退使用 guard 防递归;刷新别名/测试连接成功只提醒保存,不自动落盘。
- T-532 已完成:⑤设置页 cmhub 测试连接/查余额成功后,会从 `/balance` 返回的 `account.display_name/account.username/user` 以及 name/account_name/email/id 等字段提取 cmhub 账号身份,并显示 `cmhub 账号「<账号名>」连接成功:...`;当前接口结构 `{ "user": "cmhub_user", "points_balance": 88, "account": { "username": "cmhub_user", "display_name": "主账号" } }` 会优先显示 `主账号`;邮箱只显示脱敏形式(如 `o***r@example.com`),无账号信息时保留 `cmhub 连接成功:...` 兜底。`sanitize_for_log()` 同步脱敏 email 字段,避免 run log summary 保存完整邮箱;未改 cmhub HTTP 协议、配置 schema、保存逻辑、AI 生成或 Shopee/CDP 流程。
- T-533 已完成:②AI生成已从整条任务生成改为按缺失组件增量补齐。标题已存在但封面缺失、且本轮开启“生成封面图片(成本较高)”时,只补封面,不再调用生文、不覆盖手动标题;组件全齐时不纳入本轮生成;标题/图片进度分别按 `title_total` / `cover_total` 统计。未改 cmhub HTTP 协议、DB schema、Excel、Shopee/CDP 流程。
- T-535 已完成:cmhub 生文 `title_request` 的读取等待固定为 600 秒,不再跟随当前分辨率的 `resolution_timeouts`;连接超时仍取 `ai.cmhub.connect_timeout`,重试次数仍取 `ai.retry`。封面生成和图片下载继续按分辨率读取等待;direct 兼容路径不变。
- T-536 已完成:`MainWindow` 全局应用 `BUTTON_BASE_STYLE`,所有 `QPushButton` 统一 4px 圆角、基础边框、hover/pressed/disabled/focus 状态;③「开始更新」、①「删除批次」、④「删除账号」和①「未匹配」按钮只叠加 warning/danger 语义颜色,不再各自硬写圆角或内边距。未改任何按钮行为、启用/禁用逻辑、DB、Excel、Shopee/CDP。
- T-537 已完成:产品显示名定为「蝦皮圈優化助手」;主窗口标题、PySide6 缺失启动提示、根 README、入口/导航/愿景文档和 UI 线框图显示中文品牌;`cmshopee` 继续作为仓库、包名、exe、数据库、日志、配置和兼容文件名等技术代号保留。
- T-538 已完成:默认用户数据根统一为 `<程序目录>/data`(源码为项目根 `data/`,打包版为 exe 同级 `data/`);`main.py` 不再 `chdir` 到 exe 目录;启动时迁移 T-524 旧顶层布局数据并检测 `data/` 可写;旧布局和 `data/` 同名冲突时弹“数据迁移冲突”,不可写时才弹“数据目录不可写”;`scripts/build_exe.ps1` 发布目录校验新增禁止打包 `data/`;用户更新方式改为覆盖当前发布包里的程序文件和依赖文件并保留 `data/`。T-540 后当前锁定 PyInstaller 6.11.1,`dist/cmshopee` 必须包含 `cmshopee.exe` 和 `_internal/`。
- T-540 已完成:新增 `app/version.py` 作为唯一版本源,GUI 标题显示 `蝦皮圈優化助手 v<APP_VERSION>`;`scripts/build_exe.ps1` 读取 `APP_VERSION`,固定使用 `py -3.10` 产出 `dist/cmshopee`,再组装 `release/cmshopee-<APP_VERSION>`、写入 `version.txt`/中文 `README.txt`,并生成 `release/cmshopee-<APP_VERSION>-portable.zip`。本阶段不引入 Launcher、manifest、sha256 下载校验或自动更新。
- T-541 已完成:`MainWindow` 启动时通过 `_fit_and_center_window()` 读取 `QApplication.primaryScreen().availableGeometry()`,按可用屏幕限制初始尺寸、居中并夹进屏幕;首次 `showEvent` 后再应用一次,保证打包版在 Windows 10 VM/小分辨率环境标题栏完整可见、可拖动,不保存历史坏坐标。
- 主窗口标题当前由 `app.version.display_name()` 统一显示为「蝦皮圈優化助手 v<APP_VERSION>」;T-541 不改品牌/版本来源,只改启动尺寸与位置。
- T-521 已完成:根目录新增 `requirements.txt` 并锁定当前运行依赖版本;`docs/03-tech-stack.md` 和 `docs/README.md` 已改为 `python -m pip install -r requirements.txt` 安装;未新增运行时依赖、未改业务代码。
- T-522/T-525 已完成:`.github/workflows/tests.yml` 在 push / pull_request 上用 Windows + Python 3.11 安装 `requirements.txt` 与 `requirements-dev.txt`,设置 `QT_QPA_PLATFORM=offscreen`,自动运行 ruff 安全类 lint、语法检查和全量单元/GUI 测试;CI 不连接真实 Shopee 或真实 AI。
- T-523 已完成:旧 `app/gui.py` 已拆为 `app/gui/` 包,公开导入路径保持兼容;本轮为纯结构重构,未改 Shopee/CDP、AI、DB、Excel 行为。
- T-523a 已完成:②点击「开始生成」、③点击「检查本轮更新」或「开始更新」时,先清空对应界面的旧日志显示并写入本轮开始摘要;运行中只追加本轮日志。历史 `run_logs/run_log_events` 和本地 `logs/` 不删除、不自动混入当前运行界面。
- T-404b 已完成:`open_product()` 在导航商品详情页前后安装 toast 捕获,等待详情页关键元素超时时会读取最近 `.eds-toasts`/toast/message 节点及页面缓存,把明确商品失效/商品不存在/无权限类 toast 上浮为 `商品失效:<原始toast>`;如果失败发生在 `open_product()` 内部,本轮自动新建的失败 tab 会关闭,复用用户已有 tab 不关闭;①列表“阶段”列只在这类明确失效错误时显示“商品失效”,底层仍保持 `stage=imported/status=failed`,其他打开失败仍显示“失败”。
- T-524 已完成:新增 PyInstaller onedir 打包配置、构建脚本和发布目录校验;T-538 后打包版不再切换全进程工作目录,首次运行在 exe 同级 `data/` 生成/使用本地配置、DB、图片、日志、登录态和提示词;发布包不内置 `data/`,用户后续更新采用关闭程序后覆盖程序文件、保留 `data/` 的方式。
- Phase 7 cmhub 网关对接已完成 T-526~T-535;②生成阶段已支持按标题/封面缺失组件增量生成,②重置生成结果已支持多选/筛选范围和按标题/封面组件重置,cmhub 标题请求读取等待固定 600 秒。T-541、T-542 与 T-525 已完成,下一步按看板进入 T-539 设置简化。
- T-301/T-303 已完成通用 HTTP AI 接口、批量生成编排和 GUI 接入 mock 单测;真实 AI 生成还需要在 `data/config/ai_models.json` 填入可用 url/model/api_key 后做一次成本可控的小样本实测;URL 可填完整 endpoint 或 OpenAI-compatible base URL。
- 本地 `data/config/ai_models.json` 若由旧版本或手工维护,可能缺少 `category`;启动报 “AI 模型 category 必须是 text 或 image” 时,按 [`troubleshooting.md`](troubleshooting.md) 只补 `category` / `enabled` 等非密钥字段,保留 API Key,且不要提交该文件。
- T-403/T-501c 已完成③更新结果回写、结束汇总与真实更新安全开关;2026-06-29 已用测试商品跑到真实编辑页并完成标题/封面替换、页面主「更新」点击,但被 Shopee 站点侧确认框拦住。当前代码已补确认框处理、确认后列表页跳转观测、上传状态诊断、删除后稳定等待和 mock 单测;2026-06-30 用户复跑发现稳定等待顺序回归:满 9 张时删除前要求上传 input 可用,导致不删除第一张图;当前已修正为删除前只等图片列表稳定、删除后再等上传入口恢复,并补 mock 回归测试;2026-06-30 又发现物流/备货页面级校验 toast 会被误判成封面上传失败,当前已修复为上传阶段只识别图片/文件/上传相关错误,物流错误留到提交阶段处理。2026-06-30 用户复跑确认浏览器已成功更新标题/图片并跳转商品列表,但 GUI 仍报 `POST_UPDATE_ERROR`;已修正提交后观测优先级:列表页跳转优先判成功,残留 error toast 不再覆盖成功跳转,错误 toast 仅在未跳转且持续存在时判失败。当前又发现商品 26887160467 手动上传 220KB 新图成功,但代码直接注入文件后上传组件长期转圈;T-404 当前补丁已让 `replace_cover()` 上传前先点击上传块模拟人工入口、短暂等待、重新获取 input 后再 `DOM.setFileInputFiles`,并补 mock 回归测试。25120403046 只有 8 张商品图时未删除第一张导致 Shopee 提示 `有1張重複的圖片`;当前已落地为更新封面统一先删当前第一张再上传,并把 `重複/重复/duplicate` toast 识别为封面上传失败。新采集/新生成图片路径已改为按批次细分,避免同一账号多批次图片混放;历史 DB 已存路径继续可用。确认后若返回我的商品列表页且设置了成功后关闭本次新开编辑页,关闭前等待 2 秒。2026-07-01 用户已用包含 5 个商品 ID 的 Excel 完成导入、AI 生成标题/图片、Tab③ 更新到 Shopee 的真实链路验收,T-404 判定完成。
- T-404a/T-534 已完成:②「重置生成结果」已从单条整清升级为多选/当前筛选结果批量重置,确认框提供「重置标题 / 重置封面 / 重置全部」三种组件操作;只重置封面时保留 `new_title` 和 T-509 手动标题,只重置标题时保留 `new_cover_path`,重置后任务保持 `stage=generated/status=success` 供 T-533 按缺口补生成。默认不删除本地新封面文件,不触碰蝦皮、不自动回写 Excel;已提交线上记录会提示本地重置不回滚蝦皮、重生成后再更新会再次提交线上;运行中禁用并写 `run_type=reset` 运行日志。③「重置更新状态」仍保留新标题/新封面并退回 generated/pending,入口按 T-508 保持在任务表右键菜单。
- T-502 换封面删除流程已完成代码路径、mock 单测和真实 9 图商品不提交流程实测;更新封面统一先删当前第一张,删除前必须已有本地旧封面备份(`old_cover_path` 存在且文件存在),缺失备份时拒绝删除线上图片;mock 已覆盖 8 张图也先删第一张、重复图片 toast 立即失败。本轮实测只操作编辑页并关闭测试 tab,未点击「更新」保存线上。T-538 后 `data/images/` 新路径按 `batch_id/slug/task_id_item_id` 细分,旧 DB 路径兼容不迁移。
## 当前可运行内容
```bash
# 安装锁定依赖(T-521 后)
python -m pip install -r requirements.txt
# 安装开发检查依赖并运行 ruff(T-525 后)
python -m pip install -r requirements-dev.txt
python -m ruff check app tests main.py
# 安装打包依赖并构建免安装 exe(T-524 后)
py -3.10 -m pip install -r requirements-build.txt
powershell -ExecutionPolicy Bypass -File scripts\build_exe.ps1
# 语法检查(T-000 后;本机优先用 py -3)
py -3 -m compileall app main.py
# appconfig 默认配置读写(写入临时目录)
py -3 -c "import os,tempfile; from app import appconfig; d=tempfile.TemporaryDirectory(dir='.'); cfg=appconfig.load_config(os.path.join(d.name,'config.json')); print(appconfig.image_dir(cfg))"
# db 临时库初始化与 PRAGMA 检查
py -3 -c "import os,tempfile; from app import db; d=tempfile.TemporaryDirectory(dir='.'); p=os.path.join(d.name,'cmshopee.db'); db.init_db(p); c=db.connect(p); print(c.execute('PRAGMA foreign_keys').fetchone()[0], c.execute('PRAGMA journal_mode').fetchone()[0], c.execute('PRAGMA busy_timeout').fetchone()[0]); c.close()"
# gitignore 核心本地数据检查
git check-ignore -v -- data/ config.json config/ai_models.json config/cmhub.json cmshopee.db chrome_user_data_dir/ images/
# ai_models 临时清单读写与打码检查
py -3 -c "import os,tempfile; from app import appconfig; d=tempfile.TemporaryDirectory(dir='.'); p=os.path.join(d.name,'ai_models.json'); print([m['category'] for m in appconfig.list_ai_models(path=p)])"
# AI 接口单测(不连真实服务)
python -m unittest discover -s tests -p "test_ai.py"
# config slug 与 user-data-dir 临时目录检查
py -3 -c "import tempfile; from app import config; d=tempfile.TemporaryDirectory(dir='.'); print(config.ensure_user_data_dir(config.make_slug('alias'), root=d.name))"
# chrome 参数拼装 / 端口探测由 tests/test_chrome.py 覆盖
python -m unittest discover -s tests
# Excel 导入由 tests/test_excel.py 覆盖;默认 python 环境需可导入 openpyxl 才执行真实解析测试
python -m unittest discover -s tests -p "test_excel.py"
# GUI 骨架与 ④ 账号管理由 tests/test_gui.py 覆盖;worker 基座由 tests/test_workers.py 覆盖
# 默认 python 当前 PySide6=6.5.3,py -3 环境缺 PySide6 时相关测试会 skip
# 当前入口占位
python main.py
py -3 -m app
# 单元测试(T-006 后纯逻辑改动必跑)
python -m unittest discover -s tests
# 单账号闭环(不提交线上)
python prototypes/demo.py # 分步(T-000 后从项目根导入 app.cdp)
set AUTO=1 && python prototypes/demo.py # 自动(cmd)
# 真实提交(谨慎;T-404 前不要扩大批量)
set UPDATE=1 && python prototypes/demo.py
```
前置条件:
- Chrome 已用某 user-data-dir 带 `--remote-debugging-port` + `--remote-allow-origins=*` 启动并登录 Shopee。
- 已提供根目录 `requirements.txt` 锁定运行依赖;换机、CI 或新环境使用 `python -m pip install -r requirements.txt`。
- PySide6 当前环境已可导入(验证版本 6.5.3);GUI 实现固定使用 PySide6。
- 默认连 `127.0.0.1:9222`(开发期可用 `CDP_HOST` 指向 WSL 转发的 `192.168.0.224:9333`)。
- 本机 `python` 当前仍可能指向 `C:\Python37\python.exe`(3.7.9,isolated);正式打包不再依赖 PATH 上的 `python`,统一使用 `py -3.10`。若源码调试时 `python -m app` 不搜索当前目录,可改用 `py -3.10 main.py` 或 `py -3.10 -m app`。
## 开始编码前检查
1. 读仓库级 `AGENTS.md` / `CLAUDE.md`(如有)。
2. 读 `docs/00-ai-start-here.md`。
3. 读 `docs/05-coding-rules.md` 与 `docs/04-architecture.md` 第七节。
4. 在 `docs/06-tasks.md` 取第一个 `TODO` 且依赖 `DONE` 的任务。
5. 将该任务状态改为 `DOING`。
## 维护规则
- 新建 `config/chrome/editor/gui/workers` 或改 CDP 选择器后,更新本文与 `04-architecture.md`。
- 任务状态变化同步 [`06-tasks.md`](06-tasks.md);执行记录追加 [`../progress.md`](../progress.md)。
- 本文只保留当前快照,不保留完整历史。