feat: 保存并展示 PDD 店铺与价格采样信息 (#31)
This commit is contained in:
+38
-4
@@ -227,6 +227,7 @@ type PddProductView struct {
|
||||
GoodsID string
|
||||
URL string
|
||||
Title string // 未采集时是占位符
|
||||
ShopName string // 未采到时是占位符
|
||||
StatusText string
|
||||
SkuCountText string // 未采集时是占位符
|
||||
CollectedAt string
|
||||
@@ -269,6 +270,7 @@ func ListPddProducts(db *sql.DB, keyword string, status model.CollectStatus) (*P
|
||||
GoodsID: r.GoodsID,
|
||||
URL: r.URL,
|
||||
Title: r.Title,
|
||||
ShopName: r.ShopName,
|
||||
StatusText: statusTextFor(r.PddProduct),
|
||||
CollectedAt: formatLocalTime(r.CollectedAt),
|
||||
UpdatedAt: formatLocalTime(r.UpdatedAt),
|
||||
@@ -278,6 +280,9 @@ func ListPddProducts(db *sql.DB, keyword string, status model.CollectStatus) (*P
|
||||
if v.Title == "" {
|
||||
v.Title = "(未采集,采集后自动回填)"
|
||||
}
|
||||
if v.ShopName == "" {
|
||||
v.ShopName = placeholder
|
||||
}
|
||||
// -1 是"还没采过"。注意 0 要如实显示 0:
|
||||
// 采到 0 个规格说明采集出了问题,显示成 — 就看不出来了。
|
||||
if r.SkuCount < 0 {
|
||||
@@ -318,7 +323,9 @@ func (r *PddListResult) StatusLine() string {
|
||||
type PddSkuView struct {
|
||||
Options []string // 按 DimensionNames 的顺序排好,模板直接 range
|
||||
PriceText string
|
||||
Available string
|
||||
// PriceSource 在按颜色采样时显示“✓ 实测”或“推断”,不能只靠颜色区分。
|
||||
PriceSource string
|
||||
Available string
|
||||
}
|
||||
|
||||
// PddProductDetail 是双击弹窗要显示的全部内容。
|
||||
@@ -327,15 +334,17 @@ type PddProductDetail struct {
|
||||
GoodsID string
|
||||
URL string
|
||||
Title string
|
||||
ShopName string
|
||||
StatusText string
|
||||
CollectMsg string
|
||||
CollectedAt string
|
||||
ArtifactRef string
|
||||
|
||||
// Collected 为 false 时模板显示"尚未采集",而不是一张空表。
|
||||
Collected bool
|
||||
DimensionNames []string
|
||||
SKUs []PddSkuView
|
||||
Collected bool
|
||||
ShowPriceSource bool
|
||||
DimensionNames []string
|
||||
SKUs []PddSkuView
|
||||
|
||||
// SkusError 非空表示 skus_json 存的东西解析不了。
|
||||
// 这种情况要如实说出来,不能装作"没有规格"——
|
||||
@@ -356,6 +365,7 @@ func GetPddProductDetail(db *sql.DB, id int64) (*PddProductDetail, error) {
|
||||
GoodsID: p.GoodsID,
|
||||
URL: p.URL,
|
||||
Title: p.Title,
|
||||
ShopName: p.ShopName,
|
||||
StatusText: statusTextFor(*p),
|
||||
CollectMsg: p.CollectMsg,
|
||||
CollectedAt: formatLocalTime(p.CollectedAt),
|
||||
@@ -364,6 +374,9 @@ func GetPddProductDetail(db *sql.DB, id int64) (*PddProductDetail, error) {
|
||||
if d.Title == "" {
|
||||
d.Title = placeholder
|
||||
}
|
||||
if d.ShopName == "" {
|
||||
d.ShopName = placeholder
|
||||
}
|
||||
if d.CollectMsg == "" {
|
||||
d.CollectMsg = placeholder
|
||||
}
|
||||
@@ -379,6 +392,7 @@ func GetPddProductDetail(db *sql.DB, id int64) (*PddProductDetail, error) {
|
||||
}
|
||||
|
||||
d.Collected = true
|
||||
d.ShowPriceSource = collected.PriceGranularity == "color"
|
||||
keys, names := dimensionOrder(collected)
|
||||
d.DimensionNames = names
|
||||
|
||||
@@ -391,6 +405,12 @@ func GetPddProductDetail(db *sql.DB, id int64) (*PddProductDetail, error) {
|
||||
if sku.Available {
|
||||
row.Available = "是"
|
||||
}
|
||||
if d.ShowPriceSource {
|
||||
row.PriceSource = "推断"
|
||||
if sameOptions(sku.Options, sku.PriceObservedAt) {
|
||||
row.PriceSource = "✓ 实测"
|
||||
}
|
||||
}
|
||||
for _, k := range keys {
|
||||
value := sku.Options[k]
|
||||
if value == "" {
|
||||
@@ -403,6 +423,20 @@ func GetPddProductDetail(db *sql.DB, id int64) (*PddProductDetail, error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// sameOptions 判断价格读取时实际选中的组合是否就是当前这一行。
|
||||
// 两个 map 必须键和值都完全一致,避免只比较颜色后把多个尺码都标成实测。
|
||||
func sameOptions(options, observed map[string]string) bool {
|
||||
if len(options) == 0 || len(options) != len(observed) {
|
||||
return false
|
||||
}
|
||||
for key, value := range options {
|
||||
if observed[key] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// dimensionOrder 定下规格各维度的显示顺序,返回 (取值用的 key, 表头文字)。
|
||||
//
|
||||
// 优先用采集结果里的 dimensions;它缺失时退回"把所有 SKU 出现过的 key 排序"。
|
||||
|
||||
Reference in New Issue
Block a user