Admin:蝦皮数据页改为商品级列表与规格弹窗 #41

Closed
opened 2026-08-08 11:02:50 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:需求(界面重构)
  • 父级大工单:#14
  • 所属 MVP / 版本:#15 / MVP
  • 关联:#38(导入已完成)、#18(PDD 页弹窗机制可复用)

要解决什么

蝦皮数据页现在是 SKU 级一行,问题不在行数,在语义错了。

pdd_goods_url / pdd_goods_id 在 shopee_products 上,是商品级字段。
实测商品 24420648774 有 62 个 SKU——现在列表里 62 行显示的是
同一个 PDD 链接,将来双击任意一行编辑的也是同一个字段。
操作员会以为「我改的是这一行的链接」。

改成商品级一行,才和数据模型对得上。

[注意] 不要指望行数变少:实测 6092 → 5195,只少 15%
(平均每个商品仅 1.17 个 SKU)。收益是语义正确,不是列表变清爽。

做什么 / 不做什么

做:

  1. 列表改为商品级一行
  2. 双击行打开弹窗,显示商品信息 + 完整规格表
  3. 列改为:颜色数 / 尺码数 / SKU 数 / 待补
  4. 去掉「建議」列,挪进弹窗
  5. 商品名称列宽收到 30%

不做(各自独立工单):

  • 不实现弹窗里的保存(ShopeeSave 保持 501,PDD 链接输入框只读展示)
  • 不实现 ShopeeDelete / ShopeeCollect(保持 501)
  • 不做「手动新增 SKU」(05 §4.4)
  • 不改导入逻辑、不改表结构

怎么做

必须加「SKU 数」列 —— 否则 602 个商品会被误判

[必须] 只显示颜色数和尺码数会严重误导。实测:

颜色数×尺码数 > 实际 SKU 数的商品:602 个(占 11.6%)

goods_id      颜色数  尺码数  相乘   实际 SKU
26886533818     15     5     75      28    ← 差 2.7 倍
24773321934     10     6     60      14
27739534478     12     6     72      36

看到「颜色 15 / 尺码 5」,正常人会以为有 75 个规格要匹配,实际只有 28 个。

根因:蝦皮报表只含有销售成绩的 SKU,数据本来就不全
(平均每个商品 1.17 个)。三个数字放在一起,操作员才看得出
「这商品在报表里只有 28 条记录,不是 75 条」。

必须加「待补」列 —— 否则坏数据会静默消失

[必须] 现在 parse_ok = 0 的行显示 — 并整行标黄,一眼能看见要人工补。
聚合成数量之后这个信号会丢。实测:

23 条解析失败的 SKU,分布在 6 个商品里
  4 个是「部分失败」 → 显示「颜色 3」,坏的那几个直接消失
  2 个是「全部失败」 → 显示「颜色 0 / 尺码 0」

「部分失败」那 4 个最危险——数字看着正常,坏数据被吃掉,永远没人去补。

[必须] 加「待补」列显示该商品有几个 SKU 解析失败,> 0 时整行标黄
(沿用现有的 .row-warn)。

[必须] 颜色数 / 尺码数只统计 parse_ok = 1 的 SKU。
把解析失败的空值算进 DISTINCT 会多出一个「空颜色」。

弹窗

结构与 PDD 商品页(05 §5.4)对齐:

┌──────────────────────────────────────────────────────┐
│ 商品 24420648774                                     │
├──────────────────────────────────────────────────────┤
│ 商品名称   吊帶背心 80-200斤寬鬆大碼吊帶背心女夏季針織T │ 只读
│ 蝦皮状态   正常                                       │ 只读
│ 主商品货号 PDD1645                                    │ 只读
│ PDD 链接   https://...            (本工单只读展示)   │
│ 采集状态   未采集                                     │
├──────────────────────────────────────────────────────┤
│ 规格(28 个,2 个待人工补)                            │
│ 规格ID         颜色    尺码   建議        状态         │
│ 250531928630  咖啡色  2XL   65-70kg     ✓            │
│ 250531928635  咖啡色  3XL   70-80kg     ✓            │
│ 250531928999  —      —     —           待补         │
│               原文:紅色,3XL建議80-90公斤】            │
├──────────────────────────────────────────────────────┤
│                                          [关闭]      │
└──────────────────────────────────────────────────────┘

[必须] 待补的行要显示 spec_raw 原文。不显示的话人工不知道该填什么——
这正是保留原文这个设计的全部意义。

[必须] 状态列要有文字(✓ / 待补),不能只靠颜色(05 §10)。

[必须] 弹窗只读。ShopeeSave 仍是 501,本工单不做保存。
不要放一个点了没反应的保存按钮。

[必须] 复用 #18 的弹窗机制(data-detail-url / data-detail-slot /
data-detail-id + GET /shopee/detail?goods_id=… 返回 HTML 片段)。
该机制是通用的,app.js 不需要改——#19 已经验证过这一点。

列表列

☐ │ 商品 ID │ 商品名称(30%) │ 颜色 │ 尺码 │ SKU │ 待补 │ PDD 链接 │ 采集状态 │ 更新时间
                               15     5     28     2

[必须] 商品名称列宽用 max-width + 现有的 .truncate 类,
不要用 flex——表格单元格和工具条不一样,.search-narrow 那套在这里不适用。
给这一列单独一个类设 max-width: 30%。

[必须] 「PDD 链接」为空时显示「未填写」并标红(沿用 .missing,05 §4.2)。

[建议] 采集状态来自 pdd_products,需要 join。join 不到(没填链接)时
显示「未填链接」,不要空着。

搜索

[必须] 关键词继续匹配商品 ID(现在就是这样)。

[建议] 可以顺带匹配商品名称,但不要匹配颜色尺码——
那是 SKU 级的,商品级列表里搜出来无法定位到具体哪一行。

预计修改文件

文件 改什么
admin/repository/shopee.go 商品级聚合查询(颜色数/尺码数/SKU数/待补数);GetShopeeProductDetail
admin/service/shopee_list.go 视图组装从 SKU 级改商品级;详情组装
admin/handler/web/shopee.go ShopeeList 改写;新增 ShopeeDetail
admin/handler/web/web.go GET /shopee/detail 路由
admin/templates/shopee/list.html 表格列重写、双击绑定
admin/templates/shopee/detail_modal.html 新建
admin/static/css/app.css 商品名称列宽的类
docs/admin/01-requirements.md / 05-ui-specification.md §4.2 表格列、§4.3 弹窗重写

[注意] 不要动 admin/service/shopee_import.go(#38 刚交付且已验收流程中)。
本工单只改展示层。

验收标准

列表

  • 一个商品一行,24420648774 只出现 1 次(现在是 62 次)
  • 总行数 5195(导入样本后)
  • 颜色数 / 尺码数只统计 parse_ok = 1 的 SKU
  • 有「SKU 数」列
  • 有「待补」列,> 0 时整行标黄
  • 26886533818 显示 颜色 15 / 尺码 5 / SKU 28(不是 75)
  • 「建議」列已去掉
  • 商品名称列收窄且超长截断 + 悬停看全文
  • PDD 链接为空显示「未填写」并标红
  • 空状态分两种(从没导入过 / 搜索无结果)

弹窗

  • 双击行打开,显示商品信息 + 完整规格表
  • 规格表含 规格ID / 颜色 / 尺码 / 建議 / 状态
  • 待补的行显示 spec_raw 原文
  • 状态有文字,不只靠颜色
  • 弹窗只读,没有保存按钮
  • app.js 未改动(复用 #18 机制)

其他

  • ShopeeSave / ShopeeDelete / ShopeeCollect 仍是 501
  • shopee_import.go 未改动
  • 导入功能不受影响(导入后列表正确显示)
  • 五个页面均 200
  • GOTOOLCHAIN=go1.23.0 下 go vet / gofmt -l . / go test ./... 全过

怎么验证

cd D:\chengma\cmautobuy\admin
$env:GOTOOLCHAIN="go1.23.0"
go vet ./...; gofmt -l .; go test ./... -count=1
Remove-Item Env:GOTOOLCHAIN
go run .

端到端(导入真实样本后):

  1. 打开 /shopee,确认总行数 5195
  2. 搜 24420648774 → 只有 1 行,SKU 数显示 62
  3. 搜 26886533818 → 颜色 15 / 尺码 5 / SKU 28
  4. 双击这一行 → 弹窗显示 28 条规格
  5. 找到「待补」> 0 的商品(实测有 6 个),确认整行标黄,
    弹窗里那几条显示原文

[必须] 第 3 步和第 5 步的实际输出要贴出来——这两条是本工单的核心。

风险和回退

风险 应对
颜色数×尺码数被当成规格总数 强制加「SKU 数」列,已列为验收项并给了具体商品编号
解析失败在商品级被数字掩盖 「待补」列 + 整行标黄 + 弹窗显示原文
颜色数把空值算进去 只统计 parse_ok = 1,已列为验收项
顺手改了导入逻辑 「不做」清单已排除,验收项单列一条

回退:git revert。纯展示层改动,不影响已导入的数据。

## 基本信息 - 类型:需求(界面重构) - 父级大工单:#14 - 所属 MVP / 版本:#15 / MVP - 关联:#38(导入已完成)、#18(PDD 页弹窗机制可复用) ## 要解决什么 蝦皮数据页现在是 **SKU 级一行**,问题不在行数,在**语义错了**。 `pdd_goods_url` / `pdd_goods_id` 在 `shopee_products` 上,是**商品级**字段。 实测商品 `24420648774` 有 **62 个 SKU**——现在列表里 62 行显示的是 **同一个 PDD 链接**,将来双击任意一行编辑的也是**同一个字段**。 操作员会以为「我改的是这一行的链接」。 改成商品级一行,才和数据模型对得上。 `[注意]` **不要指望行数变少**:实测 6092 → 5195,只少 15% (平均每个商品仅 1.17 个 SKU)。收益是语义正确,不是列表变清爽。 ## 做什么 / 不做什么 做: 1. 列表改为**商品级一行** 2. 双击行打开弹窗,显示商品信息 + 完整规格表 3. 列改为:颜色数 / 尺码数 / **SKU 数** / **待补** 4. 去掉「建議」列,挪进弹窗 5. 商品名称列宽收到 30% 不做(各自独立工单): - **不实现弹窗里的保存**(`ShopeeSave` 保持 501,PDD 链接输入框只读展示) - 不实现 `ShopeeDelete` / `ShopeeCollect`(保持 501) - 不做「手动新增 SKU」(`05` §4.4) - 不改导入逻辑、不改表结构 ## 怎么做 ### 必须加「SKU 数」列 —— 否则 602 个商品会被误判 `[必须]` 只显示颜色数和尺码数会**严重误导**。实测: ``` 颜色数×尺码数 > 实际 SKU 数的商品:602 个(占 11.6%) goods_id 颜色数 尺码数 相乘 实际 SKU 26886533818 15 5 75 28 ← 差 2.7 倍 24773321934 10 6 60 14 27739534478 12 6 72 36 ``` 看到「颜色 15 / 尺码 5」,正常人会以为有 75 个规格要匹配,**实际只有 28 个**。 根因:蝦皮报表只含**有销售成绩的** SKU,数据本来就不全 (平均每个商品 1.17 个)。三个数字放在一起,操作员才看得出 「这商品在报表里只有 28 条记录,不是 75 条」。 ### 必须加「待补」列 —— 否则坏数据会静默消失 `[必须]` 现在 `parse_ok = 0` 的行显示 `—` 并**整行标黄**,一眼能看见要人工补。 聚合成数量之后这个信号会丢。实测: ``` 23 条解析失败的 SKU,分布在 6 个商品里 4 个是「部分失败」 → 显示「颜色 3」,坏的那几个直接消失 2 个是「全部失败」 → 显示「颜色 0 / 尺码 0」 ``` **「部分失败」那 4 个最危险**——数字看着正常,坏数据被吃掉,永远没人去补。 `[必须]` 加「待补」列显示该商品有几个 SKU 解析失败,`> 0` 时**整行标黄** (沿用现有的 `.row-warn`)。 `[必须]` 颜色数 / 尺码数**只统计 `parse_ok = 1` 的 SKU**。 把解析失败的空值算进 DISTINCT 会多出一个「空颜色」。 ### 弹窗 结构与 PDD 商品页(`05` §5.4)对齐: ```text ┌──────────────────────────────────────────────────────┐ │ 商品 24420648774 │ ├──────────────────────────────────────────────────────┤ │ 商品名称 吊帶背心 80-200斤寬鬆大碼吊帶背心女夏季針織T │ 只读 │ 蝦皮状态 正常 │ 只读 │ 主商品货号 PDD1645 │ 只读 │ PDD 链接 https://... (本工单只读展示) │ │ 采集状态 未采集 │ ├──────────────────────────────────────────────────────┤ │ 规格(28 个,2 个待人工补) │ │ 规格ID 颜色 尺码 建議 状态 │ │ 250531928630 咖啡色 2XL 65-70kg ✓ │ │ 250531928635 咖啡色 3XL 70-80kg ✓ │ │ 250531928999 — — — 待补 │ │ 原文:紅色,3XL建議80-90公斤】 │ ├──────────────────────────────────────────────────────┤ │ [关闭] │ └──────────────────────────────────────────────────────┘ ``` `[必须]` **待补的行要显示 `spec_raw` 原文**。不显示的话人工不知道该填什么—— 这正是保留原文这个设计的全部意义。 `[必须]` 状态列要有**文字**(`✓` / `待补`),不能只靠颜色(`05` §10)。 `[必须]` 弹窗**只读**。`ShopeeSave` 仍是 501,本工单不做保存。 不要放一个点了没反应的保存按钮。 `[必须]` 复用 #18 的弹窗机制(`data-detail-url` / `data-detail-slot` / `data-detail-id` + `GET /shopee/detail?goods_id=…` 返回 HTML 片段)。 该机制是通用的,`app.js` **不需要改**——#19 已经验证过这一点。 ### 列表列 ```text ☐ │ 商品 ID │ 商品名称(30%) │ 颜色 │ 尺码 │ SKU │ 待补 │ PDD 链接 │ 采集状态 │ 更新时间 15 5 28 2 ``` `[必须]` 商品名称列宽用 `max-width` + 现有的 `.truncate` 类, **不要用 flex**——表格单元格和工具条不一样,`.search-narrow` 那套在这里不适用。 给这一列单独一个类设 `max-width: 30%`。 `[必须]` 「PDD 链接」为空时显示「**未填写**」并标红(沿用 `.missing`,`05` §4.2)。 `[建议]` 采集状态来自 `pdd_products`,需要 join。join 不到(没填链接)时 显示「未填链接」,不要空着。 ### 搜索 `[必须]` 关键词继续匹配**商品 ID**(现在就是这样)。 `[建议]` 可以顺带匹配商品名称,但**不要匹配颜色尺码**—— 那是 SKU 级的,商品级列表里搜出来无法定位到具体哪一行。 ## 预计修改文件 | 文件 | 改什么 | |---|---| | `admin/repository/shopee.go` | 商品级聚合查询(颜色数/尺码数/SKU数/待补数);`GetShopeeProductDetail` | | `admin/service/shopee_list.go` | 视图组装从 SKU 级改商品级;详情组装 | | `admin/handler/web/shopee.go` | `ShopeeList` 改写;新增 `ShopeeDetail` | | `admin/handler/web/web.go` | `GET /shopee/detail` 路由 | | `admin/templates/shopee/list.html` | 表格列重写、双击绑定 | | `admin/templates/shopee/detail_modal.html` | 新建 | | `admin/static/css/app.css` | 商品名称列宽的类 | | `docs/admin/01-requirements.md` / `05-ui-specification.md` | §4.2 表格列、§4.3 弹窗重写 | `[注意]` **不要动 `admin/service/shopee_import.go`**(#38 刚交付且已验收流程中)。 本工单只改展示层。 ## 验收标准 **列表** - [ ] 一个商品一行,`24420648774` 只出现 **1 次**(现在是 62 次) - [ ] 总行数 5195(导入样本后) - [ ] 颜色数 / 尺码数**只统计 `parse_ok = 1`** 的 SKU - [ ] **有「SKU 数」列** - [ ] **有「待补」列**,`> 0` 时整行标黄 - [ ] `26886533818` 显示 颜色 15 / 尺码 5 / SKU 28(不是 75) - [ ] 「建議」列已去掉 - [ ] 商品名称列收窄且超长截断 + 悬停看全文 - [ ] PDD 链接为空显示「未填写」并标红 - [ ] 空状态分两种(从没导入过 / 搜索无结果) **弹窗** - [ ] 双击行打开,显示商品信息 + 完整规格表 - [ ] 规格表含 规格ID / 颜色 / 尺码 / 建議 / 状态 - [ ] **待补的行显示 `spec_raw` 原文** - [ ] 状态有文字,不只靠颜色 - [ ] 弹窗**只读**,没有保存按钮 - [ ] `app.js` 未改动(复用 #18 机制) **其他** - [ ] `ShopeeSave` / `ShopeeDelete` / `ShopeeCollect` 仍是 501 - [ ] `shopee_import.go` 未改动 - [ ] 导入功能不受影响(导入后列表正确显示) - [ ] 五个页面均 200 - [ ] `GOTOOLCHAIN=go1.23.0` 下 `go vet` / `gofmt -l .` / `go test ./...` 全过 ## 怎么验证 ```powershell cd D:\chengma\cmautobuy\admin $env:GOTOOLCHAIN="go1.23.0" go vet ./...; gofmt -l .; go test ./... -count=1 Remove-Item Env:GOTOOLCHAIN go run . ``` 端到端(导入真实样本后): 1. 打开 `/shopee`,确认总行数 **5195** 2. 搜 `24420648774` → **只有 1 行**,SKU 数显示 **62** 3. 搜 `26886533818` → 颜色 **15** / 尺码 **5** / SKU **28** 4. 双击这一行 → 弹窗显示 28 条规格 5. 找到「待补」> 0 的商品(实测有 6 个),确认整行标黄, 弹窗里那几条显示原文 `[必须]` 第 3 步和第 5 步的实际输出要贴出来——这两条是本工单的核心。 ## 风险和回退 | 风险 | 应对 | |---|---| | **颜色数×尺码数被当成规格总数** | 强制加「SKU 数」列,已列为验收项并给了具体商品编号 | | **解析失败在商品级被数字掩盖** | 「待补」列 + 整行标黄 + 弹窗显示原文 | | 颜色数把空值算进去 | 只统计 `parse_ok = 1`,已列为验收项 | | 顺手改了导入逻辑 | 「不做」清单已排除,验收项单列一条 | 回退:`git revert`。纯展示层改动,不影响已导入的数据。
Author
Owner

追加微调:商品名称列再收窄

提交: ccc146c style: 蝦皮商品名称列再收窄到 18% (#41)

用户看过实际渲染后要求「缩小到现在的 60%」,即 max-width 从 30% → 18%。

理由补进了 CSS 注释:蝦皮标题普遍很长(实测最长 60+ 字,全是关键词堆砌),不收窄的话这一列会把后面的颜色/尺码/SKU/待补几个数字挤出屏幕——而那几个数字才是这个页面要看的东西。

数值只写在 app.css 一处,模板注释改成不重复具体百分比,免得下次改了数值忘了同步。title 属性保留,悬停仍能看完整标题。

回归:五个页面均 200,gofmt / go test 全过(GOTOOLCHAIN=go1.23.0)。

仍需实机确认

max-width 用百分比作用在 <td> 上,浏览器行为不完全一致——部分浏览器对 table-cell 的 max-width 处理比较随意。如果实机看下来这一列宽度完全没变化,说明百分比在这里不生效,需要改成固定像素(现有 .truncate 用的是 max-width: 280px,那个路子是确定可行的)。

## 追加微调:商品名称列再收窄 **提交:** `ccc146c` style: 蝦皮商品名称列再收窄到 18% (#41) 用户看过实际渲染后要求「缩小到现在的 60%」,即 `max-width` 从 **30% → 18%**。 理由补进了 CSS 注释:蝦皮标题普遍很长(实测最长 60+ 字,全是关键词堆砌),不收窄的话这一列会把后面的颜色/尺码/SKU/待补几个数字挤出屏幕——而那几个数字才是这个页面要看的东西。 数值只写在 `app.css` 一处,模板注释改成不重复具体百分比,免得下次改了数值忘了同步。`title` 属性保留,悬停仍能看完整标题。 回归:五个页面均 200,`gofmt` / `go test` 全过(`GOTOOLCHAIN=go1.23.0`)。 ### 仍需实机确认 `max-width` 用**百分比**作用在 `<td>` 上,浏览器行为不完全一致——部分浏览器对 `table-cell` 的 `max-width` 处理比较随意。如果实机看下来这一列宽度**完全没变化**,说明百分比在这里不生效,需要改成固定像素(现有 `.truncate` 用的是 `max-width: 280px`,那个路子是确定可行的)。
Author
Owner

验收通过,关闭

用户实机确认通过。归档状态已更新(6d40c1e)。

  • 实现提交: 64d5e74 + ccc146c
  • 归档: docs/task/41-admin-蝦皮数据页商品级列表.md

遗留

max-width 用百分比作用在 <td> 上,浏览器行为不完全一致。若实机看下来列宽完全没变化,需改成固定像素。另:ShopeeSave/Delete/Collect 仍是 501。

## 验收通过,关闭 用户实机确认通过。归档状态已更新(`6d40c1e`)。 - **实现提交:** `64d5e74 + ccc146c` - **归档:** `docs/task/41-admin-蝦皮数据页商品级列表.md` ### 遗留 **`max-width` 用百分比作用在 `<td>` 上,浏览器行为不完全一致**。若实机看下来列宽完全没变化,需改成固定像素。另:`ShopeeSave`/`Delete`/`Collect` 仍是 501。
ila closed this issue 2026-08-09 10:06:47 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#41