feat: 实现客户端换货系统(client-exchange-system)
新增完整换货生命周期管理:后台发起 → 客户端填收货信息 → 后台发货 → 确认完成(含可选全量迁移) → 旧资产转新再销售 后台接口(7个): - POST /api/admin/exchanges(发起换货) - GET /api/admin/exchanges(换货列表) - GET /api/admin/exchanges/:id(换货详情) - POST /api/admin/exchanges/:id/ship(发货) - POST /api/admin/exchanges/:id/complete(确认完成+可选迁移) - POST /api/admin/exchanges/:id/cancel(取消) - POST /api/admin/exchanges/:id/renew(旧资产转新) 客户端接口(2个): - GET /api/c/v1/exchange/pending(查询换货通知) - POST /api/c/v1/exchange/:id/shipping-info(填写收货信息) 核心能力: - ExchangeOrder 模型与状态机(1待填写→2待发货→3已发货→4已完成,1/2可取消→5) - 全量迁移事务(11张表:钱包、套餐、标签、客户绑定等) - 旧资产转新(generation+1、状态重置、新钱包、历史隔离) - 旧 CardReplacementRecord 表改名为 legacy,is_replaced 过滤改为查新表 - 数据库迁移:000085 新建 tb_exchange_order,000086 旧表改名
This commit is contained in:
@@ -92,6 +92,9 @@ func RegisterAdminRoutes(router fiber.Router, handlers *bootstrap.Handlers, midd
|
||||
if handlers.AdminOrder != nil {
|
||||
registerAdminOrderRoutes(authGroup, handlers.AdminOrder, doc, basePath)
|
||||
}
|
||||
if handlers.AdminExchange != nil {
|
||||
registerAdminExchangeRoutes(authGroup, handlers.AdminExchange, doc, basePath)
|
||||
}
|
||||
if handlers.PollingConfig != nil {
|
||||
registerPollingConfigRoutes(authGroup, handlers.PollingConfig, doc, basePath)
|
||||
}
|
||||
|
||||
66
internal/routes/exchange.go
Normal file
66
internal/routes/exchange.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func registerAdminExchangeRoutes(router fiber.Router, handler *admin.ExchangeHandler, doc *openapi.Generator, basePath string) {
|
||||
Register(router, doc, basePath, "POST", "/exchanges", handler.Create, RouteSpec{
|
||||
Summary: "创建换货单",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.CreateExchangeRequest),
|
||||
Output: new(dto.ExchangeOrderResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "GET", "/exchanges", handler.List, RouteSpec{
|
||||
Summary: "获取换货单列表",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeListRequest),
|
||||
Output: new(dto.ExchangeListResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "GET", "/exchanges/:id", handler.Get, RouteSpec{
|
||||
Summary: "获取换货单详情",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeIDRequest),
|
||||
Output: new(dto.ExchangeOrderResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "POST", "/exchanges/:id/ship", handler.Ship, RouteSpec{
|
||||
Summary: "换货发货",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeShipParams),
|
||||
Output: new(dto.ExchangeOrderResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "POST", "/exchanges/:id/complete", handler.Complete, RouteSpec{
|
||||
Summary: "确认换货完成",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeIDRequest),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "POST", "/exchanges/:id/cancel", handler.Cancel, RouteSpec{
|
||||
Summary: "取消换货",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeCancelParams),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(router, doc, basePath, "POST", "/exchanges/:id/renew", handler.Renew, RouteSpec{
|
||||
Summary: "旧资产转新",
|
||||
Tags: []string{"换货管理"},
|
||||
Input: new(dto.ExchangeIDRequest),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
}
|
||||
@@ -97,4 +97,164 @@ func RegisterPersonalCustomerRoutes(router fiber.Router, doc *openapi.Generator,
|
||||
Input: &apphandler.UpdateProfileRequest{},
|
||||
Output: nil,
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/asset/info", handlers.ClientAsset.GetAssetInfo, RouteSpec{
|
||||
Summary: "资产信息",
|
||||
Tags: []string{"个人客户 - 资产"},
|
||||
Auth: true,
|
||||
Input: &dto.AssetInfoRequest{},
|
||||
Output: &dto.AssetInfoResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/asset/packages", handlers.ClientAsset.GetAvailablePackages, RouteSpec{
|
||||
Summary: "资产可购套餐列表",
|
||||
Tags: []string{"个人客户 - 资产"},
|
||||
Auth: true,
|
||||
Input: &dto.AssetPackageListRequest{},
|
||||
Output: &dto.AssetPackageListResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/asset/package-history", handlers.ClientAsset.GetPackageHistory, RouteSpec{
|
||||
Summary: "资产套餐历史",
|
||||
Tags: []string{"个人客户 - 资产"},
|
||||
Auth: true,
|
||||
Input: &dto.AssetPackageHistoryRequest{},
|
||||
Output: &dto.AssetPackageHistoryResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/asset/refresh", handlers.ClientAsset.RefreshAsset, RouteSpec{
|
||||
Summary: "资产刷新",
|
||||
Tags: []string{"个人客户 - 资产"},
|
||||
Auth: true,
|
||||
Input: &dto.AssetRefreshRequest{},
|
||||
Output: &dto.AssetRefreshResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/wallet/detail", handlers.ClientWallet.GetWalletDetail, RouteSpec{
|
||||
Summary: "钱包详情",
|
||||
Tags: []string{"个人客户 - 钱包"},
|
||||
Auth: true,
|
||||
Input: &dto.WalletDetailRequest{},
|
||||
Output: &dto.WalletDetailResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/wallet/transactions", handlers.ClientWallet.GetWalletTransactions, RouteSpec{
|
||||
Summary: "钱包流水列表",
|
||||
Tags: []string{"个人客户 - 钱包"},
|
||||
Auth: true,
|
||||
Input: &dto.WalletTransactionListRequest{},
|
||||
Output: &dto.WalletTransactionListResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/wallet/recharge-check", handlers.ClientWallet.GetRechargeCheck, RouteSpec{
|
||||
Summary: "充值前校验",
|
||||
Tags: []string{"个人客户 - 钱包"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientRechargeCheckRequest{},
|
||||
Output: &dto.ClientRechargeCheckResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/wallet/recharge", handlers.ClientWallet.CreateRecharge, RouteSpec{
|
||||
Summary: "创建充值订单",
|
||||
Tags: []string{"个人客户 - 钱包"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientCreateRechargeRequest{},
|
||||
Output: &dto.ClientRechargeResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/wallet/recharges", handlers.ClientWallet.GetRechargeList, RouteSpec{
|
||||
Summary: "充值记录列表",
|
||||
Tags: []string{"个人客户 - 钱包"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientRechargeListRequest{},
|
||||
Output: &dto.ClientRechargeListResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/orders/create", handlers.ClientOrder.CreateOrder, RouteSpec{
|
||||
Summary: "创建订单",
|
||||
Tags: []string{"个人客户 - 订单"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientCreateOrderRequest{},
|
||||
Output: &dto.ClientCreateOrderResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/orders", handlers.ClientOrder.ListOrders, RouteSpec{
|
||||
Summary: "订单列表",
|
||||
Tags: []string{"个人客户 - 订单"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientOrderListRequest{},
|
||||
Output: &dto.ClientOrderListResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/orders/:id", handlers.ClientOrder.GetOrderDetail, RouteSpec{
|
||||
Summary: "订单详情",
|
||||
Tags: []string{"个人客户 - 订单"},
|
||||
Auth: true,
|
||||
Input: &dto.IDReq{},
|
||||
Output: &dto.ClientOrderDetailResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/exchange/pending", handlers.ClientExchange.GetPending, RouteSpec{
|
||||
Summary: "查询待处理换货单",
|
||||
Tags: []string{"个人客户 - 换货"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientExchangePendingRequest{},
|
||||
Output: &dto.ClientExchangePendingResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/exchange/:id/shipping-info", handlers.ClientExchange.SubmitShippingInfo, RouteSpec{
|
||||
Summary: "提交收货信息",
|
||||
Tags: []string{"个人客户 - 换货"},
|
||||
Auth: true,
|
||||
Input: &dto.ClientShippingInfoParams{},
|
||||
Output: nil,
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/realname/link", handlers.ClientRealname.GetRealnameLink, RouteSpec{
|
||||
Summary: "获取实名认证链接",
|
||||
Tags: []string{"个人客户 - 实名"},
|
||||
Auth: true,
|
||||
Input: &dto.RealnimeLinkRequest{},
|
||||
Output: &dto.RealnimeLinkResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "GET", "/device/cards", handlers.ClientDevice.GetDeviceCards, RouteSpec{
|
||||
Summary: "获取设备卡列表",
|
||||
Tags: []string{"个人客户 - 设备"},
|
||||
Auth: true,
|
||||
Input: &dto.DeviceCardListRequest{},
|
||||
Output: &dto.DeviceCardListResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/device/reboot", handlers.ClientDevice.RebootDevice, RouteSpec{
|
||||
Summary: "设备重启",
|
||||
Tags: []string{"个人客户 - 设备"},
|
||||
Auth: true,
|
||||
Input: &dto.DeviceRebootRequest{},
|
||||
Output: &dto.DeviceOperationResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/device/factory-reset", handlers.ClientDevice.FactoryResetDevice, RouteSpec{
|
||||
Summary: "恢复出厂设置",
|
||||
Tags: []string{"个人客户 - 设备"},
|
||||
Auth: true,
|
||||
Input: &dto.DeviceFactoryResetRequest{},
|
||||
Output: &dto.DeviceOperationResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/device/wifi", handlers.ClientDevice.SetWiFi, RouteSpec{
|
||||
Summary: "设备WiFi配置",
|
||||
Tags: []string{"个人客户 - 设备"},
|
||||
Auth: true,
|
||||
Input: &dto.DeviceWifiRequest{},
|
||||
Output: &dto.DeviceOperationResponse{},
|
||||
})
|
||||
|
||||
Register(authGroup, doc, basePath, "POST", "/device/switch-card", handlers.ClientDevice.SwitchCard, RouteSpec{
|
||||
Summary: "设备切卡",
|
||||
Tags: []string{"个人客户 - 设备"},
|
||||
Auth: true,
|
||||
Input: &dto.DeviceSwitchCardRequest{},
|
||||
Output: &dto.DeviceSwitchCardResponse{},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user