package workflow import ( "context" "dashoo.cn/micro/app/dao/work" dao "dashoo.cn/micro/app/dao/workflow" model "dashoo.cn/micro/app/model/workflow" "dashoo.cn/micro/app/service" "dashoo.cn/opms_libary/myerrors" "dashoo.cn/opms_libary/plugin/dingtalk" "dashoo.cn/opms_libary/plugin/dingtalk/message" "dashoo.cn/opms_libary/plugin/dingtalk/workflow" WXwork "dashoo.cn/opms_libary/plugin/wechat/work" "dashoo.cn/opms_libary/utils" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" "github.com/silenceper/wechat/v2/cache" "github.com/silenceper/wechat/v2/work/config" "time" ) type workflowService struct { *service.ContextService Dao *dao.PlatWorkflowDao wfDao *work.WorkOrderTypeDao } func NewFlowService(ctx context.Context) (svc *workflowService, err error) { svc = new(workflowService) if svc.ContextService, err = svc.Init(ctx); err != nil { return nil, err } svc.Dao = dao.NewPlatWorkflowDao(svc.Tenant) svc.wfDao = work.NewWorkOrderTypeDao(svc.Tenant) return svc, nil } // GetSchemaByProcessCode 获取表单 schema(钉钉接口) func (s *workflowService) GetSchemaByProcessCode(processCode string) (*workflow.QuerySchemaByProcessCodeResponse, error) { g.Log().Info("搜索值", processCode) // 调用钉钉接口 client := dingtalk.NewClient() w := client.GetWorkflow() resp, err := w.QuerySchemaByProcessCode(processCode) if err != nil { return nil, err } return &resp, nil } // GetProcessInstanceDetail 获取审批实例详情(钉钉接口) func (s *workflowService) GetProcessInstanceDetail(instId string) (*workflow.QueryProcessInstanceResponse, error) { g.Log().Info("搜索值", instId) // 调用钉钉接口 client := dingtalk.NewClient() w := client.GetWorkflow() resp, err := w.QueryProcessInstanceDetail(instId) if err != nil { return nil, err } return &resp, nil } // DiffOrgApprovalStructConversion 不同企业审批流请求结构体转换 func (s *workflowService) DiffOrgApprovalStructConversion(bizType string, approvalData g.Map) (string, interface{}, error) { ent, err := s.wfDao.Where(s.wfDao.C.BusCode, model.BusCodeConst[bizType]).One() if err != nil { return "", nil, err } fmt.Println(ent) formItemList := gconv.Maps(ent.FormColumn) switch ent.WorkflowOrg { case "10": // 钉钉审批 appInfo := &workflow.StartProcessInstanceRequest{ ProcessCode: &ent.WorkflowCode, FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{}, } applyData := make([]*workflow.StartProcessInstanceRequestFormComponentValues, 0) for _, item := range formItemList { itemMap := gconv.MapStrStr(item) switch itemMap["component"] { case "TableField": rowList := make([][]*workflow.StartProcessInstanceRequestFormComponentValues, 0) for _, product := range gconv.Maps(approvalData[itemMap["code"]]) { colList := make([]*workflow.StartProcessInstanceRequestFormComponentValues, 0) for _, valMap := range gconv.Maps(itemMap["children"]) { valStrMap := gconv.MapStrStr(valMap) val := workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String(valStrMap["id"]), Name: utils.String(valStrMap["label"]), Value: utils.String(gconv.String(product[valStrMap["code"]])), } colList = append(colList, &val) } rowList = append(rowList, colList) } formValues := workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String(itemMap["id"]), Name: utils.String(itemMap["label"]), Value: utils.String(gconv.String(rowList)), } applyData = append(applyData, &formValues) default: formValues := workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String(itemMap["id"]), Name: utils.String(itemMap["label"]), Value: utils.String(gconv.String(approvalData[itemMap["code"]])), } applyData = append(applyData, &formValues) } } appInfo.FormComponentValues = applyData return ent.WorkflowOrg, appInfo, nil case "20": // 企业微信审批 appInfo := WXwork.OAApplyEvent{ CreatorUserID: s.CxtUser.WechatId, TemplateID: ent.WorkflowCode, UseTemplateApprover: 1, ApplyData: WXwork.OAContents{ Contents: []WXwork.OAContent{}, }, SummaryList: []WXwork.OASummaryList{{SummaryInfo: []WXwork.OAText{{ Text: gconv.String(approvalData["abstract"]), Lang: "zh_CN", }}}}, } applyData := make([]WXwork.OAContent, 0) for _, item := range formItemList { itemMap := gconv.MapStrStr(item) content, err := WeChatStructConversion(itemMap, approvalData) if err != nil { return "", nil, err } applyData = append(applyData, content) } appInfo.ApplyData.Contents = applyData return ent.WorkflowOrg, appInfo, err default: return "", nil, myerrors.TipsError("不支持的审批流组织") } } func WeChatStructConversion(itemMap g.MapStrStr, approvalData g.Map) (WXwork.OAContent, error) { content := WXwork.OAContent{ ID: itemMap["id"], Title: []WXwork.OAText{WXwork.OAText{ Text: itemMap["label"], Lang: "zh_CN", }}, } switch itemMap["component"] { case string(WXwork.OAControlText): content.Control = WXwork.OAControlText content.Value = WXwork.OAContentValue{ Text: gconv.String(approvalData[itemMap["code"]]), } case string(WXwork.OAControlTextarea): content.Control = WXwork.OAControlTextarea content.Value = WXwork.OAContentValue{ Text: gconv.String(approvalData[itemMap["code"]]), } case string(WXwork.OAControlNumber): content.Control = WXwork.OAControlNumber content.Value = WXwork.OAContentValue{ Number: gconv.String(approvalData[itemMap["code"]]), } case string(WXwork.OAControlMoney): content.Control = WXwork.OAControlMoney content.Value = WXwork.OAContentValue{ Money: gconv.String(approvalData[itemMap["code"]]), } case string(WXwork.OAControlFormula): content.Control = WXwork.OAControlFormula content.Value = WXwork.OAContentValue{ Formula: WXwork.OAContentFormula{Value: gconv.String(approvalData[itemMap["code"]])}, } case string(WXwork.OAControlDate): content.Control = WXwork.OAControlDate content.Value = WXwork.OAContentValue{ Date: WXwork.OAContentDate{Type: "day", Timestamp: gconv.String(gconv.GTime(approvalData[itemMap["code"]]).Timestamp())}, } case string(WXwork.OAControlDateRange): content.Control = WXwork.OAControlDateRange content.Value = WXwork.OAContentValue{ DateRange: WXwork.OAContentDateRange{ NewBegin: int(gconv.GTime(approvalData[itemMap["code"]]).Timestamp()), NewEnd: int(gconv.GTime(approvalData[itemMap["code"]]).Timestamp()), }, } case string(WXwork.OAControlSelector) + "-single": content.Control = WXwork.OAControlSelector content.Value = WXwork.OAContentValue{ Selector: WXwork.OAContentSelector{ Type: "single", Options: []WXwork.OAContentSelectorOption{ {Key: gconv.String(approvalData[itemMap["code"]])}, }, }, } case string(WXwork.OAControlSelector) + "-multi": content.Control = WXwork.OAControlSelector content.Value = WXwork.OAContentValue{ Selector: WXwork.OAContentSelector{ Type: "multi", Options: []WXwork.OAContentSelectorOption{}, }, } vals := gconv.Strings(approvalData[itemMap["code"]]) for _, val := range vals { content.Value.Selector.Options = append(content.Value.Selector.Options, WXwork.OAContentSelectorOption{Key: val}) } case string(WXwork.OAControlContact): content.Control = WXwork.OAControlContact content.Value = WXwork.OAContentValue{ Members: []WXwork.OAContentMember{{ UserID: "your_userid", Name: "your_name", }}, } case string(WXwork.OAControlLocation): content.Control = WXwork.OAControlLocation content.Value = WXwork.OAContentValue{ Location: WXwork.OAContentLocation{ Latitude: "30.547239", Longitude: "104.063291", Title: "腾讯科技(成都)有限公司(腾讯成都大厦)", Address: "四川省成都市武侯区天府三街198号腾讯成都大厦A座", Time: int(time.Now().Unix()), }, } case string(WXwork.OAControlRelatedApproval): content.Control = WXwork.OAControlRelatedApproval content.Value = WXwork.OAContentValue{ RelatedApproval: []WXwork.OAContentRelatedApproval{ {SpNo: gconv.String(approvalData[itemMap["code"]])}, }, } case string(WXwork.OAControlTable): content.Control = WXwork.OAControlTable dataList := gconv.Maps(approvalData[itemMap["code"]]) rowList := make([]WXwork.OAContentTableList, 0) for _, product := range dataList { colList := make([]WXwork.OAContent, 0) for _, valMap := range gconv.Maps(itemMap["children"]) { valStrMap := gconv.MapStrStr(valMap) val, err := WeChatStructConversion(valStrMap, product) if err != nil { return content, err } colList = append(colList, val) } rowList = append(rowList, WXwork.OAContentTableList{List: colList}) } content.Value = WXwork.OAContentValue{ Table: rowList, } default: return content, myerrors.TipsError("不支持的组件类型。") } return content, nil } // CheckStartProcessInstance 判断发起审批流实例 func (s *workflowService) CheckStartProcessInstance(bizCode, bizType, remark string, approvalData g.Map) (instanceId string, err error) { workflowOrg, approvalReq, err := s.DiffOrgApprovalStructConversion(bizType, approvalData) if err != nil { return "", err } switch workflowOrg { case "10": // 钉钉审批 return s.StartProcessInstance(bizCode, bizType, remark, approvalReq.(*workflow.StartProcessInstanceRequest)) case "20": // 企业微信审批 return s.WXStartProcessInstance(bizCode, bizType, remark, approvalReq.(WXwork.OAApplyEvent)) } return "", myerrors.TipsError("审批类型错误") } // WXStartProcessInstance 企业微信发起审批 func (s *workflowService) WXStartProcessInstance(bizCode, bizType, remark string, approvalReq WXwork.OAApplyEvent) (instanceId string, err error) { conf := &config.Config{ CorpID: g.Config().GetString("wechat.corp_id"), CorpSecret: g.Config().GetString("wechat.corp_secret"), AgentID: g.Config().GetString("wechat.agent_id"), Token: g.Config().GetString("wechat.token"), EncodingAESKey: g.Config().GetString("wechat.encoding_aes_key"), Cache: cache.NewMemory(), } client := WXwork.NewWork(conf) spNo, err := client.ApplyOAEvent(approvalReq) if err != nil { return "", err } _, err = s.saveWorkflowInstance(bizCode, bizType, remark, spNo) return spNo, err } // StartProcessInstance 发起一个新的审批流(钉钉接口,并回填到本地系统) // OriginatorUserId = utils.String("当前用户的钉钉中的Id") // ProcessCode = utils.String("每种审批对应固定的code") // bizType:业务类型(10领用20项目创建30合同创建 // 详情参照文档:https://open.dingtalk.com/document/orgapp/create-an-approval-instance func (s *workflowService) StartProcessInstance(bizCode, bizType, remark string, flow *workflow.StartProcessInstanceRequest) (instanceId string, err error) { // 参数调整 if flow.OriginatorUserId == nil { flow.OriginatorUserId = utils.String(s.GetCxtUserDingtalkUid()) } if flow.DeptId == nil { flow.DeptId = utils.Int64(gconv.Int64(s.GetCxtUserDeptId())) } g.Log().Info("搜索值", flow) // 调用钉钉接口 client := dingtalk.NewClient() w := client.GetWorkflow() resp, err := w.StartProcessInstance(flow) if err != nil { return "", err } _, err = s.saveWorkflowInstance(bizCode, bizType, remark, resp.InstanceId) return resp.InstanceId, err } // RevokeProcessInstance 撤销审批实例(钉钉接口) func (s *workflowService) RevokeProcessInstance(instId, remark string) (string, error) { g.Log().Info("搜索值instId, remark:", instId, remark) // 调用钉钉接口 client := dingtalk.NewClient() w := client.GetWorkflow() resp, err := w.RevokeProcessInstance(instId, remark, s.GetCxtUserDingtalkUid()) if err != nil { return "", err } return resp.InstanceId, nil } // 将审批实例同步到数据库中 func (s *workflowService) saveWorkflowInstance(bizCode, bizType, remark, instanceId string) (insertId int64, err error) { now := gtime.Now() // 构造基础数据 var instance model.PlatWorkflow instance.BizCode = bizCode instance.BizType = bizType instance.CurrentNode = "create" instance.CurrentNodeTime = now.Format("Y-m-d H:i:s") instance.ProcessInstId = instanceId instance.Remark = remark // 填充创建信息 service.SetCreatedInfo(&instance, s.GetCxtUserId(), s.GetCxtUserName()) // 保存数据并返回 return s.Dao.InsertAndGetId(instance) } // GetWorkflowInstance 获取实例(本地数据) func (s *workflowService) GetWorkflowInstance(instanceId string) (*model.PlatWorkflow, error) { // 查询日程实例 return s.Dao.Where("process_inst_id", instanceId).FindOne() } // Update 更新(本地数据) func (s *workflowService) Update(instance *model.PlatWorkflow, msg *message.MixMessage) (err error) { // 保存实例 instance.CurrentNode = msg.ProcessType instance.CurrentNodeTime = time.Unix(gconv.Int64(msg.FinishTime), 0).Format("2006-01-02 15:04:05") instance.ApprovalResult = msg.Result _, err = s.Dao.Save(instance) return } // GetList 任务信息列表(本地数据) func (s *workflowService) GetList(req *model.SearchWorkflowReq) (total int, flowList []*model.PlatWorkflow, err error) { flowModel := s.Dao.M if req.BizCode != "" { flowModel = flowModel.Where("biz_code", req.BizCode) } if req.BizType != "" { flowModel = flowModel.Where("biz_type", req.BizType) } if req.MySelf != "0" { flowModel = flowModel.Where("created_by", s.GetCxtUserId()) } total, err = flowModel.Count() if err != nil { g.Log().Error(err) err = myerrors.DbError("获取总行数失败。") return } err = flowModel.Page(req.GetPage()).Order("plat_task.created_time DESC").Scan(&flowList) return }