1、增加业务消息触发流程;

This commit is contained in:
chenlin 2025-07-04 18:16:20 +08:00
parent ac708767d7
commit ed91928ae3
3 changed files with 256 additions and 0 deletions

View File

@ -519,6 +519,12 @@ func PushWXPayNotice(c *gin.Context) {
fundRecord.FundType = model.FundTypeExpressFee fundRecord.FundType = model.FundTypeExpressFee
fundRecord.Remark = "借卡邮费" fundRecord.Remark = "借卡邮费"
// 触发消息
model.TriggerBizEvent(model.BizTypeOnRentCard, model.EventOnDeliver, map[string]interface{}{
"order_id": order.ID,
"uid": order.Uid,
"createdAt": order.CreatedAt,
}, uint32(order.StoreId))
} }
if notifyInfo.Attach == wxpay.WxPayMember { if notifyInfo.Attach == wxpay.WxPayMember {
@ -1045,6 +1051,13 @@ func PushWXPayNotice(c *gin.Context) {
if err != nil { if err != nil {
logger.Error("deliver task sub add err:", err) logger.Error("deliver task sub add err:", err)
} }
// 触发消息
model.TriggerBizEvent(model.BizTypeOnBuyGoods, model.EventOnDeliver, map[string]interface{}{
"order_id": goodsOrder.OrderId,
"uid": goodsOrder.Uid,
"goods_name": goods.Name,
})
} }
fundRecord.Uid = uint32(goodsOrder.Uid) fundRecord.Uid = uint32(goodsOrder.Uid)
@ -2053,6 +2066,12 @@ func HmPushWXPayNotice(c *gin.Context) {
fundRecord.FundType = model.FundTypeExpressFee fundRecord.FundType = model.FundTypeExpressFee
fundRecord.Remark = "借卡邮费" fundRecord.Remark = "借卡邮费"
// 触发消息
model.TriggerBizEvent(model.BizTypeOnRentCard, model.EventOnDeliver, map[string]interface{}{
"order_id": order.ID,
"uid": order.Uid,
"createdAt": order.CreatedAt,
}, uint32(order.StoreId))
} }
if record.Attach == wxpay.WxPayMember { if record.Attach == wxpay.WxPayMember {
@ -2573,6 +2592,13 @@ func HmPushWXPayNotice(c *gin.Context) {
if err != nil { if err != nil {
logger.Error("deliver task sub add err:", err) logger.Error("deliver task sub add err:", err)
} }
// 触发消息
model.TriggerBizEvent(model.BizTypeOnBuyGoods, model.EventOnDeliver, map[string]interface{}{
"order_id": goodsOrder.OrderId,
"uid": goodsOrder.Uid,
"goods_name": goods.Name,
})
} }
fundRecord.Uid = uint32(goodsOrder.Uid) fundRecord.Uid = uint32(goodsOrder.Uid)

View File

@ -433,6 +433,14 @@ func RentCardOrderCreate(c *gin.Context) {
} }
go model.ShoppingCartCreateOrder(uc.Uid, req.GameCardList) go model.ShoppingCartCreateOrder(uc.Uid, req.GameCardList)
// 触发消息
model.TriggerBizEvent(model.BizTypeOnRentCard, model.EventOnDeliver, map[string]interface{}{
"order_id": order.ID,
"uid": order.Uid,
"createdAt": order.CreatedAt,
}, uint32(order.StoreId))
RespOK(c, ret) RespOK(c, ret)
return return
} }

222
model/message.go Normal file
View File

@ -0,0 +1,222 @@
package model
import (
"bytes"
"encoding/json"
"fmt"
"text/template"
"time"
)
const (
AnnouncementMessageType = 1 // 公告消息
BusinessMessageType = 2 // 业务消息
TargetTypeByAll = 1 // 接收对象类型1=全员
TargetTypeByRole = 2 // 接收对象类型2=角色
TargetTypeByUser = 3 // 接收对象类型3=用户
MessageStatusOnDraft = 0 // 草稿
MessageStatusOnStart = 1 // 启用
MessageStatusOnDisable = 2 // 禁用
MessageStatusOnExpire = 3 // 已过期
MessageStart = 1 // 启用
MessageStop = 2 // 禁用
BizTypeOnAllot = "stock_transfer" // 库存调拨
BizTypeOnRentCard = "rent_card" // 租赁卡带
BizTypeOnBuyGoods = "buy_goods" // 购买商品(线上小程序)
EventOnAllot = "wait_receive" // 待收货
EventOnDeliver = "on_deliver" // 待发货
)
// SystemMessageConfig 消息配置主表(公告 + 业务统一)
// gen:qs
//
//go:generate goqueryset -in message.go
type SystemMessageConfig struct {
Model
MessageType uint8 `json:"message_type"` // 消息类型1=公告2=业务
Title string `json:"title"` // 消息标题
ContentTemplate string `json:"content_template"` // 消息模板内容,支持{{变量}}
Level uint8 `json:"level"` // 消息等级1=普通2=重要3=紧急
DisplayMode uint8 `json:"display_mode"` // 展示方式1=弹窗2=滚动3=弹窗+滚动
StartTime *time.Time `json:"start_time,omitempty"` // 公告生效时间
EndTime *time.Time `json:"end_time,omitempty"` // 公告失效时间
BizType string `json:"biz_type,omitempty"` // 业务类型
Event string `json:"event,omitempty"` // 事件类型
Status uint8 `json:"status"` // 状态0=草稿1=启用2=禁用3=已过期
}
// SystemMessageTarget 接收对象配置表(支持角色/部门/用户/全员)
// gen:qs
type SystemMessageTarget struct {
Model
MessageConfigID uint `json:"message_config_id"` // 对应消息配置 ID
TargetType uint8 `json:"target_type"` // 接收对象类型1=全员2=角色3=用户
TargetID int64 `json:"target_id,omitempty"` // 对象ID角色ID/用户ID
}
// SystemUserMessage 用户收到的消息记录表(实际发送记录)
// gen:qs
type SystemUserMessage struct {
Model
UserID int64 `json:"user_id"` // 接收用户ID
MessageConfigID uint `json:"message_config_id"` // 对应消息配置ID可为空被删时保留记录
MessageType uint8 `json:"message_type"` // 消息类型1=公告2=业务
Title string `json:"title"` // 消息标题快照
Content string `json:"content"` // 渲染后内容
IsRead bool `json:"is_read"` // 是否阅读
ReadTime *time.Time `json:"read_time,omitempty"` // 阅读时间
IsVisible bool `json:"is_visible"` // 是否展示给用户
}
// TriggerBizEvent 业务消息-触发消息模版
func TriggerBizEvent(bizType, event string, inputVars map[string]interface{}, optionalReceivers ...uint32) error {
fmt.Println("TriggerBizEvent-start")
// 1. 查找启用的消息配置
var cfg SystemMessageConfig
err := DB.Table("system_message_config").Where("message_type = ? AND biz_type = ? AND event = ? AND status = 1",
BusinessMessageType, bizType, event).Find(&cfg).Error
if err != nil {
fmt.Println("query system_message_config err:", err)
return nil // 无需发送
}
// 2. 渲染模板内容
content, err := RenderTemplate(cfg.ContentTemplate, inputVars)
if err != nil {
fmt.Println("模板渲染失败:", err)
return fmt.Errorf("模板渲染失败: %w", err)
}
fmt.Println("content is:", content)
// 查找门店ID
var storeId uint32
if len(optionalReceivers) > 0 {
if event == EventOnAllot || event == EventOnDeliver { // 库存调拨-待收货消息、租赁订单-待发货消息
storeId = optionalReceivers[0]
}
} else {
fmt.Println("没有传入 optionalReceivers使用默认配置")
}
// 3. 查找接收用户
receiverIDs, err := GetTargetUserIds(cfg.ID, storeId)
if err != nil {
fmt.Println("获取接收人失败:", err)
return fmt.Errorf("获取接收人失败: %w", err)
}
fmt.Println("receiverIDs is:", receiverIDs)
// 4. 写入 user_message 表
for _, uid := range receiverIDs {
msg := SystemUserMessage{
UserID: uid,
MessageConfigID: uint(cfg.ID),
MessageType: BusinessMessageType,
Title: cfg.Title,
Content: content,
IsRead: false,
IsVisible: true,
}
err = DB.Create(&msg).Error
if err != nil {
fmt.Println("插入消息失败:", err)
return err
}
}
fmt.Println("TriggerBizEvent-end")
return nil
}
// GetTargetUserIds 获取接收用户函数模板(支持角色)
func GetTargetUserIds(configID uint32, storeId uint32) ([]int64, error) {
fmt.Println("******enter GetTargetUserIds******")
fmt.Println("storeId is :", storeId)
// 1.查询角色绑定
var targets []SystemMessageTarget
err := DB.Where("message_config_id = ? AND target_type = ?", configID, TargetTypeByRole).
Find(&targets).Error
if err != nil {
return nil, err
}
// 2.查询该模版配置的所有角色
var roleIDs []int
for _, t := range targets {
roleIDs = append(roleIDs, int(t.TargetID))
}
// 3.查询该角色下的用户(包含字段 uid, store_data
var users []SysUser
err = DB.Debug().Table("sys_user").
Where("role_id IN (?)", roleIDs).
Find(&users).Error
if err != nil {
return nil, err
}
// 如果 storeId == 0直接返回所有 uid
if storeId == 0 {
var allUserIDs []int64
for _, user := range users {
allUserIDs = append(allUserIDs, int64(user.UserId))
}
return allUserIDs, nil
}
// 4.筛选出门店有效用户
now := time.Now()
var validUserIDs []int64
for _, user := range users {
var storeList []StoreInfo
if err := json.Unmarshal([]byte(user.StoreData), &storeList); err != nil {
continue
}
for _, store := range storeList {
// 解析时间
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
continue
}
// 包含当天有效时间
expireTime = expireTime.Add(24*time.Hour - time.Second)
if store.StoreID == uint64(storeId) && expireTime.After(now) {
fmt.Println("UserId is:", user.UserId)
validUserIDs = append(validUserIDs, int64(user.UserId))
break
}
}
}
fmt.Println("******leave GetTargetUserIds******")
return validUserIDs, nil
}
// RenderTemplate 渲染模版内容
func RenderTemplate(templateStr string, data map[string]interface{}) (string, error) {
// 创建模板实例
tmpl, err := template.New("msg").Option("missingkey=zero").Parse(templateStr)
if err != nil {
return "", err
}
// 渲染
var buf bytes.Buffer
err = tmpl.Execute(&buf, data)
if err != nil {
return "", err
}
return buf.String(), nil
}