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.

433 lines
14 KiB

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