cust_cron.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. package cust
  2. import (
  3. "dashoo.cn/micro/app/service"
  4. "dashoo.cn/opms_libary/plugin/dingtalk"
  5. "dashoo.cn/opms_libary/plugin/dingtalk/message/corpconversation"
  6. "fmt"
  7. "github.com/360EntSecGroup-Skylar/excelize"
  8. "github.com/gogf/gf/frame/g"
  9. "github.com/gogf/gf/os/glog"
  10. "github.com/gogf/gf/os/gtime"
  11. "github.com/gogf/gf/util/gconv"
  12. "github.com/robfig/cron"
  13. "os"
  14. )
  15. // 初始化,创建每10分钟执行一次的定时任务
  16. func init() {
  17. // 定时任务
  18. c := cron.New()
  19. spec1 := "0 0 20 * * ?" // 每晚八点
  20. spec2 := "0 0 18 * * 0" // 每周日晚6点
  21. // 新增招标信息每晚8点
  22. if err := c.AddJob(spec1, NewBidCron{}); err != nil {
  23. glog.Error(err)
  24. }
  25. // 未跟进的招标信息,每周日晚上6点
  26. if err := c.AddJob(spec2, NotFollowBidCron{}); err != nil {
  27. glog.Error(err)
  28. }
  29. c.Start()
  30. }
  31. // NewBidCron 新增招标信息
  32. type NewBidCron struct {
  33. }
  34. // NotFollowBidCron 未跟进的招标信息
  35. type NotFollowBidCron struct {
  36. }
  37. // Run 新增招标信息提醒
  38. func (c NewBidCron) Run() {
  39. tenant := g.Config().GetString("micro_srv.tenant")
  40. if tenant == "" {
  41. glog.Error("交接任务单定时任务租户码未设置,请前往配置")
  42. return
  43. }
  44. // 当前时间
  45. date := gtime.Now()
  46. 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()
  47. if err != nil {
  48. glog.Error(err)
  49. return
  50. }
  51. data := make(map[int][]map[string]string)
  52. for _, contract := range bidInfos {
  53. id := gconv.Int(contract["sales_id"])
  54. if _, ok := data[id]; !ok {
  55. data[id] = make([]map[string]string, 0)
  56. }
  57. d := map[string]string{
  58. "cuct_name": gconv.String(contract["cuct_name"]),
  59. "product_name": gconv.String(contract["product_name"]),
  60. "published_time": contract["published_time"].GTime().Format("Y-m-d"),
  61. "title": gconv.String(contract["title"]),
  62. "budget": fmt.Sprintf("%.2f", contract["budget"].Float64()),
  63. }
  64. data[id] = append(data[id], d)
  65. }
  66. if len(data) > 0 {
  67. for id, collections := range data {
  68. f := excelize.NewFile()
  69. // Create a new sheet.
  70. sheet := f.NewSheet("Sheet1")
  71. // 表头
  72. f.SetCellValue("Sheet1", Div(1)+"1", "客户名称")
  73. f.SetCellValue("Sheet1", Div(2)+"1", "招标产品名称")
  74. f.SetCellValue("Sheet1", Div(3)+"1", "发布招标日期")
  75. f.SetCellValue("Sheet1", Div(4)+"1", "招标信息标题")
  76. f.SetCellValue("Sheet1", Div(4)+"1", "项目预算")
  77. for index, collection := range collections {
  78. f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["cuct_name"])
  79. f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["product_name"])
  80. f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["published_time"])
  81. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["title"])
  82. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["budget"])
  83. }
  84. // Set active sheet of the workbook.
  85. f.SetActiveSheet(sheet)
  86. // Save xlsx file by the given path.
  87. file := "./temp/新增招标信息.xlsx"
  88. _, err = createPath("./temp")
  89. if err != nil {
  90. glog.Error(err)
  91. return
  92. }
  93. if err = f.SaveAs(file); err != nil {
  94. glog.Error(err)
  95. return
  96. }
  97. fileId, err := uploadFile(file)
  98. if err != nil {
  99. glog.Error(err)
  100. return
  101. }
  102. notifyMessageFile("新增招标信息提醒", gconv.String(id), fileId)
  103. // 删除已存在的文件
  104. err = os.Remove(file)
  105. if err != nil {
  106. glog.Error(err)
  107. return
  108. }
  109. }
  110. }
  111. }
  112. // Run 未跟进的招标信息提醒
  113. func (c NotFollowBidCron) Run() {
  114. tenant := g.Config().GetString("micro_srv.tenant")
  115. if tenant == "" {
  116. glog.Error("交接任务单定时任务租户码未设置,请前往配置")
  117. return
  118. }
  119. // 当前时间
  120. 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()
  121. if err != nil {
  122. glog.Error(err)
  123. return
  124. }
  125. data := make(map[int][]map[string]string)
  126. for _, contract := range bidInfos {
  127. id := gconv.Int(contract["sales_id"])
  128. if _, ok := data[id]; !ok {
  129. data[id] = make([]map[string]string, 0)
  130. }
  131. d := map[string]string{
  132. "cuct_name": gconv.String(contract["cuct_name"]),
  133. "product_name": gconv.String(contract["product_name"]),
  134. "published_time": contract["published_time"].GTime().Format("Y-m-d"),
  135. "title": gconv.String(contract["title"]),
  136. "budget": fmt.Sprintf("%.2f", contract["budget"].Float64()),
  137. }
  138. data[id] = append(data[id], d)
  139. }
  140. if len(data) > 0 {
  141. for id, collections := range data {
  142. f := excelize.NewFile()
  143. // Create a new sheet.
  144. sheet := f.NewSheet("Sheet1")
  145. // 表头
  146. f.SetCellValue("Sheet1", Div(1)+"1", "客户名称")
  147. f.SetCellValue("Sheet1", Div(2)+"1", "招标产品名称")
  148. f.SetCellValue("Sheet1", Div(3)+"1", "发布招标日期")
  149. f.SetCellValue("Sheet1", Div(4)+"1", "招标信息标题")
  150. f.SetCellValue("Sheet1", Div(4)+"1", "项目预算")
  151. for index, collection := range collections {
  152. f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["cuct_name"])
  153. f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["product_name"])
  154. f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["published_time"])
  155. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["title"])
  156. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["budget"])
  157. }
  158. // Set active sheet of the workbook.
  159. f.SetActiveSheet(sheet)
  160. // Save xlsx file by the given path.
  161. file := "./temp/未跟进的招标信息.xlsx"
  162. _, err = createPath("./temp")
  163. if err != nil {
  164. glog.Error(err)
  165. return
  166. }
  167. if err = f.SaveAs(file); err != nil {
  168. glog.Error(err)
  169. return
  170. }
  171. fileId, err := uploadFile(file)
  172. if err != nil {
  173. glog.Error(err)
  174. return
  175. }
  176. notifyMessageFile("未跟进的招标信息提醒", gconv.String(id), fileId)
  177. // 删除已存在的文件
  178. err = os.Remove(file)
  179. if err != nil {
  180. glog.Error(err)
  181. return
  182. }
  183. }
  184. }
  185. }
  186. func uploadFile(file string) (string, error) {
  187. var request corpconversation.UploadConversationFileRequest
  188. request.Type = "file"
  189. request.FileData = "media"
  190. request.FilePath = file
  191. c := dingtalk.Client.GetCorpConversation()
  192. resp, err := c.UploadConversationFile(&request)
  193. if err != nil {
  194. fmt.Println(err)
  195. return "", err
  196. }
  197. return resp.MediaId, nil
  198. }
  199. // notifyMessageFile 发送消息通知
  200. func notifyMessageFile(title, ids, message string) {
  201. msg := g.MapStrStr{
  202. "msgTitle": title,
  203. "msgContent": message,
  204. "msgType": "40", // 文件处理
  205. "recvUserIds": ids,
  206. "msgStatus": "10",
  207. "sendType": "30",
  208. }
  209. if err := service.CreateSystemMessage(msg); err != nil {
  210. glog.Error("消息提醒异常:", err)
  211. }
  212. }
  213. // 判断文件夹是否存在
  214. func pathExists(path string) (bool, error) {
  215. _, err := os.Stat(path)
  216. if err == nil {
  217. return true, nil
  218. }
  219. if os.IsNotExist(err) {
  220. return false, nil
  221. }
  222. return false, err
  223. }
  224. func createPath(path string) (bool, error) {
  225. exist, err := pathExists(path)
  226. if err != nil {
  227. return false, err
  228. }
  229. if exist {
  230. return true, nil
  231. } else {
  232. // 创建文件夹
  233. err := os.MkdirAll(path, os.ModePerm)
  234. if err != nil {
  235. return false, err
  236. } else {
  237. return true, err
  238. }
  239. }
  240. }
  241. // Div 数字转字母
  242. func Div(Num int) string {
  243. var (
  244. Str string = ""
  245. k int
  246. temp []int //保存转化后每一位数据的值,然后通过索引的方式匹配A-Z
  247. )
  248. //用来匹配的字符A-Z
  249. Slice := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
  250. "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
  251. if Num > 26 { //数据大于26需要进行拆分
  252. for {
  253. k = Num % 26 //从个位开始拆分,如果求余为0,说明末尾为26,也就是Z,如果是转化为26进制数,则末尾是可以为0的,这里必须为A-Z中的一个
  254. if k == 0 {
  255. temp = append(temp, 26)
  256. k = 26
  257. } else {
  258. temp = append(temp, k)
  259. }
  260. Num = (Num - k) / 26 //减去Num最后一位数的值,因为已经记录在temp中
  261. if Num <= 26 { //小于等于26直接进行匹配,不需要进行数据拆分
  262. temp = append(temp, Num)
  263. break
  264. }
  265. }
  266. } else {
  267. return Slice[Num]
  268. }
  269. for _, value := range temp {
  270. Str = Slice[value] + Str //因为数据切分后存储顺序是反的,所以Str要放在后面
  271. }
  272. return Str
  273. }