Files
gfast/app/service/common/work_flow_service/process.go
T

497 lines
14 KiB
Go

package work_flow_service
import (
"encoding/json"
"gfast/app/model/admin/user"
"gfast/app/model/admin/wf_flow_process"
"gfast/app/model/admin/wf_run"
"gfast/app/model/admin/wf_run_process"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/encoding/gjson"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
)
//流程运行数据
type ProcessData struct {
*wf_flow_process.Entity
Todo g.MapStrAny `json:"todo"`
UserInfo *user.Entity `json:"user_info"`
}
//获取流程下所有步骤信息
func ProcessAll(flowId int64) (total int64, list []*wf_flow_process.ProcessData, err error) {
return wf_flow_process.ProcessAll(flowId)
}
//获取流程转出信息
func GetProcessStep(processInfo *wf_flow_process.ProcessData, processList []*wf_flow_process.ProcessData) (
list []*wf_flow_process.ProcessStepData, err error) {
if processInfo == nil || processInfo.ProcessTo == "" || processList == nil {
return
}
processArr := garray.NewStrArrayFrom(gstr.Split(processInfo.ProcessTo, ","))
for _, process := range processList {
if processArr.Contains(gconv.String(process.Id)) {
var con []string
con, err = getProcessCondition(processInfo.Process.OutCondition, process.Id)
list = append(list, &wf_flow_process.ProcessStepData{
PrevId: processInfo.Id,
Id: process.Id,
ProcessName: process.ProcessName,
ProcessType: process.Process.ProcessType,
Condition: con,
})
}
}
return
}
//获取转出条件
func getProcessCondition(condition string, id interface{}) ([]string, error) {
if condition == "" {
return nil, nil
}
j, err := gjson.DecodeToJson(condition)
if err != nil {
g.Log().Error(err)
return nil, gerror.New("转换转出条件失败")
}
return j.GetStrings(gconv.String(id) + ".condition"), nil
}
//添加流程步骤
func ProcessAdd(flowId int64) error {
return wf_flow_process.ProcessAdd(flowId)
}
//保存流程设计
func SaveProcess(req *wf_flow_process.SaveProcessReqBatch) error {
return wf_flow_process.SaveProcess(req)
}
//获取流程管理表字段信息
func GetFlowTableFields(tableName string) (fields []*wf_flow_process.FlowTableField, err error) {
//表前缀
dbPrefix := g.DB().GetPrefix()
//数据库
database := g.Cfg().GetString("database.name")
return wf_flow_process.GetFlowTableFields(dbPrefix, database, tableName)
}
//pid 步骤ID wf_flow_process 主键
//runId 运行步骤ID wf_run 主键
func GetProcessInfo(pid, runId uint) (data *ProcessData, err error) {
var flowProcessInfo *wf_flow_process.Entity
flowProcessInfo, err = wf_flow_process.GetProcessInfoById(pid)
if err != nil {
return
}
if flowProcessInfo == nil {
err = gerror.New("不存在流程信息")
return
}
data = &ProcessData{
Entity: flowProcessInfo,
}
if flowProcessInfo.AutoPerson == 3 { //自由选择
data.Todo = g.MapStrAny{"ids": gstr.Split(flowProcessInfo.RangeUserIds, ","), "text": gstr.Split(flowProcessInfo.RangeUserText, ",")}
} else if flowProcessInfo.AutoPerson == 4 { //办理人员
data.Todo = g.MapStrAny{"text": flowProcessInfo.AutoSponsorText}
} else if flowProcessInfo.AutoPerson == 5 { //办理部门
data.Todo = g.MapStrAny{"text": flowProcessInfo.AutoRoleText}
} else if flowProcessInfo.AutoPerson == 6 { //事务接受
var runInfo *wf_run.Entity
runInfo, err = wf_run.GetRunById(runId)
if err != nil {
return
}
if runInfo == nil {
err = gerror.New("不存在运行状态信息")
return
}
var userId interface{}
userId, err = GetBilValue(runInfo.FromTable, runInfo.FromId, flowProcessInfo.WorkText)
if err != nil {
return
}
if userId == nil {
err = gerror.New("获取事务接受用户ID失败,请检测流程设计是否设置的是用户ID字段")
return
}
var userInfo *user.Entity
userInfo, err = user.GetUserById(gconv.Uint64(userId))
if err != nil {
return
}
data.Todo = g.MapStrAny{"text": userInfo.UserNickname}
data.UserInfo = userInfo
}
return
}
//同步步骤信息
func GetProcessInfos(ids []uint, runId uint) (datas []*ProcessData, err error) {
var list []*wf_flow_process.Entity
list, err = wf_flow_process.GetProcessInfosByIds(ids)
if err != nil {
return
}
datas = make([]*ProcessData, len(list))
for k, v := range list {
var todo g.MapStrAny
var userInfo *user.Entity
if v.AutoPerson == 3 { //自由选择 办理人员
todo = g.MapStrAny{
"ids": gstr.Split(v.AutoSponsorIds, ","),
"text": gstr.Split(v.AutoSponsorText, ","),
}
} else if v.AutoPerson == 4 { //办理人员
todo = g.MapStrAny{"text": v.AutoSponsorText}
} else if v.AutoPerson == 5 { //办理部门
todo = g.MapStrAny{"text": v.AutoRoleText}
} else if v.AutoPerson == 6 { //事务接受
var runInfo *wf_run.Entity
runInfo, err = wf_run.GetRunById(runId)
if err != nil {
return
}
if runInfo == nil {
err = gerror.New("不存在运行状态信息")
return
}
var userId interface{}
userId, err = GetBilValue(runInfo.FromTable, runInfo.FromId, v.WorkText)
if err != nil {
return
}
if userId == nil {
err = gerror.New("获取事务接受用户ID失败,请检测流程设计是否设置的是用户ID字段")
return
}
userInfo, err = user.GetUserById(gconv.Uint64(userId))
if err != nil {
return
}
todo = g.MapStrAny{"text": userInfo.UserNickname}
}
datas[k] = &ProcessData{
Entity: v,
Todo: todo,
UserInfo: userInfo,
}
}
return
}
//获取事务接受信息
func GetBilValue(fromTable string, fromId int, workText string) (value interface{}, err error) {
var rec gdb.Record
rec, err = GetBill(fromId, fromTable)
if err != nil {
return
}
value = rec[workText]
return
}
//获取工作流业务表信息
func GetBill(fromId int, fromTable string) (rec gdb.Record, err error) {
rec, err = g.DB().Table(fromTable).FindOne(fromId)
if err != nil {
g.Log().Error(err)
err = gerror.New("获取工作里业务数据失败")
return
}
return
}
//更新业务表信息
func UpdateBill(wfFid int, wfType string, statusField string, status int, tx *gdb.TX) error {
_, err := tx.Table(wfType).WherePri(wfFid).Update(g.Map{
statusField: status,
})
if err != nil {
g.Log().Error(err)
return gerror.New("更新单据信息失败")
}
return nil
}
//删除流程节点
func ProcessDelete(req *wf_flow_process.DeleteProcessReq) error {
return wf_flow_process.ProcessDelete(req)
}
//清空节点
func ProcessDeleteAll(flowId int) error {
_, err := wf_flow_process.Model.Where("flow_id", flowId).Delete()
if err != nil {
g.Log().Error(err)
return gerror.New("删除失败")
}
return nil
}
//获取下个审批流信息
//wfType 单据表
//wfFid 单据id
//pid 流程id
//runId 运行id
func GetNexProcessInfo(wfType string, wfFid uint, pid uint, runId uint) ([]*ProcessData, error) {
if pid == 0 {
return nil, nil
}
nex, err := wf_flow_process.GetProcessInfoById(pid)
if err != nil {
return nil, err
}
var process *ProcessData
var processes []*ProcessData
//先判断下上一个流程是什么模式
if nex.ProcessTo != "" {
//下一个流程的下一步
nexPidStr := gstr.Split(nex.ProcessTo, ",")
nexPid := make([]uint, len(nexPidStr))
for k, v := range nexPidStr {
nexPid[k] = gconv.Uint(v)
}
//下一个流程转出条件
var outCondition g.MapStrAny
err = json.Unmarshal([]byte(nex.OutCondition), &outCondition)
if err != nil {
outCondition = g.MapStrAny{}
}
switch nex.WfMode {
case 0: //单一模式
process, err = GetProcessInfo(gconv.Uint(nex.ProcessTo), runId)
if err != nil {
return nil, err
}
processes = append(processes, process)
case 1: //多个审批流
var nextProcessId uint
for key, val := range outCondition {
mapVal := gconv.Map(val)
condition := gstr.Join(gconv.SliceStr(mapVal["condition"]), " ")
//根据条件寻找匹配符合的工作流id
if gstr.ContainsI(condition, "include") {
condition = gstr.ReplaceI(condition, "include", " REGEXP ")
}
info, err := g.DB().Table(wfType).Where(condition).WherePri(wfFid).FindOne()
if err != nil {
g.Log().Error(err)
return nil, gerror.New("获取转出条件对应的审批信息失败")
}
if info != nil {
nextProcessId = gconv.Uint(key)
break
}
}
if nextProcessId == 0 { //没有权限
return nil, nil
}
process, err = GetProcessInfo(nextProcessId, runId)
if err != nil {
return nil, err
}
processes = append(processes, process)
case 2: //同步模式
processes, err = GetProcessInfos(nexPid, runId)
if err != nil {
return nil, err
}
}
} else {
process = &ProcessData{
Entity: &wf_flow_process.Entity{
Id: 0,
AutoPerson: 0,
ProcessName: "END",
},
Todo: g.MapStrAny{"text": "结束"},
}
processes = append(processes, process)
}
return processes, nil
}
func GetPreProcessInfo(runId uint) (map[int]string, error) {
var pre []*wf_flow_process.Entity
preRun, err := wf_run_process.GetProcessById(runId)
if err != nil {
return nil, err
}
//获取本流程中小于本次ID的步骤信息
var preP []*wf_run_process.Entity
preP, err = wf_run_process.GetProcessLtId(preRun)
if err != nil {
return nil, err
}
//遍历获取小于本次ID中的相关步骤
for _, v := range preP {
wfp, err := wf_flow_process.GetProcessInfoById(v.RunFlowProcess)
if err != nil {
return nil, err
}
pre = append(pre, wfp)
}
preMap := make(map[int]string, 5)
preMap[0] = "退回制单人修改"
if len(pre) > 0 {
for _, v := range pre {
todo := ""
if v.AutoPerson == 4 { //办理人员
todo = v.AutoSponsorText
} else if v.AutoPerson == 5 { //办理部门
todo = v.AutoRoleText
}
preMap[v.Id] = v.ProcessName + "(" + todo + ")"
}
}
return preMap, nil
}
//保存流程节点属性
func SaveProcessAttr(req *wf_flow_process.SaveAttrReq) error {
if req == nil {
return gerror.New("参数错误")
}
processCondition := gstr.Split(req.ProcessCondition, ",")
outCondition := make(g.MapStrAny, 10)
if len(processCondition) > 1 && req.WfMode == "1" {
return gerror.New(msgNoAction)
}
ocbt, _ := json.Marshal(outCondition)
entity, err := wf_flow_process.FindOne(req.ProcessId)
if err != nil {
g.Log().Error(err)
return gerror.New("获取流程信息失败")
}
style := gjson.New(nil)
style.Set("width", req.StyleWidth)
style.Set("height", req.StyleHeight)
style.Set("color", "#0e76a8")
entity.ProcessName = req.ProcessName
entity.ProcessType = req.ProcessType
entity.AutoPerson = gconv.Uint(req.AutoPerson)
entity.WfMode = gconv.Uint(req.WfMode)
entity.WfAction = req.WfAction
entity.AutoSponsorIds = req.AutoSponsorIds
entity.AutoSponsorText = req.AutoSponsorText
entity.AutoRoleIds = req.AutoRoleIds
entity.AutoRoleText = req.AutoRoleText
entity.RangeUserIds = req.RangeUserIds
entity.RangeUserText = req.RangeUserText
entity.WorkText = req.WorkText
entity.WorkIds = req.WorkIds
entity.WorkMsg = req.WorkMsg
entity.WorkSql = req.WorkSql
entity.IsSing = gconv.Uint(req.IsSing)
entity.IsBack = gconv.Uint(req.IsBack)
entity.OutCondition = string(ocbt)
entity.Style = style.MustToJsonString()
_, err = wf_flow_process.Model.Save(entity)
if err != nil {
g.Log().Error(err)
return gerror.New("保存失败")
}
return nil
}
//获取流程步骤第一步
func getFirstProcess(processes []*wf_flow_process.Entity) *wf_flow_process.Entity {
//找到 流程第一步
var firstProcess *wf_flow_process.Entity
for _, process := range processes {
if process.ProcessType == "is_one" {
firstProcess = process
break
}
}
return firstProcess
}
//获取步骤所有下级步骤
func GetAllNextProcessIds(id uint) (ids []uint, err error) {
processData := ([]*wf_flow_process.ProcessData)(nil)
processData, err = GetAllProcessesByProcessId(id)
if err != nil {
return
}
ids = GetNextProcessesById(id, processData)
return
}
//获取步骤所有上级步骤
func GetAllPreProcessIds(id uint) (ids []uint, err error) {
processData := ([]*wf_flow_process.ProcessData)(nil)
processData, err = GetAllProcessesByProcessId(id)
if err != nil {
return
}
ids = GetPreProcessesById(id, processData)
return
}
//获取对应步骤所属流程的所有步骤数据
func GetAllProcessesByProcessId(id uint) (processData []*wf_flow_process.ProcessData, err error) {
process := (*wf_flow_process.Entity)(nil)
process, err = wf_flow_process.GetProcessInfoById(id)
if err != nil {
return
}
if process == nil {
err = gerror.New("流程步骤信息不存在")
return
}
//获取流程下所有步骤
_, processData, err = wf_flow_process.ProcessAll(gconv.Int64(process.FlowId))
return
}
//获取所有上级步骤切片id
func GetPreProcessesById(id uint, processData []*wf_flow_process.ProcessData) (ids []uint) {
ids = make([]uint, 0, len(processData))
for _, v := range processData {
processTo := gstr.Split(v.ProcessTo, ",")
processToArr := garray.NewStrArrayFrom(processTo)
if processToArr.Contains(gconv.String(id)) {
id := gconv.Uint(v.Id)
ids = append(ids, id)
idsChd := GetPreProcessesById(id, processData)
if len(idsChd) > 0 {
ids = append(ids, idsChd...)
}
}
}
return
}
//获取所有下级步骤id切片
func GetNextProcessesById(id uint, processData []*wf_flow_process.ProcessData) (ids []uint) {
ids = make([]uint, 0, len(processData))
for _, v := range processData {
if id == gconv.Uint(v.Id) {
processTo := gstr.Split(v.ProcessTo, ",")
for _, v := range processTo {
id := gconv.Uint(v)
if id == 0 {
continue
}
ids = append(ids, id)
idsChd := make([]uint, 0, len(processData))
idsChd = GetNextProcessesById(id, processData)
if len(idsChd) > 0 {
ids = append(ids, idsChd...)
}
}
}
}
return
}