xyxie 1 долоо хоног өмнө
parent
commit
3311819e75

+ 24 - 1
controllers/classify.go

@@ -593,7 +593,8 @@ func (this *ClassifyController) ListClassify() {
 	for i, v := range list {
 		list[i].VisiableUsers = visibleUserMap[v.Id]
 	}
-	// 指定分类类型(上级中的分类类型可能与最下层的不一致,但是要把上级也一起取出来, 这需求...=_=!)
+	// 指定分类类型(上级中的分类类型可能与最下层的不一致,但是要把上级也一起取出来, 这需求...=_=!)'
+	reportMsgConfigMap := make(map[int][]int)
 	if classifyType > 0 {
 		list = make([]*models.ClassifyList, 0)
 		// 先取出指定分类以及他对应的LevelPath中的所有ID
@@ -615,6 +616,25 @@ func (this *ClassifyController) ListClassify() {
 			}
 		}
 
+		// 根据分类ID获取配置项
+		reportMsgObj := new(models.ReportMessageConfig)
+		configList, err := reportMsgObj.GetListByClassifyIdList(classifyIds)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+		
+		for _, v := range configList {
+			if v.NotifyUsers != "" {
+				notifyUsers := strings.Split(v.NotifyUsers, ",")
+				for _, user := range notifyUsers {
+					userInt, _ := strconv.Atoi(user)
+					reportMsgConfigMap[v.ClassifyId] = append(reportMsgConfigMap[v.ClassifyId], userInt)
+				}
+			}
+		}
+
 		// 过滤掉不在ID中的
 		for _, v := range originList {
 			if !utils.InArrayByInt(classifyIds, v.Id) {
@@ -653,6 +673,9 @@ func (this *ClassifyController) ListClassify() {
 			if !utils.InArrayByInt(classifyIds, v.Id) {
 				continue
 			}
+			if configList, ok := reportMsgConfigMap[v.Id]; ok {
+				v.IceMsgUsers = configList
+			}
 			list = append(list, v)
 		}
 	}

+ 439 - 0
controllers/report_ice_message.go

@@ -0,0 +1,439 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta_gn/eta_api/models"
+	"eta_gn/eta_api/models/system"
+	"eta_gn/eta_api/services/ice_message"
+	"eta_gn/eta_api/utils"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type ReportIceMessageController struct {
+	BaseAuthController
+}
+
+// MsgConfig
+// @Title 消息推送配置
+// @Description 消息推送配置
+// @Param   Id   query   int  true       "版本ID"
+// @Success 200 {object} models.ReportIceMsgConfigReq
+// @router /ice_msg/config [post]
+func (c *ReportIceMessageController) IceMsgConfig() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	
+	var req models.ReportIceMsgConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ClassifyId <= 0 {
+		br.Msg = "分类ID不能为空"
+		return
+	}
+	if len(req.NotifyUsers) == 0 {
+		br.Msg = "通知用户列表不能为空"
+		return
+	}
+	configObj := new(models.ReportMessageConfig)
+	// 获取配置
+	config, err := configObj.GetItemByClassifyId(req.ClassifyId)
+	if err != nil &&  !utils.IsErrNoRow(err) {
+		br.Msg = "获取配置失败"
+		br.ErrMsg = "获取配置失败,Err:" + err.Error()
+		return
+	}
+	if config == nil || config.ConfigId <= 0 {
+		notifyUsers := make([]string, 0)
+		for _, id := range req.NotifyUsers {
+			uid := strconv.Itoa(id)
+			notifyUsers = append(notifyUsers, uid)
+		}
+		// 新增配置
+		config = &models.ReportMessageConfig{
+			ClassifyId:  req.ClassifyId,
+			NotifyUsers: strings.Join(notifyUsers, ","),
+			CreateTime:  time.Now(),
+			ModifyTime:  time.Now(),
+		}
+		err = config.Create()
+		if err != nil {
+			br.Msg = "新增配置失败"
+			br.ErrMsg = "新增配置失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		// 更新配置
+		notifyUsers := make([]string, 0)
+		for _, id := range req.NotifyUsers {
+			uid := strconv.Itoa(id)
+			notifyUsers = append(notifyUsers, uid)
+		}
+		config.NotifyUsers = strings.Join(notifyUsers, ",")
+		config.ModifyTime = time.Now()
+		err = config.Update([]string{"notify_users", "modify_time"})
+		if err != nil {
+			br.Msg = "更新配置失败"
+			br.ErrMsg = "更新配置失败,Err:" + err.Error()
+			return
+		}
+	}
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// MsgRecord
+// @Title 消息推送记录
+// @Description 消息推送记录
+// @Param   Id   query   int  true       "版本ID"
+// @Success 200 {object} models.ReportIceMsgConfigReq
+// @router /ice_msg/record [get]
+func (c *ReportIceMessageController) IceMsgRecord() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	// 根据分类ID,分类类型,推送状态,推送时间,分页查询
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+	classifyId, _ := c.GetInt("ClassifyId")
+	classifyType, _ := c.GetInt("ClassifyType")
+	sendStatus, _ := c.GetInt("Status")
+	sendTime := c.GetString("SendTime")
+    
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize := utils.StartIndex(currentIndex, pageSize)
+	condition := ""
+	pars := make([]interface{}, 0)
+	
+	if sendTime != "" {
+		// 校验时间格式
+		_, err := time.Parse(utils.FormatDate, sendTime)
+		if err != nil {
+			br.Msg = "时间格式错误"
+			br.ErrMsg = "时间格式错误,Err:" + err.Error()
+			return
+		}
+		startTime, _ := time.Parse(utils.FormatDate, sendTime)
+		endTime := startTime.AddDate(0, 0, 1)
+		condition += " AND send_time >= ? and send_time < ?"
+		pars = append(pars, startTime)
+		pars = append(pars, endTime)
+	}
+	if classifyId > 0 {
+		condition += " AND classify_id = ?"
+		pars = append(pars, classifyId)
+	}
+	if classifyType > 0 {
+		condition += " AND classify_type = ?"
+		pars = append(pars, classifyType)
+	}
+	if sendStatus > 0 {
+		condition += " AND status = ?"
+		pars = append(pars, sendStatus)
+	}
+
+	recordObj := new(models.ReportMessageRecord)
+	total, err := recordObj.GetListCount(condition, pars)
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	tmpList, err := recordObj.GetList(condition, pars, startSize, pageSize)
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	// 获取分类名称
+	classifyFullNameMap := make(map[int]string)
+	// 有三级分类,想要获取全称,一级/二级/三级
+	classifyList, err := models.GetAllClassifyOrderByLevel()
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	for _, item := range classifyList {
+		if item.ParentId == 0 {
+			classifyFullNameMap[item.Id] = item.ClassifyName
+		}else if item.ParentId >0 {
+			parentClassifyName, ok := classifyFullNameMap[item.ParentId]
+			if ok {
+				classifyFullNameMap[item.Id] = parentClassifyName + "/" + item.ClassifyName
+			}
+		}
+	}
+
+	// 查找账号名称
+	adminIds := make([]int, 0)
+	adminNameMap := make(map[int]string)
+	for _, item := range tmpList {
+		adminIds = append(adminIds, int(item.SendAdminId), int(item.ReceiveAdminId))
+	}
+	adminList, err := system.GetAdminListByIdList(adminIds)
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	for _, item := range adminList {
+		adminNameMap[int(item.AdminId)] = item.RealName
+	}
+	
+	list := make([]*models.ReportIceMsgRecordListItem, 0)
+	for _, item := range tmpList {
+		list = append(list, &models.ReportIceMsgRecordListItem{
+			MessageId: item.MessageId,
+			ReportId: item.ReportId,
+			ReportTitle: item.ReportTitle,
+			PptId: item.PptId,
+			ClassifyId: item.ClassifyId,
+			ClassifyFullName: classifyFullNameMap[item.ClassifyId],
+			SendAdminId: item.SendAdminId,
+			SendAdminName: adminNameMap[int(item.SendAdminId)],
+			ReceiveAdminId: item.ReceiveAdminId,
+			ReceiveAdminName: adminNameMap[int(item.ReceiveAdminId)],
+			ClassifyType: item.ClassifyType,
+			SendTime: item.SendTime.Format(utils.FormatDateTime),
+		    Status: item.Status,
+			CreateTime: item.CreateTime.Format(utils.FormatDateTime),
+		})
+	}
+	
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(models.ReportIceMsgRecordListResp)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// 消息推送
+// @Title 消息推送
+// @Description 消息推送
+// @Param   Id   query   int  true       "版本ID"
+// @Success 200 {object} models.ReportIceMsgConfigReq
+// @router /ice_msg/push [post]
+func (c *ReportIceMessageController) IceMsgPush() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req models.ReportIceMsgPushReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	sendClassifyId := 0
+	classifyType := 1
+	if req.ReportId > 0 {
+		classifyType = 1
+	}else if req.PptId > 0 {
+		classifyType = 2
+	}
+	// 新增缓存判断消息还在处理中
+	cacheKey := fmt.Sprintf("%s_%d_%d", utils.CACHE_REPORT_ICE_MSG_PUSH, req.ReportId, req.PptId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+	var title, summary, content string
+	var reportInfo *models.Report
+	var pptInfo *models.PptV2
+	// 根据类型判断
+	if classifyType == 1 {// 推送研报
+		if req.ReportId <= 0 {
+			br.Msg = "研报ID不能为空"
+			return
+		}
+		//查询研报
+		reportInfo, err = models.GetBaseReportInfoByReportId(int(req.ReportId))
+		if err != nil {
+			if !utils.IsErrNoRow(err) {
+				br.Msg = "查询失败"
+				br.ErrMsg = "查询失败,Err:" + err.Error()
+				return
+			}else{
+				br.Msg = "研报不存在"
+				return
+			}
+		}
+		//判断研报状态,只有已发布的研报和已审核的研报才能推动
+		if reportInfo.State != 2 && reportInfo.State != 6 {
+			br.Msg = "该研报未发布,请发布后重试"
+			return
+		}
+		sendClassifyId = reportInfo.ClassifyIdThird
+		if sendClassifyId <= 0 {
+			sendClassifyId = reportInfo.ClassifyIdSecond
+		}
+		if sendClassifyId <= 0 {
+			sendClassifyId = reportInfo.ClassifyIdFirst
+		}
+		title = reportInfo.Title
+		summary = reportInfo.Abstract
+		content = reportInfo.Title
+	} else if classifyType == 2 {// 推送PPT
+		if req.PptId <= 0 {
+			br.Msg = "PPTID不能为空"
+			return
+		}
+		// PPT
+		pptInfo, err = models.GetBasePptV2ByPptId(int(req.PptId))
+		if err != nil {
+			br.Msg = "PPT不存在"
+			return
+		}
+		if pptInfo.State != 2 && pptInfo.State != 6 {
+			br.Msg = "该PPT未发布,请发布后重试"
+			return
+		}
+		sendClassifyId = pptInfo.ClassifyId
+		title = pptInfo.Title
+		summary = pptInfo.Abstract
+		content = pptInfo.Title
+	}
+	//
+	// 判断该分类是否设置了消息推送配置
+	configObj := new(models.ReportMessageConfig)
+	config, err := configObj.GetItemByClassifyId(sendClassifyId)
+	if err != nil {
+		if !utils.IsErrNoRow(err) {
+			br.Msg = "查询失败"
+			br.ErrMsg = "查询失败,Err:" + err.Error()
+			return
+		}else{
+			br.Msg = "该报告分类未设置接收人,请配置后重试"
+			return
+		}
+	}
+	if config == nil || config.ConfigId <= 0 {
+		br.Msg = "该报告分类未设置接收人,请配置后重试"
+		return
+	}else if config.NotifyUsers == "" {
+		br.Msg = "该报告分类未设置接收人,请配置后重试"
+		return
+	}
+
+	// 获取推送人的工号
+	adminids := strings.Split(config.NotifyUsers, ",")
+	
+	adminList, err := system.GetSysAdminByIdSlice(adminids)
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	if len(adminList) == 0 {
+		br.Msg = "该报告分类未设置接收人,请配置后重试"
+		return
+	}
+	// 生成推送记录
+	recordList := make([]*models.ReportMessageRecord, 0)
+	successCount := 0
+    for _, item := range adminList {
+		if item.EmployeeId != "" {
+			// 推送模版消息
+			sendStatus := 1
+			// 生成taskId
+	        taskId := utils.MD5(fmt.Sprintf("%s_%s_%s_%s", req.ReportId, req.PptId, item.AdminId, time.Now().Format("20060102150405")))
+	
+			err = ice_message.PushIceMessage(title, summary, content, item.EmployeeId, taskId, req.ReportId, req.PptId)
+			if err != nil {
+				sendStatus = 2
+			}else{
+				successCount++
+			}
+			pushRecord := &models.ReportMessageRecord{
+				ReportId: int64(req.ReportId),
+				PptId: int64(req.PptId),
+				ClassifyId: sendClassifyId,
+				ClassifyType: int8(classifyType),
+				SendAdminId: int64(sysUser.AdminId),
+				SendTime: time.Now(),
+				ReceiveAdminId: int64(item.AdminId),
+				ReceiveAdminCode: item.EmployeeId,
+				Status: int8(sendStatus),
+				CreateTime: time.Now(),
+				ModifyTime: time.Now(),
+				TaskId: taskId,
+			}
+			recordList = append(recordList, pushRecord)
+		}
+	}
+	
+	recordObj := new(models.ReportMessageRecord)
+	err = recordObj.BatchAdd(recordList)
+	if err != nil {
+		br.Msg = "推送失败"
+		br.ErrMsg = "推送失败,Err:" + err.Error()
+		return
+	}
+
+	if successCount > 0 {
+		// 更新报告表的推送记录
+		if classifyType == 1 {
+			reportInfo.MsgIsSend = 1
+			reportInfo.MsgSendTime = time.Now()
+			err = reportInfo.Update([]string{"MsgIsSend", "MsgSendTime"})
+			if err != nil {
+				br.Msg = "更新推送记录失败"
+				br.ErrMsg = "更新推送记录失败,Err:" + err.Error()
+				return
+			}
+		}else if classifyType == 2 {
+			pptInfo.MsgIsSend = 1
+			pptInfo.MsgSendTime = time.Now()
+			err = pptInfo.Update([]string{"MsgIsSend", "MsgSendTime"})
+			if err != nil {
+				br.Msg = "更新推送记录失败"
+				br.ErrMsg = "更新推送记录失败,Err:" + err.Error()
+				return
+			}
+		}
+		br.Msg = "推送成功"
+		br.Success = true
+		br.Ret = 200
+	}else{
+		br.Msg = "推送失败"
+		br.ErrMsg = "推送失败,Err:" + err.Error()
+		br.Ret = 408
+	}
+}

+ 8 - 0
models/classify.go

@@ -198,6 +198,7 @@ type ClassifyList struct {
 	ChartPermissionIdList []int           `gorm:"-"`                                   //`description:"绑定的权限ID"`
 	LevelPath             string          `gorm:"column:level_path" json:"level_path"` //`description:"分类的层级路径,英文逗号分隔"`
 	VisiableUsers         []int           `gorm:"-"`
+	IceMsgUsers           []int           `gorm:"-"`
 }
 
 type ClassifyItem struct {
@@ -463,3 +464,10 @@ func (m *Classify) GetItemsByCondition(condition string, pars []interface{}, fie
 	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
 	return
 }
+
+// GetAllClassifyOrderByLevel 获取所有分类,并按层级排序
+func GetAllClassifyOrderByLevel() (items []*Classify, err error) {
+	sql := `SELECT * FROM classify ORDER BY level ASC, sort ASC, create_time ASC`
+	err = global.DmSQL["rddp"].Raw(sql).Find(&items).Error
+	return
+}

+ 27 - 0
models/ice_message.go

@@ -0,0 +1,27 @@
+package models
+
+// ReportIceMsgPushLibReq ICE消息推送请求结构体
+type ReportIceMsgPushLibReq struct {
+	PlatformId  string `json:"platformId" description:"订阅号"`
+	Title       string `json:"title" description:"标题"`
+	Summary     string `json:"sumary" description:"摘要"`
+	Content     string `json:"content" description:"消息正文"`
+	Code        string `json:"code" description:"用户工号"`
+	Type        int    `json:"type" description:"消息类型:2-待办,0-非待办"`
+	URL         string `json:"url" description:"跳转链接"`
+	TaskId      string `json:"taskId" description:"任务ID"`
+//	IsCompleted string `json:"isCompleted" description:"是否已完成状态:1-待办,2-已办,0-非待办"`
+	SystemId    string `json:"systemId" description:"系统唯一标识"`
+}
+
+// IceMsgPushLibResp ICE消息推送响应结构体
+type IceMsgPushLibResp struct {
+	Code int    `json:"code"`
+	Msg  string `json:"msg"`
+	Info struct {
+		Data interface{} `json:"data"`
+		Msg  string      `json:"msg"`
+		Ret  string      `json:"ret"`
+		Time string      `json:"time"`
+	} `json:"info"`
+} 

+ 8 - 0
models/ppt_v2.go

@@ -52,6 +52,8 @@ type PptV2 struct {
 	CurrentBackgroundImgId int       `gorm:"column:current_background_img_id" description:"背景图片id"`
 	BackCoverImgId         int       `gorm:"column:back_cover_img_id" description:"封底图片id"`
 	BackgroundImgId        int       `gorm:"column:background_img_id" description:"封面图id"`
+	MsgIsSend              int       `gorm:"column:msg_is_send" description:"是否发送消息;0未发送,1已发送"`
+	MsgSendTime            time.Time `gorm:"column:msg_send_time" description:"消息发送时间"`
 }
 
 type PptV2Detail struct {
@@ -533,3 +535,9 @@ func GetPptByImageIdCount(imageId int) (count int, err error) {
 	err = global.DmSQL["rddp"].Raw(sql, imageId, imageId, imageId).Scan(&count).Error
 	return
 }
+
+func GetBasePptV2ByPptId(pptId int) (item *PptV2, err error) {
+	sql := `SELECT ppt_id, title, abstract, classify_id, ppt_version, pptx_url, ppt_page, state, msg_is_send, msg_send_time FROM ppt_v2 WHERE ppt_id = ?`
+	err = global.DmSQL["rddp"].Raw(sql, pptId).Scan(&item).Error
+	return
+}

+ 6 - 0
models/report.go

@@ -547,6 +547,12 @@ func GetSimpleReportByIds(reportIds []int) (list []*Report, err error) {
 	return
 }
 
+func GetBaseReportInfoByReportId(reportId int) (item *Report, err error) {
+	sql := `SELECT id, title, report_code, abstract, author, frequency, classify_id_first, classify_id_second, classify_id_third, classify_name_first, classify_name_second, classify_name_third, state FROM report WHERE id = ?`
+	err = global.DmSQL["rddp"].Raw(sql, reportId).First(&item).Error
+	return
+}
+
 // GetReportStage
 // @Description: 获取报告的最大期数(每一年的最大期数)
 // @author: Roc

+ 210 - 0
models/report_message_config.go

@@ -0,0 +1,210 @@
+package models
+
+import (
+	"eta_gn/eta_api/global"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+// ReportMessageConfig 研报ICE订阅号消息推送配置表
+type ReportMessageConfig struct {
+	ConfigId    int64     `gorm:"column:config_id;primaryKey;autoIncrement" description:"主键ID"`
+	ClassifyId  int       `gorm:"column:classify_id;default:0" description:"分类ID"`
+	NotifyUsers string    `gorm:"column:notify_users" description:"通知用户列表"`
+	CreateTime  time.Time `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime  time.Time `gorm:"column:modify_time" description:"修改时间"`
+}
+
+// TableName 设置表名
+func (m *ReportMessageConfig) TableName() string {
+	return "report_message_config"
+}
+
+// Create 创建配置
+func (m *ReportMessageConfig) Create() (err error) {
+	err = global.DmSQL["rddp"].Create(m).Error
+	return
+}
+
+// Update 更新配置
+func (m *ReportMessageConfig) Update(cols []string) (err error) {
+	err = global.DmSQL["rddp"].Select(cols).Updates(m).Error
+	return
+}
+
+// GetItemById 根据ID获取配置
+func (m *ReportMessageConfig) GetItemById(id int64) (item *ReportMessageConfig, err error) {
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE config_id = ? LIMIT 1`, m.TableName())
+	err = global.DmSQL["rddp"].Raw(sql, id).First(&item).Error
+	return
+}
+
+// GetItemByClassifyId 根据分类ID获取配置
+func (m *ReportMessageConfig) GetItemByClassifyId(classifyId int) (item *ReportMessageConfig, err error) {
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE classify_id = ? LIMIT 1`, m.TableName())
+	err = global.DmSQL["rddp"].Raw(sql, classifyId).First(&item).Error
+	return
+}
+
+// GetItemsByCondition 根据条件获取配置列表
+func (m *ReportMessageConfig) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ReportMessageConfig, err error) {
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+// GetPageItemsByCondition 分页获取配置列表
+func (m *ReportMessageConfig) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*ReportMessageConfig, err error) {
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	pars = append(pars, startSize)
+	pars = append(pars, pageSize)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+// GetCountByCondition 获取符合条件的配置数量
+func (m *ReportMessageConfig) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Scan(&count).Error
+	return
+}
+
+// ReportMessageConfigListReq 配置列表请求参数
+type ReportMessageConfigListReq struct {
+	PageSize     int `form:"PageSize"`
+	CurrentIndex int `form:"CurrentIndex"`
+	ClassifyId   int `form:"ClassifyId" description:"分类ID"`
+}
+
+// ReportMessageConfigListResp 配置列表响应体
+type ReportMessageConfigListResp struct {
+	List   []*ReportMessageConfig
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// ReportMessageConfigAddReq 新增配置请求体
+type ReportMessageConfigAddReq struct {
+	ClassifyId  int      `json:"classify_id" description:"分类ID"`
+	NotifyUsers string   `json:"notify_users" description:"通知用户列表"`
+}
+
+// ReportMessageConfigEditReq 编辑配置请求体
+type ReportMessageConfigEditReq struct {
+	ConfigId    int64    `json:"config_id" description:"配置ID"`
+	ClassifyId  int      `json:"classify_id" description:"分类ID"`
+	NotifyUsers string   `json:"notify_users" description:"通知用户列表"`
+}
+
+// ReportMessageRecord 研报ICE订阅号消息推送记录表
+type ReportMessageRecord struct {
+	MessageId      int64     `gorm:"column:message_id;primaryKey;autoIncrement" description:"主键ID"`
+	ReportId       int64     `gorm:"column:report_id" description:"关联的研报ID"`
+	ReportTitle    string    `gorm:"column:report_title" description:"研报标题"`
+	PptId          int64     `gorm:"column:ppt_id" description:"关联的PPT ID"`
+	ClassifyId     int       `gorm:"column:classify_id;default:0" description:"分类ID"`
+	ClassifyType     int8      `gorm:"column:classify_type" description:"分类类型1-研报,2-PPT"`
+	SendAdminId    int64     `gorm:"column:send_admin_id" description:"发送者ID"`
+	SendTime       time.Time `gorm:"column:send_time" description:"发送时间"`
+	ReceiveAdminId int64     `gorm:"column:receive_admin_id" description:"接收者ID"`
+	ReceiveAdminCode string    `gorm:"column:receive_admin_code" description:"接收者编码"`
+	Status         int8      `gorm:"column:status" description:"状态;1发送成功,2发送失败"`
+	TaskId         string    `gorm:"column:task_id" description:"任务ID"`
+	CreateTime     time.Time `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime     time.Time `gorm:"column:modify_time" description:"修改时间"`
+}
+
+type ReportIceMsgRecordListItem struct {
+	MessageId      int64     `description:"主键ID"`
+	ReportId       int64     `description:"关联的研报ID"`
+	ReportTitle    string    `description:"研报标题"`
+	PptId          int64     `description:"关联的PPT ID"`
+	ClassifyId     int       `description:"分类ID"`
+	ClassifyFullName   string    `description:"分类名称"`
+	ClassifyType     int8      `description:"分类类型:1-研报,2-PPT"`
+	SendAdminId    int64     `description:"发送者ID"`
+	SendAdminName    string    `description:"发送者名称"`
+	SendTime       string    `description:"发送时间"`
+	ReceiveAdminId int64     `description:"接收者ID"`
+	ReceiveAdminName string    `description:"接收者名称"`
+	Status         int8      `description:"状态:1发送成功,2发送失败"`
+	CreateTime     string    `description:"创建时间"`
+}
+// TableName 设置表名
+func (ReportMessageRecord) TableName() string {
+	return "report_message_record"
+}
+
+
+type ReportIceMsgConfigReq struct {
+	ClassifyId  int   `description:"分类ID"`
+	NotifyUsers []int `description:"通知用户列表"`
+}
+
+// 查询配置是否已存在
+func (m *ReportMessageConfig) IsExist(classifyId int) (bool, error) {
+	var count int64
+	err := global.DmSQL["rddp"].Model(&ReportMessageConfig{}).Where("classify_id = ?", classifyId).Count(&count).Error
+	return count > 0, err
+}
+
+// 查询消息推送记录列表
+func (m *ReportMessageRecord) GetList(condition string, pars []interface{}, startSize, pageSize int) (list []*ReportMessageRecord, err error) {
+	fields := "*"
+	order := " ORDER BY create_time DESC, message_id DESC"
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	pars = append(pars, startSize)
+	pars = append(pars, pageSize)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Scan(&list).Error
+	return
+}
+
+// 查询消息推送记录列表数量
+func (m *ReportMessageRecord) GetListCount(condition string, pars []interface{}) (count int, err error) {
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Scan(&count).Error
+	return
+}
+
+// 批量新增推送记录
+func (m *ReportMessageRecord) BatchAdd(list []*ReportMessageRecord) (err error) {
+	err = global.DmSQL["rddp"].Create(list).Error
+	return
+}
+
+// ReportIceMsgRecordListResp 消息推送记录列表响应体
+type ReportIceMsgRecordListResp struct {
+	List   []*ReportIceMsgRecordListItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+
+type ReportIceMsgPushReq struct {
+	ReportId   int  `description:"研报ID"`
+	PptId      int  `description:"PPT ID"`
+}
+
+func (m *ReportMessageConfig) GetListByClassifyIdList(classifyIdList []int) (list []*ReportMessageConfig, err error) {
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE classify_id IN (?)`, m.TableName())
+	err = global.DmSQL["rddp"].Raw(sql, classifyIdList).Find(&list).Error
+	return
+}
+

+ 27 - 0
routers/commentsRouter.go

@@ -8260,6 +8260,33 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"],
+        beego.ControllerComments{
+            Method: "IceMsgConfig",
+            Router: `/ice_msg/config`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"],
+        beego.ControllerComments{
+            Method: "IceMsgPush",
+            Router: `/ice_msg/push`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportIceMessageController"],
+        beego.ControllerComments{
+            Method: "IceMsgRecord",
+            Router: `/ice_msg/record`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportUploadCommonController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:ReportUploadCommonController"],
         beego.ControllerComments{
             Method: "UploadImg",

+ 3 - 0
routers/router.go

@@ -76,6 +76,9 @@ func init() {
 			web.NSInclude(
 				&controllers.ReportUploadCommonController{},
 			),
+			web.NSInclude(
+				&controllers.ReportIceMessageController{},
+			),
 		),
 		web.NSNamespace("/voice",
 			web.NSInclude(

+ 111 - 0
services/ice_message/ice_message_lib.go

@@ -0,0 +1,111 @@
+package ice_message
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"eta_gn/eta_api/models"
+	"eta_gn/eta_api/utils"
+	"fmt"
+	"io"
+	"net/http"
+)
+
+// pushIceMessageLib 推送ICE消息
+func pushIceMessageLib(req *models.ReportIceMsgPushLibReq) (err error) {
+	if req == nil {
+		return errors.New("request cannot be nil")
+	}
+	if utils.IceMsgPushUrl == "" {
+		return errors.New("iceMsgPushUrl cannot be empty")
+	}
+	if utils.IceMsgPushPlatformId == "" {
+		return errors.New("iceMsgPushPlatformId cannot be empty")
+	}
+
+	// 参数校验
+	req.PlatformId = utils.IceMsgPushPlatformId
+	req.Type = 0  // 此处必须传入:2,如果为非待办则传0, 本次传输的是订阅号消息,故传0
+	if req.Title == "" {
+		return errors.New("title cannot be empty")
+	}
+	if req.Code == "" {  //用户工号
+		return errors.New("code cannot be empty")
+	}
+	
+	if req.URL == "" {
+		return errors.New("url cannot be empty")
+	}
+	if req.TaskId == "" {
+		return errors.New("taskId cannot be empty")
+	}
+	if req.SystemId == "" {
+		return errors.New("systemId cannot be empty")
+	}
+
+	// 准备请求数据
+	jsonData, err := json.Marshal(req)
+	if err != nil {
+		return err
+	}
+
+	// 发送HTTP请求
+	client := &http.Client{}
+	request, err := http.NewRequest("POST", "https://coalaiinsight.ceic.com:8180/push", bytes.NewBuffer(jsonData))
+	if err != nil {
+		return err
+	}
+	request.Header.Set("Content-Type", "application/json")
+
+	// 执行请求
+	response, err := client.Do(request)
+	if err != nil {
+		return err
+	}
+	defer response.Body.Close()
+
+	// 读取响应
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		return err
+	}
+
+	// 解析响应
+	var result models.IceMsgPushLibResp
+	if err = json.Unmarshal(body, &result); err != nil {
+		return err
+	}
+
+	// 检查响应状态
+	if result.Code != 0 {
+		return errors.New(result.Msg)
+	}
+
+	return nil
+}
+
+func PushIceMessage(title, summary, content, code, taskId string, reportId, pptId int) (err error) {
+	var url string
+	if reportId > 0 {
+		url = fmt.Sprintf("%s/report/report_detail?reportId=%s", utils.IceMsgPushUrl, reportId)
+	} else if pptId > 0 {
+		url = fmt.Sprintf("%s/report/ppt_detail?pptId=%s", utils.IceMsgPushUrl, pptId)
+	}
+	req := &models.ReportIceMsgPushLibReq{
+		Title: title,
+		Summary: summary,
+		Content: content,
+		Code: code,
+		URL: url,
+		TaskId: taskId,
+		SystemId: taskId,
+	}
+	
+	err = pushIceMessageLib(req)
+	if err != nil {
+		err = errors.New(fmt.Sprintf("推送失败,Err:%s", err.Error()))
+		return err
+	}
+	return nil
+}
+

+ 10 - 0
utils/config.go

@@ -272,6 +272,12 @@ var (
 	UseMongo bool // 是否使用mongo
 )
 
+// ice订阅号推送地址
+var (
+	IceMsgPushUrl string
+	IceMsgPushPlatformId string
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -612,4 +618,8 @@ func init() {
 		}
 		ViperConfig = viper.GetViper()
 	}
+
+	// ice订阅号推送地址
+	IceMsgPushUrl = config["ice_msg_push_url"]
+	IceMsgPushPlatformId = config["ice_msg_push_platform_id"]
 }

+ 1 - 0
utils/constants.go

@@ -218,6 +218,7 @@ const (
 	CACHE_KEY_REPLACE_EDB                   = "eta:replace_edb"                   //系统用户操作日志队列
 	CACHE_KEY_BI_DASHBOARD_PREPARE_RESOURCE = "eta:bi_dashboard:prepare_resource" // 准备引用到看板的知识资源
 	CACHE_KEY_DATA_COLLECT_HANDLER          = "eta:data:collect:handler"          // 资产收藏处理队列
+	CACHE_REPORT_ICE_MSG_PUSH               = "eta:report:ice_msg:push:"           // 研报消息推送缓存
 )
 
 // 模板消息推送类型