Files
cmautobuy/admin/service/shopee_list.go
T
chengmaandClaude Opus 5 e29d6683ad feat: 蝦皮 Excel 报表导入 (#38)
蝦皮数据模块此前整个是骨架,四个入口全返回 501,excelize 连依赖都没装。
本工单做导入和列表,Save/Delete/Collect 保持 501。

真实样本实测:5195 个商品 / 6092 个 SKU,23 行解析失败。

upsert 白名单式,pdd_goods_url / pdd_goods_id 既不在 INSERT 列清单里
也不在 DO UPDATE SET 里。报表没有这两列,写进去就是写空值——操作员
攒几周的 PDD 链接会被一次导入洗光,而且不报错,等到建采购任务才发现。
有独立测试守着:往 DO UPDATE SET 里加回这一行,测试立刻变红。

按 sheet 名字取「最佳表現商品」,不用第 0 个。工作簿有 5 个 sheet,
另外 4 个是广告报表,连 商品規格ID 列都没有;蝦皮调顺序时按下标
会静默导入一张完全不相干的表。

按列名找索引。40 列里 32 列是统计指标,蝦皮加一列所有列号就错位,
而且不报错——会把「點擊率」当成「商品規格」存进去。

规格解析三种格式:含【】53.4%、逗号+空格 26.4%、只有逗号 20.2%,
只认【】会漏掉 46.6%。括号不配对(21 行)和右半整个被【】包住(2 行)
一律判整体失败,不逐段硬凑——错法不统一,针对每种错法写规则等于在猜,
而且没有人工核对过的正确答案可验证。失败时 color/size/advice 必须全空,
原文存进 spec_raw 交人工补。

不写 DELETE + INSERT 的全量替换,将来手动新增的 SKU 会被删掉。

excelize v2.9.1 的 go 指令正好是 1.23.0,与项目固定版本一致。

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

103 lines
2.8 KiB
Go
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.
// 蝦皮数据列表页的查询和界面文字组装。
//
// 分成单独文件是因为它和 shopee_import.go 职责不同:这里只读,不写库。
package service
import (
"database/sql"
"cmautobuy/admin/model"
"cmautobuy/admin/repository"
)
// ShopeeSKUView 是列表页一行要显示的全部内容,全部已经是字符串,
// 模板里不做判断和格式化。
type ShopeeSKUView struct {
GoodsID string
Title string
SKUID string
Color string
Size string
Advice string
// ParseFailed 为 true 时整行标黄,提示需要人工补颜色/尺码/建议,
// 见 docs/admin/05-ui-specification.md §4.2。
ParseFailed bool
// PddURL 为空且 PddMissing 为 true 时,模板显示"未填写"并标红——
// 这是最需要操作员注意的状态,见 §4.2。
PddURL string
PddMissing bool
StatusText string
IsManual bool
UpdatedAt string
}
// ShopeeListResult 是列表页要的全部数据。
type ShopeeListResult struct {
Rows []ShopeeSKUView
Total int // shopee_products 的总商品数(不受筛选影响),用于判断"是否已导入过"
IsFiltered bool
}
// ListShopeeSKUs 查蝦皮 SKU 列表并把每一行翻成界面文字。
//
// 采集状态来自 pdd_products(联查得到),不是蝦皮自己的字段,
// 见 docs/admin/01-requirements.md §6.1:
//
// shopee_products.pdd_goods_id 为空 -> "未填链接"
// pdd_products.collect_status -> 未采集 / 采集中 / 已采集 / 采集失败
func ListShopeeSKUs(db *sql.DB, keyword string) (*ShopeeListResult, error) {
rows, err := repository.ListShopeeSKUs(db, keyword)
if err != nil {
return nil, err
}
total, err := repository.CountShopeeProducts(db)
if err != nil {
return nil, err
}
result := &ShopeeListResult{
Rows: make([]ShopeeSKUView, 0, len(rows)),
Total: total,
IsFiltered: keyword != "",
}
for _, r := range rows {
v := ShopeeSKUView{
GoodsID: r.GoodsID,
Title: r.ProductTitle,
SKUID: r.SKUID,
IsManual: r.IsManual,
UpdatedAt: formatLocalTime(r.UpdatedAt),
}
if r.ParseOK {
v.Color, v.Size, v.Advice = r.Color, r.Size, r.Advice
if v.Advice == "" {
v.Advice = placeholder
}
} else {
v.Color, v.Size, v.Advice = placeholder, placeholder, placeholder
v.ParseFailed = true
}
if r.PddGoodsID == "" {
v.PddMissing = true
v.PddURL = "未填写"
v.StatusText = "未填链接"
} else {
v.PddURL = r.PddGoodsURL
if r.CollectStatus.Valid {
v.StatusText = collectStatusText(model.CollectStatus(r.CollectStatus.String))
} else {
// pdd_goods_id 有值但 pdd_products 里查不到对应行
// (比如那条 PDD 商品被软删除了),如实说明,不要装作"未采集"。
v.StatusText = "PDD 商品缺失"
}
}
result.Rows = append(result.Rows, v)
}
return result, nil
}