余额告警独立页面与多渠道通知:钉钉/飞书/企业微信/Bark,支持通知频率策略
- 告警设置拆分为独立页面,支持钉钉/飞书/企业微信/Bark/通用Webhook 多渠道 - 通知策略:低于阈值后按间隔重复提醒,达到最大次数停止,余额恢复自动重置 - 旧 webhook 配置自动迁移为通用渠道,渠道支持测试发送 - 优化告警话术:去商户ID展示、数字千分位格式化
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"affiliate_dash/internal/middleware"
|
||||
"affiliate_dash/internal/model"
|
||||
"affiliate_dash/internal/pkg/response"
|
||||
"affiliate_dash/internal/service"
|
||||
|
||||
@@ -113,9 +114,10 @@ func (h *RechargeHandler) GetAlertConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
type alertConfigReq struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
ThresholdPoints int64 `json:"threshold_points"`
|
||||
WebhookURL string `json:"webhook_url"`
|
||||
Enabled bool `json:"enabled"`
|
||||
ThresholdPoints int64 `json:"threshold_points"`
|
||||
NotifyIntervalMinutes int `json:"notify_interval_minutes"`
|
||||
MaxNotifications int `json:"max_notifications"`
|
||||
}
|
||||
|
||||
// SaveAlertConfig PUT /api/merchant/recharge/alert-config
|
||||
@@ -126,9 +128,10 @@ func (h *RechargeHandler) SaveAlertConfig(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
cfg, err := h.rechargeSvc.SaveAlertConfig(middleware.GetMerchantID(c), service.SaveAlertInput{
|
||||
Enabled: req.Enabled,
|
||||
ThresholdPoints: req.ThresholdPoints,
|
||||
WebhookURL: req.WebhookURL,
|
||||
Enabled: req.Enabled,
|
||||
ThresholdPoints: req.ThresholdPoints,
|
||||
NotifyIntervalMinutes: req.NotifyIntervalMinutes,
|
||||
MaxNotifications: req.MaxNotifications,
|
||||
})
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
@@ -137,6 +140,105 @@ func (h *RechargeHandler) SaveAlertConfig(c *gin.Context) {
|
||||
response.OK(c, cfg)
|
||||
}
|
||||
|
||||
// ListAlertChannels GET /api/merchant/alert-channels
|
||||
func (h *RechargeHandler) ListAlertChannels(c *gin.Context) {
|
||||
list, err := h.rechargeSvc.ListAlertChannels(middleware.GetMerchantID(c))
|
||||
if err != nil {
|
||||
response.ServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, list)
|
||||
}
|
||||
|
||||
type alertChannelReq struct {
|
||||
ChannelType string `json:"channel_type" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
WebhookURL string `json:"webhook_url"`
|
||||
Server string `json:"server"`
|
||||
Key string `json:"key"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (r alertChannelReq) toInput() service.AlertChannelInput {
|
||||
enabled := true
|
||||
if r.Enabled != nil {
|
||||
enabled = *r.Enabled
|
||||
}
|
||||
return service.AlertChannelInput{
|
||||
ChannelType: r.ChannelType,
|
||||
Name: r.Name,
|
||||
Enabled: enabled,
|
||||
Config: model.AlertChannelConfig{
|
||||
WebhookURL: r.WebhookURL,
|
||||
Server: r.Server,
|
||||
Key: r.Key,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreateAlertChannel POST /api/merchant/alert-channels
|
||||
func (h *RechargeHandler) CreateAlertChannel(c *gin.Context) {
|
||||
var req alertChannelReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误:channel_type 必填")
|
||||
return
|
||||
}
|
||||
channel, err := h.rechargeSvc.CreateAlertChannel(middleware.GetMerchantID(c), req.toInput())
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, channel)
|
||||
}
|
||||
|
||||
// UpdateAlertChannel PUT /api/merchant/alert-channels/:id
|
||||
func (h *RechargeHandler) UpdateAlertChannel(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if id == 0 {
|
||||
response.BadRequest(c, "渠道 ID 无效")
|
||||
return
|
||||
}
|
||||
var req alertChannelReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误:channel_type 必填")
|
||||
return
|
||||
}
|
||||
channel, err := h.rechargeSvc.UpdateAlertChannel(middleware.GetMerchantID(c), uint(id), req.toInput())
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, channel)
|
||||
}
|
||||
|
||||
// DeleteAlertChannel DELETE /api/merchant/alert-channels/:id
|
||||
func (h *RechargeHandler) DeleteAlertChannel(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if id == 0 {
|
||||
response.BadRequest(c, "渠道 ID 无效")
|
||||
return
|
||||
}
|
||||
if err := h.rechargeSvc.DeleteAlertChannel(middleware.GetMerchantID(c), uint(id)); err != nil {
|
||||
response.ServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, nil)
|
||||
}
|
||||
|
||||
// TestAlertChannel POST /api/merchant/alert-channels/:id/test
|
||||
func (h *RechargeHandler) TestAlertChannel(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if id == 0 {
|
||||
response.BadRequest(c, "渠道 ID 无效")
|
||||
return
|
||||
}
|
||||
if err := h.rechargeSvc.TestAlertChannel(middleware.GetMerchantID(c), uint(id)); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, nil)
|
||||
}
|
||||
|
||||
// Upload POST /api/upload 上传凭证图片(multipart 字段名 file)。
|
||||
func (h *RechargeHandler) Upload(c *gin.Context) {
|
||||
fileHeader, err := c.FormFile("file")
|
||||
|
||||
Reference in New Issue
Block a user