| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- package cust
- import (
- "dashoo.cn/micro/app/service"
- "dashoo.cn/opms_libary/plugin/dingtalk"
- "dashoo.cn/opms_libary/plugin/dingtalk/message/corpconversation"
- "fmt"
- "github.com/360EntSecGroup-Skylar/excelize"
- "github.com/gogf/gf/frame/g"
- "github.com/gogf/gf/os/glog"
- "github.com/gogf/gf/os/gtime"
- "github.com/gogf/gf/util/gconv"
- "github.com/robfig/cron"
- "os"
- )
- // 初始化,创建每10分钟执行一次的定时任务
- func init() {
- // 定时任务
- c := cron.New()
- spec1 := "0 0 20 * * ?" // 每晚八点
- spec2 := "0 0 18 * * 0" // 每周日晚6点
- spec3 := "0 0 20 * * ?" // 每晚八点
- // 新增招标信息每晚8点
- if err := c.AddJob(spec1, NewBidCron{}); err != nil {
- glog.Error(err)
- }
- // 未跟进的招标信息,每周日晚上6点
- if err := c.AddJob(spec2, NotFollowBidCron{}); err != nil {
- glog.Error(err)
- }
- // 超过2个月没有创建项目以及没有申请闭环的招投标进入已超期
- if err := c.AddJob(spec3, OverdueBidCron{}); err != nil {
- glog.Error(err)
- }
- c.Start()
- }
- // NewBidCron 新增招标信息
- type NewBidCron struct {
- }
- // NotFollowBidCron 未跟进的招标信息
- type NotFollowBidCron struct {
- }
- // OverdueBidCron 招标信息超期
- type OverdueBidCron struct {
- }
- // Run 新增招标信息提醒
- func (c NewBidCron) Run() {
- tenant := g.Config().GetString("micro_srv.tenant")
- if tenant == "" {
- glog.Error("租户码未设置,请前往配置")
- return
- }
- // 当前时间
- date := gtime.Now()
- bidInfos, err := g.DB(tenant).Model("cust_customer_bid_record a").InnerJoin("cust_customer b", "a.cust_id=b.id").Where(fmt.Sprintf("a.created_time LIKE '%v%%'", date.Format("Y-m-d"))).Fields("a.*,b.sales_id").All()
- if err != nil {
- glog.Error(err)
- return
- }
- data := make(map[int][]map[string]string)
- for _, contract := range bidInfos {
- id := gconv.Int(contract["sales_id"])
- if _, ok := data[id]; !ok {
- data[id] = make([]map[string]string, 0)
- }
- d := map[string]string{
- "cuct_name": gconv.String(contract["cuct_name"]),
- "product_name": gconv.String(contract["product_name"]),
- "published_time": contract["published_time"].GTime().Format("Y-m-d"),
- "title": gconv.String(contract["title"]),
- "budget": fmt.Sprintf("%.2f", contract["budget"].Float64()),
- }
- data[id] = append(data[id], d)
- }
- if len(data) > 0 {
- for id, collections := range data {
- f := excelize.NewFile()
- // Create a new sheet.
- sheet := f.NewSheet("Sheet1")
- // 表头
- f.SetCellValue("Sheet1", Div(1)+"1", "客户名称")
- f.SetCellValue("Sheet1", Div(2)+"1", "招标产品名称")
- f.SetCellValue("Sheet1", Div(3)+"1", "发布招标日期")
- f.SetCellValue("Sheet1", Div(4)+"1", "招标信息标题")
- f.SetCellValue("Sheet1", Div(4)+"1", "项目预算")
- for index, collection := range collections {
- f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["cuct_name"])
- f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["product_name"])
- f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["published_time"])
- f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["title"])
- f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["budget"])
- }
- // Set active sheet of the workbook.
- f.SetActiveSheet(sheet)
- // Save xlsx file by the given path.
- file := "./temp/新增招标信息.xlsx"
- _, err = createPath("./temp")
- if err != nil {
- glog.Error(err)
- return
- }
- if err = f.SaveAs(file); err != nil {
- glog.Error(err)
- return
- }
- fileId, err := uploadFile(file)
- if err != nil {
- glog.Error(err)
- return
- }
- notifyMessageFile("新增招标信息提醒", gconv.String(id), fileId)
- // 删除已存在的文件
- err = os.Remove(file)
- if err != nil {
- glog.Error(err)
- return
- }
- }
- }
- }
- // Run 未跟进的招标信息提醒
- func (c NotFollowBidCron) Run() {
- tenant := g.Config().GetString("micro_srv.tenant")
- if tenant == "" {
- glog.Error("租户码未设置,请前往配置")
- return
- }
- // 当前时间
- bidInfos, err := g.DB(tenant).Model("cust_customer_bid_record a").InnerJoin("cust_customer b", "a.cust_id=b.id").LeftJoin("(SELECT * FROM plat_followup WHERE target_type='60') c", "c.target_id=a.id").Where("c.id IS NULL").Group("a.id").Fields("a.*,b.sales_id").All()
- if err != nil {
- glog.Error(err)
- return
- }
- data := make(map[int][]map[string]string)
- for _, contract := range bidInfos {
- id := gconv.Int(contract["sales_id"])
- if _, ok := data[id]; !ok {
- data[id] = make([]map[string]string, 0)
- }
- d := map[string]string{
- "cuct_name": gconv.String(contract["cuct_name"]),
- "product_name": gconv.String(contract["product_name"]),
- "published_time": contract["published_time"].GTime().Format("Y-m-d"),
- "title": gconv.String(contract["title"]),
- "budget": fmt.Sprintf("%.2f", contract["budget"].Float64()),
- }
- data[id] = append(data[id], d)
- }
- if len(data) > 0 {
- for id, collections := range data {
- f := excelize.NewFile()
- // Create a new sheet.
- sheet := f.NewSheet("Sheet1")
- // 表头
- f.SetCellValue("Sheet1", Div(1)+"1", "客户名称")
- f.SetCellValue("Sheet1", Div(2)+"1", "招标产品名称")
- f.SetCellValue("Sheet1", Div(3)+"1", "发布招标日期")
- f.SetCellValue("Sheet1", Div(4)+"1", "招标信息标题")
- f.SetCellValue("Sheet1", Div(4)+"1", "项目预算")
- for index, collection := range collections {
- f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["cuct_name"])
- f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["product_name"])
- f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["published_time"])
- f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["title"])
- f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["budget"])
- }
- // Set active sheet of the workbook.
- f.SetActiveSheet(sheet)
- // Save xlsx file by the given path.
- file := "./temp/未跟进的招标信息.xlsx"
- _, err = createPath("./temp")
- if err != nil {
- glog.Error(err)
- return
- }
- if err = f.SaveAs(file); err != nil {
- glog.Error(err)
- return
- }
- fileId, err := uploadFile(file)
- if err != nil {
- glog.Error(err)
- return
- }
- notifyMessageFile("未跟进的招标信息提醒", gconv.String(id), fileId)
- // 删除已存在的文件
- err = os.Remove(file)
- if err != nil {
- glog.Error(err)
- return
- }
- }
- }
- }
- func (c OverdueBidCron) Run() {
- tenant := g.Config().GetString("micro_srv.tenant")
- if tenant == "" {
- glog.Error("租户码未设置,请前往配置")
- return
- }
- date := gtime.Now().AddDate(0, -2, 0).Format("Y-m-d 00:00:00")
- // 从项目发布日期起,超过2个月没有创建项目以及没有申请闭环的招投标进入已超期
- // 状态:(10跟进中,20待审批,30已闭环、40已超期)
- bidInfos, err := g.DB(tenant).Model("cust_customer_bid_record a").LeftJoin("proj_business b", "b.bid_id=a.id").Where(fmt.Sprintf("b.id IS NULL AND a.status='10' AND a.created_time<'%v'", date)).Group("a.id").Fields("a.*").All()
- if err != nil {
- glog.Error(err)
- return
- }
- if len(bidInfos) > 0 {
- ids := ""
- for _, bid := range bidInfos {
- if ids == "" {
- ids = gconv.String(bid["id"])
- } else {
- ids += "," + gconv.String(bid["id"])
- }
- }
- _, err = g.DB(tenant).Model("cust_customer_bid_record").Update("status='40'", fmt.Sprintf("id IN (%v)", ids))
- if err != nil {
- glog.Error(err)
- return
- }
- }
- }
- func uploadFile(file string) (string, error) {
- var request corpconversation.UploadConversationFileRequest
- request.Type = "file"
- request.FileData = "media"
- request.FilePath = file
- c := dingtalk.Client.GetCorpConversation()
- resp, err := c.UploadConversationFile(&request)
- if err != nil {
- fmt.Println(err)
- return "", err
- }
- return resp.MediaId, nil
- }
- // notifyMessageFile 发送消息通知
- func notifyMessageFile(title, ids, message string) {
- msg := g.MapStrStr{
- "msgTitle": title,
- "msgContent": message,
- "msgType": "40", // 文件处理
- "recvUserIds": ids,
- "msgStatus": "10",
- "sendType": "30",
- }
- if err := service.CreateSystemMessage(msg); err != nil {
- glog.Error("消息提醒异常:", err)
- }
- }
- // 判断文件夹是否存在
- func pathExists(path string) (bool, error) {
- _, err := os.Stat(path)
- if err == nil {
- return true, nil
- }
- if os.IsNotExist(err) {
- return false, nil
- }
- return false, err
- }
- func createPath(path string) (bool, error) {
- exist, err := pathExists(path)
- if err != nil {
- return false, err
- }
- if exist {
- return true, nil
- } else {
- // 创建文件夹
- err := os.MkdirAll(path, os.ModePerm)
- if err != nil {
- return false, err
- } else {
- return true, err
- }
- }
- }
- // Div 数字转字母
- func Div(Num int) string {
- var (
- Str string = ""
- k int
- temp []int //保存转化后每一位数据的值,然后通过索引的方式匹配A-Z
- )
- //用来匹配的字符A-Z
- Slice := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
- "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
- if Num > 26 { //数据大于26需要进行拆分
- for {
- k = Num % 26 //从个位开始拆分,如果求余为0,说明末尾为26,也就是Z,如果是转化为26进制数,则末尾是可以为0的,这里必须为A-Z中的一个
- if k == 0 {
- temp = append(temp, 26)
- k = 26
- } else {
- temp = append(temp, k)
- }
- Num = (Num - k) / 26 //减去Num最后一位数的值,因为已经记录在temp中
- if Num <= 26 { //小于等于26直接进行匹配,不需要进行数据拆分
- temp = append(temp, Num)
- break
- }
- }
- } else {
- return Slice[Num]
- }
- for _, value := range temp {
- Str = Slice[value] + Str //因为数据切分后存储顺序是反的,所以Str要放在后面
- }
- return Str
- }
|