diff --git a/docs/html/审核中商品提示 .html b/docs/html/审核中商品提示 .html new file mode 100644 index 0000000..cd17a52 --- /dev/null +++ b/docs/html/审核中商品提示 .html @@ -0,0 +1 @@ +
審核中

商品最晚將於提交後2個工作日內完成審核,確認通過後再由系統自動上架 (特殊案件不在此限),未通過審核的商品將依照賣家中心說明降低搜尋排序、禁賣或刪除。

\ No newline at end of file diff --git a/docs/html/未上架商品提示.html b/docs/html/未上架商品提示.html new file mode 100644 index 0000000..eb7edf8 --- /dev/null +++ b/docs/html/未上架商品提示.html @@ -0,0 +1 @@ +
您的商品未上架

您的商品已被您下架。

\ No newline at end of file diff --git a/docs/tasks/T-662.md b/docs/tasks/T-662.md new file mode 100644 index 0000000..d4a3e73 --- /dev/null +++ b/docs/tasks/T-662.md @@ -0,0 +1,134 @@ +--- +id: T-662 +title: 商品状态采集与三模块状态过滤 +status: TODO +phase: 7 +deps: [T-659] +created: 2026-07-18 +--- + +# T-662 商品状态采集与三模块状态过滤 + +## 问题 / 背景 + +①导入采集的商品ID列表中可能混有异常状态商品(未上架、审核中等)。当前链路只在采集阶段拦截「页面打不开」级别的失效商品(`app/editor.py:454` `PRODUCT_UNAVAILABLE_TEXT_MARKERS`:已删除/已下架/无权限等);**编辑页仍能打开的「未上架」「审核中」商品会正常采集入库 → ②照常消耗点数生成 → ③更新无意义或有触发重新审核的风险**。 + +`tasks` 表没有蝦皮侧商品状态字段,①②③均无法按状态过滤。 + +用户已提供两份编辑页状态横幅的真实 HTML 样本(`docs/html/未上架商品提示.html`、`docs/html/审核中商品提示 .html`),确认状态以 Shopee EDS 组件结构化暴露,CDP 抓取前置验证已基本完成。 + +## 需求定稿 + +1. 采集阶段从商品编辑页读取商品状态并落库(快照语义)。 +2. ①导入采集:任务列表增加状态列与状态筛选;采集汇总报告异常状态条数。 +3. ②AI生成:生成候选**默认排除**异常状态商品,不为其消耗点数;确认信息说明排除数量。 +4. ③更新蝦皮:更新候选**默认排除**异常状态商品;跳过统计并入 T-659 的确认弹窗模式。 +5. 历史数据无状态记为「未知」,默认**不排除**;重新采集即可补齐/刷新状态。 + +## 实现方案 + +### 1. 状态检测契约(依据 HTML 样本) + +编辑页状态横幅结构(两样本一致): + +```text +.eds-alert.eds-alert--warning + ├─ .eds-alert-title ← 状态判定锚点(文本) + └─ .eds-alert-desc ← 补充说明(存诊断) +``` + +- 判定以 `.eds-alert-title` 的**归一化文本**(trim + 繁简兼容)为准,白名单匹配: + - `審核中` / `审核中`(样本尾部有空格,必须 trim)→ `审核中`; + - `您的商品未上架` → `未上架`(样本 desc「您的商品已被您下架。」为卖家自主下架;平台强制下架 desc 不同,原文落库后日后可细分)。 +- 无已识别横幅 → `在售`。 +- **纪律**: + - 禁止依赖 `data-v-*` 属性(Vue scoped-CSS 构建哈希,发版即变);只用 `eds-alert`/`eds-alert-title` 设计系统类名 + 文本白名单; + - `eds-alert--warning` 是通用组件,编辑页可能有无关警告(如图片质量建议)——未识别的横幅**不改变状态**,但 title 原文写入状态原文字段供日后扩白名单(如违规/禁卖,暂无样本); + - 状态检测失败(DOM 查询异常等)不使采集失败,记「未知」并写日志; + - 现有 `PRODUCT_UNAVAILABLE_TEXT_MARKERS` 失效检测**保留不动**,作为③执行层最后防线。 + +### 2. 数据模型(additive 迁移) + +- `tasks` 表新增可空列: + - `product_status TEXT`——枚举:`在售`/`未上架`/`审核中`/`未知`(NULL 视同「未知」); + - `product_status_note TEXT`——横幅 title+desc 原文(诊断与日后细分); + - `product_status_at TEXT`——快照时间(ISO 8601)。 +- 采集成功时写入三列;重新采集覆盖刷新(快照语义:状态可能过期,以最近采集为准)。 +- 迁移幂等,旧库直接升级;历史行三列为 NULL。 + +### 3. 采集抓取(`app/editor.py::collect()`) + +- 在编辑页已加载后、抓取旧标题旧封面的同一会话内,按第 1 节契约读取状态横幅(一次 DOM 查询,不增加页面跳转)。 +- 采集步骤回调与日志包含状态结果;采集汇总新增「异常状态 N 条(未上架 x / 审核中 y)」。 +- 实现时把检测契约与两份 HTML 样本作为证据登记进 `docs/04-architecture.md` 第七节「CDP 已验证事实」。 + +### 4. ①导入采集(`app/gui/tabs/collect.py`) + +- 任务列表增加「商品状态」列(在售/未上架/审核中/未知,异常状态用警示色)。 +- 筛选条增加状态下拉:`全部`(默认)/`在售`/`未上架`/`审核中`/`未知`。 +- 悬停或详情可见状态原文与快照时间。 + +### 5. ②AI生成(`app/gui/tabs/generate.py`) + +- 生成候选默认排除 `未上架`/`审核中`;`在售`/`未知` 正常参与(「未知」不排除,避免历史数据全被拦)。 +- 筛选条增加状态下拉(默认「排除异常状态」,可切「全部」后异常商品重新可选——用户明确要生成时不拦死)。 +- 开始生成的确认/状态信息注明「已排除异常状态 N 条(示例商品ID:…)」;被排除记录不消耗点数、状态与 stage 不变。 + +### 6. ③更新蝦皮(`app/gui/tabs/apply.py`) + +- 更新候选默认排除 `未上架`/`审核中`,并入 T-659 的「剔除 + 知情确认」框架:确认弹窗新增「跳过 N 条异常状态商品(未上架 x / 审核中 y,示例商品ID:…)」行。 +- 剔除后无任务可执行时沿用 T-659 的整体中止路径,文案区分「全部为异常状态商品」的情况。 +- 状态下拉同②(默认排除,可切全部);「检查本轮更新」(dry_run)与正式更新行为一致。 +- 快照过期兜底:③执行层现有商品失效检测不动;更新因商品状态失败的记录,`last_error` 如实记录。 + +## 验收标准 + +- [ ] 采集「审核中」样本结构页面 → `product_status=审核中`;「未上架」样本 → `未上架`;无横幅 → `在售`;未识别横幅 → 状态不变但原文落库。 +- [ ] 状态判定不依赖 `data-v-*`;title 文本 trim 后繁简均可匹配。 +- [ ] 状态检测异常不使采集失败,记「未知」并写日志;`PRODUCT_UNAVAILABLE_TEXT_MARKERS` 行为不变。 +- [ ] 旧库升级迁移幂等;历史行状态显示「未知」,②③默认不排除。 +- [ ] 重新采集刷新状态与快照时间。 +- [ ] ①列表显示状态列与筛选;采集汇总含异常状态统计。 +- [ ] ②默认不为「未上架/审核中」商品创建生成任务、不消耗点数;切「全部」后可强制生成;排除说明含条数与示例商品ID。 +- [ ] ③确认弹窗含异常状态跳过统计;剔除后为 0 走 T-659 中止路径;dry_run 与正式一致。 +- [ ] 被排除记录的 stage、status、Excel 均不因排除而改变。 +- [ ] 状态列/筛选在 `1180x760` 与最小窗口尺寸不截断;全部用户可见文案为中文。 +- [ ] ②③既有筛选(批次/店铺/商品ID/状态)与本状态筛选可叠加,互不破坏。 + +## 测试要求 + +- 纯逻辑:状态横幅解析(两份样本 HTML 的 title/desc、trim、繁简、未识别横幅、无横幅、多横幅共存取白名单命中项)。 +- DB:迁移幂等、三列读写、NULL 语义、重新采集覆盖。 +- ②:默认排除口径、「未知」不排除、切全部后可选、点数不消耗断言。 +- ③:跳过统计文案、全异常中止、dry_run 一致性(延用 T-659 在 `tests/test_gui.py` 的用例框架)。 +- 采集:状态检测失败降级「未知」不阻断采集。 + +## 文档同步 + +- `docs/04-architecture.md` 第七节登记「编辑页状态横幅」CDP 已验证事实(含选择器契约、两份 HTML 样本路径、data-v 禁用纪律)。 +- 不修改冻结的 `docs/06-tasks.md`。 + +## 验证 + +```bash +py -3.10 -m unittest tests.test_editor_login +py -3.10 -m unittest tests.test_db +py -3.10 -m unittest tests.test_gui +py -3.10 -m unittest discover -s tests +py -3.10 -m ruff check app tests main.py +py -3.10 -m compileall app main.py +git diff --check +``` + +## 非目标 + +- 不采集/识别「已售罄」「违规/禁卖」状态(无样本;违规文案留白名单扩展口,遇实例再补)。 +- 不自动删除或修改异常状态商品的记录,只过滤不改数据。 +- 不在①导入阶段拦截(导入时仅有商品ID,状态未知)。 +- 不做状态定时自动刷新;状态以采集快照为准,用户重新采集即刷新。 +- 不修改 CDP 登录、Chrome 启动、并发与蝦皮风控相关行为。 +- 不回写商品状态到 Excel(如需,另立任务)。 + +## 执行记录 + +- 待实现。