Browse Source

Merge branch 'feature/community_research_question' of hongze/hongze_task into master

xyxie 7 months ago
parent
commit
1d3f11ff53

+ 10 - 1
models/admin.go

@@ -1,6 +1,9 @@
 package models
 
-import "github.com/beego/beego/v2/client/orm"
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_task/utils"
+)
 
 type Admin struct {
 	AdminId      int
@@ -24,6 +27,12 @@ func GetAdminByAdminId(adminId int) (item *Admin, err error) {
 	return
 }
 
+func GetAdminByAdminIds(adminIds []int) (items []*Admin, err error) {
+	sql := `SELECT * FROM admin WHERE admin_id in (` + utils.GetOrmInReplace(len(adminIds)) + `) `
+	_, err = orm.NewOrm().Raw(sql, adminIds).QueryRows(&items)
+	return
+}
+
 type AdminView struct {
 	AdminId      int
 	AdminName    string `description:"系统用户名称"`

+ 110 - 0
models/yb/community_question.go

@@ -0,0 +1,110 @@
+package yb
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+const (
+	// 回复状态
+	ReplyStatusDitribute = 1
+	ReplyStatusWait      = 2
+	ReplyStatusDone      = 3
+	ReplyStatusStop      = 4
+)
+
+// CommunityQuestion 问答社区
+type CommunityQuestion struct {
+	CommunityQuestionId     int       `orm:"column(community_question_id);pk" description:"问题ID"`
+	UserId                  int       `description:"提问用户ID"`
+	UserOpenid              string    `description:"提问用户openid"`
+	Mobile                  string    `description:"用户手机号"`
+	RealName                string    `description:"用户名"`
+	QuestionContent         string    `description:"问题描述"`
+	ReplierUserId           int       `description:"回复人的user_id"`
+	ReplierOpenid           string    `description:"回复人openid"`
+	ReplierAdminId          int       `description:"回复人关联的admin_id"`
+	ReplierRealName         string    `description:"回复人姓名"`
+	ReplierAvatar           string    `description:"回复人头像"`
+	ResearchGroupFirstId    int       `description:"回复人研究方向一级分组ID"`
+	ResearchGroupSecondId   int       `description:"回复人研究方向二级分组ID"`
+	ResearchGroupFirstName  string    `description:"研究方向一级分组名称"`
+	ResearchGroupSecondName string    `description:"研究方向二级分组名称"`
+	DistributeAdminId       int       `description:"分配人admin_id"`
+	DistributeTime          time.Time `description:"分配时间"`
+	VarietyTagId            int       `description:"标签ID"`
+	VarietyTagName          string    `description:"标签名称"`
+	IsRead                  int       `description:"用户是否已读 0-未读 1-已读"`
+	ReplierIsRead           int       `description:"回复人是否已读 0-未读 1-已读"`
+	ReplyStatus             int       `description:"状态 1-待分配 2-待回答 3-已回答 4-已终止"`
+	MsgSendStatus           int       `description:"消息推送进度 0-待推送 1-已推送回答人 2-已推送提问人"`
+	ReplyTime               time.Time `description:"回复时间"`
+	CreateTime              time.Time `description:"提问时间"`
+	ModifyTime              time.Time `description:"修改时间"`
+	IsDeleted               int       `description:"是否已删除 0-否 1-是"`
+	DeleteTime              time.Time `description:"删除时间"`
+	StopReason              string    `description:"终止原因"`
+}
+
+type CommunityQuestionMore struct {
+	CommunityQuestion
+	ClickNum    int `description:"点击量"`
+	UserQaCount int `description:"用户提问数"`
+}
+
+func (item *CommunityQuestion) TableName() string {
+	return "yb_community_question"
+}
+
+func (item *CommunityQuestion) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// GetQuestionById 主键获取提问
+func GetQuestionById(questionId int) (item *CommunityQuestion, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM yb_community_question WHERE community_question_id = ? AND is_deleted = 0 LIMIT 1`
+	err = o.Raw(sql, questionId).QueryRow(&item)
+	return
+}
+
+// GetCommunityQuestionListByCondition 获取问答列表
+func GetCommunityQuestionListByCondition(condition string, pars []interface{}, order string, startSize, pageSize int) (list []*CommunityQuestion, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT
+				*
+			FROM
+				yb_community_question
+			WHERE
+				is_deleted = 0 `
+	sql += condition
+	if order != "" {
+		sql += order
+	} else {
+		sql += ` ORDER BY create_time DESC`
+	}
+	sql += ` LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&list)
+	return
+}
+
+// GetCommunityQuestionTotalByCondition 获取问答列表
+func GetCommunityQuestionTotalByCondition(condition string, pars []interface{}) (total int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT
+				*
+			FROM
+				yb_community_question
+			WHERE
+				is_deleted = 0 `
+	sql += condition
+
+	totalSQl := `SELECT COUNT(1) total FROM (` + sql + `) z`
+	if err = o.Raw(totalSQl, pars).QueryRow(&total); err != nil {
+		return
+	}
+
+	return
+}

+ 4 - 0
services/task.go

@@ -287,6 +287,10 @@ func releaseTask() {
 	// 同步进门财经白名单定时任务
 	syncWhiteList := task.NewTask("syncWhiteList", "0 */10 * * * *", comein.SyncWhiteList)
 	task.AddTask("syncWhiteList", syncWhiteList)
+
+	//问答社区定时发送模版消息给研究员
+	notifyNeedAnswerQuestionToResearch := task.NewTask("notifyNeedAnswerQuestionToResearch", "0 0 10 * * *", NotifyNeedAnswerQuestionToResearch)
+	task.AddTask("问答社区定时发送模版消息给研究员", notifyNeedAnswerQuestionToResearch)
 }
 
 //func TaskTest() {

+ 67 - 0
services/wx_template_msg.go

@@ -296,3 +296,70 @@ func SendWxMsgWithEtaBusinessRemind(first, keyword1, keyword2, remark, code stri
 	err = SendTemplateMsgV2(sendInfo)
 	return
 }
+
+// SendYbQuestionToResearcher 给弘则FICC公众号,推送研报小程序模板消息-用户提问时,通知到研究员
+func SendYbQuestionToResearcher(questionId, adminId int, openid, questionTitle, remark string) (err error) {
+	var errMsg string
+	defer func() {
+		if err != nil {
+			alarmMsg := fmt.Sprintf("SendYbQuestionToResearcher-用户提问时,通知到研究员; QuestionId: %d; Err: %s; Msg: %s", questionId, err.Error(), errMsg)
+			utils.FileLog.Error(alarmMsg)
+			go alarm_msg.SendAlarmMsg(alarmMsg, 3)
+		}
+	}()
+
+	//accessToken, err := models.GetWxAccessToken()
+	//if err != nil {
+	//	errMsg = "GetWxAccessToken Err:" + err.Error()
+	//	return
+	//}
+	//if accessToken == "" {
+	//	errMsg = "accessToken is empty"
+	//	return
+	//}
+	openIdArr := make([]string, 0)
+	openIdArr = append(openIdArr, openid)
+
+	//sendUrl := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken
+	//sendMap := make(map[string]interface{})
+	//sendData := make(map[string]interface{})
+
+	first := "您好,有新的提问待回复"
+	keyword1 := questionTitle
+	keyword2 := "待回复"
+	if remark == "" {
+		remark = "请点击详情尽快处理"
+		keyword2 = remark
+	}
+
+	//sendData["first"] = map[string]interface{}{"value": first, "color": "#173177"}
+	//sendData["keyword1"] = map[string]interface{}{"value": keyword1, "color": "#173177"}
+	//sendData["keyword2"] = map[string]interface{}{"value": keyword2, "color": "#173177"}
+	//sendData["remark"] = map[string]interface{}{"value": remark, "color": "#173177"}
+	//
+	//sendMap["template_id"] = utils.WxMsgTemplateIdWithYbCommunityQuestion
+	//sendMap["data"] = sendData
+
+	wxAppPath := fmt.Sprintf("pages-question/answerDetail?id=%d", questionId)
+	if utils.RunMode == "debug" {
+		// 仅测试环境测试用
+		wxAppPath = "pages-report/chapterList?reportId=3800"
+	}
+
+	sendInfo := new(SendWxTemplate)
+	sendInfo.WxAppId = utils.AdminWxAppId
+	sendInfo.First = first
+	sendInfo.Keyword1 = keyword1
+	sendInfo.Keyword2 = keyword2
+	sendInfo.Remark = remark
+	sendInfo.RedirectUrl = wxAppPath
+	sendInfo.TemplateId = utils.WxMsgTemplateIdWithYbCommunityQuestion
+	sendInfo.RedirectTarget = 1
+	sendInfo.Resource = wxAppPath
+	sendInfo.SendType = utils.TEMPLATE_MSG_YB_COMMUNITY_QUESTION //研报问答社区
+	sendInfo.OpenIdArr = openIdArr
+
+	err = SendTemplateMsgV2(sendInfo)
+
+	return
+}

+ 95 - 0
services/yb_community_question.go

@@ -0,0 +1,95 @@
+package services
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"hongze/hongze_task/models"
+	"hongze/hongze_task/models/yb"
+	"hongze/hongze_task/services/alarm_msg"
+	"hongze/hongze_task/utils"
+)
+
+// NotifyNeedAnswerQuestionToResearch 定时通知研究员回复新提问
+func NotifyNeedAnswerQuestionToResearch(ctx context.Context) (err error) {
+	errmsg := ""
+	//分页处理沙盘表
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("NotifyNeedAnswerQuestionToResearch,errmsg:"+errmsg+err.Error(), 3)
+		}
+		if errmsg != "" {
+			utils.FileLog.Info(fmt.Sprintf("NotifyNeedAnswerQuestionToResearch,errmsg:" + errmsg))
+		}
+	}()
+	condition := " AND reply_status = 2 AND replier_admin_id > 0"
+	var pars []interface{}
+	//遍历查询待回复的问答列表
+	total, err := yb.GetCommunityQuestionTotalByCondition(condition, pars)
+	if err != nil {
+		err = fmt.Errorf("获取问题列表总数失败 Err:%s", err)
+		return
+	}
+	if total == 0 {
+		return
+	}
+
+	pageSize := 100
+	// 根据沙盘列表总数,分页查询
+	// 计算总页数
+	totalPage := (total + pageSize - 1) / pageSize // 使用整数除法,并添加一页以防有余数
+	// 查询管理员信息列表
+	adminInfoMap := make(map[int]*models.Admin)
+	//查询沙盘列表
+	for i := 0; i < totalPage; i += 1 {
+		startSize := i * pageSize
+		list, e := yb.GetCommunityQuestionListByCondition(condition, pars, "", startSize, pageSize)
+		if e != nil {
+			err = fmt.Errorf("查询沙盘列表失败 Err:%s\n", e)
+			errmsg += err.Error()
+			return
+		}
+		// 查询管理员信息列表,已查询过的不再重复查
+		adminIds := make([]int, 0)
+		for _, v := range list {
+			if _, ok := adminInfoMap[v.ReplierAdminId]; !ok {
+				adminIds = append(adminIds, v.ReplierAdminId)
+			}
+		}
+		if len(adminIds) > 0 {
+			//查询管理员信息列表
+			adminList, e := models.GetAdminByAdminIds(adminIds)
+			if e != nil {
+				err = fmt.Errorf("查询管理员信息列表失败 Err:%s\n", e)
+				errmsg += err.Error()
+				return
+			}
+
+			for _, v := range adminList {
+				adminInfoMap[v.AdminId] = v
+			}
+		}
+
+		// 查询问答列表
+		for _, item := range list {
+			// 查询管理员信息列表
+			adminInfo, ok := adminInfoMap[item.ReplierAdminId]
+			if !ok {
+				err = errors.New("发送失败, 研究员账号查询失败")
+				errmsg += fmt.Sprintf("发送失败, 研究员账号查询失败, 研究员id:%d, 提问id:%d\n", item.ReplierAdminId, item.CommunityQuestionId)
+				continue
+			}
+			if adminInfo.OpenId == "" {
+				err = errors.New("该研究员未关注公众号,无法发送消息通知,回复人openid为空, 不可推送")
+				errmsg += fmt.Sprintf("发送失败,该研究员未关注公众号,无法发送消息通知,回复人openid为空, 不可推送 研究员id:%d, 提问id:%d\n", item.ReplierAdminId, item.CommunityQuestionId)
+				continue
+			}
+			// 发送模版消息给研究员
+			if e := SendYbQuestionToResearcher(item.CommunityQuestionId, adminInfo.AdminId, adminInfo.OpenId, item.QuestionContent, ""); e != nil {
+				errmsg += fmt.Sprintf("发送失败,推送模板消息失败 研究员id:%d, 提问id:%d\n", item.ReplierAdminId, item.CommunityQuestionId)
+				return
+			}
+		}
+	}
+	return
+}

+ 8 - 5
utils/config.go

@@ -43,7 +43,8 @@ var (
 	AdminWxAppId     string
 	AdminWxAppSecret string
 
-	TemplateIdByProduct string //产品运行报告通知-模板ID
+	TemplateIdByProduct                    string //产品运行报告通知-模板ID
+	WxMsgTemplateIdWithYbCommunityQuestion string
 )
 
 // oss配置
@@ -95,10 +96,10 @@ var (
 
 // 进门财经账号信息
 var (
-	COMEIN_URL      string
-	COMEIN_APPID    string
-	COMEIN_SECREKEY string
-	COMEIN_WHITELIST_APPID string
+	COMEIN_URL                string
+	COMEIN_APPID              string
+	COMEIN_SECREKEY           string
+	COMEIN_WHITELIST_APPID    string
 	COMEIN_WHITELIST_SECREKEY string
 )
 
@@ -196,6 +197,7 @@ ZwIDAQAB
 
 		SendWxTemplateMsgUrl = "http://127.0.0.1:8086/v1/wechat/send_template_msg"
 		YbCommonTemplateId = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0"
+		WxMsgTemplateIdWithYbCommunityQuestion = "rciDm9ThigRBGi1SZ4TFd74XA4aoAxSz_ugdv_tZ450" // 研报小程序->问答社区回复通知
 	} else {
 		CompanyId = 16
 		RealName = "超级管理员"
@@ -217,6 +219,7 @@ ZwIDAQAB
 
 		SendWxTemplateMsgUrl = "http://127.0.0.1:8086/v1/wechat/send_template_msg"
 		YbCommonTemplateId = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM"
+		WxMsgTemplateIdWithYbCommunityQuestion = "rciDm9ThigRBGi1SZ4TFd74XA4aoAxSz_ugdv_tZ450" // 研报小程序->问答社区回复通知
 	}
 
 	// 微信模版消息

+ 2 - 0
utils/constants.go

@@ -45,6 +45,8 @@ const (
 	TEMPLATE_MSG_REPORT = iota + 1 //日度点评报告推送
 )
 
+const TEMPLATE_MSG_YB_COMMUNITY_QUESTION = 11
+
 // 聚合短信
 var (
 	TplId    = "65692"