#41 归档记录了两条防信息丢失的设计(SKU 数列、待补列),以及最危险的 「部分失败」场景实测:28431952912 颜色4/尺码5 数字看着正常, 里面有 4 个 SKU 解析失败,靠整行标黄才藏不住。 #43 归档记录了实现踩到的 html/template URL 上下文转义坑: 夹在字面量 & 中间的动态内容会被整体当成一个参数值转义, ?/= 变成 %3F/%3D 让链接失效,只有真跑起来看 HTML 才发现。 也记了架构角色第二个变异第一次打偏、显示「跳过」的事—— 探针无效和代码有问题是两回事,#38 刚犯过一次。 三份都如实列了「未验证到的部分」,主要是浏览器实机交互和 列宽百分比在 table-cell 上的实际行为。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7.0 KiB
41 Admin 蝦皮数据页改为商品级列表与规格弹窗
- 类型:需求(界面重构)
- 父级大工单:#14
- 所属 MVP / 版本:#15 / MVP
- 关联:#38(导入)、#18(弹窗机制来源)
- 状态:验收通过
- 日期:2026-08-08
- Gitea 工单:#41
背景与目标
蝦皮数据页原来是 SKU 级一行。问题不在行数(6092 → 5195 只少 15%, 平均每个商品仅 1.17 个 SKU),在语义错了:
pdd_goods_url / pdd_goods_id 在 shopee_products 上,是商品级字段。
实测商品 24420648774 有 62 个 SKU——列表里 62 行显示的是同一个
PDD 链接,将来双击任意一行编辑的也是同一个字段。操作员会以为
「我改的是这一行的链接」。
最终方案
☐ │ 商品 ID │ 商品名称 │ 颜色 │ 尺码 │ SKU │ 待补 │ PDD 链接 │ 采集状态 │ 更新时间
15 5 28 2
必须加「SKU 数」列
[必须] 只显示颜色数和尺码数会严重误导。实测:
颜色数×尺码数 > 实际 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,数据本来就不全。三个数字放在一起, 操作员才看得出「这商品在报表里只有 28 条记录,不是 75 条」。
必须加「待补」列并整行标黄
[必须] 原来 parse_ok = 0 的行显示 — 并整行标黄,一眼能看见要人工补。
聚合成数量之后这个信号会丢。实测:
23 条解析失败的 SKU,分布在 6 个商品里
4 个是「部分失败」 → 显示「颜色 3」,坏的那几个直接消失
2 个是「全部失败」 → 显示「颜色 0 / 尺码 0」
「部分失败」那 4 个最危险——数字看着正常,坏数据被吃掉,永远没人去补。
[必须] 颜色数 / 尺码数只统计 parse_ok = 1 的 SKU。
把解析失败的空值算进 DISTINCT 会多出一个「空颜色」。
弹窗只读,待补的行显示原文
[必须] 待补的行必须显示 spec_raw 原文——不显示的话人工不知道该填什么,
保留原文这个设计就白做了。
[必须] 弹窗只读,ShopeeSave 仍是 501。不放一个点了没反应的保存按钮。
复用 #18 的弹窗机制(data-detail-url / data-detail-slot / data-detail-id),
app.js 未改动。
与建单方案的差异
- 详情路由用
?id=而不是工单写的?goods_id=。app.js里fetch(base + "?id=" + ...)的参数名是硬编码的,而「不改app.js」是 更高优先级的约束。与 PDD 页的/pdd/detail?id=也保持了一致。 - 新增
admin/service/shopee_list_test.go(工单预计文件表未列)。
改了哪些
admin/repository/shopee.go:ListShopeeProducts商品级聚合查询、GetShopeeProductByGoodsID、GetShopeeCollectStatus、ListShopeeSKUsByGoodsID;删除不再使用的 SKU 级查询。admin/service/shopee_list.go:视图改商品级,新增弹窗用的ShopeeProductDetail。admin/service/shopee_list_test.go:新建。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:.col-title。
验收结果
架构角色独立复跑,用真实样本导入后逐条核对:
| 检查 | 实测结果 |
|---|---|
| 总行数 | 共 5195 个商品 |
24420648774 |
1 行(原 62 行),颜色10 / 尺码8 / SKU62 / 待补0 |
26886533818 |
颜色15 / 尺码5 / SKU28(不是 75) |
28431952912(部分失败) |
颜色4 / 尺码5 / SKU24 / 待补4,整行标黄 |
24023581128(全部失败) |
颜色0 / 尺码0 / SKU1 / 待补1,整行标黄 |
| 弹窗显示原文 | 原文:面膜安全褲3條膚色,【2xl 70-85公斤可穿】 |
| PDD 链接为空 | 显示「未填写」并标红 |
app.js / shopee_import.go |
均未改动 |
ShopeeSave / Delete / Collect |
仍是 501(3 处) |
| 五个页面 | 全部 200 |
28431952912 那条是最危险的场景——「部分失败」,颜色尺码数字看着完全正常
(4 和 5),但里面有 4 个 SKU 解析失败。标黄之后藏不住了。
测试
架构角色亲自执行,用 GOTOOLCHAIN=go1.23.0 固定工具链:
GOTOOLCHAIN=go1.23.0 go vet ./... 无输出
GOTOOLCHAIN=go1.23.0 gofmt -l . 无输出
GOTOOLCHAIN=go1.23.0 go test ./... -count=1
ok cmautobuy/admin 0.049s
ok cmautobuy/admin/repository 0.753s
ok cmautobuy/admin/service 2.081s
变异测试(工单未要求,架构角色补做)
| 变异 | 结果 |
|---|---|
颜色/尺码数不再过滤 parse_ok = 1 |
4 个用例变红 |
| 待补数恒为 0(标黄失效) | 4 个用例变红 |
这两条正是本工单加进去防信息丢失的,现在有测试守着。
未验证到的部分:
- 浏览器里的真实交互:双击开弹窗只验证了服务端 HTML 和
/shopee/detail的返回内容,没在真实浏览器里点过。 - 1366×768 下的表格横向滚动未做视觉走查。
max-width用百分比作用在<td>上,浏览器行为不完全一致—— 部分浏览器对table-cell的max-width处理比较随意。若实机看下来 宽度完全没变化,需改成固定像素(.truncate用的max-width: 280px那个路子是确定可行的)。
用户已实机确认并验收通过。
追加微调
用户看过实际渲染后要求商品名称列「缩小到现在的 60%」,
max-width 从 30% → 18%(提交 ccc146c)。
理由写进 CSS 注释:蝦皮标题普遍很长(实测最长 60+ 字,全是关键词堆砌),
不收窄的话这一列会把后面的颜色/尺码/SKU/待补几个数字挤出屏幕——
而那几个数字才是这个页面要看的东西。完整标题靠悬停的 title 属性看。
数值只写在 app.css 一处,模板注释不再重复具体百分比,
免得下次改了数值忘了同步。
遗留问题
ShopeeSave/ShopeeDelete/ShopeeCollect仍是 501,属后续工单。- 手动新增 SKU(
05§4.4)未做。蝦皮报表只含有销售成绩的 SKU, 导入进来的数据本身就是不全的。 - 浏览器实机交互与列宽百分比的实际效果需人工确认。
相关提交
64d5e74feat: 蝦皮数据页改为商品级列表与规格弹窗 (#41)ccc146cstyle: 蝦皮商品名称列再收窄到 18% (#41)