feat: 保存并展示 PDD 店铺与价格采样信息 (#31)

This commit is contained in:
chengma
2026-08-07 17:13:25 +08:00
parent a2fc1501c4
commit 93beef8b36
17 changed files with 492 additions and 73 deletions
+13 -9
View File
@@ -12,7 +12,7 @@ import (
// pddColumns 是所有查询共用的列清单。
// 写成常量是为了让下面几个查询的列顺序和 scanPddProduct 永远对得上——
// 改列的时候只改这一处,改漏了会 Scan 到错的字段上,而且不报错。
const pddColumns = `id, goods_id, url, title, skus_json,
const pddColumns = `id, goods_id, url, title, shop_name, skus_json,
collect_status, collect_msg, artifact_ref, collected_at,
deleted_at, created_at, updated_at`
@@ -24,10 +24,10 @@ type rowScanner interface {
// scanPddProduct 按 pddColumns 的顺序读一行。
func scanPddProduct(s rowScanner, extra ...any) (*model.PddProduct, error) {
var p model.PddProduct
var title, skus, msg, artifact, collectedAt, deletedAt sql.NullString
var title, shopName, skus, msg, artifact, collectedAt, deletedAt sql.NullString
dest := []any{
&p.ID, &p.GoodsID, &p.URL, &title, &skus,
&p.ID, &p.GoodsID, &p.URL, &title, &shopName, &skus,
&p.CollectStatus, &msg, &artifact, &collectedAt,
&deletedAt, &p.CreatedAt, &p.UpdatedAt,
}
@@ -38,6 +38,7 @@ func scanPddProduct(s rowScanner, extra ...any) (*model.PddProduct, error) {
}
p.Title = title.String
p.ShopName = shopName.String
p.SkusJSON = skus.String
p.CollectMsg = msg.String
p.ArtifactRef = artifact.String
@@ -91,13 +92,13 @@ func EnsurePddProduct(q Execer, goodsID, url string) (*model.PddProduct, error)
// 复活:清掉删除标记,状态回到待采集。
// 采集结果一并清空——记录被删过一次,旧数据不能再当成有效的用。
//
// title 也要清:它是**采集回来的**(SetCollectResult 写的),
// title 和 shop_name 也要清:它们是**采集回来的**(SetCollectResult 写的),
// 属于采集结果的一部分。留着的话状态显示"未采集"、标题却有值,
// 操作员会以为已经采过了。
_, err := q.Exec(`
UPDATE pdd_products
SET deleted_at = NULL, url = ?, collect_status = 'pending',
title = NULL, skus_json = NULL, collect_msg = NULL,
title = NULL, shop_name = NULL, skus_json = NULL, collect_msg = NULL,
artifact_ref = NULL, collected_at = NULL, updated_at = ?
WHERE goods_id = ?`,
url, now, goodsID)
@@ -304,18 +305,21 @@ func SoftDeletePddProducts(q Execer, goodsIDs []string) (int64, error) {
//
// `[必须]` 按 **PDD 的 goods_id** 定位,不是蝦皮的。采集的对象是 PDD 商品。
//
// title 由调用方从采集结果里取出来传进来,用于人工核对"采的是不是要的那个商品"。
func SetCollectResult(q Execer, pddGoodsID, title, skusJSON string) error {
// title 和 shopName 由调用方从采集结果里取出来,用于人工核对商品来源。
// shopName 为空时保留数据库已有值:这次没采到不代表上次采到的店铺名失效。
func SetCollectResult(q Execer, pddGoodsID, title, shopName, skusJSON string) error {
if pddGoodsID == "" {
return fmt.Errorf("pdd goods_id 不能为空")
}
now := model.NowISO()
res, err := q.Exec(`
UPDATE pdd_products
SET skus_json = ?, title = ?, collect_status = 'collected',
SET skus_json = ?, title = ?,
shop_name = CASE WHEN TRIM(?) = '' THEN shop_name ELSE ? END,
collect_status = 'collected',
collect_msg = NULL, collected_at = ?, updated_at = ?
WHERE goods_id = ? AND deleted_at IS NULL`,
skusJSON, title, now, now, pddGoodsID)
skusJSON, title, shopName, shopName, now, now, pddGoodsID)
if err != nil {
return fmt.Errorf("保存 PDD 商品 %s 的采集结果失败: %w", pddGoodsID, err)
}