feat: 支持顺运宝多订单号搜索 (#217)

This commit is contained in:
chengma
2026-08-13 14:58:19 +08:00
parent 2ebe6bf695
commit 8f2b3f725d
13 changed files with 372 additions and 46 deletions
+34 -7
View File
@@ -530,18 +530,21 @@ func nullableText(s string) any {
// SybOrderFilter 是货运单列表页支持的筛选条件。
type SybOrderFilter struct {
Keyword string // 匹配订单号或商品标题
Shop string // 店铺名模糊匹配;空字符串表示全部
Stage string // 处理阶段;空字符串表示全部
OrderNos []string // 订单号精确匹配;多个值之间是 OR,空切片表示全部
Shop string // 店铺名模糊匹配;空字符串表示全部
Stage string // 处理阶段;空字符串表示全部
}
func sybOrderFilterClause(filter SybOrderFilter) (string, []any) {
var clauses []string
var args []any
if kw := filter.Keyword; kw != "" {
like := "%" + escapeLike(kw) + "%"
clauses = append(clauses, `(so.order_no LIKE ? ESCAPE '!' OR so.title LIKE ? ESCAPE '!')`)
args = append(args, like, like)
if len(filter.OrderNos) > 0 {
placeholders := make([]string, len(filter.OrderNos))
for i, orderNo := range filter.OrderNos {
placeholders[i] = "?"
args = append(args, orderNo)
}
clauses = append(clauses, `so.order_no IN (`+strings.Join(placeholders, ",")+`)`)
}
if shop := strings.TrimSpace(filter.Shop); shop != "" {
clauses = append(clauses, `so.shop_name LIKE ? ESCAPE '!'`)
@@ -752,6 +755,30 @@ func CountSybOrders(q Execer, filter SybOrderFilter) (int, error) {
return n, nil
}
// ListMatchedSybOrderNos 返回当前可由 SQL 表达的组合筛选实际命中的订单号。
// 页面用它区分“输入了多少订单”和“命中了多少商品明细”;查询继续复用
// idx_syb_orders_order,所有订单号都通过占位符传入。
func ListMatchedSybOrderNos(q Execer, filter SybOrderFilter) ([]string, error) {
if len(filter.OrderNos) == 0 {
return nil, nil
}
where, args := sybOrderFilterClause(filter)
rows, err := q.Query(`SELECT DISTINCT so.order_no`+sybOrderContextFrom+where+` ORDER BY so.order_no`, args...)
if err != nil {
return nil, fmt.Errorf("查询顺运宝命中订单号失败: %w", err)
}
defer rows.Close()
matched := make([]string, 0, len(filter.OrderNos))
for rows.Next() {
var orderNo string
if err := rows.Scan(&orderNo); err != nil {
return nil, fmt.Errorf("读取顺运宝命中订单号失败: %w", err)
}
matched = append(matched, orderNo)
}
return matched, rows.Err()
}
// CountSybOrdersTotal 统计全部货运单明细数量(不带筛选),
// 供列表页判断"是否已经同步过任何数据"。
func CountSybOrdersTotal(q Execer) (int, error) {
+14 -9
View File
@@ -408,7 +408,7 @@ func TestInterruptRunningSybSyncRuns_只中断未完成记录(t *testing.T) {
}
}
func TestListSybOrders_订单标题店铺组合筛选(t *testing.T) {
func TestListSybOrders_多订单精确与店铺组合筛选(t *testing.T) {
db := newSybTestDB(t)
mustUpsert := func(sybID, orderNo, shop, title string) {
if _, err := UpsertSybOrder(db, model.SybOrder{
@@ -420,28 +420,33 @@ func TestListSybOrders_订单标题店铺组合筛选(t *testing.T) {
mustUpsert("SYB-A", "260728AAA", "台北服饰旗舰店", "纯棉上衣")
mustUpsert("SYB-B", "260728BBB", "台南生活馆", "牛仔裤")
rows, err := ListSybOrders(db, SybOrderFilter{Keyword: "AAA"}, 20, 0)
rows, err := ListSybOrders(db, SybOrderFilter{OrderNos: []string{"260728AAA", "260728BBB"}}, 20, 0)
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(rows) != 1 || rows[0].SybID != "SYB-A" {
t.Fatalf("按订单号筛选应该只查到 SYB-A,实际 %+v", rows)
if len(rows) != 2 {
t.Fatalf("两个精确订单号应该查到两条,实际 %+v", rows)
}
rows2, err := ListSybOrders(db, SybOrderFilter{Keyword: "牛仔"}, 20, 0)
rows2, err := ListSybOrders(db, SybOrderFilter{OrderNos: []string{"AAA", "牛仔"}}, 20, 0)
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(rows2) != 1 || rows2[0].SybID != "SYB-B" {
t.Fatalf("按标题筛选应该只查到 SYB-B,实际 %+v", rows2)
if len(rows2) != 0 {
t.Fatalf("订单号片段和商品标题都不应再命中,实际 %+v", rows2)
}
rows3, err := ListSybOrders(db, SybOrderFilter{Shop: " 服饰 "}, 20, 0)
if err != nil || len(rows3) != 1 || rows3[0].SybID != "SYB-A" || rows3[0].ShopName != "台北服饰旗舰店" {
t.Fatalf("按店铺模糊筛选错误:rows=%+v err=%v", rows3, err)
}
count, err := CountSybOrders(db, SybOrderFilter{Keyword: "牛仔", Shop: "台南"})
filter := SybOrderFilter{OrderNos: []string{"260728AAA", "260728BBB", "NOT-FOUND"}, Shop: "台南"}
count, err := CountSybOrders(db, filter)
if err != nil || count != 1 {
t.Fatalf("标题与店铺组合 COUNT 错误:count=%d err=%v", count, err)
t.Fatalf("订单号与店铺组合 COUNT 错误:count=%d err=%v", count, err)
}
matched, err := ListMatchedSybOrderNos(db, filter)
if err != nil || len(matched) != 1 || matched[0] != "260728BBB" {
t.Fatalf("当前筛选命中订单号错误:matched=%v err=%v", matched, err)
}
}