taskService.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "server/dao"
  7. "server/dao/flow"
  8. "strconv"
  9. "sync"
  10. "time"
  11. "github.com/jinzhu/gorm"
  12. "github.com/mumushuiding/util"
  13. )
  14. // TaskReceiver 任务
  15. type TaskReceiver struct {
  16. TaskID int `json:"taskID"`
  17. UserID string `json:"userID,omitempty"`
  18. UserName string `json:"username,omitempty"`
  19. Pass string `json:"pass,omitempty"`
  20. Company string `json:"company,omitempty"`
  21. ProcInstID int `json:"procInstID,omitempty"`
  22. Comment string `json:"comment,omitempty"`
  23. Candidate string `json:"candidate,omitempty"`
  24. }
  25. var completeLock sync.Mutex
  26. // NewTask 新任务
  27. func NewTask(t *dao.Task) (int, error) {
  28. if len(t.NodeID) == 0 {
  29. return 0, errors.New("request param nodeID can not be null / 任务当前所在节点nodeId不能为空!")
  30. }
  31. t.CreateTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
  32. return t.NewTask()
  33. }
  34. // NewTaskTx NewTaskTx
  35. // 开启事务
  36. func NewTaskTx(t *dao.Task, tx *gorm.DB) (int, error) {
  37. if len(t.NodeID) == 0 {
  38. return 0, errors.New("request param nodeID can not be null / 任务当前所在节点nodeId不能为空!")
  39. }
  40. t.CreateTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
  41. return t.NewTaskTx(tx)
  42. }
  43. // DeleteTask 删除任务
  44. func DeleteTask(id int) error {
  45. return dao.DeleteTask(id)
  46. }
  47. // GetTaskByID GetTaskById
  48. func GetTaskByID(id int) (task *dao.Task, err error) {
  49. return dao.GetTaskByID(id)
  50. }
  51. // GetTaskLastByProInstID GetTaskLastByProInstID
  52. func GetTaskLastByProInstID(procInstID int) (*dao.Task, error) {
  53. return dao.GetTaskLastByProInstID(procInstID)
  54. }
  55. // CompleteByToken 通过token 审批任务
  56. func CompleteByToken(token string, receiver *TaskReceiver) error {
  57. userinfo, err := GetUserinfoFromRedis(token)
  58. if err != nil {
  59. return err
  60. }
  61. pass, err := strconv.ParseBool(receiver.Pass)
  62. if err != nil {
  63. return err
  64. }
  65. err = Complete(receiver.TaskID, userinfo.ID, userinfo.Username, userinfo.Company, receiver.Comment, receiver.Candidate, pass)
  66. if err != nil {
  67. return err
  68. }
  69. return nil
  70. }
  71. // Complete Complete
  72. // 审批
  73. func Complete(taskID int, userID, username, company, comment, candidate string, pass bool) error {
  74. tx := dao.GetTx()
  75. err := CompleteTaskTx(taskID, userID, username, company, comment, candidate, pass, tx)
  76. if err != nil {
  77. tx.Rollback()
  78. return err
  79. }
  80. tx.Commit()
  81. return nil
  82. }
  83. // UpdateTaskWhenComplete 完成后更新任务
  84. func UpdateTaskWhenComplete(taskID int, userID string, pass bool, tx *gorm.DB) (*model.Task, error) {
  85. // 获取task
  86. completeLock.Lock() // 关锁
  87. defer completeLock.Unlock() //解锁
  88. // 查询任务
  89. task, err := GetTaskByID(taskID)
  90. if err != nil {
  91. return nil, err
  92. }
  93. if task == nil {
  94. return nil, errors.New("任务【" + fmt.Sprintf("%d", task.ID) + "】不存在")
  95. }
  96. // 判断是否已经结束
  97. if task.IsFinished == true {
  98. if task.NodeID == "结束" {
  99. return nil, errors.New("流程已经结束")
  100. }
  101. return nil, errors.New("任务【" + fmt.Sprintf("%d", taskID) + "】已经被审批过了!!")
  102. }
  103. // 设置处理人和处理时间
  104. task.Assignee = userID
  105. task.ClaimTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
  106. // ----------------会签 (默认全部通过才结束),只要存在一个不通过,就结束,然后流转到上一步
  107. //同意
  108. if pass {
  109. task.AgreeNum++
  110. } else {
  111. task.IsFinished = true
  112. }
  113. // 未审批人数减一
  114. task.UnCompleteNum--
  115. // 判断是否结束
  116. if task.UnCompleteNum == 0 {
  117. task.IsFinished = true
  118. }
  119. err = task.UpdateTx(tx)
  120. // str, _ := util.ToJSONStr(task)
  121. // log.Println(str)
  122. if err != nil {
  123. return nil, err
  124. }
  125. return task, nil
  126. }
  127. // CompleteTaskTx CompleteTaskTx
  128. // 执行任务
  129. func CompleteTaskTx(taskID int, userID, username, company, comment, candidate string, pass bool, tx *gorm.DB) error {
  130. //更新任务
  131. task, err := UpdateTaskWhenComplete(taskID, userID, pass, tx)
  132. if err != nil {
  133. return err
  134. }
  135. // 如果是会签
  136. if task.ActType == "and" {
  137. // fmt.Println("------------------是会签,判断用户是否已经审批过了,避免重复审批-------")
  138. // 判断用户是否已经审批过了(存在会签的情况)
  139. yes, err := IfParticipantByTaskID(userID, company, taskID)
  140. if err != nil {
  141. tx.Rollback()
  142. return err
  143. }
  144. if yes {
  145. tx.Rollback()
  146. return errors.New("您已经审批过了,请等待他人审批!)")
  147. }
  148. }
  149. // 查看任务的未审批人数是否为0,不为0就不流转
  150. if task.UnCompleteNum > 0 && pass == true { // 默认是全部通过
  151. // 添加参与人
  152. err := AddParticipantTx(userID, username, company, comment, task.ID, task.ProcInstID, task.Step, tx)
  153. if err != nil {
  154. return err
  155. }
  156. return nil
  157. }
  158. // 流转到下一流程
  159. // nodeInfos, err := GetExecNodeInfosByProcInstID(task.ProcInstID)
  160. // if err != nil {
  161. // return err
  162. // }
  163. err = MoveStageByProcInstID(userID, username, company, comment, candidate, task.ID, task.ProcInstID, task.Step, pass, tx)
  164. if err != nil {
  165. return err
  166. }
  167. return nil
  168. }
  169. // WithDrawTaskByToken 撤回任务
  170. func WithDrawTaskByToken(token string, receiver *TaskReceiver) error {
  171. userinfo, err := GetUserinfoFromRedis(token)
  172. if err != nil {
  173. return err
  174. }
  175. if len(userinfo.ID) == 0 {
  176. return errors.New("保存在redis中的【用户信息 userinfo】字段 ID 不能为空!!")
  177. }
  178. if len(userinfo.Username) == 0 {
  179. return errors.New("保存在redis中的【用户信息 userinfo】字段 username 不能为空!!")
  180. }
  181. if len(userinfo.Company) == 0 {
  182. return errors.New("保存在redis中的【用户信息 userinfo】字段 company 不能为空")
  183. }
  184. return WithDrawTask(receiver.TaskID, receiver.ProcInstID, userinfo.ID, userinfo.Username, userinfo.Company, receiver.Comment)
  185. }
  186. // WithDrawTask 撤回任务
  187. func WithDrawTask(taskID, procInstID int, userID, username, company, comment string) error {
  188. var err1, err2 error
  189. var currentTask, lastTask *model.Task
  190. var timesx time.Time
  191. var wg sync.WaitGroup
  192. timesx = time.Now()
  193. wg.Add(2)
  194. go func() {
  195. currentTask, err1 = GetTaskByID(taskID)
  196. wg.Done()
  197. }()
  198. go func() {
  199. lastTask, err2 = GetTaskLastByProInstID(procInstID)
  200. wg.Done()
  201. }()
  202. wg.Wait()
  203. if err1 != nil {
  204. if err1 == gorm.ErrRecordNotFound {
  205. return errors.New("任务不存在")
  206. }
  207. return err1
  208. }
  209. if err2 != nil {
  210. if err2 == gorm.ErrRecordNotFound {
  211. return errors.New("找不到流程实例id为【" + fmt.Sprintf("%d", procInstID) + "】的任务,无权撤回")
  212. }
  213. return err2
  214. }
  215. // str1,_:=util.ToJSONStr(currentTask)
  216. // str2,_:=util.ToJSONStr(lastTask)
  217. // fmt.Println(str1)
  218. // fmt.Println(str2)
  219. if currentTask.Step == 0 {
  220. return errors.New("开始位置无法撤回")
  221. }
  222. if lastTask.Assignee != userID {
  223. return errors.New("只能撤回本人审批过的任务!!")
  224. }
  225. if currentTask.IsFinished {
  226. return errors.New("已经审批结束,无法撤回!")
  227. }
  228. if currentTask.UnCompleteNum != currentTask.MemberCount {
  229. return errors.New("已经有人审批过了,无法撤回!")
  230. }
  231. sub := currentTask.Step - lastTask.Step
  232. if math.Abs(float64(sub)) != 1 {
  233. return errors.New("只能撤回相邻的任务!!")
  234. }
  235. var pass = false
  236. if sub < 0 {
  237. pass = true
  238. }
  239. fmt.Printf("判断是否可以撤回,耗时:%v\n", time.Since(timesx))
  240. timesx = time.Now()
  241. tx := model.GetTx()
  242. // 更新当前的任务
  243. currentTask.IsFinished = true
  244. err := currentTask.UpdateTx(tx)
  245. if err != nil {
  246. tx.Rollback()
  247. return err
  248. }
  249. // 撤回
  250. err = MoveStageByProcInstID(userID, username, company, comment, "", currentTask.ID, procInstID, currentTask.Step, pass, tx)
  251. if err != nil {
  252. tx.Rollback()
  253. return err
  254. }
  255. tx.Commit()
  256. fmt.Printf("撤回流程耗时:%v\n", time.Since(timesx))
  257. return nil
  258. }
  259. // MoveStageByProcInstID MoveStageByProcInstID
  260. func MoveStageByProcInstID(userID, username, company, comment, candidate string, taskID, procInstID, step int, pass bool, tx *gorm.DB) (err error) {
  261. nodeInfos, err := GetExecNodeInfosByProcInstID(procInstID)
  262. if err != nil {
  263. return err
  264. }
  265. return MoveStage(nodeInfos, userID, username, company, comment, candidate, taskID, procInstID, step, pass, tx)
  266. }
  267. // MoveStage MoveStage
  268. // 流程流转
  269. func MoveStage(nodeInfos []*flow.NodeInfo, userID, username, company, comment, candidate string, taskID, procInstID, step int, pass bool, tx *gorm.DB) (err error) {
  270. // 添加上一步的参与人
  271. err = AddParticipantTx(userID, username, company, comment, taskID, procInstID, step, tx)
  272. if err != nil {
  273. return err
  274. }
  275. if pass {
  276. step++
  277. if step-1 > len(nodeInfos) {
  278. return errors.New("已经结束无法流转到下一个节点")
  279. }
  280. } else {
  281. step--
  282. if step < 0 {
  283. return errors.New("处于开始位置,无法回退到上一个节点")
  284. }
  285. }
  286. // 指定下一步执行人
  287. if len(candidate) > 0 {
  288. nodeInfos[step].Aprover = candidate
  289. }
  290. // 判断下一流程: 如果是审批人是:抄送人
  291. // fmt.Printf("下一审批人类型:%s\n", nodeInfos[step].AproverType)
  292. // fmt.Println(nodeInfos[step].AproverType == flow.NodeTypes[flow.NOTIFIER])
  293. if nodeInfos[step].AproverType == flow.NodeTypes[flow.NOTIFIER] {
  294. // 生成新的任务
  295. var task = model.Task{
  296. NodeID: flow.NodeTypes[flow.NOTIFIER],
  297. Step: step,
  298. ProcInstID: procInstID,
  299. IsFinished: true,
  300. }
  301. task.IsFinished = true
  302. _, err := task.NewTaskTx(tx)
  303. if err != nil {
  304. return err
  305. }
  306. // 添加抄送人
  307. err = AddNotifierTx(nodeInfos[step].Aprover, company, step, procInstID, tx)
  308. if err != nil {
  309. return err
  310. }
  311. return MoveStage(nodeInfos, userID, username, company, comment, candidate, taskID, procInstID, step, pass, tx)
  312. }
  313. if pass {
  314. return MoveToNextStage(nodeInfos, userID, company, taskID, procInstID, step, tx)
  315. }
  316. return MoveToPrevStage(nodeInfos, userID, company, taskID, procInstID, step, tx)
  317. }
  318. // MoveToNextStage MoveToNextStage
  319. // 通过
  320. func MoveToNextStage(nodeInfos []*flow.NodeInfo, userID, company string, currentTaskID, procInstID, step int, tx *gorm.DB) error {
  321. var currentTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
  322. var task = getNewTask(nodeInfos, step, procInstID, currentTime) //新任务
  323. var procInst = &model.ProcInst{ // 流程实例要更新的字段
  324. NodeID: nodeInfos[step].NodeID,
  325. Candidate: nodeInfos[step].Aprover,
  326. }
  327. procInst.ID = procInstID
  328. if (step + 1) != len(nodeInfos) { // 下一步不是【结束】
  329. // 生成新的任务
  330. taksID, err := task.NewTaskTx(tx)
  331. if err != nil {
  332. return err
  333. }
  334. // 添加candidate group
  335. err = AddCandidateGroupTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
  336. if err != nil {
  337. return err
  338. }
  339. // 更新流程实例
  340. procInst.TaskID = taksID
  341. err = UpdateProcInst(procInst, tx)
  342. if err != nil {
  343. return err
  344. }
  345. } else { // 最后一步直接结束
  346. // 生成新的任务
  347. task.IsFinished = true
  348. task.ClaimTime = currentTime
  349. taksID, err := task.NewTaskTx(tx)
  350. if err != nil {
  351. return err
  352. }
  353. // 删除候选用户组
  354. err = DelCandidateByProcInstID(procInstID, tx)
  355. if err != nil {
  356. return err
  357. }
  358. // 更新流程实例
  359. procInst.TaskID = taksID
  360. procInst.EndTime = currentTime
  361. procInst.IsFinished = true
  362. procInst.Candidate = "审批结束"
  363. err = UpdateProcInst(procInst, tx)
  364. if err != nil {
  365. return err
  366. }
  367. }
  368. return nil
  369. }
  370. // MoveToPrevStage MoveToPrevStage
  371. // 驳回
  372. func MoveToPrevStage(nodeInfos []*flow.NodeInfo, userID, company string, currentTaskID, procInstID, step int, tx *gorm.DB) error {
  373. // 生成新的任务
  374. var task = getNewTask(nodeInfos, step, procInstID, util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)) //新任务
  375. taksID, err := task.NewTaskTx(tx)
  376. if err != nil {
  377. return err
  378. }
  379. var procInst = &model.ProcInst{ // 流程实例要更新的字段
  380. NodeID: nodeInfos[step].NodeID,
  381. Candidate: nodeInfos[step].Aprover,
  382. TaskID: taksID,
  383. }
  384. procInst.ID = procInstID
  385. err = UpdateProcInst(procInst, tx)
  386. if err != nil {
  387. return err
  388. }
  389. if step == 0 { // 流程回到起始位置,注意起始位置为0,
  390. err = AddCandidateUserTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
  391. if err != nil {
  392. return err
  393. }
  394. return nil
  395. }
  396. // 添加candidate group
  397. err = AddCandidateGroupTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
  398. if err != nil {
  399. return err
  400. }
  401. return nil
  402. }
  403. func getNewTask(nodeInfos []*flow.NodeInfo, step, procInstID int, currentTime string) *model.Task {
  404. var task = &model.Task{ // 新任务
  405. NodeID: nodeInfos[step].NodeID,
  406. Step: step,
  407. CreateTime: currentTime,
  408. ProcInstID: procInstID,
  409. MemberCount: nodeInfos[step].MemberCount,
  410. UnCompleteNum: nodeInfos[step].MemberCount,
  411. ActType: nodeInfos[step].ActType,
  412. }
  413. return task
  414. }