sys_workflow.go 14.8 KB
Newer Older
1 2 3
package service

import (
Mr.奇淼('s avatar
Mr.奇淼( 已提交
4
	"errors"
5
	"fmt"
Mr.奇淼('s avatar
Mr.奇淼( 已提交
6
	"gin-vue-admin/constant"
7 8 9
	"gin-vue-admin/global"
	"gin-vue-admin/model"
	"gin-vue-admin/model/request"
Mr.奇淼('s avatar
Mr.奇淼( 已提交
10
	"gorm.io/gorm"
11
	"gorm.io/gorm/schema"
Mr.奇淼('s avatar
Mr.奇淼( 已提交
12
	"strconv"
13 14
)

15 16 17 18
func getTable(businessType string) interface{} {
	return model.WorkflowBusinessTable[businessType]()
}

19 20 21 22 23
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 创建工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
24 25 26 27 28 29

func CreateWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
	err = global.GVA_DB.Create(&workflowProcess).Error
	return err
}

30 31 32 33 34
//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteWorkflowProcess
//@description: 删除工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
35 36

func DeleteWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		var txErr error
		txErr = tx.Delete(workflowProcess).Error
		if txErr != nil {
			return txErr
		}
		var edges []model.WorkflowEdge
		txErr = tx.Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
		if txErr != nil {
			return txErr
		}
52 53 54
		if len(edges) > 0 {
			txErr = tx.Select("StartPoint", "EndPoint").Delete(&edges).Error
		}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
55 56 57 58 59
		if txErr != nil {
			return txErr
		}
		return nil
	})
60 61 62
	return err
}

63 64 65 66 67
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 批量删除工作流信息(暂未启用)
//@param: ids request.IdsReq
//@return: err error
68 69 70 71 72 73

func DeleteWorkflowProcessByIds(ids request.IdsReq) (err error) {
	err = global.GVA_DB.Delete(&[]model.WorkflowProcess{}, "id in ?", ids.Ids).Error
	return err
}

74 75 76 77 78
//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateWorkflowProcess
//@description: 更新工作流相关信息
//@param: workflowProcess *model.WorkflowProcess
//@return: err error
79 80

func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		var txErr error
		var edges []model.WorkflowEdge
		var edgesIds []string
		txErr = tx.Unscoped().Delete(workflowProcess).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Unscoped().Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Unscoped().Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Unscoped().Delete(&edges).Error
		if txErr != nil {
			return txErr
		}
		for _, v := range edges {
			edgesIds = append(edgesIds, v.ID)
		}
		txErr = tx.Unscoped().Delete(model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Unscoped().Delete(model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Create(&workflowProcess).Error
		if txErr != nil {
			return txErr
		}
		return nil
	})
118 119
}

120 121 122 123
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcess
//@description: 获取工作流相关信息
//@param: id string
124
//@return: err error,workflowProcess model.WorkflowProcess
125 126

func GetWorkflowProcess(id string) (err error, workflowProcess model.WorkflowProcess) {
127
	err = global.GVA_DB.Preload("Nodes").Preload("Edges").Where("id = ?", id).First(&workflowProcess).Error
128 129 130
	return
}

131 132 133 134 135 136
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowCreateStep
//@description: 获取工作流步骤信息
//@param: id string
//@return: err error, workflowNodes []model.WorkflowNode

Mr.奇淼('s avatar
Mr.奇淼( 已提交
137
func FindWorkflowStep(id string) (err error, workflowNode model.WorkflowProcess) {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
138
	err = global.GVA_DB.Preload("Nodes", "clazz = ?", constant.START).Where("id = ?", id).First(&workflowNode).Error
139 140 141
	return
}

142 143 144 145 146
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcessInfoList
//@description: 获取工作流列表
//@param: info request.WorkflowProcessSearch
//@return: err error, list interface{}, total int64
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

func GetWorkflowProcessInfoList(info request.WorkflowProcessSearch) (err error, list interface{}, total int64) {
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	// 创建db
	db := global.GVA_DB.Model(&model.WorkflowProcess{})
	var workflowProcesss []model.WorkflowProcess
	// 如果有条件搜索 下方会自动创建搜索语句
	if info.Name != "" {
		db = db.Where("`name` LIKE ?", "%"+info.Name+"%")
	}
	if info.Label != "" {
		db = db.Where("`label` LIKE ?", "%"+info.Label+"%")
	}
	err = db.Count(&total).Error
	err = db.Limit(limit).Offset(offset).Find(&workflowProcesss).Error
	return err, workflowProcesss, total
}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
165 166 167 168 169 170 171 172 173 174

//@author: [piexlmax](https://github.com/piexlmax)
//@function: StartWorkflow
//@description: 开启一个工作流
//@param: wfInterface model.GVA_Workflow
//@return: err error

func StartWorkflow(wfInterface model.GVA_Workflow) (err error) {
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		var txErr error
175 176
		tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
		txErr = tx.Table(tableName).Create(wfInterface).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
		if txErr != nil {
			return txErr
		}
		wfm := wfInterface.CreateWorkflowMove()
		txErr = tx.Create(wfm).Error
		if txErr != nil {
			return txErr
		}
		txErr = complete(tx, wfm)
		if txErr != nil {
			return txErr
		}
		return nil
	})
	return err
}

Mr.奇淼('s avatar
Mr.奇淼( 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
func CompleteWorkflowMove(wfInterface model.GVA_Workflow) (err error) {
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		var txErr error
		tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
		txErr = tx.Table(tableName).Where("id = ?", wfInterface.GetBusinessID()).Updates(wfInterface).Error
		if txErr != nil {
			return txErr
		}
		nowWorkflowMove := wfInterface.CreateWorkflowMove()
		txErr = complete(tx, nowWorkflowMove)
		if txErr != nil {
			return txErr
		}
		return nil
	})
	return err
}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
211 212 213 214 215

func complete(tx *gorm.DB, wfm *model.WorkflowMove) (err error) {
	var returnWfm model.WorkflowMove
	var nodeInfo model.WorkflowNode
	var Edges []model.WorkflowEdge
Mr.奇淼('s avatar
Mr.奇淼( 已提交
216
	txErr := tx.First(&returnWfm, "id = ? AND is_active = ?", wfm.ID, true).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
217 218 219
	if txErr != nil {
		return txErr
	}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
220
	txErr = tx.First(&nodeInfo, "id = ?", wfm.WorkflowNodeID).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
221 222 223 224
	if txErr != nil {
		return txErr
	}

Mr.奇淼('s avatar
Mr.奇淼( 已提交
225
	if nodeInfo.Clazz == constant.START || nodeInfo.Clazz == constant.USER_TASK {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
226 227 228 229 230 231 232 233
		txErr = tx.Find(&Edges, "workflow_process_id = ? and source = ?", wfm.WorkflowProcessID, wfm.WorkflowNodeID).Error
		if txErr != nil {
			return txErr
		}
		if len(Edges) == 0 {
			return errors.New("不存在当前节点为起点的后续流程")
		}
		if len(Edges) == 1 {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
234
			txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
235 236 237
			if txErr != nil {
				return txErr
			}
238
			txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, Edges[0].Target)
Mr.奇淼('s avatar
Mr.奇淼( 已提交
239 240 241
			if txErr != nil {
				return txErr
			}
242
			if len(newWfm) > 0 {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
243 244 245 246 247
				txErr = tx.Create(&newWfm).Error
				if txErr != nil {
					return txErr
				}
			}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
248 249 250 251
			//	当target为自动节点时候 需要做一些事情 这里暂时先不处理 后续慢慢完善
		}
		if len(Edges) > 1 {
			var needUseTargetNodeID string
Mr.奇淼('s avatar
Mr.奇淼( 已提交
252 253

			txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
254 255 256 257 258 259 260 261 262
			if txErr != nil {
				return txErr
			}
			for _, v := range Edges {
				if v.ConditionExpression == wfm.Param {
					needUseTargetNodeID = v.Target
					break
				}
			}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
263 264 265
			if needUseTargetNodeID == "" {
				return errors.New("未发现流转参数,流转失败")
			}
266
			txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, needUseTargetNodeID)
Mr.奇淼('s avatar
Mr.奇淼( 已提交
267 268 269
			if txErr != nil {
				return txErr
			}
270
			if len(newWfm) > 0 {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
271 272 273 274 275
				txErr = tx.Create(&newWfm).Error
				if txErr != nil {
					return txErr
				}
			}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
276
		}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
277
	} else if nodeInfo.Clazz == constant.EXCLUSIVE_GATEWAY {
278
		return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
Mr.奇淼('s avatar
Mr.奇淼( 已提交
279
	} else if nodeInfo.Clazz == constant.INCLUSIVE_GATEWAY {
280
		return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
Mr.奇淼('s avatar
Mr.奇淼( 已提交
281
	} else if nodeInfo.Clazz == constant.PARELLEL_GATEWAY {
282
		return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
Mr.奇淼('s avatar
Mr.奇淼( 已提交
283 284 285 286 287 288
	} else {
		return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
	}
	return nil
}

289
func createNewWorkflowMove(tx *gorm.DB, oldWfm *model.WorkflowMove, targetNodeID string) (err error, newWfm []model.WorkflowMove) {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
290
	// 以下所有非 default的节点的下一步流转均应该处理为递归形式
291 292 293 294 295 296 297
	var nodeInfo model.WorkflowNode
	var edge model.WorkflowEdge
	var edges []model.WorkflowEdge
	var wfms []model.WorkflowMove
	txErr := tx.First(&nodeInfo, "id = ?", targetNodeID).Error
	if txErr != nil {
		return txErr, []model.WorkflowMove{}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
298
	}
299
	switch nodeInfo.Clazz {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
300
	case constant.EXCLUSIVE_GATEWAY:
Mr.奇淼('s avatar
Mr.奇淼( 已提交
301
		// 当为排他网关时候 选择一个参数进行排他线路选择
302 303
		txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, oldWfm.Param).Error
		if txErr != nil {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
304 305
			return txErr, []model.WorkflowMove{}
		}
306 307 308 309 310 311 312 313 314 315 316
		newWfm = append(newWfm, model.WorkflowMove{
			BusinessID:        oldWfm.BusinessID,
			BusinessType:      oldWfm.BusinessType,
			PromoterID:        oldWfm.PromoterID,
			OperatorID:        0,
			WorkflowNodeID:    edge.Target,
			WorkflowProcessID: oldWfm.WorkflowProcessID,
			Param:             "",
			Action:            "",
			IsActive:          true})
		return nil, newWfm
Mr.奇淼('s avatar
Mr.奇淼( 已提交
317
	case constant.INCLUSIVE_GATEWAY:
Mr.奇淼('s avatar
Mr.奇淼( 已提交
318 319
		// 当为包容网关时,需要等待其他网关执行结束才进行创建
		txErr := tx.Find(&edges, "workflow_process_id = ? and target = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
320 321
		if txErr != nil {
			return txErr, []model.WorkflowMove{}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
322 323
		}
		var sourceIds []string
324
		for _, v := range edges {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
325 326
			sourceIds = append(sourceIds, v.Source)
		}
327 328 329
		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
		if txErr != nil {
			return txErr, []model.WorkflowMove{}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
330
		}
331 332
		if len(wfms) != len(edges) {
			return nil, []model.WorkflowMove{}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
333
		}
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
		if len(wfms) == len(edges) {
			params := make(map[string]int)
			var param string
			var temp int
			for _, v := range wfms {
				params[v.Param]++
			}
			for k, v := range params {
				if temp < v {
					temp = v
					param = k
				}
			}
			//参数携带模式暂时未定 暂时为少数服从多数原则  后续会增加原则配置 (少数服从多数,仅一关键字即为关键字,所有关键字才为关键字 三种方案)
			txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, param).Error
			if txErr != nil {
				return txErr, []model.WorkflowMove{}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
351 352 353 354 355 356 357 358 359 360
			}
			newWfm = append(newWfm, model.WorkflowMove{
				BusinessID:        oldWfm.BusinessID,
				BusinessType:      oldWfm.BusinessType,
				PromoterID:        oldWfm.PromoterID,
				OperatorID:        0,
				WorkflowNodeID:    edge.Target,
				WorkflowProcessID: oldWfm.WorkflowProcessID,
				Param:             "",
				Action:            "",
361
				IsActive:          true})
Mr.奇淼('s avatar
Mr.奇淼( 已提交
362 363 364
		}
		return nil, newWfm

Mr.奇淼('s avatar
Mr.奇淼( 已提交
365
	case constant.PARELLEL_GATEWAY:
Mr.奇淼('s avatar
Mr.奇淼( 已提交
366 367
		// 当为并行网关时候 找出所有线路创建并行节点
		txErr := tx.Find(&edges, "workflow_process_id = ? and source = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
368
		if txErr != nil {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
369 370
			return txErr, []model.WorkflowMove{}
		}
371
		for _, v := range edges {
Mr.奇淼('s avatar
Mr.奇淼( 已提交
372 373 374 375 376 377 378 379 380
			newWfm = append(newWfm, model.WorkflowMove{
				BusinessID:        oldWfm.BusinessID,
				BusinessType:      oldWfm.BusinessType,
				PromoterID:        oldWfm.PromoterID,
				OperatorID:        0,
				WorkflowNodeID:    v.Target,
				WorkflowProcessID: oldWfm.WorkflowProcessID,
				Param:             "",
				Action:            "",
381
				IsActive:          true})
Mr.奇淼('s avatar
Mr.奇淼( 已提交
382 383
		}

384
		return nil, newWfm
385 386 387 388 389 390 391 392 393 394 395 396
	case constant.END:
		newWfm = append(newWfm, model.WorkflowMove{
			BusinessID:        oldWfm.BusinessID,
			BusinessType:      oldWfm.BusinessType,
			PromoterID:        oldWfm.PromoterID,
			OperatorID:        oldWfm.OperatorID,
			WorkflowNodeID:    targetNodeID,
			WorkflowProcessID: oldWfm.WorkflowProcessID,
			Param:             "",
			Action:            "",
			IsActive:          false})
		return nil, newWfm
Mr.奇淼('s avatar
Mr.奇淼( 已提交
397 398 399 400 401 402 403 404 405 406
	default:
		newWfm = append(newWfm, model.WorkflowMove{
			BusinessID:        oldWfm.BusinessID,
			BusinessType:      oldWfm.BusinessType,
			PromoterID:        oldWfm.PromoterID,
			OperatorID:        0,
			WorkflowNodeID:    targetNodeID,
			WorkflowProcessID: oldWfm.WorkflowProcessID,
			Param:             "",
			Action:            "",
407
			IsActive:          true})
Mr.奇淼('s avatar
Mr.奇淼( 已提交
408
		return nil, newWfm
Mr.奇淼('s avatar
Mr.奇淼( 已提交
409 410 411 412
	}
}

func GetMyStated(userID uint) (err error, wfms []model.WorkflowMove) {
413
	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
Mr.奇淼('s avatar
Mr.奇淼( 已提交
414 415 416 417 418 419
	return err, wfms
}

func GetMyNeed(userID uint, AuthorityID string) (err error, wfms []model.WorkflowMove) {
	user := "%," + strconv.Itoa(int(userID)) + ",%"
	auth := "%," + AuthorityID + ",%"
420
	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
Mr.奇淼('s avatar
Mr.奇淼( 已提交
421 422
	return err, wfms
}
423

424 425
func GetWorkflowMoveByID(id float64) (err error, move model.WorkflowMove, moves []model.WorkflowMove, business interface{}) {
	var result interface{}
426 427 428 429 430 431 432
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		var txErr error
		txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").First(&move, "id = ?", id).Error
		if txErr != nil {
			return txErr
		}
		txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Find(&moves, "business_id = ? AND business_type = ?", move.BusinessID, move.BusinessType).Error
433 434 435 436 437 438
		if txErr != nil {
			return txErr
		}
		result = getTable(move.BusinessType)
		fmt.Println(result)
		txErr = tx.First(result, "id = ?", move.BusinessID).Error
439 440 441 442 443
		if txErr != nil {
			return txErr
		}
		return nil
	})
444
	return err, move, moves, result
445
}