Files
cmautobuy/admin/templates/shopee/list.html
T
chengmaandClaude Opus 5 64d5e74d0d feat: 蝦皮数据页改为商品级列表与规格弹窗 (#41)
原来是 SKU 级一行,问题不在行数(6092→5195 只少 15%),在语义错了:
pdd_goods_url / pdd_goods_id 在 shopee_products 上,是商品级字段。
商品 24420648774 有 62 个 SKU,列表里 62 行显示同一个 PDD 链接,
将来双击任意一行编辑的也是同一个字段,操作员会以为改的是这一行。

加了两列,都是防止聚合后丢信息:

「SKU 数」—— 只显示颜色数和尺码数会严重误导。实测 602 个商品(11.6%)
的颜色数×尺码数大于实际 SKU 数,最悬殊的 26886533818 是 15×5=75 但
实际只有 28 个。蝦皮报表只含有销售成绩的 SKU,数据本来就不全。

「待补」—— 原来解析失败的行整行标黄,聚合成数量后这个信号会丢。
23 条失败分布在 6 个商品里,其中 4 个是「部分失败」:数字看着正常,
坏数据被吃掉,永远没人去补。现在待补>0 整行标黄。

颜色数/尺码数只统计 parse_ok=1,否则空值会被算进 DISTINCT 多出
一个「空颜色」。

弹窗只读,待补的行显示 spec_raw 原文——不显示的话人工不知道该填什么,
保留原文这个设计就白做了。复用 #18 的弹窗机制,app.js 未改动。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 11:12:25 +08:00

133 lines
5.1 KiB
HTML
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.
{{define "shopee/list"}}
{{template "header" .}}
{{/* ── 第一段:顶部工具条 ────────────────────────────── */}}
<div class="toolbar">
<form class="inline" method="post" action="/shopee/import" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="file" name="file" accept=".xlsx" required>
<button type="submit">导入 Excel</button>
</form>
<form class="inline" method="post" action="/shopee/collect">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<button type="submit" data-need-checked>批量采集</button>
</form>
<form class="inline grow" method="get" action="/shopee">
<label for="q">商品 ID</label>
<input id="q" type="text" name="goods_id" value="{{.Keyword}}" placeholder="商品 ID">
<button type="submit">搜索</button>
</form>
<form class="inline" method="post" action="/shopee/delete"
data-confirm-delete>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<button type="submit" class="danger" data-need-checked>删除</button>
</form>
</div>
{{/* ── 第二段:带勾选的表格 ──────────────────────────── */}}
{{/* 一个商品一行(不是一个 SKU 一行),见工单 #41。
双击行打开详情弹窗,见 static/js/app.js。 */}}
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="col-check"><input type="checkbox" data-check-all></th>
<th>商品 ID</th>
<th>商品名称</th>
<th>颜色</th>
<th>尺码</th>
{{/* SKU 数是这个商品报表里实际出现过的规格条数。
`[必须]` 必须单独显示——颜色数 × 尺码数经常大于它(蝦皮报表只含
有销售成绩的 SKU),只看前两列会让人误以为要匹配的规格更多,见 #41。 */}}
<th>SKU</th>
{{/* `[必须]` 待补 > 0 说明该商品有 SKU 解析失败,整行标黄(.row-warn)。
聚合成商品级之后,"部分失败"的行光看数字是正常的,
不加这一列坏数据就会被悄悄吃掉,见 #41。 */}}
<th>待补</th>
<th>PDD 链接</th>
<th>采集状态</th>
<th>更新时间</th>
</tr>
</thead>
<tbody>
{{range .Rows}}
<tr data-detail-id="{{.GoodsID}}"{{if gt .PendingCount 0}} class="row-warn"{{end}}>
<td class="col-check"><input type="checkbox" name="ids" value="{{.GoodsID}}"></td>
<td>{{.GoodsID}}</td>
{{/* 商品名称列收窄到 30%,用独立的 .col-title 类设 max-width,
不用 flex——表格单元格和工具条的 .search-narrow 那套不一样,见 #41。 */}}
<td class="truncate col-title" title="{{.Title}}">{{.Title}}</td>
<td>{{.ColorCount}}</td>
<td>{{.SizeCount}}</td>
<td>{{.SKUCount}}</td>
<td>{{.PendingCount}}</td>
<td{{if .PddMissing}} class="missing"{{end}}>{{.PddURL}}</td>
<td>{{.StatusText}}</td>
<td>{{.UpdatedAt}}</td>
</tr>
{{else}}
<tr class="empty">
<td colspan="10">
{{if .IsFiltered}}
没有匹配的数据,换个商品 ID 或商品名称试试。
{{else}}
还没有数据,点左上角「导入 Excel」开始。<br>
<small>样本文件不在仓库里,需向项目负责人索取,放到 raw_data/ 下。</small>
{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<p class="hint">
双击任意一行可以查看这个商品的完整规格表。
</p>
{{/* ── 导入失败行:全部列出来,不折叠、不只显示条数 ──── */}}
{{if .Failures}}
<div class="table-wrap">
<p>本次导入有 {{len .Failures}} 行解析失败,规格原文已按原样保存,需人工补颜色/尺码/建议:</p>
<table>
<thead>
<tr>
<th>行号</th>
<th>规格原文</th>
<th>原因</th>
</tr>
</thead>
<tbody>
{{range .Failures}}
<tr>
<td>{{.Row}}</td>
<td>{{.Raw}}</td>
<td>{{.Reason}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{end}}
{{/* ── 详情弹窗的壳子 ───────────────────────────
里面的内容双击行时由 /shopee/detail 返回,前端只负责放进来和显示,
复用 #18 的机制(data-detail-url / data-detail-slot / data-detail-id),
app.js 不需要改,见工单 #41。
这个弹窗**只读**:商品信息 + 完整规格表,没有保存按钮。
从蝦皮商品出发录入 PDD 链接、发起采集的入口(含 ShopeeSave/
ShopeeCollect 的实现)由后续的「蝦皮↔PDD 关联入口」工单负责,
本工单不做,ShopeeSave/ShopeeDelete/ShopeeCollect 仍是 501。 */}}
<div class="modal-backdrop" id="detail-modal" data-detail-url="/shopee/detail" hidden>
<div class="modal" role="dialog" aria-modal="true" data-detail-slot>
<div class="modal-body">正在加载…</div>
</div>
</div>
{{template "footer" .}}
{{end}}