feat: 统一 Admin 主列表分页 (#64)

This commit is contained in:
chengma
2026-08-09 21:51:20 +08:00
parent 5c9ebd968c
commit 155dd3b4a2
23 changed files with 549 additions and 120 deletions
+33 -20
View File
@@ -174,33 +174,43 @@ const pddSkuCountExpr = `
ELSE COALESCE(json_array_length(skus_json, '$.skus'), -1)
END`
// ListPddProducts 查列表。keyword 匹配 goods_id 或链接,status 为空表示不筛选。
//
// 只返回未删除的。软删除的记录还在库里(sku_mappings 指着它),
// 但界面上不该看见。
func ListPddProducts(q Execer, keyword string, status model.CollectStatus) ([]PddProductRow, error) {
sqlText := `SELECT ` + pddColumns + `,` + pddSkuCountExpr + `
FROM pdd_products
WHERE deleted_at IS NULL`
var args []any
// pddListFilter 统一生成 PDD 列表和总数查询的筛选条件。
// 两个查询必须共用这一处,避免新增筛选时只改列表、漏改页数。
func pddListFilter(keyword string, status model.CollectStatus) (string, []any) {
where := ` WHERE deleted_at IS NULL`
args := make([]any, 0, 3)
if keyword = strings.TrimSpace(keyword); keyword != "" {
// ESCAPE 不能省:操作员搜 "_" 时,LIKE 会把它当"任意一个字符",
// 结果是全部行都命中,看着像搜索坏了。
pattern := "%" + escapeLike(keyword) + "%"
sqlText += ` AND (goods_id LIKE ? ESCAPE '\' OR url LIKE ? ESCAPE '\')`
where += ` AND (goods_id LIKE ? ESCAPE '\' OR url LIKE ? ESCAPE '\')`
args = append(args, pattern, pattern)
}
if status != "" {
sqlText += ` AND collect_status = ?`
where += ` AND collect_status = ?`
args = append(args, string(status))
}
// 刚动过的排前面,操作员点完"创建采集任务"一眼能看到结果
sqlText += ` ORDER BY updated_at DESC, id DESC`
return where, args
}
rows, err := q.Query(sqlText, args...)
// ListPddProducts 查一页列表和当前筛选下的总数。
// keyword 匹配 goods_id 或链接,status 为空表示不筛选。
//
// 只返回未删除的。软删除的记录还在库里(sku_mappings 指着它),
// 但界面上不该看见。
func ListPddProducts(q Execer, keyword string, status model.CollectStatus, limit, offset int) ([]PddProductRow, int, error) {
where, args := pddListFilter(keyword, status)
var total int
if err := q.QueryRow(`SELECT COUNT(*) FROM pdd_products`+where, args...).Scan(&total); err != nil {
return nil, 0, fmt.Errorf("统计 PDD 商品列表失败: %w", err)
}
sqlText := `SELECT ` + pddColumns + `,` + pddSkuCountExpr + `
FROM pdd_products` + where
// 刚动过的排前面,操作员点完"创建采集任务"一眼能看到结果
sqlText += ` ORDER BY updated_at DESC, id DESC LIMIT ? OFFSET ?`
listArgs := append(append([]any{}, args...), limit, offset)
rows, err := q.Query(sqlText, listArgs...)
if err != nil {
return nil, fmt.Errorf("查询 PDD 商品列表失败: %w", err)
return nil, 0, fmt.Errorf("查询 PDD 商品列表失败: %w", err)
}
defer rows.Close()
@@ -209,12 +219,15 @@ func ListPddProducts(q Execer, keyword string, status model.CollectStatus) ([]Pd
var r PddProductRow
p, err := scanPddProduct(rows, &r.SkuCount)
if err != nil {
return nil, fmt.Errorf("读取 PDD 商品列表失败: %w", err)
return nil, 0, fmt.Errorf("读取 PDD 商品列表失败: %w", err)
}
r.PddProduct = *p
list = append(list, r)
}
return list, rows.Err()
if err := rows.Err(); err != nil {
return nil, 0, err
}
return list, total, nil
}
// escapeLike 把 LIKE 的三个特殊字符转义掉,配合 ESCAPE '\' 使用。