564 lines
16 KiB
Go
564 lines
16 KiB
Go
package message
|
||
|
||
import (
|
||
"encoding/json"
|
||
"github.com/gin-gonic/gin"
|
||
"go-admin/app/admin/models"
|
||
orm "go-admin/common/global"
|
||
"go-admin/logger"
|
||
"go-admin/tools/app"
|
||
"net/http"
|
||
"time"
|
||
)
|
||
|
||
// BusMessageCreate 业务消息-新增
|
||
// @Summary 业务消息-新增
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Produce json
|
||
// @Accept json
|
||
// @Param request body models.BusMessageCreateReq true "新增业务消息模型"
|
||
// @Success 200 {object} models.BusMessageCreateResp
|
||
// @Router /api/v1/bus_message/create [post]
|
||
func BusMessageCreate(c *gin.Context) {
|
||
var req models.BusMessageCreateReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, err, "参数绑定失败")
|
||
return
|
||
}
|
||
|
||
// 校验业务类型、事件类型、模板变量
|
||
if err := models.ValidateBizEventAndTemplate(req.BizType, req.Event, req.ContentTemplate); err != nil {
|
||
app.Error(c, http.StatusBadRequest, err, "模板校验失败")
|
||
return
|
||
}
|
||
|
||
// 创建业务消息配置
|
||
msg := models.SystemMessageConfig{
|
||
MessageType: models.BusinessMessageType, // 业务消息
|
||
Title: req.Title,
|
||
ContentTemplate: req.ContentTemplate,
|
||
BizType: req.BizType,
|
||
Event: req.Event,
|
||
Status: req.Status,
|
||
}
|
||
if err := orm.Eloquent.Create(&msg).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, err, "创建业务消息失败")
|
||
return
|
||
}
|
||
|
||
// 创建接收对象配置(target_type = 2)
|
||
for _, roleID := range req.RoleID {
|
||
target := models.SystemMessageTarget{
|
||
MessageConfigID: uint(msg.ID),
|
||
TargetType: models.TargetTypeByRole, // 角色
|
||
TargetID: roleID,
|
||
}
|
||
if err := orm.Eloquent.Create(&target).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, err, "接收对象配置失败")
|
||
return
|
||
}
|
||
}
|
||
|
||
app.OK(c, models.BusMessageCreateResp{ID: uint(msg.ID)}, "创建成功")
|
||
}
|
||
|
||
// BusMessageList 业务消息-列表
|
||
// @Summary 业务消息-列表
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BusMessageListReq true "查询条件"
|
||
// @Success 200 {object} models.BusMessageListResp
|
||
// @Router /api/v1/bus_message/list [post]
|
||
func BusMessageList(c *gin.Context) {
|
||
var req models.BusMessageListReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
// 基础查询:业务消息
|
||
db := orm.Eloquent.Table("system_message_config").
|
||
Where("message_type = ?", models.BusinessMessageType)
|
||
|
||
if req.BizType != "" {
|
||
db = db.Where("biz_type = ?", req.BizType)
|
||
}
|
||
if req.Event != "" {
|
||
db = db.Where("event = ?", req.Event)
|
||
}
|
||
if req.Status != 0 {
|
||
db = db.Where("status = ?", req.Status)
|
||
}
|
||
|
||
// 角色过滤(JOIN subquery)
|
||
if len(req.RoleID) > 0 {
|
||
subQuery := orm.Eloquent.Table("system_message_target").
|
||
Select("message_config_id").
|
||
Where("target_type = ?", models.TargetTypeByRole).
|
||
Where("target_id IN (?)", req.RoleID)
|
||
db = db.Where("id IN (?)", subQuery)
|
||
}
|
||
|
||
var total int64
|
||
if err := db.Count(&total).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "统计失败: "+err.Error())
|
||
return
|
||
}
|
||
|
||
var list []models.SystemMessageConfig
|
||
if err := db.
|
||
Order("created_at DESC").
|
||
Offset((req.Page - 1) * req.PageSize).
|
||
Limit(req.PageSize).
|
||
Find(&list).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "查询失败: "+err.Error())
|
||
return
|
||
}
|
||
|
||
//查询全部启用的事件注册表
|
||
var eventRegistryList []models.SystemEventRegistry
|
||
eventRegistryMap := make(map[string]models.SystemEventRegistry)
|
||
|
||
if err := orm.Eloquent.
|
||
Where("is_enabled = ?", true).
|
||
Find(&eventRegistryList).Error; err == nil {
|
||
for _, ev := range eventRegistryList {
|
||
key := ev.BizType + "#" + ev.Event
|
||
eventRegistryMap[key] = ev
|
||
}
|
||
}
|
||
|
||
var items []models.BusMessageItem
|
||
for _, cfg := range list {
|
||
key := cfg.BizType + "#" + cfg.Event
|
||
reg := eventRegistryMap[key]
|
||
|
||
item := models.BusMessageItem{
|
||
ID: cfg.ID,
|
||
CreatedAt: cfg.CreatedAt,
|
||
UpdatedAt: cfg.UpdatedAt,
|
||
Title: cfg.Title,
|
||
ContentTemplate: cfg.ContentTemplate,
|
||
BizType: cfg.BizType,
|
||
BizName: reg.BizName,
|
||
Event: cfg.Event,
|
||
EventName: reg.EventName,
|
||
Status: cfg.Status,
|
||
}
|
||
|
||
// 查询该消息绑定的所有角色
|
||
var targets []models.SystemMessageTarget
|
||
if err := orm.Eloquent.Where("message_config_id = ? AND target_type = ?", cfg.ID,
|
||
models.TargetTypeByRole).Find(&targets).Error; err == nil {
|
||
for _, t := range targets {
|
||
item.RoleID = append(item.RoleID, t.TargetID)
|
||
}
|
||
}
|
||
|
||
items = append(items, item)
|
||
}
|
||
|
||
resp := models.BusMessageListResp{
|
||
List: items,
|
||
Total: total,
|
||
Page: req.Page,
|
||
PageSize: req.PageSize,
|
||
}
|
||
app.OK(c, resp, "查询成功")
|
||
}
|
||
|
||
// BusMessageSetStatus 业务消息-设置状态(启用/禁用)
|
||
// @Summary 业务消息-设置状态(启用/禁用)
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BusMessageSetStatusReq true "状态更新请求"
|
||
// @Success 200 {object} app.Response
|
||
// @Router /api/v1/bus_message/set_status [post]
|
||
func BusMessageSetStatus(c *gin.Context) {
|
||
var req models.BusMessageSetStatusReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
var config models.SystemMessageConfig
|
||
if err := orm.Eloquent.Where("id = ? AND message_type = ?", req.ID, models.BusinessMessageType).
|
||
First(&config).Error; err != nil {
|
||
app.Error(c, http.StatusNotFound, nil, "业务消息不存在")
|
||
return
|
||
}
|
||
|
||
// 校验状态切换合法性
|
||
switch req.Status {
|
||
case 1: // 启用
|
||
if config.Status != models.MessageStatusOnDisable {
|
||
app.Error(c, http.StatusBadRequest, nil, "只有禁用状态才能启用")
|
||
return
|
||
}
|
||
case 2: // 禁用
|
||
if config.Status != models.MessageStatusOnStart {
|
||
app.Error(c, http.StatusBadRequest, nil, "只有启用状态才能禁用")
|
||
return
|
||
}
|
||
default:
|
||
app.Error(c, http.StatusBadRequest, nil, "不支持的目标状态")
|
||
return
|
||
}
|
||
|
||
// 状态更新
|
||
if err := orm.Eloquent.Model(&config).Update("status", req.Status).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "状态更新失败")
|
||
return
|
||
}
|
||
|
||
app.OK(c, nil, "状态更新成功")
|
||
}
|
||
|
||
// BusMessageDelete 业务消息-删除(禁用状态可删)
|
||
// @Summary 业务消息-删除(禁用状态可删)
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BusMessageDeleteReq true "删除业务消息"
|
||
// @Success 200 {object} app.Response
|
||
// @Router /api/v1/bus_message/delete [post]
|
||
func BusMessageDelete(c *gin.Context) {
|
||
var req models.BusMessageDeleteReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
var config models.SystemMessageConfig
|
||
if err := orm.Eloquent.Where("id = ? AND message_type = ?", req.ID, models.BusinessMessageType).
|
||
First(&config).Error; err != nil {
|
||
app.Error(c, http.StatusNotFound, nil, "业务消息不存在")
|
||
return
|
||
}
|
||
|
||
if config.Status != models.MessageStatusOnDisable {
|
||
app.Error(c, http.StatusBadRequest, nil, "仅禁用状态可删除")
|
||
return
|
||
}
|
||
|
||
begin := orm.Eloquent.Begin()
|
||
// 删除主配置(软删除)
|
||
if err := begin.Delete(&config).Error; err != nil {
|
||
begin.Rollback()
|
||
app.Error(c, http.StatusInternalServerError, nil, "删除公告失败")
|
||
return
|
||
}
|
||
|
||
// 删除接收对象配置
|
||
if err := begin.Where("message_config_id = ?", config.ID).
|
||
Delete(&models.SystemMessageTarget{}).Error; err != nil {
|
||
begin.Rollback()
|
||
app.Error(c, http.StatusInternalServerError, nil, "删除公告失败")
|
||
return
|
||
}
|
||
|
||
err := begin.Commit().Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("BusMessageDelete commit err:", logger.Field("err", err))
|
||
app.Error(c, http.StatusInternalServerError, nil, "删除公告失败")
|
||
return
|
||
}
|
||
|
||
app.OK(c, nil, "删除成功")
|
||
}
|
||
|
||
// BusMessageEdit 业务消息-编辑
|
||
// @Summary 业务消息-编辑
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BusMessageEditReq true "编辑业务消息"
|
||
// @Success 200 {object} app.Response
|
||
// @Router /api/v1/bus_message/edit [post]
|
||
func BusMessageEdit(c *gin.Context) {
|
||
var req models.BusMessageEditReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
if req.ID == 0 {
|
||
app.Error(c, http.StatusBadRequest, nil, "缺少消息ID")
|
||
return
|
||
}
|
||
|
||
// 校验事件与模板字段是否合法
|
||
if err := models.ValidateBizEventAndTemplate(req.BizType, req.Event, req.ContentTemplate); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "模板校验失败: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 更新主记录
|
||
update := map[string]interface{}{
|
||
"title": req.Title,
|
||
"biz_type": req.BizType,
|
||
"event": req.Event,
|
||
"content_template": req.ContentTemplate,
|
||
"status": req.Status,
|
||
"updated_at": time.Now(),
|
||
}
|
||
if err := orm.Eloquent.Model(&models.SystemMessageConfig{}).
|
||
Where("id = ? AND message_type = ?", req.ID, models.BusinessMessageType).
|
||
Updates(update).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "更新失败: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 删除旧的接收对象记录
|
||
_ = orm.Eloquent.Where("message_config_id = ?", req.ID).
|
||
Delete(&models.SystemMessageTarget{})
|
||
|
||
// 重建角色接收对象(target_type = 2)
|
||
for _, roleID := range req.RoleID {
|
||
target := models.SystemMessageTarget{
|
||
MessageConfigID: uint(req.ID),
|
||
TargetType: models.TargetTypeByRole, // 角色
|
||
TargetID: roleID,
|
||
}
|
||
_ = orm.Eloquent.Create(&target).Error
|
||
}
|
||
|
||
app.OK(c, nil, "编辑成功")
|
||
}
|
||
|
||
// BusMessageDetail 业务消息-详情
|
||
// @Summary 业务消息-详情
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BusMessageDetailReq true "业务消息ID"
|
||
// @Success 200 {object} models.BusMessageItem
|
||
// @Router /api/v1/bus_message/detail [post]
|
||
func BusMessageDetail(c *gin.Context) {
|
||
var req models.BusMessageDetailReq
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.ID == 0 {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误:缺少或非法ID")
|
||
return
|
||
}
|
||
|
||
// 查询主表
|
||
var cfg models.SystemMessageConfig
|
||
if err := orm.Eloquent.
|
||
Where("id = ? AND message_type = ?", req.ID, models.BusinessMessageType).
|
||
First(&cfg).Error; err != nil {
|
||
app.Error(c, http.StatusNotFound, nil, "未找到业务消息")
|
||
return
|
||
}
|
||
|
||
// 查询事件注册表,补充 BizName、EventName
|
||
var reg models.SystemEventRegistry
|
||
if err := orm.Eloquent.
|
||
Where("biz_type = ? AND event = ? AND is_enabled = ?", cfg.BizType, cfg.Event, true).
|
||
First(®).Error; err != nil {
|
||
// 可选:未找到事件名称也允许正常返回,只是字段为空
|
||
}
|
||
|
||
// 构建响应
|
||
item := models.BusMessageItem{
|
||
ID: cfg.ID,
|
||
CreatedAt: cfg.CreatedAt,
|
||
UpdatedAt: cfg.UpdatedAt,
|
||
Title: cfg.Title,
|
||
ContentTemplate: cfg.ContentTemplate,
|
||
BizType: cfg.BizType,
|
||
BizName: reg.BizName,
|
||
Event: cfg.Event,
|
||
EventName: reg.EventName,
|
||
Status: cfg.Status,
|
||
}
|
||
|
||
// 查询角色绑定
|
||
var targets []models.SystemMessageTarget
|
||
if err := orm.Eloquent.
|
||
Where("message_config_id = ? AND target_type = ?", cfg.ID, models.TargetTypeByRole).
|
||
Find(&targets).Error; err == nil {
|
||
for _, t := range targets {
|
||
item.RoleID = append(item.RoleID, t.TargetID)
|
||
}
|
||
}
|
||
|
||
app.OK(c, item, "查询成功")
|
||
}
|
||
|
||
// GetBizTypes 业务消息-查询业务类型
|
||
// @Summary 业务消息-查询业务类型
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.BizTypeListReq true "分页请求"
|
||
// @Success 200 {object} models.BizTypeListResp
|
||
// @Router /api/v1/bus_message/biz_types [post]
|
||
func GetBizTypes(c *gin.Context) {
|
||
var req models.BizTypeListReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
db := orm.Eloquent.Table("system_event_registry").
|
||
Select("biz_type, biz_name, MIN(created_at) as created_at, MAX(updated_at) as updated_at, MAX(is_enabled) as is_enabled").
|
||
Where("is_enabled = ?", true).
|
||
Group("biz_type, biz_name")
|
||
|
||
var total int64
|
||
err := orm.Eloquent.
|
||
Table("(?) as t", db).
|
||
Count(&total).Error
|
||
if err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "统计总数失败")
|
||
return
|
||
}
|
||
|
||
var list []models.BizTypeItem
|
||
err = orm.Eloquent.
|
||
Table("(?) as t", db).
|
||
Limit(req.PageSize).
|
||
Offset((req.Page - 1) * req.PageSize).
|
||
Scan(&list).Error
|
||
if err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "查询失败")
|
||
return
|
||
}
|
||
|
||
resp := models.BizTypeListResp{
|
||
List: list,
|
||
Total: total,
|
||
Page: req.Page,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
app.OK(c, resp, "查询成功")
|
||
}
|
||
|
||
// GetEventsByBizType 业务消息-查询事件类型
|
||
// @Summary 业务消息-查询事件类型
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.EventListReq true "分页请求"
|
||
// @Success 200 {object} models.EventListResp
|
||
// @Router /api/v1/bus_message/events [post]
|
||
func GetEventsByBizType(c *gin.Context) {
|
||
var req models.EventListReq
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.BizType == "" {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误")
|
||
return
|
||
}
|
||
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
db := orm.Eloquent.Model(&models.SystemEventRegistry{}).
|
||
Where("biz_type = ? AND is_enabled = ?", req.BizType, true)
|
||
|
||
var total int64
|
||
if err := db.Count(&total).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "统计失败")
|
||
return
|
||
}
|
||
|
||
var list []models.EventItem
|
||
if err := db.Select("event, event_name, description, created_at, updated_at, is_enabled").
|
||
Order("created_at DESC").
|
||
Limit(req.PageSize).
|
||
Offset((req.Page - 1) * req.PageSize).
|
||
Scan(&list).Error; err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "查询失败")
|
||
return
|
||
}
|
||
|
||
resp := models.EventListResp{
|
||
List: list,
|
||
Total: total,
|
||
Page: req.Page,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
app.OK(c, resp, "查询成功")
|
||
}
|
||
|
||
// GetTemplateVariables 业务消息-查询模板变量
|
||
// @Summary 业务消息-查询模板变量
|
||
// @Tags 消息中心,V1.5.0
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body models.TemplateVarReq true "模板变量请求参数"
|
||
// @Success 200 {object} models.TemplateVarListResp
|
||
// @Router /api/v1/bus_message/template_variables [post]
|
||
func GetTemplateVariables(c *gin.Context) {
|
||
var req models.TemplateVarReq
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 设置默认分页参数
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
// 查询事件配置
|
||
var record models.SystemEventRegistry
|
||
err := orm.Eloquent.
|
||
Where("biz_type = ? AND event = ? AND is_enabled = ?", req.BizType, req.Event, true).
|
||
First(&record).Error
|
||
if err != nil {
|
||
app.Error(c, http.StatusNotFound, nil, "未找到对应模板配置")
|
||
return
|
||
}
|
||
|
||
// 解析模板变量
|
||
var allVars []models.TemplateVariable
|
||
if err := json.Unmarshal([]byte(record.TemplateVariables), &allVars); err != nil {
|
||
app.Error(c, http.StatusInternalServerError, nil, "模板变量解析失败")
|
||
return
|
||
}
|
||
|
||
// 分页切片
|
||
start := (req.Page - 1) * req.PageSize
|
||
end := start + req.PageSize
|
||
if start > len(allVars) {
|
||
start = len(allVars)
|
||
}
|
||
if end > len(allVars) {
|
||
end = len(allVars)
|
||
}
|
||
|
||
resp := models.TemplateVarListResp{
|
||
List: allVars[start:end],
|
||
Total: int64(len(allVars)),
|
||
Page: req.Page,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
app.OK(c, resp, "查询成功")
|
||
}
|