plat_task.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. package plat
  2. import (
  3. "bytes"
  4. "context"
  5. "database/sql"
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "dashoo.cn/opms_libary/myerrors"
  10. "github.com/360EntSecGroup-Skylar/excelize"
  11. "github.com/gogf/gf/frame/g"
  12. "github.com/gogf/gf/os/gtime"
  13. "github.com/gogf/gf/util/gconv"
  14. "dashoo.cn/micro/app/dao/plat"
  15. model "dashoo.cn/micro/app/model/plat"
  16. "dashoo.cn/micro/app/service"
  17. )
  18. type taskService struct {
  19. *service.ContextService
  20. Dao *plat.PlatTaskDao
  21. }
  22. func NewTaskService(ctx context.Context) (svc *taskService, err error) {
  23. svc = new(taskService)
  24. if svc.ContextService, err = svc.Init(ctx); err != nil {
  25. return nil, err
  26. }
  27. svc.Dao = plat.NewPlatTaskDao(svc.Tenant)
  28. return svc, nil
  29. }
  30. // 任务信息列表
  31. func (s *taskService) GetList(req *model.SearchPlatTaskReq) (total int, TaskList []*model.PlatTaskEx, err error) {
  32. TaskModel := s.Dao.InnerJoin("plat_task_handle", "plat_task_handle.task_id=plat_task.id")
  33. if req.TaskTitle != "" {
  34. TaskModel = TaskModel.Where("plat_task.task_title LIKE ?", "%"+req.TaskTitle+"%")
  35. }
  36. if req.TaskType != "" {
  37. TaskModel = TaskModel.Where("plat_task.task_type", req.TaskType)
  38. }
  39. if req.TaskStatus != "" {
  40. TaskModel = TaskModel.Where("plat_task.task_status", req.TaskStatus)
  41. }
  42. if req.IsOverdue != "" {
  43. TaskModel = TaskModel.Where("plat_task.is_overdue", req.IsOverdue)
  44. }
  45. if req.MainUserId != "" {
  46. TaskModel = TaskModel.Where("plat_task.main_user_id", req.MainUserId)
  47. }
  48. if req.TargetId != "" {
  49. TaskModel = TaskModel.Where("plat_task.target_id", req.TargetId)
  50. }
  51. if req.TargetType != "" {
  52. TaskModel = TaskModel.Where("plat_task.target_type", req.TargetType)
  53. }
  54. if req.MySelf == "1" {
  55. TaskModel = TaskModel.Where("plat_task.created_by", s.GetCxtUserId())
  56. }
  57. if req.IsMain == "1" {
  58. TaskModel = TaskModel.Where("plat_task.main_user_id", s.GetCxtUserId())
  59. }
  60. if req.OperateType == "1" {
  61. TaskModel = TaskModel.Where(fmt.Sprintf("plat_task_handle.task_status='10' AND (plat_task_handle.main_user_id=%v OR FIND_IN_SET(%v, plat_task_handle.owner_user_id))", s.GetCxtUserId(), s.GetCxtUserId()))
  62. } else if req.OperateType == "2" {
  63. TaskModel = TaskModel.Where("plat_task.created_by", s.GetCxtUserId())
  64. } else if req.OperateType == "3" {
  65. TaskModel = TaskModel.Where(fmt.Sprintf("plat_task_handle.task_status='20' AND plat_task_handle.handle_user_id=%v", s.GetCxtUserId()))
  66. }
  67. TaskModel = TaskModel.Group("plat_task.id")
  68. total, err = TaskModel.Count()
  69. if err != nil {
  70. g.Log().Error(err)
  71. err = myerrors.DbError("获取总行数失败。")
  72. return
  73. }
  74. err = TaskModel.Page(req.GetPage()).Order("plat_task.created_time DESC").Fields("plat_task.*,plat_task_handle.step").Scan(&TaskList)
  75. return
  76. }
  77. // 导出数据
  78. func (s *taskService) Export(req *model.ExportReq) (content *model.ExportContent, err error) {
  79. var con model.ExportContent
  80. // 获取数据
  81. total, list, err := s.GetList(&req.SearchPlatTaskReq)
  82. if err != nil {
  83. return nil, err
  84. }
  85. //rsp.List
  86. f := excelize.NewFile()
  87. // Create a new sheet.
  88. index := f.NewSheet("Sheet1")
  89. for index, item := range req.Columns {
  90. sheetPosition := service.Div(index+1) + "1"
  91. f.SetCellValue("Sheet1", sheetPosition, item)
  92. }
  93. if total > 0 {
  94. // 构造用户和类型填充数据
  95. userMap := make(map[int]string, 0)
  96. typeMap := make(map[string]string, 0)
  97. users, err := s.Dao.DB.Model("sys_user").FindAll()
  98. if err != nil {
  99. return nil, err
  100. }
  101. types, err := s.Dao.DB.Model("sys_dict_data").Where("dict_type='TaskType'").FindAll()
  102. if err != nil {
  103. return nil, err
  104. }
  105. for _, item := range users {
  106. userMap[item["id"].Int()] = item["nick_name"].String()
  107. }
  108. for _, item := range types {
  109. typeMap[item["dict_value"].String()] = item["dict_label"].String()
  110. }
  111. // 构造excel数据
  112. for lineNum, item := range list {
  113. for index, value := range req.Columns {
  114. if value == "督办标题" {
  115. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.TaskTitle)
  116. }
  117. if value == "督办类型" {
  118. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), typeMap[item.TaskType])
  119. }
  120. if value == "状态" {
  121. data := ""
  122. if item.TaskStatus == "10" {
  123. data = "发起"
  124. } else if item.TaskStatus == "20" {
  125. data = "进行中"
  126. } else if item.TaskStatus == "30" {
  127. data = "流程完成"
  128. }
  129. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), data)
  130. }
  131. if value == "督办事项来源" {
  132. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.Source)
  133. }
  134. if value == "超期" {
  135. data := ""
  136. if gtime.Now().Format("Y-m-d H:i:s") <= item.TaskEndDate.Format("Y-m-d 23:59:59") {
  137. data = "否"
  138. } else {
  139. data = "是"
  140. }
  141. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), data)
  142. }
  143. if value == "督办说明" {
  144. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.TaskDesc)
  145. }
  146. if value == "关联对象" {
  147. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.TargetName)
  148. }
  149. if value == "负责人" {
  150. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), userMap[item.MainUserId])
  151. }
  152. if value == "协办人" {
  153. names := ""
  154. if item.OwnerUserId != "" {
  155. ids := strings.Split(item.OwnerUserId, ",")
  156. for _, id := range ids {
  157. if names == "" {
  158. names = userMap[gconv.Int(id)]
  159. } else {
  160. names += "," + userMap[gconv.Int(id)]
  161. }
  162. }
  163. }
  164. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), names)
  165. }
  166. if value == "督办人" {
  167. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), userMap[item.SupervisorUserId])
  168. }
  169. if value == "发布时间" {
  170. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.TaskStartDate.Format("Y-m-d"))
  171. }
  172. if value == "要求完成时间" {
  173. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.TaskEndDate.Format("Y-m-d"))
  174. }
  175. if value == "创建时间" {
  176. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(lineNum+2), item.CreatedTime.Format("Y-m-d H:i:s"))
  177. }
  178. }
  179. }
  180. }
  181. f.SetActiveSheet(index)
  182. var buffer *bytes.Buffer
  183. buffer, _ = f.WriteToBuffer()
  184. con.Content = buffer.Bytes()
  185. return &con, err
  186. }
  187. // 统计
  188. func (s *taskService) Statistics(req *model.SearchPlatTaskReq) (*model.TaskNumberCount, error) {
  189. var result model.TaskNumberCount
  190. // 统计数量
  191. count, err := s.Dao.InnerJoin("plat_task_handle", "plat_task.Id=plat_task_handle.task_id").Where(fmt.Sprintf("plat_task_handle.task_status='10' AND (plat_task_handle.main_user_id=%v OR FIND_IN_SET(%v, plat_task_handle.owner_user_id))", s.GetCxtUserId(), s.GetCxtUserId())).Group("plat_task.Id").Count()
  192. if err != nil {
  193. return nil, err
  194. }
  195. result.ToDoNumber = count
  196. return &result, nil
  197. }
  198. // 添加信息
  199. func (s *taskService) Create(req *model.AddPlatTaskReq) (err error) {
  200. platTask := new(model.PlatTask)
  201. if err = gconv.Struct(req, platTask); err != nil {
  202. return
  203. }
  204. // 初始数据
  205. platTask.IsOverdue = "10" // 是否超期(10否20是)
  206. if platTask.TaskStartDate == nil || platTask.TaskStartDate.IsZero() {
  207. platTask.TaskStartDate = gtime.Now()
  208. }
  209. // 填充创建信息
  210. service.SetCreatedInfo(platTask, s.GetCxtUserId(), s.GetCxtUserName())
  211. // 填充更新信息
  212. //service.SetUpdatedInfo(platTask, s.GetCxtUserId(), s.GetCxtUserName())
  213. res, err := s.Dao.Insert(platTask)
  214. if err != nil {
  215. return
  216. }
  217. // 创建操作任务
  218. id, _ := res.LastInsertId()
  219. platTask.Id = int(id)
  220. nextHandle := createNextTaskHandel(s, platTask, 10)
  221. _, err = s.Dao.DB.Insert("plat_task_handle", nextHandle)
  222. if err != nil {
  223. return
  224. }
  225. // 流程日志
  226. err = CreateTaskLog(s, nil, int(id), s.GetCxtUserId(), s.GetCxtUserName(), "创建督办", "创建督办成功", "")
  227. return
  228. }
  229. // 修改状态
  230. func (s *taskService) ChangeStatus(req *model.ChangeStatusReq) (err error) {
  231. data := ""
  232. where := fmt.Sprintf("id='%v'", req.TaskId)
  233. nodeName := "状态修改"
  234. desc := "修改成功"
  235. // 类型合规判断
  236. if req.Type == "TaskStatus" {
  237. data = fmt.Sprintf("task_status='%v'", req.NowStatus)
  238. nodeName = "状态修改"
  239. if req.NowStatus == "20" {
  240. desc = "关闭"
  241. data += fmt.Sprintf(",task_end_date='%v'", gtime.Now().Format("Y-m-d H:i:s"))
  242. }
  243. } else if req.Type == "IsOverdue" {
  244. nodeName = "超期状态修改"
  245. if req.NowStatus == "20" {
  246. desc = "超期"
  247. }
  248. data = fmt.Sprintf("is_overdue='%v'", req.NowStatus)
  249. } else {
  250. err = myerrors.TipsError("类型不匹配,请仔细检查。")
  251. return err
  252. }
  253. // 读取现有数据
  254. task, err := s.Dao.Where(where).FindOne()
  255. if err != nil {
  256. return err
  257. }
  258. if task == nil {
  259. err = myerrors.TipsError("数据异常,无匹配数据。")
  260. return err
  261. }
  262. // 状态数据一致性判断
  263. if (req.Type == "TaskStatus" && task.TaskStatus != req.OldStatus) || (req.Type == "IsOverdue" && task.IsOverdue != req.OldStatus) {
  264. err = myerrors.TipsError("状态不匹配,进行该操作")
  265. return err
  266. }
  267. // 更新数据
  268. _, err = s.Dao.Update(data, where)
  269. if err != nil {
  270. return
  271. }
  272. // 流程日志
  273. taskId, _ := strconv.Atoi(req.TaskId)
  274. err = CreateTaskLog(s, nil, taskId, s.GetCxtUserId(), s.GetCxtUserName(), nodeName, desc, "")
  275. return
  276. }
  277. //步骤号(10接收 15暂存 20提交 30审批(督办人) 40评价(监办人))
  278. // 督办任务处理
  279. func (s *taskService) Handle(req *model.HandleReq) (err error) {
  280. // 步骤号(10接收 15暂存 20提交 30审批(督办人) 40评价(监办人))
  281. // 处理结果(10接收20提交30审批通过40审批退回)
  282. logNodeName := ""
  283. logDesc := ""
  284. var taskHandle model.PlatTaskHandle
  285. if req.Step != 15 {
  286. err = s.Dao.DB.Model("plat_task_handle").Where(fmt.Sprintf("task_id='%v' AND step=%v AND task_status='10' AND (main_user_id=%v OR FIND_IN_SET(%v, owner_user_id))", req.TaskId, req.Step, s.GetCxtUserId(), s.GetCxtUserId())).Scan(&taskHandle)
  287. if err != nil {
  288. if err == sql.ErrNoRows {
  289. err = myerrors.TipsError("数据不匹配,刷新数据重试")
  290. return err
  291. }
  292. return err
  293. }
  294. }
  295. now := gtime.Now()
  296. // 数据暂存,不做任何流程修改
  297. if req.Step == 15 {
  298. // 暂存
  299. logNodeName = "暂存"
  300. logDesc = s.GetCxtUserName() + "暂存进展信息"
  301. // 更新进展数据
  302. err = s.saveProgressList(req, now)
  303. if err != nil {
  304. return err
  305. }
  306. } else {
  307. var nextHandle = new(model.PlatTaskHandle)
  308. task, err := s.Dao.Where("id", req.TaskId).FindOne()
  309. if err != nil {
  310. return err
  311. }
  312. if task == nil {
  313. err = myerrors.TipsError("数据异常,无匹配数据")
  314. return err
  315. }
  316. // 构造更新数据
  317. handleData := g.Map{
  318. "task_status": "20",
  319. "handle_user_id": s.GetCxtUserId(),
  320. "handle_date": now.Format("Y-m-d H:i:s"),
  321. "handle_status": req.HandleStatus,
  322. "handle_desc": req.HandleDesc,
  323. "updated_by": s.GetCxtUserId(),
  324. "updated_name": s.GetCxtUserName(),
  325. "updated_time": now.Format("Y-m-d H:i:s"),
  326. }
  327. taskData := g.Map{
  328. "updated_by": s.GetCxtUserId(),
  329. "updated_name": s.GetCxtUserName(),
  330. "updated_time": now.Format("Y-m-d H:i:s"),
  331. }
  332. // 督办任务接收
  333. if req.Step == 10 {
  334. // 接收任务
  335. taskData["task_status"] = "20"
  336. taskData["receive_date"] = now.Format("Y-m-d H:i:s")
  337. nextHandle = createNextTaskHandel(s, task, 20)
  338. logNodeName = "接收"
  339. logDesc = s.GetCxtUserName() + "接收督办任务"
  340. } else if req.Step == 20 {
  341. // 提交数据
  342. nextHandle = createNextTaskHandel(s, task, 30)
  343. logNodeName = "提交"
  344. logDesc = s.GetCxtUserName() + "提交督办任务"
  345. // 更新进展数据
  346. err = s.saveProgressList(req, now)
  347. if err != nil {
  348. return err
  349. }
  350. } else if req.Step == 30 {
  351. // 督办人审批
  352. taskData["approver_id"] = s.GetCxtUserId()
  353. taskData["appro_date"] = now.Format("Y-m-d H:i:s")
  354. taskData["appro_status"] = req.HandleStatus
  355. taskData["appro_desc"] = req.HandleDesc
  356. logNodeName = "审批"
  357. if req.HandleStatus == "30" {
  358. logDesc = s.GetCxtUserName() + "审批通过"
  359. nextHandle = createNextTaskHandel(s, task, 40)
  360. } else if req.HandleStatus == "40" {
  361. logDesc = s.GetCxtUserName() + "审批退回"
  362. nextHandle = createNextTaskHandel(s, task, 20)
  363. }
  364. } else if req.Step == 40 {
  365. // 监办人评价
  366. taskData["evaluator_id"] = s.GetCxtUserId()
  367. taskData["evaluate_date"] = now.Format("Y-m-d H:i:s")
  368. taskData["evaluate_status"] = req.HandleStatus
  369. taskData["evaluate_desc"] = req.HandleDesc
  370. logNodeName = "评价"
  371. if req.HandleStatus == "30" {
  372. // 监办人评价,审批通过,任务结束
  373. logDesc = s.GetCxtUserName() + "审批通过"
  374. nextHandle = nil
  375. taskData["actual_close_date"] = now.Format("Y-m-d H:i:s")
  376. taskData["task_status"] = "30"
  377. } else if req.HandleStatus == "40" {
  378. logDesc = s.GetCxtUserName() + "审批退回"
  379. nextHandle = createNextTaskHandel(s, task, 20)
  380. }
  381. } else {
  382. err = myerrors.TipsError("未知步骤,无法操作")
  383. return err
  384. }
  385. // 更新数据
  386. // 更新督办任务数据
  387. _, err = s.Dao.Update(taskData, fmt.Sprintf("id='%v'", req.TaskId))
  388. if err != nil {
  389. return err
  390. }
  391. // 更新任务数据
  392. _, err = s.Dao.DB.Update("plat_task_handle", handleData, fmt.Sprintf("ID='%v'", taskHandle.ID))
  393. if err != nil {
  394. return err
  395. }
  396. // 创建下一条任务
  397. if nextHandle != nil {
  398. _, err = s.Dao.DB.Save("plat_task_handle", nextHandle)
  399. if err != nil {
  400. return err
  401. }
  402. }
  403. }
  404. // 流程日志
  405. err = CreateTaskLog(s, nil, req.TaskId, s.GetCxtUserId(), s.GetCxtUserName(), logNodeName, logDesc, "")
  406. if err != nil {
  407. return err
  408. }
  409. return nil
  410. }
  411. // 任务日志创建方法
  412. func CreateTaskLog(s1 *taskService, s2 *taskProgressService, taskId, userId int, userName, nodeName, desc, remark string) (err error) {
  413. var log model.PlatTaskLog
  414. startTime := gtime.Now()
  415. endTime := startTime
  416. // 默认为当前时间,然后随已有日志情况进行更新
  417. if s1 != nil {
  418. logs, err := s1.Dao.DB.Model(plat.PlatTaskLog.Table).Where(fmt.Sprintf("task_id='%v'", taskId)).Order("created_time DESC").FindAll()
  419. if err != nil && err != sql.ErrNoRows {
  420. return err
  421. }
  422. if len(logs) > 0 {
  423. startTime = logs[0]["end_time"].GTime()
  424. }
  425. } else {
  426. logs, err := s2.Dao.DB.Model(plat.PlatTaskLog.Table).Where(fmt.Sprintf("task_id='%v'", taskId)).Order("created_time DESC").FindAll()
  427. if err != nil && err != sql.ErrNoRows {
  428. return err
  429. }
  430. if len(logs) > 0 {
  431. startTime = logs[0]["end_time"].GTime()
  432. }
  433. }
  434. // 填入日志相关数据
  435. log.TaskId = taskId
  436. log.NodeName = nodeName
  437. log.Desc = desc
  438. log.StartTime = startTime
  439. log.EndTime = endTime
  440. log.Remark = remark
  441. log.CreatedTime = endTime
  442. log.CreatedName = userName
  443. log.CreatedBy = userId
  444. if s1 != nil {
  445. _, err = s1.Dao.DB.Save(plat.PlatTaskLog.Table, log)
  446. } else {
  447. _, err = s2.Dao.DB.Save(plat.PlatTaskLog.Table, log)
  448. }
  449. return err
  450. }
  451. // 创建个人的督办任务(其中,暂存不会生成个人任务,不会改变任何东西,只会新增一条日志)
  452. func createNextTaskHandel(s *taskService, task *model.PlatTask, step int) *model.PlatTaskHandle {
  453. // 步骤号(10接收 15暂存 20提交 30审批(督办人) 40评价(监办人))
  454. var personTask model.PlatTaskHandle
  455. personTask.TaskId = task.Id
  456. personTask.TaskStatus = "10"
  457. personTask.Step = step
  458. // 督办任务为发起时
  459. if step == 10 {
  460. personTask.MainUserId = task.MainUserId
  461. personTask.OwnerUserId = task.OwnerUserId
  462. } else if step == 20 {
  463. // 创建提交任务
  464. personTask.MainUserId = task.MainUserId
  465. personTask.OwnerUserId = task.OwnerUserId
  466. } else if step == 30 {
  467. // 提交给督办人审批
  468. personTask.MainUserId = task.SupervisorUserId
  469. } else if step == 40 {
  470. // 提交给监办人评价
  471. personTask.MainUserId = task.WatchUserId
  472. }
  473. // 填充创建信息
  474. service.SetCreatedInfo(&personTask, s.GetCxtUserId(), s.GetCxtUserName())
  475. return &personTask
  476. }
  477. // 处理暂存、提交任务进展
  478. func (s *taskService) saveProgressList(req *model.HandleReq, now *gtime.Time) (err error) {
  479. ids := ""
  480. deleteWhere := fmt.Sprintf("task_id='%v'", req.TaskId)
  481. for index, progress := range req.ProgressList {
  482. if progress.Id != 0 {
  483. if ids == "" {
  484. ids = fmt.Sprintf("%v", progress.Id)
  485. } else {
  486. ids += fmt.Sprintf(",%v", progress.Id)
  487. }
  488. }
  489. req.ProgressList[index].TaskId = req.TaskId
  490. // 填充创建信息
  491. if progress.CreatedBy == 0 {
  492. service.SetCreatedInfo(req.ProgressList[index], s.GetCxtUserId(), s.GetCxtUserName())
  493. }
  494. // 填充更新信息
  495. service.SetUpdatedInfo(req.ProgressList[index], s.GetCxtUserId(), s.GetCxtUserName())
  496. }
  497. if ids != "" {
  498. deleteWhere += fmt.Sprintf(" AND ID NOT IN (%v)", ids)
  499. }
  500. // 保存督办进展
  501. // 1 标记删除旧的进展数据
  502. _, err = s.Dao.DB.Update("plat_task_progress", fmt.Sprintf("deleted_time='%v'", now.Format("Y-m-d H:i:s")), deleteWhere)
  503. if err != nil {
  504. return err
  505. }
  506. // 2 保存新的数据
  507. _, err = s.Dao.DB.Save("plat_task_progress", req.ProgressList)
  508. if err != nil {
  509. return err
  510. }
  511. return nil
  512. }