diff --git a/backend/internal/service/delivery.go b/backend/internal/service/delivery.go index ba04f57..b59e3b1 100644 --- a/backend/internal/service/delivery.go +++ b/backend/internal/service/delivery.go @@ -415,7 +415,9 @@ func (s *DeliveryService) bindWithOrder(orderNo, gameAccount string, auth *Deliv var lastErr error var bindRes *ProviderBindResult var usedProvider FulfillmentProvider + tried := map[string]bool{} for _, p := range providers { + tried[p.Name()] = true res, err := p.Bind(context.Background(), order, gameAccount) if err == nil && res != nil { bindRes = res @@ -424,6 +426,29 @@ func (s *DeliveryService) bindWithOrder(orderNo, gameAccount string, auth *Deliv } lastErr = err } + + // Prepare 可能因 GET 成功先锁住乐玩;随后写接口凭据/IP 校验失败时,清除锁定并尝试其余渠道(如 DLC)。 + if bindRes == nil { + lockedName := resultDataString(order.ResultData, "provider") + if lockedName != "" || lastErr != nil { + s.clearSelectedProvider(order) + fallbackProviders, _ := s.router.ResolveProviders(order) + for _, p := range fallbackProviders { + if tried[p.Name()] { + continue + } + tried[p.Name()] = true + res, err := p.Bind(context.Background(), order, gameAccount) + if err == nil && res != nil { + bindRes = res + usedProvider = p + break + } + lastErr = err + } + } + } + if bindRes == nil { if lastErr != nil { return nil, lastErr diff --git a/backend/internal/service/provider_lewan.go b/backend/internal/service/provider_lewan.go index 1223810..c1cf56b 100644 --- a/backend/internal/service/provider_lewan.go +++ b/backend/internal/service/provider_lewan.go @@ -181,11 +181,39 @@ func (p *LewanProvider) Bind(ctx context.Context, order *model.FulfillmentOrder, // 3. 判断是否需要绑定 if bindingAction != nil && !bindingAction.BindingRequired { - // 角色已在乐玩绑定过,免扫码直接已绑定 + // 角色已在乐玩绑定过,免扫码直接已绑定;尽量补齐角色名/区服,便于领取页展示。 + roleName, gameChannel, boundRoleID := extractLewanRoleDisplay(lewanOrder, nil) + if refreshRes, refreshErr := p.client.RefreshBinding(ctx, lewanOrderID); refreshErr == nil { + rn, gc, rid := extractLewanRoleDisplay(nil, refreshRes) + if rn != "" { + roleName = rn + } + if gc != "" { + gameChannel = gc + } + if rid != "" { + boundRoleID = rid + } + } + if roleName != "" { + patch["role_name"] = roleName + } + if gameChannel != "" { + patch["game_channel"] = gameChannel + } + bindURL := strings.TrimSpace(bindingAction.BindingUrl) + qrURL := "" + if bindURL != "" { + qrURL = qrCodeURL(bindURL) + } return &ProviderBindResult{ BindUUID: lewanOrderID, + BindURL: bindURL, + QRURL: qrURL, Bound: true, - GameAccount: gameAccount, + GameAccount: firstNonEmpty(boundRoleID, gameAccount), + RoleName: roleName, + GameChannel: gameChannel, Message: "账号已在平台授权,免扫码直接进入发货", Provider: ProviderLewan, PatchResultData: patch, @@ -231,10 +259,13 @@ func (p *LewanProvider) CheckBind(ctx context.Context, order *model.FulfillmentO orderDetail, getErr := p.client.GetOrder(ctx, lewanOrderID) if getErr == nil && orderDetail != nil { if orderDetail.Status != "WAITING_BINDING" { + roleName, gameChannel, boundRoleID := extractLewanRoleDisplay(orderDetail, nil) return &ProviderBindResult{ BindUUID: lewanOrderID, Bound: true, - GameAccount: orderDetail.RoleID, + GameAccount: firstNonEmpty(boundRoleID, orderDetail.RoleID), + RoleName: roleName, + GameChannel: gameChannel, Message: "绑定已完成", Provider: ProviderLewan, }, nil @@ -251,13 +282,27 @@ func (p *LewanProvider) CheckBind(ctx context.Context, order *model.FulfillmentO bound := false gameAccount := "" roleName := "" + gameChannel := "" if refreshRes != nil && refreshRes.Binding != nil { bound = refreshRes.Binding.Matched gameAccount = refreshRes.Binding.RoleID roleName = refreshRes.Binding.RoleName + gameChannel = firstNonEmpty(refreshRes.Binding.RoleArea, refreshRes.Binding.ServerName) } - if refreshRes != nil && refreshRes.Order != nil && refreshRes.Order.Status != "WAITING_BINDING" { - bound = true + if refreshRes != nil && refreshRes.Order != nil { + if refreshRes.Order.Status != "WAITING_BINDING" { + bound = true + } + rn, gc, rid := extractLewanRoleDisplay(refreshRes.Order, nil) + if roleName == "" { + roleName = rn + } + if gameChannel == "" { + gameChannel = gc + } + if gameAccount == "" { + gameAccount = rid + } } msg := "绑定成功" @@ -270,6 +315,7 @@ func (p *LewanProvider) CheckBind(ctx context.Context, order *model.FulfillmentO Bound: bound, GameAccount: gameAccount, RoleName: roleName, + GameChannel: gameChannel, Message: msg, Provider: ProviderLewan, }, nil @@ -323,8 +369,19 @@ func (p *LewanProvider) Submit(ctx context.Context, order *model.FulfillmentOrde } roleName := "" + gameChannel := "" if refreshRes != nil && refreshRes.Binding != nil { roleName = refreshRes.Binding.RoleName + gameChannel = firstNonEmpty(refreshRes.Binding.RoleArea, refreshRes.Binding.ServerName) + } + if roleName == "" || gameChannel == "" { + rn, gc, _ := extractLewanRoleDisplay(lewanOrder, nil) + if roleName == "" { + roleName = rn + } + if gameChannel == "" { + gameChannel = gc + } } return &ProviderSubmitResult{ @@ -334,6 +391,7 @@ func (p *LewanProvider) Submit(ctx context.Context, order *model.FulfillmentOrde GameAccount: map[string]interface{}{ "game_account": gameAccount, "role_name": roleName, + "game_channel": gameChannel, }, UpstreamOrder: lewanOrder, PatchResultData: map[string]interface{}{ @@ -345,6 +403,7 @@ func (p *LewanProvider) Submit(ctx context.Context, order *model.FulfillmentOrde "lewan_status": lewanOrder.Status, "game_uid": gameAccount, "role_name": roleName, + "game_channel": gameChannel, "delivery": lewanOrder, }, }, nil @@ -472,3 +531,35 @@ func (p *LewanProvider) SyncStatus(ctx context.Context, order *model.Fulfillment }, nil } } + +// extractLewanRoleDisplay 从乐玩订单/刷新结果提取角色名、区服与 RoleID,供领取页展示。 +func extractLewanRoleDisplay( + order *lewan.LewanOrder, + refresh *lewan.RefreshBindingResult, +) (roleName, gameChannel, roleID string) { + if refresh != nil && refresh.Binding != nil { + roleName = strings.TrimSpace(refresh.Binding.RoleName) + gameChannel = firstNonEmpty(refresh.Binding.RoleArea, refresh.Binding.ServerName) + roleID = strings.TrimSpace(refresh.Binding.RoleID) + } + if refresh != nil && refresh.Order != nil && order == nil { + order = refresh.Order + } + if order != nil { + if roleID == "" { + roleID = strings.TrimSpace(order.RoleID) + } + if order.Binding != nil { + if roleName == "" { + roleName = strings.TrimSpace(order.Binding.RoleName) + } + if gameChannel == "" { + gameChannel = firstNonEmpty(order.Binding.RoleArea, order.Binding.ServerName) + } + if roleID == "" { + roleID = strings.TrimSpace(order.Binding.RoleID) + } + } + } + return roleName, gameChannel, roleID +}