You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
15 KiB

  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "gin-vue-admin/constant"
  6. "gin-vue-admin/global"
  7. "gin-vue-admin/model"
  8. "gin-vue-admin/model/request"
  9. "gorm.io/gorm"
  10. "gorm.io/gorm/schema"
  11. "strconv"
  12. )
  13. func getTable(businessType string) interface{} {
  14. return model.WorkflowBusinessTable[businessType]()
  15. }
  16. //@author: [piexlmax](https://github.com/piexlmax)
  17. //@function: CreateWorkflowProcess
  18. //@description: 创建工作流相关信息
  19. //@param: workflowProcess model.WorkflowProcess
  20. //@return: err error
  21. func CreateWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
  22. err = global.GVA_DB.Create(&workflowProcess).Error
  23. return err
  24. }
  25. //@author: [piexlmax](https://github.com/piexlmax)
  26. //@function: DeleteWorkflowProcess
  27. //@description: 删除工作流相关信息
  28. //@param: workflowProcess model.WorkflowProcess
  29. //@return: err error
  30. func DeleteWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
  31. err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  32. var txErr error
  33. txErr = tx.Delete(&workflowProcess).Error
  34. if txErr != nil {
  35. return txErr
  36. }
  37. var edges []model.WorkflowEdge
  38. txErr = tx.Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
  39. if txErr != nil {
  40. return txErr
  41. }
  42. txErr = tx.Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
  43. if txErr != nil {
  44. return txErr
  45. }
  46. if len(edges) > 0 {
  47. txErr = tx.Select("StartPoint", "EndPoint").Delete(&edges).Error
  48. }
  49. if txErr != nil {
  50. return txErr
  51. }
  52. return nil
  53. })
  54. return err
  55. }
  56. //@author: [piexlmax](https://github.com/piexlmax)
  57. //@function: CreateWorkflowProcess
  58. //@description: 批量删除工作流信息(暂未启用)
  59. //@param: ids request.IdsReq
  60. //@return: err error
  61. func DeleteWorkflowProcessByIds(ids request.IdsReq) (err error) {
  62. err = global.GVA_DB.Delete(&[]model.WorkflowProcess{}, "id in ?", ids.Ids).Error
  63. return err
  64. }
  65. //@author: [piexlmax](https://github.com/piexlmax)
  66. //@function: UpdateWorkflowProcess
  67. //@description: 更新工作流相关信息
  68. //@param: workflowProcess *model.WorkflowProcess
  69. //@return: err error
  70. func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
  71. return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  72. var txErr error
  73. var edges []model.WorkflowEdge
  74. var edgesIds []string
  75. txErr = tx.Unscoped().Delete(workflowProcess).Error
  76. if txErr != nil {
  77. return txErr
  78. }
  79. txErr = tx.Unscoped().Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
  80. if txErr != nil {
  81. return txErr
  82. }
  83. txErr = tx.Unscoped().Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
  84. if txErr != nil {
  85. return txErr
  86. }
  87. txErr = tx.Unscoped().Delete(&edges).Error
  88. if txErr != nil {
  89. return txErr
  90. }
  91. for _, v := range edges {
  92. edgesIds = append(edgesIds, v.ID)
  93. }
  94. txErr = tx.Unscoped().Delete(&model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
  95. if txErr != nil {
  96. return txErr
  97. }
  98. txErr = tx.Unscoped().Delete(&model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
  99. if txErr != nil {
  100. return txErr
  101. }
  102. txErr = tx.Create(&workflowProcess).Error
  103. if txErr != nil {
  104. return txErr
  105. }
  106. return nil
  107. })
  108. }
  109. //@author: [piexlmax](https://github.com/piexlmax)
  110. //@function: GetWorkflowProcess
  111. //@description: 获取工作流相关信息
  112. //@param: id string
  113. //@return: err error,workflowProcess model.WorkflowProcess
  114. func GetWorkflowProcess(id string) (err error, workflowProcess model.WorkflowProcess) {
  115. err = global.GVA_DB.Preload("Nodes").Preload("Edges").Where("id = ?", id).First(&workflowProcess).Error
  116. return
  117. }
  118. //@author: [piexlmax](https://github.com/piexlmax)
  119. //@function: GetWorkflowCreateStep
  120. //@description: 获取工作流步骤信息
  121. //@param: id string
  122. //@return: err error, workflowNodes []model.WorkflowNode
  123. func FindWorkflowStep(id string) (err error, workflowNode model.WorkflowProcess) {
  124. err = global.GVA_DB.Preload("Nodes", "clazz = ?", constant.START).Where("id = ?", id).First(&workflowNode).Error
  125. return
  126. }
  127. //@author: [piexlmax](https://github.com/piexlmax)
  128. //@function: GetWorkflowProcessInfoList
  129. //@description: 获取工作流列表
  130. //@param: info request.WorkflowProcessSearch
  131. //@return: err error, list interface{}, total int64
  132. func GetWorkflowProcessInfoList(info request.WorkflowProcessSearch) (err error, list interface{}, total int64) {
  133. limit := info.PageSize
  134. offset := info.PageSize * (info.Page - 1)
  135. // 创建db
  136. db := global.GVA_DB.Model(&model.WorkflowProcess{})
  137. var workflowProcesss []model.WorkflowProcess
  138. // 如果有条件搜索 下方会自动创建搜索语句
  139. if info.Name != "" {
  140. db = db.Where("`name` LIKE ?", "%"+info.Name+"%")
  141. }
  142. if info.Label != "" {
  143. db = db.Where("`label` LIKE ?", "%"+info.Label+"%")
  144. }
  145. err = db.Count(&total).Error
  146. err = db.Limit(limit).Offset(offset).Find(&workflowProcesss).Error
  147. return err, workflowProcesss, total
  148. }
  149. //@author: [piexlmax](https://github.com/piexlmax)
  150. //@function: StartWorkflow
  151. //@description: 开启一个工作流
  152. //@param: wfInterface model.GVA_Workflow
  153. //@return: err error
  154. func StartWorkflow(wfInterface model.GVA_Workflow) (err error) {
  155. err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  156. var txErr error
  157. tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
  158. txErr = tx.Table(tableName).Create(wfInterface).Error
  159. if txErr != nil {
  160. return txErr
  161. }
  162. wfm := wfInterface.CreateWorkflowMove()
  163. txErr = tx.Create(wfm).Error
  164. if txErr != nil {
  165. return txErr
  166. }
  167. txErr = complete(tx, wfm)
  168. if txErr != nil {
  169. return txErr
  170. }
  171. return nil
  172. })
  173. return err
  174. }
  175. func CompleteWorkflowMove(wfInterface model.GVA_Workflow) (err error) {
  176. err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  177. var txErr error
  178. tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
  179. txErr = tx.Table(tableName).Where("id = ?", wfInterface.GetBusinessID()).Updates(wfInterface).Error
  180. if txErr != nil {
  181. return txErr
  182. }
  183. nowWorkflowMove := wfInterface.CreateWorkflowMove()
  184. txErr = complete(tx, nowWorkflowMove)
  185. if txErr != nil {
  186. return txErr
  187. }
  188. return nil
  189. })
  190. return err
  191. }
  192. func complete(tx *gorm.DB, wfm *model.WorkflowMove) (err error) {
  193. var returnWfm model.WorkflowMove
  194. var nodeInfo model.WorkflowNode
  195. var Edges []model.WorkflowEdge
  196. txErr := tx.First(&returnWfm, "id = ? AND is_active = ?", wfm.ID, true).Error
  197. if txErr != nil {
  198. return txErr
  199. }
  200. txErr = tx.First(&nodeInfo, "id = ?", wfm.WorkflowNodeID).Error
  201. if txErr != nil {
  202. return txErr
  203. }
  204. if nodeInfo.Clazz == constant.START || nodeInfo.Clazz == constant.USER_TASK {
  205. txErr = tx.Find(&Edges, "workflow_process_id = ? and source = ?", wfm.WorkflowProcessID, wfm.WorkflowNodeID).Error
  206. if txErr != nil {
  207. return txErr
  208. }
  209. if len(Edges) == 0 {
  210. return errors.New("不存在当前节点为起点的后续流程")
  211. }
  212. if len(Edges) == 1 {
  213. txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
  214. if txErr != nil {
  215. return txErr
  216. }
  217. txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, Edges[0].Target)
  218. if txErr != nil {
  219. return txErr
  220. }
  221. if len(newWfm) > 0 {
  222. txErr = tx.Create(&newWfm).Error
  223. if txErr != nil {
  224. return txErr
  225. }
  226. }
  227. // 当target为自动节点时候 需要做一些事情 这里暂时先不处理 后续慢慢完善
  228. }
  229. if len(Edges) > 1 {
  230. var needUseTargetNodeID string
  231. txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
  232. if txErr != nil {
  233. return txErr
  234. }
  235. for _, v := range Edges {
  236. if v.ConditionExpression == wfm.Param {
  237. needUseTargetNodeID = v.Target
  238. break
  239. }
  240. }
  241. if needUseTargetNodeID == "" {
  242. return errors.New("未发现流转参数,流转失败")
  243. }
  244. txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, needUseTargetNodeID)
  245. if txErr != nil {
  246. return txErr
  247. }
  248. if len(newWfm) > 0 {
  249. txErr = tx.Create(&newWfm).Error
  250. if txErr != nil {
  251. return txErr
  252. }
  253. }
  254. }
  255. } else if nodeInfo.Clazz == constant.EXCLUSIVE_GATEWAY {
  256. return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
  257. } else if nodeInfo.Clazz == constant.INCLUSIVE_GATEWAY {
  258. return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
  259. } else if nodeInfo.Clazz == constant.PARELLEL_GATEWAY {
  260. return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
  261. } else {
  262. return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
  263. }
  264. return nil
  265. }
  266. func createNewWorkflowMove(tx *gorm.DB, oldWfm *model.WorkflowMove, targetNodeID string) (err error, newWfm []model.WorkflowMove) {
  267. // 以下所有非 default的节点的下一步流转均应该处理为递归形式
  268. var nodeInfo model.WorkflowNode
  269. var edge model.WorkflowEdge
  270. var edges []model.WorkflowEdge
  271. var wfms []model.WorkflowMove
  272. txErr := tx.First(&nodeInfo, "id = ?", targetNodeID).Error
  273. if txErr != nil {
  274. return txErr, []model.WorkflowMove{}
  275. }
  276. switch nodeInfo.Clazz {
  277. case constant.EXCLUSIVE_GATEWAY:
  278. // 当为排他网关时候 选择一个参数进行排他线路选择
  279. txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, oldWfm.Param).Error
  280. if txErr != nil {
  281. return txErr, []model.WorkflowMove{}
  282. }
  283. newWfm = append(newWfm, model.WorkflowMove{
  284. BusinessID: oldWfm.BusinessID,
  285. BusinessType: oldWfm.BusinessType,
  286. PromoterID: oldWfm.PromoterID,
  287. OperatorID: 0,
  288. WorkflowNodeID: edge.Target,
  289. WorkflowProcessID: oldWfm.WorkflowProcessID,
  290. Param: "",
  291. Action: "",
  292. IsActive: true})
  293. return nil, newWfm
  294. case constant.INCLUSIVE_GATEWAY:
  295. // 当为包容网关时,需要等待其他网关执行结束才进行创建
  296. txErr := tx.Find(&edges, "workflow_process_id = ? and target = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
  297. if txErr != nil {
  298. return txErr, []model.WorkflowMove{}
  299. }
  300. var sourceIds []string
  301. for _, v := range edges {
  302. sourceIds = append(sourceIds, v.Source)
  303. }
  304. txErr = tx.Find(&wfms, "workflow_process_id = ? and business_id = ? and workflow_node_id in (?) and is_active = ?", oldWfm.WorkflowProcessID, oldWfm.BusinessID, sourceIds, false).Error
  305. if txErr != nil {
  306. return txErr, []model.WorkflowMove{}
  307. }
  308. if len(wfms) != len(edges) {
  309. return nil, []model.WorkflowMove{}
  310. }
  311. if len(wfms) == len(edges) {
  312. params := make(map[string]int)
  313. var param string
  314. var temp int
  315. for _, v := range wfms {
  316. params[v.Param]++
  317. }
  318. for k, v := range params {
  319. if temp < v {
  320. temp = v
  321. param = k
  322. }
  323. }
  324. //参数携带模式暂时未定 暂时为少数服从多数原则 后续会增加原则配置 (少数服从多数,仅一关键字即为关键字,所有关键字才为关键字 三种方案)
  325. txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, param).Error
  326. if txErr != nil {
  327. return txErr, []model.WorkflowMove{}
  328. }
  329. newWfm = append(newWfm, model.WorkflowMove{
  330. BusinessID: oldWfm.BusinessID,
  331. BusinessType: oldWfm.BusinessType,
  332. PromoterID: oldWfm.PromoterID,
  333. OperatorID: 0,
  334. WorkflowNodeID: edge.Target,
  335. WorkflowProcessID: oldWfm.WorkflowProcessID,
  336. Param: "",
  337. Action: "",
  338. IsActive: true})
  339. }
  340. return nil, newWfm
  341. case constant.PARELLEL_GATEWAY:
  342. // 当为并行网关时候 找出所有线路创建并行节点
  343. txErr := tx.Find(&edges, "workflow_process_id = ? and source = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
  344. if txErr != nil {
  345. return txErr, []model.WorkflowMove{}
  346. }
  347. for _, v := range edges {
  348. newWfm = append(newWfm, model.WorkflowMove{
  349. BusinessID: oldWfm.BusinessID,
  350. BusinessType: oldWfm.BusinessType,
  351. PromoterID: oldWfm.PromoterID,
  352. OperatorID: 0,
  353. WorkflowNodeID: v.Target,
  354. WorkflowProcessID: oldWfm.WorkflowProcessID,
  355. Param: "",
  356. Action: "",
  357. IsActive: true})
  358. }
  359. return nil, newWfm
  360. case constant.END:
  361. newWfm = append(newWfm, model.WorkflowMove{
  362. BusinessID: oldWfm.BusinessID,
  363. BusinessType: oldWfm.BusinessType,
  364. PromoterID: oldWfm.PromoterID,
  365. OperatorID: oldWfm.OperatorID,
  366. WorkflowNodeID: targetNodeID,
  367. WorkflowProcessID: oldWfm.WorkflowProcessID,
  368. Param: "",
  369. Action: "",
  370. IsActive: false})
  371. return nil, newWfm
  372. default:
  373. newWfm = append(newWfm, model.WorkflowMove{
  374. BusinessID: oldWfm.BusinessID,
  375. BusinessType: oldWfm.BusinessType,
  376. PromoterID: oldWfm.PromoterID,
  377. OperatorID: 0,
  378. WorkflowNodeID: targetNodeID,
  379. WorkflowProcessID: oldWfm.WorkflowProcessID,
  380. Param: "",
  381. Action: "",
  382. IsActive: true})
  383. return nil, newWfm
  384. }
  385. }
  386. func GetMyStated(userID uint) (err error, wfms []model.WorkflowMove) {
  387. err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Find(&wfms, "promoter_id = ? and ( is_active = ? OR node.clazz = ?)", userID, true, "end").Error
  388. return err, wfms
  389. }
  390. func GetMyNeed(userID uint, AuthorityID string) (err error, wfms []model.WorkflowMove) {
  391. user := "%," + strconv.Itoa(int(userID)) + ",%"
  392. auth := "%," + AuthorityID + ",%"
  393. err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Where("is_active = ? AND ((node.assign_type = ? AND node.assign_value LIKE ? ) OR (node.assign_type = ? AND node.assign_value LIKE ? ) OR (node.assign_type = ? AND promoter_id = ? ))", true, "user", user, "authority", auth, "self", userID).Find(&wfms).Error
  394. return err, wfms
  395. }
  396. func GetWorkflowMoveByID(id float64) (err error, move model.WorkflowMove, moves []model.WorkflowMove, business interface{}) {
  397. var result interface{}
  398. err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  399. var txErr error
  400. txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").First(&move, "id = ?", id).Error
  401. if txErr != nil {
  402. return txErr
  403. }
  404. txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Find(&moves, "business_id = ? AND business_type = ?", move.BusinessID, move.BusinessType).Error
  405. if txErr != nil {
  406. return txErr
  407. }
  408. result = getTable(move.BusinessType)
  409. fmt.Println(result)
  410. txErr = tx.First(result, "id = ?", move.BusinessID).Error
  411. if txErr != nil {
  412. return txErr
  413. }
  414. return nil
  415. })
  416. return err, move, moves, result
  417. }