Files
junhong_cmp_fiber/internal/routes/personal.go
huang e78f5794b9 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 旧表改名
2026-03-19 13:26:54 +08:00

261 lines
9.4 KiB
Go

package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/bootstrap"
apphandler "github.com/break/junhong_cmp_fiber/internal/handler/app"
"github.com/break/junhong_cmp_fiber/internal/middleware"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/openapi"
)
// RegisterPersonalCustomerRoutes 注册个人客户路由
// 路由挂载在 /api/c/v1 下
func RegisterPersonalCustomerRoutes(router fiber.Router, doc *openapi.Generator, basePath string, handlers *bootstrap.Handlers, personalAuthMiddleware *middleware.PersonalAuthMiddleware) {
authBasePath := "/auth"
authPublicGroup := router.Group(authBasePath)
authProtectedGroup := router.Group(authBasePath)
authProtectedGroup.Use(personalAuthMiddleware.Authenticate())
Register(authPublicGroup, doc, basePath+authBasePath, "POST", "/verify-asset", handlers.ClientAuth.VerifyAsset, RouteSpec{
Summary: "资产验证",
Tags: []string{"个人客户 - 认证"},
Auth: false,
Input: &dto.VerifyAssetRequest{},
Output: &dto.VerifyAssetResponse{},
})
Register(authPublicGroup, doc, basePath+authBasePath, "POST", "/wechat-login", handlers.ClientAuth.WechatLogin, RouteSpec{
Summary: "公众号登录",
Tags: []string{"个人客户 - 认证"},
Auth: false,
Input: &dto.WechatLoginRequest{},
Output: &dto.WechatLoginResponse{},
})
Register(authPublicGroup, doc, basePath+authBasePath, "POST", "/miniapp-login", handlers.ClientAuth.MiniappLogin, RouteSpec{
Summary: "小程序登录",
Tags: []string{"个人客户 - 认证"},
Auth: false,
Input: &dto.MiniappLoginRequest{},
Output: &dto.WechatLoginResponse{},
})
Register(authPublicGroup, doc, basePath+authBasePath, "POST", "/send-code", handlers.ClientAuth.SendCode, RouteSpec{
Summary: "发送验证码",
Tags: []string{"个人客户 - 认证"},
Auth: false,
Input: &dto.ClientSendCodeRequest{},
Output: &dto.ClientSendCodeResponse{},
})
Register(authProtectedGroup, doc, basePath+authBasePath, "POST", "/bind-phone", handlers.ClientAuth.BindPhone, RouteSpec{
Summary: "绑定手机号",
Tags: []string{"个人客户 - 认证"},
Auth: true,
Input: &dto.BindPhoneRequest{},
Output: &dto.BindPhoneResponse{},
})
Register(authProtectedGroup, doc, basePath+authBasePath, "POST", "/change-phone", handlers.ClientAuth.ChangePhone, RouteSpec{
Summary: "更换手机号",
Tags: []string{"个人客户 - 认证"},
Auth: true,
Input: &dto.ChangePhoneRequest{},
Output: &dto.ChangePhoneResponse{},
})
Register(authProtectedGroup, doc, basePath+authBasePath, "POST", "/logout", handlers.ClientAuth.Logout, RouteSpec{
Summary: "退出登录",
Tags: []string{"个人客户 - 认证"},
Auth: true,
Input: nil,
Output: &dto.LogoutResponse{},
})
// 需要认证的路由
authGroup := router.Group("")
authGroup.Use(personalAuthMiddleware.Authenticate())
// 获取个人资料
Register(authGroup, doc, basePath, "GET", "/profile", handlers.PersonalCustomer.GetProfile, RouteSpec{
Summary: "获取个人资料",
Description: "获取当前登录客户的个人资料",
Tags: []string{"个人客户 - 账户"},
Auth: true,
Input: nil,
Output: &apphandler.PersonalCustomerDTO{},
})
// 更新个人资料
Register(authGroup, doc, basePath, "PUT", "/profile", handlers.PersonalCustomer.UpdateProfile, RouteSpec{
Summary: "更新个人资料",
Description: "更新当前登录客户的昵称和头像",
Tags: []string{"个人客户 - 账户"},
Auth: true,
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{},
})
}