积分充值全流程落地:申请审核入账、凭证上传压缩转webp、管理员调账收权

- 新增积分充值申请与审核:商户提交充值申请(凭证图片必填,1元=100积分),
  管理员审核通过后事务内自动入账,幂等键防重复
- 新增通用图片上传组件 ImageUploader:canvas 压缩转 webp、预览、删除,
  后端按魔数校验图片格式并持久化到 data/uploads
- 管理员钱包调整改为按商户维度:移除商户侧调账接口,新增管理员
  平台商户积分调整与钱包流水查看
- 低余额 Webhook 告警配置持久化,充值入账/调账后自动检查推送
- 平台商户操作列移除进入/成员,积分充值页接入真实接口并修复金额单位换算
This commit is contained in:
yml2213
2026-08-04 13:03:29 +08:00
parent 54f05c15a4
commit 941e7ad79a
22 changed files with 1658 additions and 18 deletions
+12 -9
View File
@@ -17,14 +17,16 @@ type MerchantHandler struct {
fulfillmentSvc *service.FulfillmentService
callbackSvc *service.CallbackService
deliverySvc *service.DeliveryService
rechargeSvc *service.RechargeService
}
func NewMerchantHandler(merchantSvc *service.MerchantService, fulfillmentSvc *service.FulfillmentService, callbackSvc *service.CallbackService, deliverySvc *service.DeliveryService) *MerchantHandler {
func NewMerchantHandler(merchantSvc *service.MerchantService, fulfillmentSvc *service.FulfillmentService, callbackSvc *service.CallbackService, deliverySvc *service.DeliveryService, rechargeSvc *service.RechargeService) *MerchantHandler {
return &MerchantHandler{
merchantSvc: merchantSvc,
fulfillmentSvc: fulfillmentSvc,
callbackSvc: callbackSvc,
deliverySvc: deliverySvc,
rechargeSvc: rechargeSvc,
}
}
@@ -274,6 +276,7 @@ func (h *MerchantHandler) AdminAdjustWallet(c *gin.Context) {
response.BadRequest(c, err.Error())
return
}
h.rechargeSvc.CheckLowBalanceAndNotify(uint(id))
response.OK(c, wallet)
}
@@ -359,10 +362,10 @@ func (h *MerchantHandler) ListCallbacks(c *gin.Context) {
}
type callbackReq struct {
Name string `json:"name"`
URL string `json:"url" binding:"required"`
Events string `json:"events" binding:"required"`
Status string `json:"status"`
Name string `json:"name"`
URL string `json:"url" binding:"required"`
Events string `json:"events" binding:"required"`
Status string `json:"status"`
RotateSecret bool `json:"rotate_secret"`
}
@@ -373,10 +376,10 @@ func (h *MerchantHandler) CreateCallback(c *gin.Context) {
return
}
credential, err := h.callbackSvc.CreateSubscription(middleware.GetMerchantID(c), service.CreateCallbackInput{
Name: req.Name,
URL: req.URL,
Events: req.Events,
Status: req.Status,
Name: req.Name,
URL: req.URL,
Events: req.Events,
Status: req.Status,
RotateSecret: req.RotateSecret,
}, middleware.GetUserID(c))
if err != nil {