60 KiB
60 KiB
根据文档分析,该API使用阿里云Darabonba OpenAPI SDK进行ROA签名调用(SDK内部自动处理签名),无需额外加密工具。我将直接生成所有代码文件。
// File: server_tb_LinkedMall/go.mod
module server_tb_LinkedMall
go 1.26
require (
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
github.com/alibabacloud-go/tea/v2 v2.2.8
github.com/gofiber/fiber/v2 v2.52.5
github.com/google/uuid v1.6.0
github.com/json-iterator/go v1.1.12
)
require (
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.57.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.28.0 // indirect
)
// File: server_tb_LinkedMall/pkg/crypto/crypto.go
package crypto
import (
"crypto/rand"
"encoding/hex"
"fmt"
"time"
)
// GenerateNonce 生成随机字符串,用于防重放
func GenerateNonce() string {
buf := make([]byte, 16)
_, _ = rand.Read(buf)
return hex.EncodeToString(buf)
}
// GenerateTimestamp 生成当前时间戳(毫秒)
func GenerateTimestamp() int64 {
return time.Now().UnixMilli()
}
// FormatTimestamp 格式化时间戳为字符串
func FormatTimestamp(ts int64) string {
return fmt.Sprintf("%d", ts)
}
// File: server_tb_LinkedMall/internal/config/config.go
package config
import (
"os"
)
// Config 应用配置
type Config struct {
ServerPort string
AccessKeyId string
AccessKeySecret string
RegionId string
Endpoint string
BasePath string
DefaultPurchaserId string
CallbackURL string
}
// LoadConfig 从环境变量加载配置
func LoadConfig() *Config {
return &Config{
ServerPort: getEnv("SERVER_PORT", "8080"),
AccessKeyId: getEnv("LINKEDMALL_AK", ""),
AccessKeySecret: getEnv("LINKEDMALL_SK", ""),
RegionId: getEnv("LINKEDMALL_REGION_ID", "cn-zhangjiakou"),
Endpoint: getEnv("LINKEDMALL_ENDPOINT", "linkedmall.cn-zhangjiakou.aliyuncs.com"),
BasePath: getEnv("LINKEDMALL_BASE_PATH", "/opensaas-s2b/opensaas-s2b-biz-trade/v2"),
DefaultPurchaserId: getEnv("LINKEDMALL_PURCHASER_ID", ""),
CallbackURL: getEnv("LINKEDMALL_CALLBACK_URL", ""),
}
}
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
// File: server_tb_LinkedMall/internal/entities/request.go
package entities
// ============================================================
// 通用请求结构
// ============================================================
// PaginationReq 分页请求公共参数
type PaginationReq struct {
PageNum int `json:"PageNum" query:"PageNum"`
PageSize int `json:"PageSize" query:"PageSize"`
}
// PurchaserQuery 采购方ID查询参数
type PurchaserQuery struct {
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 1: ListPurchaserShops
// ============================================================
type ListPurchaserShopsReq struct {
PageNum int `json:"PageNum" query:"PageNum"`
PageSize int `json:"PageSize" query:"PageSize"`
}
// ============================================================
// 接口 2: GetPurchaserShop
// ============================================================
type GetPurchaserShopReq struct {
ShopId string `json:"ShopId" params:"ShopId"`
}
// ============================================================
// 接口 3: ListSelectionProducts
// ============================================================
type ListSelectionProductsReq struct {
PageNum int `json:"PageNum" query:"PageNum"`
PageSize int `json:"PageSize" query:"PageSize"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 4: GetSelectionProduct
// ============================================================
type GetSelectionProductReq struct {
ProductId string `json:"ProductId" params:"ProductId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
DivisionCode string `json:"DivisionCode" query:"DivisionCode"`
}
// ============================================================
// 接口 5: GetSelectionProductSaleInfo
// ============================================================
type GetSelectionProductSaleInfoReq struct {
ProductId string `json:"ProductId" params:"ProductId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
DivisionCode string `json:"DivisionCode" query:"DivisionCode"`
}
// ============================================================
// 接口 6: ListSelectionProductSaleInfos
// ============================================================
type ListSelectionProductSaleInfosReq struct {
PurchaserId string `json:"PurchaserId"`
ProductIdList []string `json:"ProductIdList"`
DivisionCode string `json:"DivisionCode"`
}
// ============================================================
// 接口 7: ListSelectionSkuSaleInfos
// ============================================================
type ListSelectionSkuSaleInfosReq struct {
PurchaserId string `json:"PurchaserId"`
SkuIdList []string `json:"SkuIdList"`
DivisionCode string `json:"DivisionCode"`
}
// ============================================================
// 接口 8: ListCategories
// ============================================================
type ListCategoriesReq struct {
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
ParentCategoryId string `json:"ParentCategoryId" query:"ParentCategoryId"`
}
// ============================================================
// 接口 9: SearchProducts
// ============================================================
type SearchProductsReq struct {
Keyword string `json:"Keyword"`
CategoryId string `json:"CategoryId"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
PurchaserId string `json:"PurchaserId"`
}
// ============================================================
// 接口 10: SelectionGroupAddProduct
// ============================================================
type SelectionGroupAddProductReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
ProductIdList []string `json:"ProductIdList"`
}
// ============================================================
// 接口 11: SelectionGroupRemoveProduct
// ============================================================
type SelectionGroupRemoveProductReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
ProductIdList []string `json:"ProductIdList"`
}
// ============================================================
// 接口 12: RenderPurchaseOrder
// ============================================================
type RenderPurchaseOrderReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
DivisionCode string `json:"DivisionCode"`
ItemList []RenderOrderItem `json:"ItemList"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
}
type RenderOrderItem struct {
SkuId string `json:"SkuId"`
Quantity int64 `json:"Quantity"`
}
type ReceiverInfo struct {
ReceiverName string `json:"ReceiverName"`
ReceiverPhone string `json:"ReceiverPhone"`
ProvinceCode string `json:"ProvinceCode"`
CityCode string `json:"CityCode"`
DistrictCode string `json:"DistrictCode"`
TownCode string `json:"TownCode"`
DetailAddress string `json:"DetailAddress"`
}
// ============================================================
// 接口 13: SplitPurchaseOrder
// ============================================================
type SplitPurchaseOrderReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
DivisionCode string `json:"DivisionCode"`
ItemList []RenderOrderItem `json:"ItemList"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
}
// ============================================================
// 接口 14: CreatePurchaseOrder
// ============================================================
type CreatePurchaseOrderReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
OuterPurchaseOrderId string `json:"OuterPurchaseOrderId"`
DivisionCode string `json:"DivisionCode"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
SubOrderList []CreateSubOrderItem `json:"SubOrderList"`
}
type CreateSubOrderItem struct {
SkuId string `json:"SkuId"`
Quantity int64 `json:"Quantity"`
}
// ============================================================
// 接口 15: GetPurchaseOrderStatus
// ============================================================
type GetPurchaseOrderStatusReq struct {
PurchaseOrderId string `json:"PurchaseOrderId" params:"PurchaseOrderId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 16: GetOrder
// ============================================================
type GetOrderReq struct {
OrderId string `json:"OrderId" params:"OrderId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 17: QueryOrders
// ============================================================
type QueryOrdersReq struct {
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
PurchaseOrderId string `json:"PurchaseOrderId" query:"PurchaseOrderId"`
PageNum int `json:"PageNum" query:"PageNum"`
PageSize int `json:"PageSize" query:"PageSize"`
StartTime string `json:"StartTime" query:"StartTime"`
EndTime string `json:"EndTime" query:"EndTime"`
}
// ============================================================
// 接口 18: ListLogisticsOrders
// ============================================================
type ListLogisticsOrdersReq struct {
OrderId string `json:"OrderId" params:"OrderId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 19: ConfirmDisburse
// ============================================================
type ConfirmDisburseReq struct {
OrderId string `json:"OrderId" params:"OrderId"`
PurchaserId string `json:"PurchaserId"`
}
// ============================================================
// 接口 20: RenderRefundOrder
// ============================================================
type RenderRefundOrderReq struct {
PurchaserId string `json:"PurchaserId"`
OrderId string `json:"OrderId"`
OrderItemId string `json:"OrderItemId"`
RefundQuantity int64 `json:"RefundQuantity"`
RefundType string `json:"RefundType"`
}
// ============================================================
// 接口 21: CreateRefundOrder
// ============================================================
type CreateRefundOrderReq struct {
PurchaserId string `json:"PurchaserId"`
OrderId string `json:"OrderId"`
OrderItemId string `json:"OrderItemId"`
RefundQuantity int64 `json:"RefundQuantity"`
RefundAmount int64 `json:"RefundAmount"`
RefundType string `json:"RefundType"`
RefundReason string `json:"RefundReason"`
OuterRefundNo string `json:"OuterRefundNo"`
}
// ============================================================
// 接口 22: CancelRefundOrder
// ============================================================
type CancelRefundOrderReq struct {
RefundOrderId string `json:"RefundOrderId" params:"RefundOrderId"`
PurchaserId string `json:"PurchaserId"`
}
// ============================================================
// 接口 23: GetRefundOrder
// ============================================================
type GetRefundOrderReq struct {
RefundOrderId string `json:"RefundOrderId" params:"RefundOrderId"`
PurchaserId string `json:"PurchaserId" query:"PurchaserId"`
}
// ============================================================
// 接口 24: CreateGoodsShippingNotice
// ============================================================
type CreateGoodsShippingNoticeReq struct {
RefundOrderId string `json:"RefundOrderId" params:"RefundOrderId"`
PurchaserId string `json:"PurchaserId"`
LogisticsCompany string `json:"LogisticsCompany"`
TrackingNumber string `json:"TrackingNumber"`
}
// ============================================================
// 接口 25: QueryChildDivisionCode
// ============================================================
type QueryChildDivisionCodeReq struct {
ParentDivisionCode string `json:"ParentDivisionCode" query:"ParentDivisionCode"`
}
// ============================================================
// 回调通知
// ============================================================
type CallbackNotification struct {
EventCode string `json:"EventCode"`
PurchaseOrderId string `json:"PurchaseOrderId"`
OrderIdList []string `json:"OrderIdList"`
Status string `json:"Status"`
RequestId string `json:"RequestId"`
}
// File: server_tb_LinkedMall/internal/entities/response.go
package entities
// ============================================================
// 公共响应结构
// ============================================================
// CommonResponse 阿里云LinkedMall公共响应外层
type CommonResponse struct {
RequestId string `json:"RequestId"`
Success bool `json:"Success"`
Code string `json:"Code"`
Message string `json:"Message"`
SubCode string `json:"SubCode"`
SubMessage string `json:"SubMessage"`
Data interface{} `json:"Data"`
}
// APIResponse 服务端统一返回结构
type APIResponse struct {
Success bool `json:"Success"`
Code string `json:"Code"`
Message string `json:"Message"`
RequestId string `json:"RequestId,omitempty"`
Data interface{} `json:"Data,omitempty"`
}
// ============================================================
// 接口 1: ListPurchaserShops
// ============================================================
type ListPurchaserShopsRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
ShopList []PurchaserShopItem `json:"ShopList"`
}
type PurchaserShopItem struct {
ShopId string `json:"ShopId"`
PurchaserId string `json:"PurchaserId"`
ShopName string `json:"ShopName"`
ShopStatus string `json:"ShopStatus"`
}
// ============================================================
// 接口 2: GetPurchaserShop
// ============================================================
type GetPurchaserShopRespData struct {
ShopId string `json:"ShopId"`
PurchaserId string `json:"PurchaserId"`
ShopName string `json:"ShopName"`
ShopStatus string `json:"ShopStatus"`
ContactInfo string `json:"ContactInfo"`
}
// ============================================================
// 接口 3: ListSelectionProducts
// ============================================================
type ListSelectionProductsRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
ProductList []SelectionProductItem `json:"ProductList"`
}
type SelectionProductItem struct {
ProductId string `json:"ProductId"`
Title string `json:"Title"`
MainImage string `json:"MainImage"`
BrandName string `json:"BrandName"`
CategoryId string `json:"CategoryId"`
}
// ============================================================
// 接口 4: GetSelectionProduct
// ============================================================
type GetSelectionProductRespData struct {
ProductId string `json:"ProductId"`
Title string `json:"Title"`
MainImage string `json:"MainImage"`
Images []string `json:"Images"`
BrandName string `json:"BrandName"`
CategoryId string `json:"CategoryId"`
Desc string `json:"Desc"`
SkuList []SelectionSkuItem `json:"SkuList"`
CanSale bool `json:"CanSale"`
StockQuantity int64 `json:"StockQuantity"`
}
type SelectionSkuItem struct {
SkuId string `json:"SkuId"`
SkuSpec string `json:"SkuSpec"`
SalePrice int64 `json:"SalePrice"`
MarketPrice int64 `json:"MarketPrice"`
StockQuantity int64 `json:"StockQuantity"`
}
// ============================================================
// 接口 5: GetSelectionProductSaleInfo
// ============================================================
type GetSelectionProductSaleInfoRespData struct {
ProductId string `json:"ProductId"`
Title string `json:"Title"`
CanSale bool `json:"CanSale"`
SalePrice int64 `json:"SalePrice"`
StockQuantity int64 `json:"StockQuantity"`
}
// ============================================================
// 接口 6: ListSelectionProductSaleInfos
// ============================================================
type ListSelectionProductSaleInfosRespData struct {
ProductSaleInfoList []ProductSaleInfoItem `json:"ProductSaleInfoList"`
}
type ProductSaleInfoItem struct {
ProductId string `json:"ProductId"`
CanSale bool `json:"CanSale"`
SalePrice int64 `json:"SalePrice"`
StockQuantity int64 `json:"StockQuantity"`
}
// ============================================================
// 接口 7: ListSelectionSkuSaleInfos
// ============================================================
type ListSelectionSkuSaleInfosRespData struct {
SkuSaleInfoList []SkuSaleInfoItem `json:"SkuSaleInfoList"`
}
type SkuSaleInfoItem struct {
SkuId string `json:"SkuId"`
CanSale bool `json:"CanSale"`
SalePrice int64 `json:"SalePrice"`
StockQuantity int64 `json:"StockQuantity"`
}
// ============================================================
// 接口 8: ListCategories
// ============================================================
type ListCategoriesRespData struct {
CategoryList []CategoryItem `json:"CategoryList"`
}
type CategoryItem struct {
CategoryId string `json:"CategoryId"`
CategoryName string `json:"CategoryName"`
ParentId string `json:"ParentId"`
Level int `json:"Level"`
}
// ============================================================
// 接口 9: SearchProducts
// ============================================================
type SearchProductsRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
ProductList []SelectionProductItem `json:"ProductList"`
}
// ============================================================
// 接口 10: SelectionGroupAddProduct
// ============================================================
type SelectionGroupAddProductRespData struct {
SuccessCount int `json:"SuccessCount"`
FailList []string `json:"FailList"`
}
// ============================================================
// 接口 11: SelectionGroupRemoveProduct
// ============================================================
type SelectionGroupRemoveProductRespData struct {
SuccessCount int `json:"SuccessCount"`
FailList []string `json:"FailList"`
}
// ============================================================
// 接口 12: RenderPurchaseOrder
// ============================================================
type RenderPurchaseOrderRespData struct {
TotalFee int64 `json:"TotalFee"`
TotalFreight int64 `json:"TotalFreight"`
ItemList []RenderResultItem `json:"ItemList"`
CanSale bool `json:"CanSale"`
UnSaleReason string `json:"UnSaleReason"`
}
type RenderResultItem struct {
SkuId string `json:"SkuId"`
SalePrice int64 `json:"SalePrice"`
Quantity int64 `json:"Quantity"`
SubTotalFee int64 `json:"SubTotalFee"`
CanSale bool `json:"CanSale"`
UnSaleReason string `json:"UnSaleReason"`
}
// ============================================================
// 接口 13: SplitPurchaseOrder
// ============================================================
type SplitPurchaseOrderRespData struct {
SubOrderList []SubOrderItem `json:"SubOrderList"`
}
type SubOrderItem struct {
ShopId string `json:"ShopId"`
ItemList []RenderOrderItem `json:"ItemList"`
TotalFee int64 `json:"TotalFee"`
TotalFreight int64 `json:"TotalFreight"`
}
// ============================================================
// 接口 14: CreatePurchaseOrder
// ============================================================
type CreatePurchaseOrderRespData struct {
PurchaseOrderId string `json:"PurchaseOrderId"`
}
// ============================================================
// 接口 15: GetPurchaseOrderStatus
// ============================================================
type GetPurchaseOrderStatusRespData struct {
PurchaseOrderId string `json:"PurchaseOrderId"`
Status string `json:"Status"`
StatusDesc string `json:"StatusDesc"`
}
// ============================================================
// 接口 16: GetOrder
// ============================================================
type GetOrderRespData struct {
OrderId string `json:"OrderId"`
PurchaseOrderId string `json:"PurchaseOrderId"`
ShopId string `json:"ShopId"`
OrderStatus string `json:"OrderStatus"`
TotalFee int64 `json:"TotalFee"`
FreightFee int64 `json:"FreightFee"`
ActualPayFee int64 `json:"ActualPayFee"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
OrderItemList []OrderItemDetail `json:"OrderItemList"`
CreateTime string `json:"CreateTime"`
}
type OrderItemDetail struct {
OrderItemId string `json:"OrderItemId"`
SkuId string `json:"SkuId"`
Title string `json:"Title"`
Quantity int64 `json:"Quantity"`
PayFee int64 `json:"PayFee"`
UnitPrice int64 `json:"UnitPrice"`
}
// ============================================================
// 接口 17: QueryOrders
// ============================================================
type QueryOrdersRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
OrderList []GetOrderRespData `json:"OrderList"`
}
// ============================================================
// 接口 18: ListLogisticsOrders
// ============================================================
type ListLogisticsOrdersRespData struct {
LogisticsList []LogisticsItem `json:"LogisticsList"`
}
type LogisticsItem struct {
LogisticsCompany string `json:"LogisticsCompany"`
TrackingNumber string `json:"TrackingNumber"`
TrajectoryList []LogisticsTrajectory `json:"TrajectoryList"`
}
type LogisticsTrajectory struct {
Time string `json:"Time"`
Context string `json:"Context"`
Location string `json:"Location"`
}
// ============================================================
// 接口 19: ConfirmDisburse
// ============================================================
type ConfirmDisburseRespData struct {
Success bool `json:"Success"`
}
// ============================================================
// 接口 20: RenderRefundOrder
// ============================================================
type RenderRefundOrderRespData struct {
RefundableAmount int64 `json:"RefundableAmount"`
RefundableQuantity int64 `json:"RefundableQuantity"`
CanRefund bool `json:"CanRefund"`
UnRefundReason string `json:"UnRefundReason"`
}
// ============================================================
// 接口 21: CreateRefundOrder
// ============================================================
type CreateRefundOrderRespData struct {
RefundOrderId string `json:"RefundOrderId"`
Status string `json:"Status"`
}
// ============================================================
// 接口 22: CancelRefundOrder
// ============================================================
type CancelRefundOrderRespData struct {
Success bool `json:"Success"`
}
// ============================================================
// 接口 23: GetRefundOrder
// ============================================================
type GetRefundOrderRespData struct {
RefundOrderId string `json:"RefundOrderId"`
OrderId string `json:"OrderId"`
OrderItemId string `json:"OrderItemId"`
RefundQuantity int64 `json:"RefundQuantity"`
RefundAmount int64 `json:"RefundAmount"`
RefundType string `json:"RefundType"`
RefundStatus string `json:"RefundStatus"`
RefundReason string `json:"RefundReason"`
CreateTime string `json:"CreateTime"`
}
// ============================================================
// 接口 24: CreateGoodsShippingNotice
// ============================================================
type CreateGoodsShippingNoticeRespData struct {
Success bool `json:"Success"`
}
// ============================================================
// 接口 25: QueryChildDivisionCode
// ============================================================
type QueryChildDivisionCodeRespData struct {
DivisionList []DivisionItem `json:"DivisionList"`
}
type DivisionItem struct {
DivisionCode string `json:"DivisionCode"`
DivisionName string `json:"DivisionName"`
Level int `json:"Level"`
ParentCode string `json:"ParentCode"`
}
// File: server_tb_LinkedMall/internal/biz/biz.go
package biz
import (
"encoding/json"
"fmt"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/v2"
"server_tb_LinkedMall/internal/config"
"server_tb_LinkedMall/internal/entities"
)
// LinkedMallBiz 业务逻辑层 - 封装对LinkedMall OpenAPI的调用
type LinkedMallBiz struct {
client *openapi.Client
cfg *config.Config
basePath string
}
// NewLinkedMallBiz 创建业务逻辑实例
func NewLinkedMallBiz(cfg *config.Config) (*LinkedMallBiz, error) {
cli, err := newLinkedMallClient(cfg.AccessKeyId, cfg.AccessKeySecret, cfg.RegionId, cfg.Endpoint)
if err != nil {
return nil, fmt.Errorf("初始化LinkedMall客户端失败: %w", err)
}
return &LinkedMallBiz{
client: cli,
cfg: cfg,
basePath: cfg.BasePath,
}, nil
}
// newLinkedMallClient 创建Darabonba OpenAPI客户端
func newLinkedMallClient(ak, sk, regionId, endpoint string) (*openapi.Client, error) {
config := &openapi.Config{
AccessKeyId: tea.String(ak),
AccessKeySecret: tea.String(sk),
RegionId: tea.String(regionId),
Endpoint: tea.String(endpoint),
ReadTimeout: tea.Int(30000),
ConnectTimeout: tea.Int(10000),
}
return openapi.NewClient(config)
}
// doRoaGet 发起ROA GET请求
func (b *LinkedMallBiz) doRoaGet(path string, query map[string]*string) (*entities.CommonResponse, error) {
resp, err := b.client.RoaRequest(
tea.String("GET"),
tea.String(b.basePath+path),
query,
nil, // body
nil, // header
)
if err != nil {
return nil, fmt.Errorf("ROA GET请求失败 [%s]: %w", path, err)
}
return b.parseResponse(resp)
}
// doRoaPost 发起ROA POST请求
func (b *LinkedMallBiz) doRoaPost(path string, body interface{}, query map[string]*string) (*entities.CommonResponse, error) {
jsonBytes, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("序列化请求Body失败: %w", err)
}
var bodyObj interface{}
if err := json.Unmarshal(jsonBytes, &bodyObj); err != nil {
return nil, fmt.Errorf("反序列化请求Body失败: %w", err)
}
resp, err := b.client.RoaRequest(
tea.String("POST"),
tea.String(b.basePath+path),
query,
bodyObj,
nil,
)
if err != nil {
return nil, fmt.Errorf("ROA POST请求失败 [%s]: %w", path, err)
}
return b.parseResponse(resp)
}
// parseResponse 解析公共响应
func (b *LinkedMallBiz) parseResponse(resp interface{}) (*entities.CommonResponse, error) {
respBytes, err := json.Marshal(resp)
if err != nil {
return nil, fmt.Errorf("序列化响应失败: %w", err)
}
var commonResp entities.CommonResponse
if err := json.Unmarshal(respBytes, &commonResp); err != nil {
return nil, fmt.Errorf("解析公共响应失败: %w", err)
}
return &commonResp, nil
}
// ============================================================
// 接口实现:调用阿里云LinkedMall OpenAPI
// ============================================================
// 接口 1: ListPurchaserShops
func (b *LinkedMallBiz) ListPurchaserShops(req *entities.ListPurchaserShopsReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
if req.PageNum > 0 {
query["PageNum"] = tea.String(fmt.Sprintf("%d", req.PageNum))
}
if req.PageSize > 0 {
query["PageSize"] = tea.String(fmt.Sprintf("%d", req.PageSize))
}
return b.doRoaGet("/purchaser-shops", query)
}
// 接口 2: GetPurchaserShop
func (b *LinkedMallBiz) GetPurchaserShop(req *entities.GetPurchaserShopReq) (*entities.CommonResponse, error) {
return b.doRoaGet(fmt.Sprintf("/purchaser-shops/%s", req.ShopId), nil)
}
// 接口 3: ListSelectionProducts
func (b *LinkedMallBiz) ListSelectionProducts(req *entities.ListSelectionProductsReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
if req.PageNum > 0 {
query["PageNum"] = tea.String(fmt.Sprintf("%d", req.PageNum))
}
if req.PageSize > 0 {
query["PageSize"] = tea.String(fmt.Sprintf("%d", req.PageSize))
}
return b.doRoaGet("/selection-products", query)
}
// 接口 4: GetSelectionProduct
func (b *LinkedMallBiz) GetSelectionProduct(req *entities.GetSelectionProductReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
if req.DivisionCode != "" {
query["DivisionCode"] = tea.String(req.DivisionCode)
}
return b.doRoaGet(fmt.Sprintf("/selection-products/%s", req.ProductId), query)
}
// 接口 5: GetSelectionProductSaleInfo
func (b *LinkedMallBiz) GetSelectionProductSaleInfo(req *entities.GetSelectionProductSaleInfoReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
if req.DivisionCode != "" {
query["DivisionCode"] = tea.String(req.DivisionCode)
}
return b.doRoaGet(fmt.Sprintf("/selection-products/%s/sale-info", req.ProductId), query)
}
// 接口 6: ListSelectionProductSaleInfos
func (b *LinkedMallBiz) ListSelectionProductSaleInfos(req *entities.ListSelectionProductSaleInfosReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/selection-products:batch-sale-info", req, nil)
}
// 接口 7: ListSelectionSkuSaleInfos
func (b *LinkedMallBiz) ListSelectionSkuSaleInfos(req *entities.ListSelectionSkuSaleInfosReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/selection-skus:batch-sale-info", req, nil)
}
// 接口 8: ListCategories
func (b *LinkedMallBiz) ListCategories(req *entities.ListCategoriesReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
if req.ParentCategoryId != "" {
query["ParentCategoryId"] = tea.String(req.ParentCategoryId)
}
return b.doRoaGet("/categories", query)
}
// 接口 9: SearchProducts
func (b *LinkedMallBiz) SearchProducts(req *entities.SearchProductsReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/selection-products:search", req, nil)
}
// 接口 10: SelectionGroupAddProduct
func (b *LinkedMallBiz) SelectionGroupAddProduct(req *entities.SelectionGroupAddProductReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/selection-group/products:add", req, nil)
}
// 接口 11: SelectionGroupRemoveProduct
func (b *LinkedMallBiz) SelectionGroupRemoveProduct(req *entities.SelectionGroupRemoveProductReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/selection-group/products:remove", req, nil)
}
// 接口 12: RenderPurchaseOrder
func (b *LinkedMallBiz) RenderPurchaseOrder(req *entities.RenderPurchaseOrderReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/purchase-orders:render", req, nil)
}
// 接口 13: SplitPurchaseOrder
func (b *LinkedMallBiz) SplitPurchaseOrder(req *entities.SplitPurchaseOrderReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/purchase-orders:split-render", req, nil)
}
// 接口 14: CreatePurchaseOrder
func (b *LinkedMallBiz) CreatePurchaseOrder(req *entities.CreatePurchaseOrderReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/purchase-orders", req, nil)
}
// 接口 15: GetPurchaseOrderStatus
func (b *LinkedMallBiz) GetPurchaseOrderStatus(req *entities.GetPurchaseOrderStatusReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
return b.doRoaGet(fmt.Sprintf("/purchase-orders/%s/status", req.PurchaseOrderId), query)
}
// 接口 16: GetOrder
func (b *LinkedMallBiz) GetOrder(req *entities.GetOrderReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
return b.doRoaGet(fmt.Sprintf("/orders/%s", req.OrderId), query)
}
// 接口 17: QueryOrders
func (b *LinkedMallBiz) QueryOrders(req *entities.QueryOrdersReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
if req.PurchaseOrderId != "" {
query["PurchaseOrderId"] = tea.String(req.PurchaseOrderId)
}
if req.PageNum > 0 {
query["PageNum"] = tea.String(fmt.Sprintf("%d", req.PageNum))
}
if req.PageSize > 0 {
query["PageSize"] = tea.String(fmt.Sprintf("%d", req.PageSize))
}
if req.StartTime != "" {
query["StartTime"] = tea.String(req.StartTime)
}
if req.EndTime != "" {
query["EndTime"] = tea.String(req.EndTime)
}
return b.doRoaGet("/orders", query)
}
// 接口 18: ListLogisticsOrders
func (b *LinkedMallBiz) ListLogisticsOrders(req *entities.ListLogisticsOrdersReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
return b.doRoaGet(fmt.Sprintf("/orders/%s/logistics", req.OrderId), query)
}
// 接口 19: ConfirmDisburse
func (b *LinkedMallBiz) ConfirmDisburse(req *entities.ConfirmDisburseReq) (*entities.CommonResponse, error) {
body := map[string]string{"PurchaserId": req.PurchaserId}
return b.doRoaPost(fmt.Sprintf("/orders/%s:confirm-disburse", req.OrderId), body, nil)
}
// 接口 20: RenderRefundOrder
func (b *LinkedMallBiz) RenderRefundOrder(req *entities.RenderRefundOrderReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/refund-orders:render", req, nil)
}
// 接口 21: CreateRefundOrder
func (b *LinkedMallBiz) CreateRefundOrder(req *entities.CreateRefundOrderReq) (*entities.CommonResponse, error) {
return b.doRoaPost("/refund-orders", req, nil)
}
// 接口 22: CancelRefundOrder
func (b *LinkedMallBiz) CancelRefundOrder(req *entities.CancelRefundOrderReq) (*entities.CommonResponse, error) {
body := map[string]string{"PurchaserId": req.PurchaserId}
return b.doRoaPost(fmt.Sprintf("/refund-orders/%s:cancel", req.RefundOrderId), body, nil)
}
// 接口 23: GetRefundOrder
func (b *LinkedMallBiz) GetRefundOrder(req *entities.GetRefundOrderReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
query["PurchaserId"] = tea.String(req.PurchaserId)
return b.doRoaGet(fmt.Sprintf("/refund-orders/%s", req.RefundOrderId), query)
}
// 接口 24: CreateGoodsShippingNotice
func (b *LinkedMallBiz) CreateGoodsShippingNotice(req *entities.CreateGoodsShippingNoticeReq) (*entities.CommonResponse, error) {
body := map[string]string{
"PurchaserId": req.PurchaserId,
"LogisticsCompany": req.LogisticsCompany,
"TrackingNumber": req.TrackingNumber,
}
return b.doRoaPost(fmt.Sprintf("/refund-orders/%s:fill-logistics", req.RefundOrderId), body, nil)
}
// 接口 25: QueryChildDivisionCode
func (b *LinkedMallBiz) QueryChildDivisionCode(req *entities.QueryChildDivisionCodeReq) (*entities.CommonResponse, error) {
query := make(map[string]*string)
if req.ParentDivisionCode != "" {
query["ParentDivisionCode"] = tea.String(req.ParentDivisionCode)
}
return b.doRoaGet("/divisions:children", query)
}
// File: server_tb_LinkedMall/internal/service/service.go
package service
import (
"encoding/json"
"server_tb_LinkedMall/internal/biz"
"server_tb_LinkedMall/internal/config"
"server_tb_LinkedMall/internal/entities"
)
// LinkedMallService 服务层 - 封装业务逻辑,处理响应解析
type LinkedMallService struct {
biz *biz.LinkedMallBiz
}
// NewLinkedMallService 创建服务实例
func NewLinkedMallService(cfg *config.Config) (*LinkedMallService, error) {
bizInstance, err := biz.NewLinkedMallBiz(cfg)
if err != nil {
return nil, err
}
return &LinkedMallService{biz: bizInstance}, nil
}
// parseData 解析Data字段到目标结构体
func (s *LinkedMallService) parseData(commonResp *entities.CommonResponse, target interface{}) error {
if commonResp.Data == nil {
return nil
}
dataBytes, err := json.Marshal(commonResp.Data)
if err != nil {
return err
}
return json.Unmarshal(dataBytes, target)
}
// buildAPIResponse 构建统一API响应
func (s *LinkedMallService) buildAPIResponse(commonResp *entities.CommonResponse, data interface{}) *entities.APIResponse {
resp := &entities.APIResponse{
Success: commonResp.Success,
Code: commonResp.Code,
Message: commonResp.Message,
RequestId: commonResp.RequestId,
}
if commonResp.Success && data != nil {
resp.Data = data
}
if !commonResp.Success {
if commonResp.SubCode != "" {
resp.Message = commonResp.SubMessage
}
}
return resp
}
// ============================================================
// 接口 1: ListPurchaserShops
// ============================================================
func (s *LinkedMallService) ListPurchaserShops(req *entities.ListPurchaserShopsReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListPurchaserShops(req)
if err != nil {
return nil, err
}
var data entities.ListPurchaserShopsRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 2: GetPurchaserShop
func (s *LinkedMallService) GetPurchaserShop(req *entities.GetPurchaserShopReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetPurchaserShop(req)
if err != nil {
return nil, err
}
var data entities.GetPurchaserShopRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 3: ListSelectionProducts
func (s *LinkedMallService) ListSelectionProducts(req *entities.ListSelectionProductsReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListSelectionProducts(req)
if err != nil {
return nil, err
}
var data entities.ListSelectionProductsRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 4: GetSelectionProduct
func (s *LinkedMallService) GetSelectionProduct(req *entities.GetSelectionProductReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetSelectionProduct(req)
if err != nil {
return nil, err
}
var data entities.GetSelectionProductRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 5: GetSelectionProductSaleInfo
func (s *LinkedMallService) GetSelectionProductSaleInfo(req *entities.GetSelectionProductSaleInfoReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetSelectionProductSaleInfo(req)
if err != nil {
return nil, err
}
var data entities.GetSelectionProductSaleInfoRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 6: ListSelectionProductSaleInfos
func (s *LinkedMallService) ListSelectionProductSaleInfos(req *entities.ListSelectionProductSaleInfosReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListSelectionProductSaleInfos(req)
if err != nil {
return nil, err
}
var data entities.ListSelectionProductSaleInfosRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 7: ListSelectionSkuSaleInfos
func (s *LinkedMallService) ListSelectionSkuSaleInfos(req *entities.ListSelectionSkuSaleInfosReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListSelectionSkuSaleInfos(req)
if err != nil {
return nil, err
}
var data entities.ListSelectionSkuSaleInfosRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 8: ListCategories
func (s *LinkedMallService) ListCategories(req *entities.ListCategoriesReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListCategories(req)
if err != nil {
return nil, err
}
var data entities.ListCategoriesRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 9: SearchProducts
func (s *LinkedMallService) SearchProducts(req *entities.SearchProductsReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.SearchProducts(req)
if err != nil {
return nil, err
}
var data entities.SearchProductsRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 10: SelectionGroupAddProduct
func (s *LinkedMallService) SelectionGroupAddProduct(req *entities.SelectionGroupAddProductReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.SelectionGroupAddProduct(req)
if err != nil {
return nil, err
}
var data entities.SelectionGroupAddProductRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 11: SelectionGroupRemoveProduct
func (s *LinkedMallService) SelectionGroupRemoveProduct(req *entities.SelectionGroupRemoveProductReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.SelectionGroupRemoveProduct(req)
if err != nil {
return nil, err
}
var data entities.SelectionGroupRemoveProductRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 12: RenderPurchaseOrder
func (s *LinkedMallService) RenderPurchaseOrder(req *entities.RenderPurchaseOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.RenderPurchaseOrder(req)
if err != nil {
return nil, err
}
var data entities.RenderPurchaseOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 13: SplitPurchaseOrder
func (s *LinkedMallService) SplitPurchaseOrder(req *entities.SplitPurchaseOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.SplitPurchaseOrder(req)
if err != nil {
return nil, err
}
var data entities.SplitPurchaseOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 14: CreatePurchaseOrder
func (s *LinkedMallService) CreatePurchaseOrder(req *entities.CreatePurchaseOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.CreatePurchaseOrder(req)
if err != nil {
return nil, err
}
var data entities.CreatePurchaseOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 15: GetPurchaseOrderStatus
func (s *LinkedMallService) GetPurchaseOrderStatus(req *entities.GetPurchaseOrderStatusReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetPurchaseOrderStatus(req)
if err != nil {
return nil, err
}
var data entities.GetPurchaseOrderStatusRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 16: GetOrder
func (s *LinkedMallService) GetOrder(req *entities.GetOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetOrder(req)
if err != nil {
return nil, err
}
var data entities.GetOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 17: QueryOrders
func (s *LinkedMallService) QueryOrders(req *entities.QueryOrdersReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.QueryOrders(req)
if err != nil {
return nil, err
}
var data entities.QueryOrdersRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 18: ListLogisticsOrders
func (s *LinkedMallService) ListLogisticsOrders(req *entities.ListLogisticsOrdersReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ListLogisticsOrders(req)
if err != nil {
return nil, err
}
var data entities.ListLogisticsOrdersRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 19: ConfirmDisburse
func (s *LinkedMallService) ConfirmDisburse(req *entities.ConfirmDisburseReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.ConfirmDisburse(req)
if err != nil {
return nil, err
}
var data entities.ConfirmDisburseRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 20: RenderRefundOrder
func (s *LinkedMallService) RenderRefundOrder(req *entities.RenderRefundOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.RenderRefundOrder(req)
if err != nil {
return nil, err
}
var data entities.RenderRefundOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 21: CreateRefundOrder
func (s *LinkedMallService) CreateRefundOrder(req *entities.CreateRefundOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.CreateRefundOrder(req)
if err != nil {
return nil, err
}
var data entities.CreateRefundOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 22: CancelRefundOrder
func (s *LinkedMallService) CancelRefundOrder(req *entities.CancelRefundOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.CancelRefundOrder(req)
if err != nil {
return nil, err
}
var data entities.CancelRefundOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 23: GetRefundOrder
func (s *LinkedMallService) GetRefundOrder(req *entities.GetRefundOrderReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.GetRefundOrder(req)
if err != nil {
return nil, err
}
var data entities.GetRefundOrderRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 24: CreateGoodsShippingNotice
func (s *LinkedMallService) CreateGoodsShippingNotice(req *entities.CreateGoodsShippingNoticeReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.CreateGoodsShippingNotice(req)
if err != nil {
return nil, err
}
var data entities.CreateGoodsShippingNoticeRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// 接口 25: QueryChildDivisionCode
func (s *LinkedMallService) QueryChildDivisionCode(req *entities.QueryChildDivisionCodeReq) (*entities.APIResponse, error) {
commonResp, err := s.biz.QueryChildDivisionCode(req)
if err != nil {
return nil, err
}
var data entities.QueryChildDivisionCodeRespData
if commonResp.Success {
_ = s.parseData(commonResp, &data)
}
return s.buildAPIResponse(commonResp, &data), nil
}
// File: server_tb_LinkedMall/internal/middleware/middleware.go
package middleware
import (
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
)
// RequestID 为每个请求注入RequestID
func RequestID() fiber.Handler {
return func(c *fiber.Ctx) error {
rid := c.Get("X-Request-Id")
if rid == "" {
rid = uuid.New().String()
}
c.Set("X-Request-Id", rid)
c.Locals("requestId", rid)
return c.Next()
}
}
// StandardResponse 统一响应格式中间件
func StandardResponse() fiber.Handler {
return func(c *fiber.Ctx) error {
// 先执行handler
err := c.Next()
if err != nil {
// 处理handler返回的错误
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"Success": false,
"Code": "INTERNAL_ERROR",
"Message": err.Error(),
})
}
return nil
}
}
// CORS 跨域中间件
func CORS() fiber.Handler {
return func(c *fiber.Ctx) error {
c.Set("Access-Control-Allow-Origin", "*")
c.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Request-Id")
if c.Method() == "OPTIONS" {
return c.SendStatus(fiber.StatusNoContent)
}
return c.Next()
}
}
// File: server_tb_LinkedMall/internal/router/router.go
package router
import (
"github.com/gofiber/fiber/v2"
"server_tb_LinkedMall/internal/middleware"
"server_tb_LinkedMall/internal/service"
)
// SetupRouter 注册所有路由
func SetupRouter(app *fiber.App, svc *service.LinkedMallService) {
// 全局中间件
app.Use(middleware.RequestID())
app.Use(middleware.CORS())
// 健康检查
app.Get("/health", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})
})
// API v1 路由组
api := app.Group("/api/v1", middleware.StandardResponse())
// ============================================================
// 采购方店铺相关
// ============================================================
// 接口 1: ListPurchaserShops - 分页获取采购方店铺列表
api.Get("/purchaser-shops", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListPurchaserShops - 待实现"})
})
// 接口 2: GetPurchaserShop - 获取单个采购店铺详情
api.Get("/purchaser-shops/:shopId", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetPurchaserShop - 待实现"})
})
// ============================================================
// 选品池商品相关
// ============================================================
// 接口 3: ListSelectionProducts - 分页查询选品池商品列表
api.Get("/selection-products", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListSelectionProducts - 待实现"})
})
// 接口 4: GetSelectionProduct - 查询选品池商品详情
api.Get("/selection-products/:productId", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetSelectionProduct - 待实现"})
})
// 接口 5: GetSelectionProductSaleInfo - 查询选品池商品销售信息
api.Get("/selection-products/:productId/sale-info", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetSelectionProductSaleInfo - 待实现"})
})
// 接口 6: ListSelectionProductSaleInfos - 批量查询商品销售信息
api.Post("/selection-products:batch-sale-info", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListSelectionProductSaleInfos - 待实现"})
})
// 接口 7: ListSelectionSkuSaleInfos - 批量SKU销售信息
api.Post("/selection-skus:batch-sale-info", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListSelectionSkuSaleInfos - 待实现"})
})
// 接口 8: ListCategories - 查询类目列表
api.Get("/categories", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListCategories - 待实现"})
})
// 接口 9: SearchProducts - 搜索选品池商品
api.Post("/selection-products:search", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "SearchProducts - 待实现"})
})
// 接口 10: SelectionGroupAddProduct - 选品池商品入库
api.Post("/selection-group/products:add", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "SelectionGroupAddProduct - 待实现"})
})
// 接口 11: SelectionGroupRemoveProduct - 选品池商品出库
api.Post("/selection-group/products:remove", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "SelectionGroupRemoveProduct - 待实现"})
})
// ============================================================
// 采购单相关
// ============================================================
// 接口 12: RenderPurchaseOrder - 采购单渲染(下单预校验)
api.Post("/purchase-orders:render", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "RenderPurchaseOrder - 待实现"})
})
// 接口 13: SplitPurchaseOrder - 采购单渲染并拆单
api.Post("/purchase-orders:split-render", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "SplitPurchaseOrder - 待实现"})
})
// 接口 14: CreatePurchaseOrder - 创建采购单【异步】
api.Post("/purchase-orders", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "CreatePurchaseOrder - 待实现"})
})
// 接口 15: GetPurchaseOrderStatus - 获取采购单状态
api.Get("/purchase-orders/:purchaseOrderId/status", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetPurchaseOrderStatus - 待实现"})
})
// ============================================================
// 订单相关
// ============================================================
// 接口 16: GetOrder - 获取订单详情
api.Get("/orders/:orderId", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetOrder - 待实现"})
})
// 接口 17: QueryOrders - 查询订单列表
api.Get("/orders", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "QueryOrders - 待实现"})
})
// 接口 18: ListLogisticsOrders - 查询订单物流信息
api.Get("/orders/:orderId/logistics", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ListLogisticsOrders - 待实现"})
})
// 接口 19: ConfirmDisburse - 确认收货
api.Post("/orders/:orderId:confirm-disburse", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "ConfirmDisburse - 待实现"})
})
// ============================================================
// 售后相关
// ============================================================
// 接口 20: RenderRefundOrder - 售后渲染预校验
api.Post("/refund-orders:render", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "RenderRefundOrder - 待实现"})
})
// 接口 21: CreateRefundOrder - 创建售后单
api.Post("/refund-orders", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "CreateRefundOrder - 待实现"})
})
// 接口 22: CancelRefundOrder - 取消售后单
api.Post("/refund-orders/:refundOrderId:cancel", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "CancelRefundOrder - 待实现"})
})
// 接口 23: GetRefundOrder - 获取售后单详情
api.Get("/refund-orders/:refundOrderId", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "GetRefundOrder - 待实现"})
})
// 接口 24: CreateGoodsShippingNotice - 回填退货物流运单
api.Post("/refund-orders/:refundOrderId:fill-logistics", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "CreateGoodsShippingNotice - 待实现"})
})
// ============================================================
// 区域编码
// ============================================================
// 接口 25: QueryChildDivisionCode - 查询子区域编码
api.Get("/divisions:children", func(c *fiber.Ctx) error {
// TODO: 实现参数绑定和调用
return c.JSON(fiber.Map{"message": "QueryChildDivisionCode - 待实现"})
})
// ============================================================
// 回调通知(供LinkedMall回调)
// ============================================================
api.Post("/callback", func(c *fiber.Ctx) error {
// TODO: 实现回调处理逻辑
return c.JSON(fiber.Map{"success": true})
})
}
// File: server_tb_LinkedMall/cmd/server/main.go
package main
import (
"fmt"
"log"
"github.com/gofiber/fiber/v2"
"server_tb_LinkedMall/internal/config"
"server_tb_LinkedMall/internal/router"
"server_tb_LinkedMall/internal/service"
)
func main() {
// 加载配置
cfg := config.LoadConfig()
// 检查必要配置
if cfg.AccessKeyId == "" || cfg.AccessKeySecret == "" {
log.Fatal("环境变量 LINKEDMALL_AK 和 LINKEDMALL_SK 必须设置")
}
// 初始化服务
svc, err := service.NewLinkedMallService(cfg)
if err != nil {
log.Fatalf("初始化服务失败: %v", err)
}
// 创建Fiber应用
app := fiber.New(fiber.Config{
AppName: "LinkedMall Server",
ErrorHandler: func(c *fiber.Ctx, err error) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"Success": false,
"Code": "SERVER_ERROR",
"Message": err.Error(),
})
},
})
// 注册路由
router.SetupRouter(app, svc)
// 启动服务
addr := fmt.Sprintf(":%s", cfg.ServerPort)
log.Printf("启动服务,监听地址: %s", addr)
if err := app.Listen(addr); err != nil {
log.Fatalf("服务启动失败: %v", err)
}
}
// File: server_tb_LinkedMall/internal/test/example_test.go
package test
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"server_tb_LinkedMall/internal/config"
"server_tb_LinkedMall/internal/entities"
"server_tb_LinkedMall/internal/router"
"server_tb_LinkedMall/internal/service"
)
// setupTestApp 初始化测试应用
func setupTestApp(t *testing.T) (*fiber.App, *service.LinkedMallService) {
t.Helper()
cfg := &config.Config{
ServerPort: "8080",
AccessKeyId: "test-ak",
AccessKeySecret: "test-sk",
RegionId: "cn-zhangjiakou",
Endpoint: "linkedmall.cn-zhangjiakou.aliyuncs.com",
BasePath: "/opensaas-s2b/opensaas-s2b-biz-trade/v2",
DefaultPurchaserId: "test-purchaser-id",
}
svc, err := service.NewLinkedMallService(cfg)
if err != nil {
t.Skipf("跳过测试(无法初始化服务,可能需要有效AK/SK): %v", err)
}
app := fiber.New()
router.SetupRouter(app, svc)
return app, svc
}
// performRequest 执行测试HTTP请求
func performRequest(app *fiber.App, method, path string, body interface{}) *http.Response {
var reqBody []byte
if body != nil {
reqBody, _ = json.Marshal(body)
}
req := httptest.NewRequest(method, path, bytes.NewReader(reqBody))
req.Header.Set("Content-Type", "application/json")
resp, _ := app.Test(req, -1)
return resp
}
// TestHealthCheck 健康检查测试
func TestHealthCheck(t *testing.T) {
app, _ := setupTestApp(t)
resp