package service import ( "encoding/json" "errors" "ferry/global/orm" "ferry/models/base" "ferry/models/process" "ferry/models/system" "ferry/pkg/notify" "ferry/tools" "fmt" "reflect" "time" "github.com/jinzhu/gorm" "github.com/gin-gonic/gin" ) /* @Author : lanyulei @Desc : 处理工单 */ /* -- 节点 -- start: 开始节点 userTask: 审批节点 receiveTask: 处理节点 scriptTask: 任务节点 end: 结束节点 -- 网关 -- exclusiveGateway: 排他网关 parallelGateway: 并行网关 inclusiveGateway: 包容网关 */ type Handle struct { cirHistoryList []process.CirculationHistory workOrderId int updateValue map[string]interface{} stateValue map[string]interface{} targetStateValue map[string]interface{} WorkOrderData [][]byte workOrderDetails process.WorkOrderInfo endHistory bool flowProperties int circulationValue string processState ProcessState tx *gorm.DB } // 会签 func (h *Handle) Countersign(c *gin.Context) (err error) { var ( stateList []map[string]interface{} stateIdMap map[string]interface{} currentState map[string]interface{} cirHistoryCount int userInfoList []system.SysUser circulationStatus bool ) err = json.Unmarshal(h.workOrderDetails.State, &stateList) if err != nil { return } stateIdMap = make(map[string]interface{}) for _, v := range stateList { stateIdMap[v["id"].(string)] = v["label"] if v["id"].(string) == h.stateValue["id"].(string) { currentState = v } } userStatusCount := 0 circulationStatus = false for _, cirHistoryValue := range h.cirHistoryList { if len(currentState["processor"].([]interface{})) > 1 { if _, ok := stateIdMap[cirHistoryValue.Source]; !ok { break } } if currentState["process_method"].(string) == "person" { // 用户会签 for _, processor := range currentState["processor"].([]interface{}) { if cirHistoryValue.ProcessorId != tools.GetUserId(c) && cirHistoryValue.Source == currentState["id"].(string) && cirHistoryValue.ProcessorId == int(processor.(float64)) { cirHistoryCount += 1 } } if cirHistoryCount == len(currentState["processor"].([]interface{}))-1 { circulationStatus = true break } } else if currentState["process_method"].(string) == "role" || currentState["process_method"].(string) == "department" { // 全员处理 var tmpUserList []system.SysUser if h.stateValue["fullHandle"].(bool) { db := orm.Eloquent.Model(&system.SysUser{}) if currentState["process_method"].(string) == "role" { db = db.Where("role_id in (?)", currentState["processor"].([]interface{})) } else if currentState["process_method"].(string) == "department" { db = db.Where("dept_id in (?)", currentState["processor"].([]interface{})) } err = db.Find(&userInfoList).Error if err != nil { return } temp := map[string]struct{}{} for _, user := range userInfoList { if _, ok := temp[user.Username]; !ok { temp[user.Username] = struct{}{} tmpUserList = append(tmpUserList, user) } } for _, user := range tmpUserList { if cirHistoryValue.Source == currentState["id"].(string) && cirHistoryValue.ProcessorId != tools.GetUserId(c) && cirHistoryValue.ProcessorId == user.UserId { userStatusCount += 1 break } } } else { // 普通会签 for _, processor := range currentState["processor"].([]interface{}) { db := orm.Eloquent.Model(&system.SysUser{}) if currentState["process_method"].(string) == "role" { db = db.Where("role_id = ?", processor) } else if currentState["process_method"].(string) == "department" { db = db.Where("dept_id = ?", processor) } err = db.Find(&userInfoList).Error if err != nil { return } for _, user := range userInfoList { if user.UserId != tools.GetUserId(c) && cirHistoryValue.Source == currentState["id"].(string) && cirHistoryValue.ProcessorId == user.UserId { userStatusCount += 1 break } } } } if h.stateValue["fullHandle"].(bool) { if userStatusCount == len(tmpUserList)-1 { circulationStatus = true } } else { if userStatusCount == len(currentState["processor"].([]interface{}))-1 { circulationStatus = true } } } } if circulationStatus { h.endHistory = true err = h.circulation() if err != nil { return } } return } // 工单跳转 func (h *Handle) circulation() (err error) { var ( stateValue []byte ) stateList := make([]interface{}, 0) for _, v := range h.updateValue["state"].([]map[string]interface{}) { stateList = append(stateList, v) } err = GetVariableValue(stateList, h.workOrderDetails.Creator) if err != nil { return } stateValue, err = json.Marshal(h.updateValue["state"]) if err != nil { return } err = h.tx.Model(&process.WorkOrderInfo{}). Where("id = ?", h.workOrderId). Updates(map[string]interface{}{ "state": stateValue, "related_person": h.updateValue["related_person"], }).Error if err != nil { h.tx.Rollback() return } // 如果是跳转到结束节点,则需要修改节点状态 if h.targetStateValue["clazz"] == "end" { err = h.tx.Model(&process.WorkOrderInfo{}). Where("id = ?", h.workOrderId). Update("is_end", 1).Error if err != nil { h.tx.Rollback() return } } return } // 条件判断 func (h *Handle) ConditionalJudgment(condExpr map[string]interface{}) (result bool, err error) { var ( condExprOk bool condExprValue interface{} ) defer func() { if r := recover(); r != nil { switch e := r.(type) { case string: err = errors.New(e) case error: err = e default: err = errors.New("未知错误") } return } }() for _, data := range h.WorkOrderData { var formData map[string]interface{} err = json.Unmarshal(data, &formData) if err != nil { return } if condExprValue, condExprOk = formData[condExpr["key"].(string)]; condExprOk { break } } if condExprValue == nil { err = errors.New("未查询到对应的表单数据。") return } // todo 待优化 switch reflect.TypeOf(condExprValue).String() { case "string": switch condExpr["sign"] { case "==": if condExprValue.(string) == condExpr["value"].(string) { result = true } case "!=": if condExprValue.(string) != condExpr["value"].(string) { result = true } case ">": if condExprValue.(string) > condExpr["value"].(string) { result = true } case ">=": if condExprValue.(string) >= condExpr["value"].(string) { result = true } case "<": if condExprValue.(string) < condExpr["value"].(string) { result = true } case "<=": if condExprValue.(string) <= condExpr["value"].(string) { result = true } default: err = errors.New("目前仅支持6种常规判断类型,包括(等于、不等于、大于、大于等于、小于、小于等于)") } case "float64": switch condExpr["sign"] { case "==": if condExprValue.(float64) == condExpr["value"].(float64) { result = true } case "!=": if condExprValue.(float64) != condExpr["value"].(float64) { result = true } case ">": if condExprValue.(float64) > condExpr["value"].(float64) { result = true } case ">=": if condExprValue.(float64) >= condExpr["value"].(float64) { result = true } case "<": if condExprValue.(float64) < condExpr["value"].(float64) { result = true } case "<=": if condExprValue.(float64) <= condExpr["value"].(float64) { result = true } default: err = errors.New("目前仅支持6种常规判断类型,包括(等于、不等于、大于、大于等于、小于、小于等于)") } default: err = errors.New("条件判断目前仅支持字符串、整型。") } return } // 并行网关,确认其他节点是否完成 func (h *Handle) completeAllParallel(target string) (statusOk bool, err error) { var ( stateList []map[string]interface{} ) err = json.Unmarshal(h.workOrderDetails.State, &stateList) if err != nil { err = fmt.Errorf("反序列化失败,%v", err.Error()) return } continueHistoryTag: for _, v := range h.cirHistoryList { status := false for i, s := range stateList { if v.Source == s["id"].(string) && v.Target == target { status = true stateList = append(stateList[:i], stateList[i+1:]...) continue continueHistoryTag } } if !status { break } } if len(stateList) == 1 && stateList[0]["id"].(string) == h.stateValue["id"] { statusOk = true } return } func (h *Handle) commonProcessing(c *gin.Context) (err error) { // 如果是拒绝的流转则直接跳转 if h.flowProperties == 0 { err = h.circulation() if err != nil { err = fmt.Errorf("工单跳转失败,%v", err.Error()) } return } // 会签 if h.stateValue["assignValue"] != nil && len(h.stateValue["assignValue"].([]interface{})) > 0 { if isCounterSign, ok := h.stateValue["isCounterSign"]; ok { if isCounterSign.(bool) { h.endHistory = false err = h.Countersign(c) if err != nil { return } } else { err = h.circulation() if err != nil { return } } } else { err = h.circulation() if err != nil { return } } } else { err = h.circulation() if err != nil { return } } return } func (h *Handle) HandleWorkOrder( c *gin.Context, workOrderId int, tasks []string, targetState string, sourceState string, circulationValue string, flowProperties int, remarks string, tpls []map[string]interface{}, ) (err error) { h.workOrderId = workOrderId h.flowProperties = flowProperties h.endHistory = true var ( execTasks []string relatedPersonList []int cirHistoryValue []process.CirculationHistory cirHistoryData process.CirculationHistory costDurationValue int64 sourceEdges []map[string]interface{} targetEdges []map[string]interface{} condExprStatus bool relatedPersonValue []byte parallelStatusOk bool processInfo process.Info currentUserInfo system.SysUser applyUserInfo system.SysUser sendToUserList []system.SysUser noticeList []int sendSubject string = "您有一条待办工单,请及时处理" sendDescription string = "您有一条待办工单请及时处理,工单描述如下" paramsValue struct { Id int `json:"id"` Title string `json:"title"` Priority int `json:"priority"` FormData []interface{} `json:"form_data"` } ) defer func() { if r := recover(); r != nil { switch e := r.(type) { case string: err = errors.New(e) case error: err = e default: err = errors.New("未知错误") } return } }() // 获取工单信息 err = orm.Eloquent.Model(&process.WorkOrderInfo{}).Where("id = ?", workOrderId).Find(&h.workOrderDetails).Error if err != nil { return } // 查询工单创建人信息 err = orm.Eloquent.Model(&system.SysUser{}).Where("user_id = ?", h.workOrderDetails.Creator).Find(&applyUserInfo).Error if err != nil { return } // 获取流程信息 err = orm.Eloquent.Model(&process.Info{}).Where("id = ?", h.workOrderDetails.Process).Find(&processInfo).Error if err != nil { return } err = json.Unmarshal(processInfo.Structure, &h.processState.Structure) if err != nil { return } // 获取当前节点 h.stateValue, err = h.processState.GetNode(sourceState) if err != nil { return } // 目标状态 h.targetStateValue, err = h.processState.GetNode(targetState) if err != nil { return } // 获取工单数据 err = orm.Eloquent.Model(&process.TplData{}). Where("work_order = ?", workOrderId). Pluck("form_data", &h.WorkOrderData).Error if err != nil { return } // 根据处理人查询出需要会签的条数 err = orm.Eloquent.Model(&process.CirculationHistory{}). Where("work_order = ?", workOrderId). Order("id desc"). Find(&h.cirHistoryList).Error if err != nil { return } err = json.Unmarshal(h.workOrderDetails.RelatedPerson, &relatedPersonList) if err != nil { return } relatedPersonStatus := false for _, r := range relatedPersonList { if r == tools.GetUserId(c) { relatedPersonStatus = true break } } if !relatedPersonStatus { relatedPersonList = append(relatedPersonList, tools.GetUserId(c)) } relatedPersonValue, err = json.Marshal(relatedPersonList) if err != nil { return } h.updateValue = map[string]interface{}{ "related_person": relatedPersonValue, } // 开启事务 h.tx = orm.Eloquent.Begin() stateValue := map[string]interface{}{ "label": h.targetStateValue["label"].(string), "id": h.targetStateValue["id"].(string), } sourceEdges, err = h.processState.GetEdge(h.targetStateValue["id"].(string), "source") if err != nil { return } switch h.targetStateValue["clazz"] { case "exclusiveGateway": // 排他网关 breakTag: for _, edge := range sourceEdges { edgeCondExpr := make([]map[string]interface{}, 0) err = json.Unmarshal([]byte(edge["conditionExpression"].(string)), &edgeCondExpr) if err != nil { return } for _, condExpr := range edgeCondExpr { // 条件判断 condExprStatus, err = h.ConditionalJudgment(condExpr) if err != nil { return } if condExprStatus { // 进行节点跳转 h.targetStateValue, err = h.processState.GetNode(edge["target"].(string)) if err != nil { return } if h.targetStateValue["clazz"] == "userTask" || h.targetStateValue["clazz"] == "receiveTask" { if h.targetStateValue["assignValue"] == nil || h.targetStateValue["assignType"] == "" { err = errors.New("处理人不能为空") return } } h.updateValue["state"] = []map[string]interface{}{{ "id": h.targetStateValue["id"].(string), "label": h.targetStateValue["label"], "processor": h.targetStateValue["assignValue"], "process_method": h.targetStateValue["assignType"], }} err = h.commonProcessing(c) if err != nil { err = fmt.Errorf("流程流程跳转失败,%v", err.Error()) return } break breakTag } } } if !condExprStatus { err = errors.New("所有流转均不符合条件,请确认。") return } case "parallelGateway": // 并行/聚合网关 // 入口,判断 targetEdges, err = h.processState.GetEdge(h.targetStateValue["id"].(string), "target") if err != nil { err = fmt.Errorf("查询流转信息失败,%v", err.Error()) return } if len(sourceEdges) > 0 { h.targetStateValue, err = h.processState.GetNode(sourceEdges[0]["target"].(string)) if err != nil { return } } else { err = errors.New("并行网关流程不正确") return } if len(sourceEdges) > 1 && len(targetEdges) == 1 { // 入口 h.updateValue["state"] = make([]map[string]interface{}, 0) for _, edge := range sourceEdges { targetStateValue, err := h.processState.GetNode(edge["target"].(string)) if err != nil { return err } h.updateValue["state"] = append(h.updateValue["state"].([]map[string]interface{}), map[string]interface{}{ "id": edge["target"].(string), "label": targetStateValue["label"], "processor": targetStateValue["assignValue"], "process_method": targetStateValue["assignType"], }) } err = h.circulation() if err != nil { err = fmt.Errorf("工单跳转失败,%v", err.Error()) return } } else if len(sourceEdges) == 1 && len(targetEdges) > 1 { // 出口 parallelStatusOk, err = h.completeAllParallel(sourceEdges[0]["target"].(string)) if err != nil { err = fmt.Errorf("并行检测失败,%v", err.Error()) return } if parallelStatusOk { h.endHistory = true endAssignValue, ok := h.targetStateValue["assignValue"] if !ok { endAssignValue = []int{} } endAssignType, ok := h.targetStateValue["assignType"] if !ok { endAssignType = "" } h.updateValue["state"] = []map[string]interface{}{{ "id": h.targetStateValue["id"].(string), "label": h.targetStateValue["label"], "processor": endAssignValue, "process_method": endAssignType, }} err = h.circulation() if err != nil { err = fmt.Errorf("工单跳转失败,%v", err.Error()) return } } else { h.endHistory = false } } else { err = errors.New("并行网关流程不正确") return } // 包容网关 case "inclusiveGateway": return case "start": stateValue["processor"] = []int{h.workOrderDetails.Creator} stateValue["process_method"] = "person" h.updateValue["state"] = []map[string]interface{}{stateValue} err = h.circulation() if err != nil { return } case "userTask": stateValue["processor"] = h.targetStateValue["assignValue"].([]interface{}) stateValue["process_method"] = h.targetStateValue["assignType"].(string) h.updateValue["state"] = []map[string]interface{}{stateValue} err = h.commonProcessing(c) if err != nil { return } case "receiveTask": stateValue["processor"] = h.targetStateValue["assignValue"].([]interface{}) stateValue["process_method"] = h.targetStateValue["assignType"].(string) h.updateValue["state"] = []map[string]interface{}{stateValue} err = h.commonProcessing(c) if err != nil { return } case "scriptTask": stateValue["processor"] = []int{} stateValue["process_method"] = "" h.updateValue["state"] = []map[string]interface{}{stateValue} case "end": stateValue["processor"] = []int{} stateValue["process_method"] = "" h.updateValue["state"] = []map[string]interface{}{stateValue} err = h.commonProcessing(c) if err != nil { return } } // 更新表单数据 for _, t := range tpls { var ( tplValue []byte ) tplValue, err = json.Marshal(t["tplValue"]) if err != nil { h.tx.Rollback() return } paramsValue.FormData = append(paramsValue.FormData, t["tplValue"]) // 是否可写,只有可写的模版可以更新数据 updateStatus := false if h.stateValue["clazz"].(string) == "start" { updateStatus = true } else if writeTplList, writeOK := h.stateValue["writeTpls"]; writeOK { tplListTag: for _, writeTplId := range writeTplList.([]interface{}) { if writeTplId == t["tplId"] { // 可写 // 是否隐藏,隐藏的模版无法修改数据 if hideTplList, hideOK := h.stateValue["hideTpls"]; hideOK { if hideTplList != nil && len(hideTplList.([]interface{})) > 0 { for _, hideTplId := range hideTplList.([]interface{}) { if hideTplId == t["tplId"] { // 隐藏的 updateStatus = false break tplListTag } else { updateStatus = true } } } else { updateStatus = true } } else { updateStatus = true } } } } else { // 不可写 updateStatus = false } if updateStatus { err = h.tx.Model(&process.TplData{}).Where("id = ?", t["tplDataId"]).Update("form_data", tplValue).Error if err != nil { h.tx.Rollback() return } } } // 流转历史写入 err = orm.Eloquent.Model(&cirHistoryValue). Where("work_order = ?", workOrderId). Find(&cirHistoryValue). Order("create_time desc").Error if err != nil { h.tx.Rollback() return } for _, t := range cirHistoryValue { if t.Source != h.stateValue["id"] { costDuration := time.Since(t.CreatedAt.Time) costDurationValue = int64(costDuration) / 1000 / 1000 / 1000 } } // 获取当前用户信息 err = orm.Eloquent.Model(¤tUserInfo). Where("user_id = ?", tools.GetUserId(c)). Find(¤tUserInfo).Error if err != nil { return } cirHistoryData = process.CirculationHistory{ Model: base.Model{}, Title: h.workOrderDetails.Title, WorkOrder: h.workOrderDetails.Id, State: h.stateValue["label"].(string), Source: h.stateValue["id"].(string), Target: h.targetStateValue["id"].(string), Circulation: circulationValue, Processor: currentUserInfo.NickName, ProcessorId: tools.GetUserId(c), Status: flowProperties, CostDuration: costDurationValue, Remarks: remarks, } err = h.tx.Create(&cirHistoryData).Error if err != nil { h.tx.Rollback() return } // 获取流程通知类型列表 err = json.Unmarshal(processInfo.Notice, ¬iceList) if err != nil { return } // 获取需要抄送的邮件 emailCCList := make([]string, 0) if len(h.stateValue["cc"].([]interface{})) > 0 { err = orm.Eloquent.Model(&system.SysUser{}). Where("user_id in (?)", h.stateValue["cc"]). Pluck("email", &emailCCList).Error if err != nil { err = errors.New("查询邮件抄送人失败") return } } bodyData := notify.BodyData{ SendTo: map[string]interface{}{ "userList": sendToUserList, }, EmailCcTo: emailCCList, Subject: sendSubject, Description: sendDescription, Classify: noticeList, ProcessId: h.workOrderDetails.Process, Id: h.workOrderDetails.Id, Title: h.workOrderDetails.Title, Creator: applyUserInfo.NickName, Priority: h.workOrderDetails.Priority, CreatedAt: h.workOrderDetails.CreatedAt.Format("2006-01-02 15:04:05"), } // 判断目标是否是结束节点 if h.targetStateValue["clazz"] == "end" && h.endHistory == true { sendSubject = "您的工单已处理完成" sendDescription = "您的工单已处理完成,工单描述如下" err = h.tx.Create(&process.CirculationHistory{ Model: base.Model{}, Title: h.workOrderDetails.Title, WorkOrder: h.workOrderDetails.Id, State: h.targetStateValue["label"].(string), Source: h.targetStateValue["id"].(string), Processor: currentUserInfo.NickName, ProcessorId: tools.GetUserId(c), Circulation: "结束", Remarks: "工单已结束", Status: 2, // 其他状态 }).Error if err != nil { h.tx.Rollback() return } if len(noticeList) > 0 { // 查询工单创建人信息 err = h.tx.Model(&system.SysUser{}). Where("user_id = ?", h.workOrderDetails.Creator). Find(&sendToUserList).Error if err != nil { return } bodyData.SendTo = map[string]interface{}{ "userList": sendToUserList, } bodyData.Subject = sendSubject bodyData.Description = sendDescription // 发送通知 go func(bodyData notify.BodyData) { err = bodyData.SendNotify() if err != nil { return } }(bodyData) } } h.tx.Commit() // 提交事务 // 发送通知 if len(noticeList) > 0 { stateList := make([]interface{}, 0) for _, v := range h.updateValue["state"].([]map[string]interface{}) { stateList = append(stateList, v) } sendToUserList, err = GetPrincipalUserInfo(stateList, h.workOrderDetails.Creator) if err != nil { return } bodyData.SendTo = map[string]interface{}{ "userList": sendToUserList, } bodyData.Subject = sendSubject bodyData.Description = sendDescription // 发送通知 go func(bodyData notify.BodyData) { err = bodyData.SendNotify() if err != nil { return } }(bodyData) } // 执行流程公共任务及节点任务 if h.stateValue["task"] != nil { for _, task := range h.stateValue["task"].([]interface{}) { tasks = append(tasks, task.(string)) } } continueTag: for _, task := range tasks { for _, t := range execTasks { if t == task { continue continueTag } } execTasks = append(execTasks, task) } paramsValue.Id = h.workOrderDetails.Id paramsValue.Title = h.workOrderDetails.Title paramsValue.Priority = h.workOrderDetails.Priority params, err := json.Marshal(paramsValue) if err != nil { return err } go ExecTask(execTasks, string(params)) return }