- 后端 internal/service 按职责拆分: fulfillment.go(1397→527)拆出 wallet/timeout/data/order/query/dashboard/shipnotify delivery.go(1124→801)拆出 upstream/link/state/helpers merchant.go(855→251)拆出 member/product/api_client/catalog/helpers - 前端 MerchantCenter.tsx(1327→606)拆出 merchantCenterTabs/merchantCenterUtils - docker-compose backend 透传 CORS_ALLOWED_ORIGINS - CORS 白名单实现(config/router/README/.env.example 配套) - 修复 gofmt 与文件尾部多余空行
138 lines
4.0 KiB
Go
138 lines
4.0 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func (s *DeliveryService) goodsDetail(goodID string) (map[string]interface{}, error) {
|
|
var out struct {
|
|
Good map[string]interface{} `json:"good"`
|
|
}
|
|
if err := s.signProxy("/public/goods/detail", "POST", map[string]interface{}{
|
|
"good_id": goodID,
|
|
}, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return out.Good, nil
|
|
}
|
|
|
|
func (s *DeliveryService) accountBound(bindUUID, goodID string) (map[string]interface{}, error) {
|
|
var out struct {
|
|
GameAccount map[string]interface{} `json:"gameAccount"`
|
|
Snake map[string]interface{} `json:"game_account"`
|
|
}
|
|
if err := s.signProxy("/public/games/account-bound", "POST", map[string]interface{}{
|
|
"bind_uuid": bindUUID,
|
|
"bindUuid": bindUUID,
|
|
"goodId": goodID,
|
|
"good_id": goodID,
|
|
}, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
if out.GameAccount == nil {
|
|
out.GameAccount = out.Snake
|
|
}
|
|
if out.GameAccount == nil {
|
|
return nil, errors.New("账号尚未绑定,请扫码完成绑定后再提交")
|
|
}
|
|
return out.GameAccount, nil
|
|
}
|
|
|
|
func (s *DeliveryService) createOrderQueue(goodID, orderNo string) (string, error) {
|
|
var out struct {
|
|
Orders []map[string]interface{} `json:"orders"`
|
|
}
|
|
if err := s.signProxy("/public/users/orders-queue", "POST", map[string]interface{}{
|
|
"good_id": goodID,
|
|
"quantity": 1,
|
|
"order_sn": orderNo,
|
|
}, &out); err != nil {
|
|
return "", err
|
|
}
|
|
if len(out.Orders) == 0 {
|
|
return "", errors.New("发货服务未返回队列订单")
|
|
}
|
|
orderID := firstNonEmpty(stringFromMap(out.Orders[0], "_id"), stringFromMap(out.Orders[0], "id"))
|
|
if orderID == "" {
|
|
return "", errors.New("发货服务未返回队列订单 ID")
|
|
}
|
|
return orderID, nil
|
|
}
|
|
|
|
func (s *DeliveryService) patchOrderQueue(orderID, gameAccount, bindUUID string) error {
|
|
var out map[string]interface{}
|
|
return s.signProxy("/public/users/orders-queue", "PATCH", map[string]interface{}{
|
|
"order_id": orderID,
|
|
"game_account": gameAccount,
|
|
"bind_uuid": bindUUID,
|
|
}, &out)
|
|
}
|
|
|
|
func (s *DeliveryService) createUpstreamOrder(orderID, gameAccount, goodID, orderNo string) (map[string]interface{}, error) {
|
|
var out struct {
|
|
Order map[string]interface{} `json:"order"`
|
|
}
|
|
if err := s.signProxy("/public/users/orders", "POST", map[string]interface{}{
|
|
"order_id": orderID,
|
|
"game_account": gameAccount,
|
|
"good_id": goodID,
|
|
"h5_prefix": s.channel,
|
|
"order_sn": orderNo,
|
|
}, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
if out.Order == nil {
|
|
out.Order = map[string]interface{}{"order_id": orderID, "order_sn": orderNo}
|
|
}
|
|
return out.Order, nil
|
|
}
|
|
|
|
func (s *DeliveryService) signProxy(path, method string, data interface{}, out interface{}) error {
|
|
payload, err := json.Marshal(map[string]interface{}{
|
|
"path": path,
|
|
"method": strings.ToUpper(method),
|
|
"data": data,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req, err := http.NewRequest(http.MethodPost, s.bffBaseURL+"/sign-proxy", bytes.NewReader(payload))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := s.httpClient.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("发货服务请求失败:%w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
|
var envelope struct {
|
|
Code interface{} `json:"code"`
|
|
Message string `json:"message"`
|
|
Data json.RawMessage `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(body, &envelope); err != nil {
|
|
return fmt.Errorf("发货服务响应无法解析:%s", truncateDeliveryText(string(body)))
|
|
}
|
|
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices || !isZeroCode(envelope.Code) {
|
|
if envelope.Message != "" {
|
|
return errors.New(envelope.Message)
|
|
}
|
|
return fmt.Errorf("发货服务请求失败:HTTP %d", resp.StatusCode)
|
|
}
|
|
if out == nil || len(envelope.Data) == 0 || string(envelope.Data) == "null" {
|
|
return nil
|
|
}
|
|
if err := json.Unmarshal(envelope.Data, out); err != nil {
|
|
return fmt.Errorf("发货服务数据无法解析:%w", err)
|
|
}
|
|
return nil
|
|
}
|