From 6aab34a60a0bbff2ebdc08660f5a430df6836097 Mon Sep 17 00:00:00 2001 From: zhx Date: Wed, 22 Jul 2026 19:33:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B8=81=E5=95=86=E6=8F=90?= =?UTF-8?q?=E7=8E=B0=E9=85=8D=E7=BD=AE=E5=B1=95=E7=A4=BA=E5=8F=B7=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/pointwithdrawalconfig/service.go | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/server/admin/internal/modules/pointwithdrawalconfig/service.go b/server/admin/internal/modules/pointwithdrawalconfig/service.go index fcc89099..ef1e78ed 100644 --- a/server/admin/internal/modules/pointwithdrawalconfig/service.go +++ b/server/admin/internal/modules/pointwithdrawalconfig/service.go @@ -78,9 +78,13 @@ func (s *Service) Upsert(ctx context.Context, appCode string, req upsertRequest, if status != "active" && status != "disabled" { return itemDTO{}, errors.New("状态只能是 active 或 disabled") } - if _, _, _, _, err := s.lookupSeller(ctx, appCode, req.SellerUserID, true); err != nil { + resolvedSellerUserID, err := s.resolveActiveSellerUserID(ctx, appCode, req.SellerUserID) + if err != nil { return itemDTO{}, err } + // 后台运营看到并输入的是短展示号,而提现配置必须持久化不可变的内部 user_id;解析后统一覆盖请求值, + // 避免展示号变更时配置失联,也避免 18 位内部 ID 经过浏览器 Number 后发生精度损失。 + req.SellerUserID = resolvedSellerUserID if err := s.ensureSchema(ctx); err != nil { return itemDTO{}, err } @@ -190,6 +194,40 @@ func (s *Service) lookupSeller(ctx context.Context, appCode string, sellerUserID return } +func (s *Service) resolveActiveSellerUserID(ctx context.Context, appCode string, inputID int64) (int64, error) { + if s.userDB == nil { + return 0, errors.New("user db is not configured") + } + // 与后台其他用户身份入口保持一致:数字展示号优先于同值内部 ID。两次查询分别命中 + // users(app_code,current_display_user_id) 唯一索引和 users 主键,避免 OR 条件破坏索引选择。 + var sellerUserID int64 + err := s.userDB.QueryRowContext(ctx, ` + SELECT u.user_id + FROM users u + JOIN coin_seller_profiles csp ON csp.user_id = u.user_id AND csp.app_code = u.app_code + WHERE u.app_code = ? AND u.current_display_user_id = ? + AND u.status = 'active' AND csp.status = 'active' + LIMIT 1`, appCode, strconv.FormatInt(inputID, 10)).Scan(&sellerUserID) + if err == nil { + return sellerUserID, nil + } + if !errors.Is(err, sql.ErrNoRows) { + return 0, err + } + + err = s.userDB.QueryRowContext(ctx, ` + SELECT u.user_id + FROM users u + JOIN coin_seller_profiles csp ON csp.user_id = u.user_id AND csp.app_code = u.app_code + WHERE u.app_code = ? AND u.user_id = ? + AND u.status = 'active' AND csp.status = 'active' + LIMIT 1`, appCode, inputID).Scan(&sellerUserID) + if errors.Is(err, sql.ErrNoRows) { + return 0, errors.New("目标用户不是当前 App 的启用币商") + } + return sellerUserID, err +} + func (s *Service) validateServiceScope(ctx context.Context, appCode string, regionIDs []int64, countryCodes []string) error { if s.userDB == nil { return errors.New("user db is not configured")