diff --git a/server/internal/api/exports.go b/server/internal/api/exports.go index 55fb03d..c8260f9 100644 --- a/server/internal/api/exports.go +++ b/server/internal/api/exports.go @@ -156,23 +156,34 @@ func (a *ExportsAPI) create(w http.ResponseWriter, r *http.Request) { // 注意:不再从 URL 参数 userId 或 current_user_id 自动转换为 creator_in 过滤 // current_user_id 仅用于记录导出任务的 owner,不用于数据过滤 // support multiple merchantId in query: e.g., merchantId=1,2,3 → filters.merchant_id_in + // 注意:对于 YMT 数据源,reseller_id_eq 和 merchant_id_in 映射到同一物理列 order_info.merchant_id, + // 当 reseller_id_eq 已存在且非零时,跳过 merchantId URL 参数注入以避免冲突导致过滤条件丢失 { - midStr := r.URL.Query().Get("merchantId") - if midStr != "" { - parts := strings.Split(midStr, ",") - ids := make([]interface{}, 0, len(parts)) - for _, s := range parts { - s = strings.TrimSpace(s) - if s == "" { - continue + skipMerchantIdIn := false + // 当 reseller_id_eq 已存在且非零时,跳过 merchantId URL 参数注入 + // YMT: reseller_id_eq 和 merchant_id_in 映射同一物理列 order_info.merchant_id,注入会导致冲突 + // Marketing: merchant_id_in 未在 schema 中定义,但其存在会阻止 reseller_id_eq 的应用 + if v, ok := p.Filters["reseller_id_eq"]; ok && v != nil && v != "" && v != 0 { + skipMerchantIdIn = true + } + if !skipMerchantIdIn { + midStr := r.URL.Query().Get("merchantId") + if midStr != "" { + parts := strings.Split(midStr, ",") + ids := make([]interface{}, 0, len(parts)) + for _, s := range parts { + s = strings.TrimSpace(s) + if s == "" { + continue + } + if n, err := strconv.ParseUint(s, 10, 64); err == nil { + ids = append(ids, n) + } } - if n, err := strconv.ParseUint(s, 10, 64); err == nil { - ids = append(ids, n) - } - } - if len(ids) > 0 { - if _, exists := p.Filters["merchant_id_in"]; !exists { - p.Filters["merchant_id_in"] = ids + if len(ids) > 0 { + if _, exists := p.Filters["merchant_id_in"]; !exists { + p.Filters["merchant_id_in"] = ids + } } } } diff --git a/server/internal/exporter/sqlbuilder.go b/server/internal/exporter/sqlbuilder.go index 041d0aa..908d74d 100644 --- a/server/internal/exporter/sqlbuilder.go +++ b/server/internal/exporter/sqlbuilder.go @@ -317,6 +317,13 @@ func BuildSQLWithFields(req BuildRequest, whitelist map[string]bool) (string, [] where = append(where, fmt.Sprintf("`%s`.%s IN (%s)", sch.TableName(tbl), escape(col), ph)) args = append(args, creatorArgs...) } + } else if hasMerchant { + if tbl, col, ok := sch.FilterColumn("merchant_id_in"); ok { + ph := strings.Repeat("?,", len(merchantArgs)) + ph = strings.TrimSuffix(ph, ",") + where = append(where, fmt.Sprintf("`%s`.%s IN (%s)", sch.TableName(tbl), escape(col), ph)) + args = append(args, merchantArgs...) + } } if v, ok := req.Filters["create_time_between"]; ok { @@ -647,6 +654,13 @@ func BuildCountSQL(req BuildRequest, whitelist map[string]bool) (string, []inter where = append(where, fmt.Sprintf("`%s`.%s IN (%s)", sch.TableName(tbl), escape(col), ph)) args = append(args, creatorArgs...) } + } else if hasMerchant { + if tbl, col, ok := sch.FilterColumn("merchant_id_in"); ok { + ph := strings.Repeat("?,", len(merchantArgs)) + ph = strings.TrimSuffix(ph, ",") + where = append(where, fmt.Sprintf("`%s`.%s IN (%s)", sch.TableName(tbl), escape(col), ph)) + args = append(args, merchantArgs...) + } } // build WHERE from other filters