package work_flow_service import ( "fmt" "gfast/app/model/admin/user" flowModel "gfast/app/model/admin/wf_flow" "gfast/app/model/admin/wf_flow_process" "gfast/app/model/admin/wf_run" "gfast/app/model/admin/wf_run_process" "gfast/app/model/admin/wf_run_sign" "gfast/library/utils" "github.com/gogf/gf/container/garray" "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 WorkFlow struct { WfModel int `json:"wf_model"` //模式 SingSt int `json:"sing_st"` FlowId uint `json:"flow_id"` Status *wf_run_process.Entity `json:"status"` FlowProcess uint `json:"flow_process"` RunId uint `json:"run_id"` RunProcess uint `json:"run_process"` FlowName string `json:"flow_name"` Process *ProcessData `json:"process"` NextProcess []*ProcessData `json:"next_process"` Preprocess map[int]string `json:"preprocess"` SingUser []uint64 `json:"sing_user"` SignInfo *wf_run_sign.Entity `json:"sign_info"` BillCheck string `json:"bill_check"` BillTime string `json:"bill_time"` } var msgNoAction = "该功能仅对捐赠用户开放,捐赠199即可获得完整工作流功能及配套视频。" //获取流程信息 func GetFlowInfoById(flowId int64) (entity *flowModel.Entity, err error) { return flowModel.GetByID(flowId) } //获取流程名称 func GetFlowName(flowId int64) (name string, err error) { var info *flowModel.Entity info, err = GetFlowInfoById(flowId) if err != nil || info == nil { return } name = info.FlowName return } //检查流程逻辑 func CheckFlow(flowId int64) error { _, processList, err := ProcessAll(flowId) if err != nil { return err } if processList == nil { return gerror.New("没有找到步骤信息!") } oneStep := 0 for _, process := range processList { if process.Process.ProcessType == "is_one" { oneStep++ } } if oneStep == 0 { return gerror.New("没有设置第一步骤,请修改!") } if oneStep > 1 { return gerror.New(fmt.Sprintf("有 %d 个起始步骤,请修改!", oneStep)) } return nil } //获取发起流程按钮及状态 func SetBtn(wfFid uint, wfType, wfTitle, wfStatusField string, status int, userId uint64, departmentId uint64) (g.MapStrAny, error) { switch status { case 0: return g.MapStrAny{ "title": "发起审批", "api": "wfStart", "wf_type": wfType, "wf_status_field": wfStatusField, "wf_title": wfTitle, "wf_fid": wfFid, "type": "link", }, nil case 1: st := 0 userName := "" flowInfo, err := WorkFlowInfo(wfFid, wfType, userId, departmentId) if err != nil { return nil, err } if flowInfo != nil && flowInfo.NextProcess != nil { if flowInfo.Status == nil { return g.MapStrAny{ "title": "提示:当前流程故障,请联系管理员重置流程!", "type": "alert", }, nil } if flowInfo.SingSt == 0 { user := garray.NewStrArrayFrom(gstr.Split(flowInfo.Status.SponsorIds, ",")) userName = flowInfo.Status.SponsorText if flowInfo.Status.AutoPerson == 3 || flowInfo.Status.AutoPerson == 4 || flowInfo.Status.AutoPerson == 6 { if user.Contains(gconv.String(userId)) { st = 1 } } else if flowInfo.Status.AutoPerson == 5 { if user.Contains(gconv.String(departmentId)) { st = 1 } } } else { userInfo, err := user.GetUserById(gconv.Uint64(flowInfo.SignInfo.Uid)) if err != nil { return nil, err } userName = userInfo.UserNickname if gconv.Uint64(flowInfo.SignInfo.Uid) == userId { st = 1 } } } else { return nil, nil } if st == 1 { return g.MapStrAny{ "title": "审批(" + userName + ")", "api": "wfCheck", "wf_type": wfType, "wf_status_field": wfStatusField, "wf_title": wfTitle, "wf_fid": wfFid, "type": "link", }, nil } else { return g.MapStrAny{ "title": "无审批权限(" + userName + ")", "type": "text", }, nil } case 100: return g.MapStrAny{ "title": "代审", "api": "wfCheck", "wf_type": wfType, "wf_status_field": wfStatusField, "wf_title": wfTitle, "wf_fid": wfFid, "type": "link", "sup": "1", }, nil } return nil, nil } //流程状态查询 func WorkFlowInfo(wfFid uint, wfType string, userId uint64, departmentId uint64) (*WorkFlow, error) { workFlow := &WorkFlow{} if wfFid == 0 || wfType == "" { return nil, gerror.New("单据编号,单据表不可为空!") } //根据表信息,判断当前流程是否还在运行 runInfo, err := wf_run.GetRunning(&wf_run.RunSearch{ FromId: wfFid, FromTable: wfType, IsDel: 0, Status: 0, }) if err != nil { return nil, err } if runInfo != nil { info := new(wf_run_process.Entity) //获取当前运行的信息 where := &wf_run_process.SearchRunProcess{ RunId: runInfo.Id, RunFlow: runInfo.FlowId, RunFlowProcess: runInfo.RunFlowProcess, Status: "0", } processList, err := wf_run_process.GetProcessList(where) if err != nil { return nil, err } if processList == nil || len(processList) == 0 { process, err := wf_run_process.GetProcess(where) if err != nil { return nil, err } processList = append(processList, process) } //如果有两个以上的运行步骤,则认定为同步模式 if len(processList) < 2 { workFlow.WfModel = 0 info = processList[0] } else { workFlow.WfModel = 2 //同步模式 for _, process := range processList { uIds := garray.NewStrArrayFrom(gstr.Split(process.SponsorIds, ",")) if process.AutoPerson == 4 || process.AutoPerson == 3 { if uIds.Contains(gconv.String(userId)) { info = process break } } else { if uIds.Contains(gconv.String(departmentId)) { info = process break } } } if info == nil || info.Id == 0 { return nil, gerror.New("无权限") } } //设置运行信息数据 workFlow.SingSt = 0 workFlow.FlowId = runInfo.FlowId if info == nil { info = new(wf_run_process.Entity) } workFlow.Status = info workFlow.FlowProcess = info.RunFlowProcess workFlow.RunId = runInfo.Id workFlow.RunProcess = info.Id //获取流程名称 flowName, err := GetFlowName(gconv.Int64(runInfo.FlowId)) if err != nil { return nil, err } workFlow.FlowName = flowName //获取流程步骤信息 var processData *ProcessData processData, err = GetProcessInfo(info.RunFlowProcess, runInfo.Id) if err != nil { return nil, err } workFlow.Process = processData //获取下一个步骤信息 var nextProcess []*ProcessData nextProcess, err = GetNexProcessInfo(wfType, wfFid, info.RunFlowProcess, runInfo.Id) if err != nil { return nil, err } workFlow.NextProcess = nextProcess //获取前几个步骤信息,用于步骤回退 var preProcess map[int]string preProcess, err = GetPreProcessInfo(info.Id) workFlow.Preprocess = preProcess //获取所有会签人员 todo... if runInfo.IsSing == 1 { info, err = wf_run_process.GetProcess(&wf_run_process.SearchRunProcess{ RunId: runInfo.Id, RunFlow: runInfo.FlowId, RunFlowProcess: runInfo.RunFlowProcess, Status: "0", }) if err != nil { return nil, err } workFlow.SingSt = 1 workFlow.FlowProcess = info.RunFlowProcess process, err := GetProcessInfo(info.RunFlowProcess, runInfo.Id) if err != nil { return nil, err } workFlow.Status = &wf_run_process.Entity{ WfMode: gconv.Int(process.WfMode), WfAction: process.WfAction, } nextProcess, err = GetNexProcessInfo(wfType, wfFid, info.RunFlowProcess, runInfo.Id) if err != nil { return nil, err } workFlow.NextProcess = nextProcess workFlow.Process = process workFlow.RunProcess = info.Id workFlow.SignInfo, err = GetSignInfoById(gconv.Uint(runInfo.SingId)) } else { workFlow.BillCheck = "" workFlow.BillTime = "" } } else { workFlow.BillCheck = "" workFlow.BillTime = "" } return workFlow, nil } //获取对应类型的工作流 func GetWorkFlowByType(wfType string) (flows []*flowModel.Entity, err error) { return flowModel.GetWorkFlowByType(wfType) } func StartWorkFlow(req *flowModel.SaveWfFlowReq) error { //判断流程是否存在--获取所选工作流信息 flowInfo, err := flowModel.GetByID(req.WfId) if err != nil { return err } if flowInfo == nil { return gerror.New("未找到工作流信息") } //判断单据(业务表信息)是否存在 bill, err := GetBill(req.WfFid, req.WfType) if err != nil { return err } if bill == nil { return gerror.New("单据不存在") } //根据流程获取流程第一个步骤 wfProcesses, err := wf_flow_process.GetProcessesByMap(g.Map{"flow_id": req.WfId}) if err != nil { return err } if wfProcesses == nil { gerror.New("没有流程信息。") } firstProcess := getFirstProcess(wfProcesses) if firstProcess == nil { return gerror.New("流程设计出错,未找到第一步流程,请联系管理员!") } tx, err := g.DB().Begin() if err != nil { g.Log().Error(err) return gerror.New("开启事务处理失败") } //保存流程数据 runId, err := AddWfRun(req.WfId, firstProcess.Id, req.WfFid, req.WfType, req.WfTitle, req.WfStatusField, req.UserId, tx) if err != nil { tx.Rollback() return gerror.New("流程设计出错,未找到第一步流程,请联系管理员!") } //添加流程运行步骤 err = AddWorkflowProcess(req.WfId, firstProcess, runId, req.UserId, "", tx) if err != nil { tx.Rollback() return err } //设置第一步审批人员/部门信息 err = SetBusinessChecker(req.WfFid, req.WfType, runId, firstProcess, "", tx) if err != nil { tx.Rollback() return err } //添加流程日志 err = AddWorkflowCache(runId, flowInfo, firstProcess, req.WfFid, tx) if err != nil { tx.Rollback() return err } //更新单据数据 err = UpdateBill(req.WfFid, req.WfType, req.WfStatusField, 1, tx) if err != nil { tx.Rollback() return err } err = AddRunLog(runId, req, "Send", tx) if err != nil { tx.Rollback() return err } tx.Commit() return nil } //获取审批日志 func FlowLog(logType string, wfFid uint, wfType string) ([]*RunLogInfo, error) { if logType == "logs" { infos, err := RunLog(wfFid, wfType) if err != nil { return nil, err } return infos, nil } return nil, gerror.New("参数出错!") } func WorkCheckAction(req *flowModel.CheckWfSaveReq) error { if req.Art != "" { art := gjson.New(req.Art) url := art.GetString("0.url") if url != "" { url, err := utils.GetFilesPath(url) if err != nil { return err } art.Set("0.url", url) } req.Art, _ = art.ToJsonString() } if req.SingSt == 0 { runCheck, err := RunCheck(req.RunProcess) if err != nil { return err } if runCheck == 2 { return gerror.New("该业务已办理,请勿重复提交!") } if req.SubmitToSave == "ok" { //提交处理 err = DoTask(req) if err != nil { return err } } else if req.SubmitToSave == "back" { //退回处理 err = DoBack(req) if err != nil { return err } } else if req.SubmitToSave == "sing" { //会签处理 err = DoSing(req) if err != nil { return err } } else { return gerror.New("参数出错") } } else { err := DoSingEnt(req) if err != nil { return err } } return nil } type Running struct { *wf_run.Entity FlowName string `json:"flow_name"` User string `json:"user"` } func GetRunningFlow() ([]*Running, error) { run, err := wf_run.GetRuns("status", 0) if err != nil { return nil, err } running := make([]*Running, len(run)) for k, v := range run { rn := &Running{Entity: v} flow, _ := flowModel.GetByID(gconv.Int64(v.FlowId)) if flow != nil { rn.FlowName = flow.FlowName } process, err := wf_run_process.GetProcessByMap(g.Map{ "run_id": v.Id, "run_flow_process": v.RunFlowProcess, }) if err != nil { return nil, err } sponsorText := "" for _, s := range process { sponsorText += s.SponsorText + "," } sponsorText = gstr.TrimRightStr(sponsorText, ",") rn.User = sponsorText running[k] = rn } return running, nil }