| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- 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
- }
|