123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- package service
- import (
- "errors"
- "fmt"
- "math"
- "server/dao"
- "server/dao/flow"
- "strconv"
- "sync"
- "time"
- "github.com/jinzhu/gorm"
- "github.com/mumushuiding/util"
- )
- // TaskReceiver 任务
- type TaskReceiver struct {
- TaskID int `json:"taskID"`
- UserID string `json:"userID,omitempty"`
- UserName string `json:"username,omitempty"`
- Pass string `json:"pass,omitempty"`
- Company string `json:"company,omitempty"`
- ProcInstID int `json:"procInstID,omitempty"`
- Comment string `json:"comment,omitempty"`
- Candidate string `json:"candidate,omitempty"`
- }
- var completeLock sync.Mutex
- // NewTask 新任务
- func NewTask(t *dao.Task) (int, error) {
- if len(t.NodeID) == 0 {
- return 0, errors.New("request param nodeID can not be null / 任务当前所在节点nodeId不能为空!")
- }
- t.CreateTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
- return t.NewTask()
- }
- // NewTaskTx NewTaskTx
- // 开启事务
- func NewTaskTx(t *dao.Task, tx *gorm.DB) (int, error) {
- if len(t.NodeID) == 0 {
- return 0, errors.New("request param nodeID can not be null / 任务当前所在节点nodeId不能为空!")
- }
- t.CreateTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
- return t.NewTaskTx(tx)
- }
- // DeleteTask 删除任务
- func DeleteTask(id int) error {
- return dao.DeleteTask(id)
- }
- // GetTaskByID GetTaskById
- func GetTaskByID(id int) (task *dao.Task, err error) {
- return dao.GetTaskByID(id)
- }
- // GetTaskLastByProInstID GetTaskLastByProInstID
- func GetTaskLastByProInstID(procInstID int) (*dao.Task, error) {
- return dao.GetTaskLastByProInstID(procInstID)
- }
- // CompleteByToken 通过token 审批任务
- func CompleteByToken(token string, receiver *TaskReceiver) error {
- userinfo, err := GetUserinfoFromRedis(token)
- if err != nil {
- return err
- }
- pass, err := strconv.ParseBool(receiver.Pass)
- if err != nil {
- return err
- }
- err = Complete(receiver.TaskID, userinfo.ID, userinfo.Username, userinfo.Company, receiver.Comment, receiver.Candidate, pass)
- if err != nil {
- return err
- }
- return nil
- }
- // Complete Complete
- // 审批
- func Complete(taskID int, userID, username, company, comment, candidate string, pass bool) error {
- tx := dao.GetTx()
- err := CompleteTaskTx(taskID, userID, username, company, comment, candidate, pass, tx)
- if err != nil {
- tx.Rollback()
- return err
- }
- tx.Commit()
- return nil
- }
- // UpdateTaskWhenComplete 完成后更新任务
- func UpdateTaskWhenComplete(taskID int, userID string, pass bool, tx *gorm.DB) (*model.Task, error) {
- // 获取task
- completeLock.Lock() // 关锁
- defer completeLock.Unlock() //解锁
- // 查询任务
- task, err := GetTaskByID(taskID)
- if err != nil {
- return nil, err
- }
- if task == nil {
- return nil, errors.New("任务【" + fmt.Sprintf("%d", task.ID) + "】不存在")
- }
- // 判断是否已经结束
- if task.IsFinished == true {
- if task.NodeID == "结束" {
- return nil, errors.New("流程已经结束")
- }
- return nil, errors.New("任务【" + fmt.Sprintf("%d", taskID) + "】已经被审批过了!!")
- }
- // 设置处理人和处理时间
- task.Assignee = userID
- task.ClaimTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
- // ----------------会签 (默认全部通过才结束),只要存在一个不通过,就结束,然后流转到上一步
- //同意
- if pass {
- task.AgreeNum++
- } else {
- task.IsFinished = true
- }
- // 未审批人数减一
- task.UnCompleteNum--
- // 判断是否结束
- if task.UnCompleteNum == 0 {
- task.IsFinished = true
- }
- err = task.UpdateTx(tx)
- // str, _ := util.ToJSONStr(task)
- // log.Println(str)
- if err != nil {
- return nil, err
- }
- return task, nil
- }
- // CompleteTaskTx CompleteTaskTx
- // 执行任务
- func CompleteTaskTx(taskID int, userID, username, company, comment, candidate string, pass bool, tx *gorm.DB) error {
- //更新任务
- task, err := UpdateTaskWhenComplete(taskID, userID, pass, tx)
- if err != nil {
- return err
- }
- // 如果是会签
- if task.ActType == "and" {
- // fmt.Println("------------------是会签,判断用户是否已经审批过了,避免重复审批-------")
- // 判断用户是否已经审批过了(存在会签的情况)
- yes, err := IfParticipantByTaskID(userID, company, taskID)
- if err != nil {
- tx.Rollback()
- return err
- }
- if yes {
- tx.Rollback()
- return errors.New("您已经审批过了,请等待他人审批!)")
- }
- }
- // 查看任务的未审批人数是否为0,不为0就不流转
- if task.UnCompleteNum > 0 && pass == true { // 默认是全部通过
- // 添加参与人
- err := AddParticipantTx(userID, username, company, comment, task.ID, task.ProcInstID, task.Step, tx)
- if err != nil {
- return err
- }
- return nil
- }
- // 流转到下一流程
- // nodeInfos, err := GetExecNodeInfosByProcInstID(task.ProcInstID)
- // if err != nil {
- // return err
- // }
- err = MoveStageByProcInstID(userID, username, company, comment, candidate, task.ID, task.ProcInstID, task.Step, pass, tx)
- if err != nil {
- return err
- }
- return nil
- }
- // WithDrawTaskByToken 撤回任务
- func WithDrawTaskByToken(token string, receiver *TaskReceiver) error {
- userinfo, err := GetUserinfoFromRedis(token)
- if err != nil {
- return err
- }
- if len(userinfo.ID) == 0 {
- return errors.New("保存在redis中的【用户信息 userinfo】字段 ID 不能为空!!")
- }
- if len(userinfo.Username) == 0 {
- return errors.New("保存在redis中的【用户信息 userinfo】字段 username 不能为空!!")
- }
- if len(userinfo.Company) == 0 {
- return errors.New("保存在redis中的【用户信息 userinfo】字段 company 不能为空")
- }
- return WithDrawTask(receiver.TaskID, receiver.ProcInstID, userinfo.ID, userinfo.Username, userinfo.Company, receiver.Comment)
- }
- // WithDrawTask 撤回任务
- func WithDrawTask(taskID, procInstID int, userID, username, company, comment string) error {
- var err1, err2 error
- var currentTask, lastTask *model.Task
- var timesx time.Time
- var wg sync.WaitGroup
- timesx = time.Now()
- wg.Add(2)
- go func() {
- currentTask, err1 = GetTaskByID(taskID)
- wg.Done()
- }()
- go func() {
- lastTask, err2 = GetTaskLastByProInstID(procInstID)
- wg.Done()
- }()
- wg.Wait()
- if err1 != nil {
- if err1 == gorm.ErrRecordNotFound {
- return errors.New("任务不存在")
- }
- return err1
- }
- if err2 != nil {
- if err2 == gorm.ErrRecordNotFound {
- return errors.New("找不到流程实例id为【" + fmt.Sprintf("%d", procInstID) + "】的任务,无权撤回")
- }
- return err2
- }
- // str1,_:=util.ToJSONStr(currentTask)
- // str2,_:=util.ToJSONStr(lastTask)
- // fmt.Println(str1)
- // fmt.Println(str2)
- if currentTask.Step == 0 {
- return errors.New("开始位置无法撤回")
- }
- if lastTask.Assignee != userID {
- return errors.New("只能撤回本人审批过的任务!!")
- }
- if currentTask.IsFinished {
- return errors.New("已经审批结束,无法撤回!")
- }
- if currentTask.UnCompleteNum != currentTask.MemberCount {
- return errors.New("已经有人审批过了,无法撤回!")
- }
- sub := currentTask.Step - lastTask.Step
- if math.Abs(float64(sub)) != 1 {
- return errors.New("只能撤回相邻的任务!!")
- }
- var pass = false
- if sub < 0 {
- pass = true
- }
- fmt.Printf("判断是否可以撤回,耗时:%v\n", time.Since(timesx))
- timesx = time.Now()
- tx := model.GetTx()
- // 更新当前的任务
- currentTask.IsFinished = true
- err := currentTask.UpdateTx(tx)
- if err != nil {
- tx.Rollback()
- return err
- }
- // 撤回
- err = MoveStageByProcInstID(userID, username, company, comment, "", currentTask.ID, procInstID, currentTask.Step, pass, tx)
- if err != nil {
- tx.Rollback()
- return err
- }
- tx.Commit()
- fmt.Printf("撤回流程耗时:%v\n", time.Since(timesx))
- return nil
- }
- // MoveStageByProcInstID MoveStageByProcInstID
- func MoveStageByProcInstID(userID, username, company, comment, candidate string, taskID, procInstID, step int, pass bool, tx *gorm.DB) (err error) {
- nodeInfos, err := GetExecNodeInfosByProcInstID(procInstID)
- if err != nil {
- return err
- }
- return MoveStage(nodeInfos, userID, username, company, comment, candidate, taskID, procInstID, step, pass, tx)
- }
- // MoveStage MoveStage
- // 流程流转
- func MoveStage(nodeInfos []*flow.NodeInfo, userID, username, company, comment, candidate string, taskID, procInstID, step int, pass bool, tx *gorm.DB) (err error) {
- // 添加上一步的参与人
- err = AddParticipantTx(userID, username, company, comment, taskID, procInstID, step, tx)
- if err != nil {
- return err
- }
- if pass {
- step++
- if step-1 > len(nodeInfos) {
- return errors.New("已经结束无法流转到下一个节点")
- }
- } else {
- step--
- if step < 0 {
- return errors.New("处于开始位置,无法回退到上一个节点")
- }
- }
- // 指定下一步执行人
- if len(candidate) > 0 {
- nodeInfos[step].Aprover = candidate
- }
- // 判断下一流程: 如果是审批人是:抄送人
- // fmt.Printf("下一审批人类型:%s\n", nodeInfos[step].AproverType)
- // fmt.Println(nodeInfos[step].AproverType == flow.NodeTypes[flow.NOTIFIER])
- if nodeInfos[step].AproverType == flow.NodeTypes[flow.NOTIFIER] {
- // 生成新的任务
- var task = model.Task{
- NodeID: flow.NodeTypes[flow.NOTIFIER],
- Step: step,
- ProcInstID: procInstID,
- IsFinished: true,
- }
- task.IsFinished = true
- _, err := task.NewTaskTx(tx)
- if err != nil {
- return err
- }
- // 添加抄送人
- err = AddNotifierTx(nodeInfos[step].Aprover, company, step, procInstID, tx)
- if err != nil {
- return err
- }
- return MoveStage(nodeInfos, userID, username, company, comment, candidate, taskID, procInstID, step, pass, tx)
- }
- if pass {
- return MoveToNextStage(nodeInfos, userID, company, taskID, procInstID, step, tx)
- }
- return MoveToPrevStage(nodeInfos, userID, company, taskID, procInstID, step, tx)
- }
- // MoveToNextStage MoveToNextStage
- // 通过
- func MoveToNextStage(nodeInfos []*flow.NodeInfo, userID, company string, currentTaskID, procInstID, step int, tx *gorm.DB) error {
- var currentTime = util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)
- var task = getNewTask(nodeInfos, step, procInstID, currentTime) //新任务
- var procInst = &model.ProcInst{ // 流程实例要更新的字段
- NodeID: nodeInfos[step].NodeID,
- Candidate: nodeInfos[step].Aprover,
- }
- procInst.ID = procInstID
- if (step + 1) != len(nodeInfos) { // 下一步不是【结束】
- // 生成新的任务
- taksID, err := task.NewTaskTx(tx)
- if err != nil {
- return err
- }
- // 添加candidate group
- err = AddCandidateGroupTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
- if err != nil {
- return err
- }
- // 更新流程实例
- procInst.TaskID = taksID
- err = UpdateProcInst(procInst, tx)
- if err != nil {
- return err
- }
- } else { // 最后一步直接结束
- // 生成新的任务
- task.IsFinished = true
- task.ClaimTime = currentTime
- taksID, err := task.NewTaskTx(tx)
- if err != nil {
- return err
- }
- // 删除候选用户组
- err = DelCandidateByProcInstID(procInstID, tx)
- if err != nil {
- return err
- }
- // 更新流程实例
- procInst.TaskID = taksID
- procInst.EndTime = currentTime
- procInst.IsFinished = true
- procInst.Candidate = "审批结束"
- err = UpdateProcInst(procInst, tx)
- if err != nil {
- return err
- }
- }
- return nil
- }
- // MoveToPrevStage MoveToPrevStage
- // 驳回
- func MoveToPrevStage(nodeInfos []*flow.NodeInfo, userID, company string, currentTaskID, procInstID, step int, tx *gorm.DB) error {
- // 生成新的任务
- var task = getNewTask(nodeInfos, step, procInstID, util.FormatDate(time.Now(), util.YYYY_MM_DD_HH_MM_SS)) //新任务
- taksID, err := task.NewTaskTx(tx)
- if err != nil {
- return err
- }
- var procInst = &model.ProcInst{ // 流程实例要更新的字段
- NodeID: nodeInfos[step].NodeID,
- Candidate: nodeInfos[step].Aprover,
- TaskID: taksID,
- }
- procInst.ID = procInstID
- err = UpdateProcInst(procInst, tx)
- if err != nil {
- return err
- }
- if step == 0 { // 流程回到起始位置,注意起始位置为0,
- err = AddCandidateUserTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
- if err != nil {
- return err
- }
- return nil
- }
- // 添加candidate group
- err = AddCandidateGroupTx(nodeInfos[step].Aprover, company, step, taksID, procInstID, tx)
- if err != nil {
- return err
- }
- return nil
- }
- func getNewTask(nodeInfos []*flow.NodeInfo, step, procInstID int, currentTime string) *model.Task {
- var task = &model.Task{ // 新任务
- NodeID: nodeInfos[step].NodeID,
- Step: step,
- CreateTime: currentTime,
- ProcInstID: procInstID,
- MemberCount: nodeInfos[step].MemberCount,
- UnCompleteNum: nodeInfos[step].MemberCount,
- ActType: nodeInfos[step].ActType,
- }
- return task
- }
|