Browse Source

feature(订单管理系统):
1、超期三天未跟进邮件提醒

niezch 2 years ago
parent
commit
d03000eded

+ 19 - 0
opms_admin/app/handler/message.go

@@ -99,6 +99,25 @@ func (h *MessageHandler) DeleteByIds(ctx context.Context, req *comm_def.IdsReq,
 	return err
 }
 
+//sendmail 发送邮件
+func (s *MessageHandler) SendMail(ctx context.Context, req g.MapStrStr, rsp *comm_def.CommonMsg) error {
+	reqData := new(model.SendMessageReq)
+	if err := gconv.Struct(req, reqData); err != nil {
+		return err
+	}
+	// 检查请求参数
+	if err := gvalid.CheckStruct(ctx, reqData, nil); err != nil {
+		return err
+	}
+	msgService, err := service.NewMessageService(ctx)
+	if err != nil {
+		return err
+	}
+	err = msgService.SendMail(reqData)
+	return err
+
+}
+
 // AllRead 全部已读
 func (h *MessageHandler) AllRead(ctx context.Context, null, rsp *comm_def.CommonMsg) error {
 	msgService, err := service.NewMessageService(ctx)

+ 6 - 0
opms_admin/app/model/sys_message.go

@@ -32,6 +32,12 @@ type CreateSysMessageReq struct {
 	IsRead      string `json:"isRead"`                                                          // 是否已读(10否20是)
 	Remark      string `json:"remark"`                                                          // 备注
 }
+type SendMessageReq struct {
+	MsgTitle    string `json:"msgTitle"      v:"required#消息标题不能为空"` // 消息标题
+	MsgContent  string `json:"msgContent"    v:"required#消息内容不能为空"` // 消息内容
+	RecvUserIds string `json:"recvUserIds"`                         // 接收用户
+	OpnUrl      string `json:"opnUrl"`                              //附件地址
+}
 
 type UpdateSysMessageReq struct {
 	Id int64 `json:"id" v:"required|min:1#主键ID不能为空|主键ID参数错误"`

+ 22 - 0
opms_admin/app/service/sys_message.go

@@ -135,6 +135,28 @@ func (s *MessageService) Create(req *model.CreateSysMessageReq) (err error) {
 	return
 }
 
+//SendMail 发送邮件
+func (s *MessageService) SendMail(req *model.SendMessageReq) (err error) {
+	data := new(model.SysMessage)
+	if err := gconv.Struct(req, data); err != nil {
+		return err
+	}
+	//SetCreatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName())
+	//lastId, err := s.Dao.InsertAndGetId(data)
+	//if err != nil {
+	//	return err
+	//}
+	//data.Id = int(lastId)
+	//log := g.Map{
+	//	s.logDao.C.MsgId:  lastId,
+	//	s.logDao.C.UserId: data.RecvUserIds,
+	//	s.logDao.C.IsRead: "10",
+	//}
+	//s.logDao.Data(log).Insert()
+	s.SendUserEmailMsg(data.RecvUserIds, data.MsgTitle, data.MsgContent, data.OpnUrl)
+	return
+}
+
 // UpdateById 修改系统参数
 func (s *MessageService) UpdateById(req *model.UpdateSysMessageReq) (err error) {
 	data := new(model.SysMessage)

+ 2 - 2
opms_admin/app/service/sys_send_message.go

@@ -11,7 +11,7 @@ import (
 )
 
 // 发送邮箱
-func (c *contextService) SendUserEmailMsg(userId, msgTitle, msgContent string) error {
+func (c *contextService) SendUserEmailMsg(userId, msgTitle, msgContent string, zipurl string) error {
 	userInfo, err := dao.NewSysUserDao(c.Tenant).Fields(dao.SysUser.C.NickName, dao.SysUser.C.Email).WherePri(userId).One()
 	if err != nil {
 		g.Log().Error(err)
@@ -27,7 +27,7 @@ func (c *contextService) SendUserEmailMsg(userId, msgTitle, msgContent string) e
 	m.SetHeader("To", userInfo.Email)
 	m.SetHeader("Subject", msgTitle)
 	m.SetBody("text/html", msgContent)
-
+	m.Attach(zipurl) // 附件
 	err = email.Client.DialAndSend(m)
 	if err != nil {
 		g.Log().Error("发送用户 "+userInfo.NickName+" 邮箱邮件失败:"+userInfo.Email, err)

+ 2 - 0
opms_admin/main.go

@@ -60,6 +60,8 @@ var AuthExcludePaths = []string{
 	"/User/SendResetPasswordEmail",
 	"/User/ResetPasswordFromEmail",
 	"/SystemMessage/Create",
+	"/Message/SendMail",
+	"/Dict/GetDictDataByType",
 }
 
 // 处理Auth

+ 16 - 0
opms_parent/app/service/base.go

@@ -279,3 +279,19 @@ func GetUsersByRoleCode(ctx context.Context, roleCode []string, pageSize ...int)
 	}
 	return res, nil
 }
+
+//跟进发送邮件消息
+func GSendMail(msg g.MapStrStr) error {
+	srv := micro_srv.InitMicroSrvClient("Message", "micro_srv.auth")
+	defer srv.Close()
+	resp := &comm_def.CommonMsg{}
+	tenant := g.Config().GetString("micro_srv.tenant")
+	ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
+	err := srv.Call(ctx, "SendMail", msg, resp)
+	if err != nil {
+		g.Log().Error(err)
+		return myerrors.MicroCallError("项目未跟进发送邮件提醒失败")
+	}
+	fmt.Println(resp.Data)
+	return nil
+}

+ 141 - 0
opms_parent/app/service/proj/business_cron.go

@@ -1,10 +1,13 @@
 package proj
 
 import (
+	"context"
 	projDao "dashoo.cn/micro/app/dao/proj"
+	model "dashoo.cn/micro/app/model/proj"
 	"dashoo.cn/micro/app/service"
 	"database/sql"
 	"fmt"
+	"github.com/360EntSecGroup-Skylar/excelize"
 	"github.com/gogf/gf/container/gset"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/os/gcron"
@@ -12,7 +15,9 @@ import (
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/text/gstr"
 	"github.com/gogf/gf/util/gconv"
+	"github.com/smallnest/rpcx/share"
 	"strings"
+	"time"
 )
 
 // 初始化,创建每10分钟执行一次的定时任务
@@ -20,6 +25,9 @@ func init() {
 	// 定时任务
 	spec := "0 0 9 * * *" // 每天凌晨9点执行
 	gcron.AddSingleton(spec, businessFollowRun)
+	//定时任务
+	specs := "0 0 0 * * 1 *" //每周一一点
+	gcron.AddSingleton(specs, businesspeopleUpReminder)
 }
 
 // businessFollowRun 项目跟进超时任务逻辑
@@ -164,6 +172,127 @@ func businessFollowOverdueSalesAssociate(tenant string, userIds []string) {
 	}
 }
 
+// 项目每周进行一次超期三天未跟进统计表,每周给销售助理发一次邮件
+func businesspeopleUpReminder() {
+
+	tenant := g.Config().GetString("micro_srv.tenant")
+	if tenant == "" {
+		glog.Error("定时任务租户码未设置,请前往配置")
+		return
+	}
+	// 从配置中获取消息提醒设置
+	configs, err := g.DB(tenant).Model("sys_config").Where("config_key IN ('SalesDirector','SalesAssociate')").FindAll()
+	if err != nil && err != sql.ErrNoRows {
+		glog.Error(err)
+		return
+	}
+	// 销售助理用户Id
+	salesAssociate := []string{}
+	for _, config := range configs {
+		if config["config_key"].String() == "SalesAssociate" {
+			salesAssociate = strings.Split(config["config_value"].String(), ",")
+		}
+	}
+	var list []*model.ProjBusinessRes
+	var listA []*model.ProjBusinessRes
+	var listB []*model.ProjBusinessRes
+	var listC []*model.ProjBusinessRes
+	now := gtime.Now().StartOfDay()
+	LastWeekDay := now.AddDate(0, 0, -8)
+	LastTwoWeekDay := now.AddDate(0, 0, -15)
+	LastMonthDay := now.AddDate(0, -1, -1)
+	err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
+		WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekDay).OrderDesc("id").Scan(&listA)
+	if err != nil {
+		g.Log().Error("获取A类超期3天未跟进项目", err)
+	}
+	if len(listA) > 0 {
+		list = append(list, listA...)
+	}
+	err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
+		WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekDay).OrderDesc("id").Scan(&listB)
+	if err != nil {
+		g.Log().Error("获取B类超期3天未跟进项目", err)
+	}
+	if len(listB) > 0 {
+		list = append(list, listB...)
+	}
+	err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
+		WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthDay).OrderDesc("id").Scan(&listC)
+	if err != nil {
+		g.Log().Error("获取C类超期3天未跟进项目", err)
+	}
+	if len(listC) > 0 {
+		list = append(list, listC...)
+	}
+	if err != nil {
+		g.Log().Error("获取未跟进项目", err)
+	}
+	ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
+	rsp, err := service.GetDictDataByType(ctx, "proj_nbo_type")
+	if err != nil {
+		g.Log().Error("项目类别数据字典", err)
+	}
+	if err != nil {
+		g.Log().Error("获取未跟进项目", err)
+		return
+	}
+	var msg string
+	if len(list) > 0 {
+		msg += fmt.Sprintf("您有超期3天未跟进项目%v个,请登录系统查看", len(list))
+	}
+	f := excelize.NewFile()
+	f.MergeCell("Sheet1", "A1", "D1")
+	style, _ := f.NewStyle(`{"alignment":{"horizontal":"center"}}`)
+	f.SetCellValue("Sheet1", "A1", "超期三天未跟进项目")
+	f.SetCellStyle("sheet1", "A1", "D1", style)
+	f.SetColWidth("Sheet1", "A", "K", 20)
+	f.SetCellValue("Sheet1", "A2", "序号")
+	f.SetCellValue("Sheet1", "B2", "项目名称")
+	f.SetCellValue("Sheet1", "C2", "项目类别")
+	f.SetCellValue("Sheet1", "D2", "最新跟进时间")
+	line := 2
+	if len(list) > 0 {
+		for _, v := range list {
+			line++
+			f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), gconv.String(line-2))
+			f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.NboName)
+			if len(rsp) > 0 {
+				f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), rsp[v.NboType])
+			} else {
+				f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.NboType)
+			}
+			f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.FinalFollowTime)
+
+		}
+	}
+	dir := g.Config().GetString("file.cronstatic")
+	filename := "项目跟进" + gconv.String(time.Now().UnixNano()) + ".xlsx"
+	path := dir + filename
+	if err = f.SaveAs(path); err != nil {
+		g.Log().Error("Excel保存失败", err)
+	}
+	if len(salesAssociate) > 0 {
+		for _, val := range salesAssociate {
+			if val == "" {
+				continue
+			}
+			msgs := g.MapStrStr{
+				"msgTitle":    "超期3天未跟进项目提醒",
+				"msgContent":  msg,
+				"recvUserIds": "1",
+				"recvUser":    "系统管理员",
+				"opnUrl":      path,
+			}
+			if err = service.GSendMail(msgs); err != nil {
+				g.Log().Error("SendMail() error = %v", err)
+			}
+		}
+
+	}
+
+}
+
 type FollowOverdue struct {
 	SaleId int64 `json:"saleId"`
 	Count  int64 `json:"count"`
@@ -337,3 +466,15 @@ func notifyMessage(ids, message string) {
 		glog.Error("消息提醒异常:", err)
 	}
 }
+
+type alignment struct {
+	horizontal      string `json:"horizontal"`
+	indent          int    `json:"indent"`
+	justifylastline bool   `json:"justify_last_line"`
+	readingorder    uint64 `json:"reading_order"`
+	relativeindent  int    `json:"relative_indent"`
+	shrinktofit     bool   `json:"shrink_to_fit"`
+	textrotation    int    `json:"text_rotation"`
+	vertical        string `json:"vertical"`
+	wraptext        bool   `json:"wrap_text"`
+}

BIN
opms_parent/app/static/项目跟进1680592053758030700.xlsx