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, "查询成功") }