Prechádzať zdrojové kódy

feature(项目):
1、创建项目添加审批流
2、项目其他审批流添加产品线字段
3、rpcx文件传输修改支持多个文件

ZZH-wl 2 rokov pred
rodič
commit
f882358e14

+ 15 - 0
opms_admin/app/handler/dict.go

@@ -199,3 +199,18 @@ func (h *DictHandler) DeleteDictDataByIds(ctx context.Context, req *comm_def.Ids
 	}
 	return nil
 }
+
+// GetDictLabelByTypeAndValue 根据字典类型和字典值获取字典明细名称
+func (h *DictHandler) GetDictLabelByTypeAndValue(ctx context.Context, req *model.GetDictLabelByTypeAndValueReq, rsp *comm_def.CommonMsg) error {
+	dictService, err := service.NewDictDataService(ctx)
+	if err != nil {
+		return err
+	}
+
+	list, err := dictService.GetDictLabelByTypeAndValue(req)
+	if err != nil {
+		return err
+	}
+	rsp.Data = list
+	return nil
+}

+ 5 - 0
opms_admin/app/model/sys_dict_data.go

@@ -67,3 +67,8 @@ type EditDictDataReq struct {
 	DictCode int `p:"dictCode" v:"required|min:1#主键ID不能为空|主键ID不能小于1"`
 	DictDataAddReq
 }
+
+type GetDictLabelByTypeAndValueReq struct {
+	DictType  string `p:"dictType"`  //字典类型
+	DictValue string `p:"dictValue"` //字典标签
+}

+ 10 - 0
opms_admin/app/service/sys_dict_data.go

@@ -151,3 +151,13 @@ func (s *DictDataService) DeleteDictDataByIds(ids []int64) error {
 	}
 	return nil
 }
+
+// GetDictLabelByTypeAndValue 根据字典类型和字典值获取字典明细名称
+func (s *DictDataService) GetDictLabelByTypeAndValue(req *model.GetDictLabelByTypeAndValueReq) (string, error) {
+	result, err := s.Dao.Where(s.Dao.C.DictType, req.DictType).Where(s.Dao.C.DictValue, req.DictValue).Fields(s.Dao.C.DictLabel).Value()
+	if err != nil {
+		g.Log().Error(err)
+		return req.DictValue, myerrors.TipsError("查询失败")
+	}
+	return result.String(), nil
+}

+ 5 - 1
opms_libary/dynamic/invoker.go

@@ -2,9 +2,11 @@ package dynamic
 
 import (
 	"context"
+	"dashoo.cn/opms_libary/myerrors"
 	"fmt"
 	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/util/gconv"
 	"github.com/smallnest/rpcx/log"
 	"github.com/smallnest/rpcx/share"
 	"reflect"
@@ -207,7 +209,9 @@ func (s *InvokerImpl) HandleInvoker(ctx context.Context, req *Message) (res *Mes
 	if err != nil {
 		if reply != nil {
 			reflectTypePools.Put(mtype.ReplyType, reply)
-			res.Payload = reply
+			result := gconv.Map(reply)
+			myerrors.HandlerErrorMsg(err, result)
+			res.Payload = result
 		}
 	} else {
 		// return reply to object pool

+ 4 - 2
opms_libary/micro_srv/micro_srv.go

@@ -130,8 +130,10 @@ func streamHandler(conn net.Conn, args *share.StreamServiceArgs) {
 	ctx = context.WithValue(ctx, share.ReqMetaDataKey, args.Meta)
 
 	var form = new(multipart.Form)
+	form.Value = map[string]string{}
+	form.File = map[string]*multipart.FileHeader{}
 	for key, value := range args.Meta {
-		form.Value[key][0] = value
+		form.Value[key] = value
 	}
 
 	fileNum := gconv.Int(args.Meta["fileNum"])
@@ -166,7 +168,7 @@ func streamHandler(conn net.Conn, args *share.StreamServiceArgs) {
 			conn.Read(buf)
 			tmpFile.Write(buf)
 
-			form.File[paramName][0] = &multipart.FileHeader{FileName: fileName, FileSize: int64(size), File: tmpFile}
+			form.File[paramName] = &multipart.FileHeader{FileName: fileName, FileSize: int64(size), File: tmpFile}
 
 			// 判断是否结束
 			isEnd := make([]byte, 1)

+ 2 - 2
opms_libary/multipart/formdata.go

@@ -9,6 +9,6 @@ type FileHeader struct {
 }
 
 type Form struct {
-	Value map[string][]string
-	File  map[string][]*FileHeader
+	Value map[string]string
+	File  map[string]*FileHeader
 }

+ 13 - 7
opms_libary/myerrors/error.go

@@ -122,6 +122,18 @@ func (p HandleErrorPlugin) PreWriteResponse(ctx context.Context, req *protocol.M
 		res.Payload, _ = serializer.Encode(resData)
 		return nil
 	}
+	// error 信息转换赋值
+	HandlerErrorMsg(err, resData)
+	res.Payload, _ = serializer.Encode(resData)
+	res.SetMessageStatusType(protocol.Normal)
+	if res.Metadata != nil {
+		delete(res.Metadata, protocol.ServiceError)
+	}
+
+	return nil
+}
+
+func HandlerErrorMsg(err error, resData g.Map) {
 	// error 堆栈信息输出
 	g.Log().Error(gerror.Stack(err))
 	topCode := gerror.Code(err).Code()
@@ -153,13 +165,7 @@ func (p HandleErrorPlugin) PreWriteResponse(ctx context.Context, req *protocol.M
 		resData["code"] = int32(codeSysErr.Code())
 		resData["msg"] = codeSysErr.Message()
 	}
-	res.Payload, _ = serializer.Encode(resData)
-	res.SetMessageStatusType(protocol.Normal)
-	if res.Metadata != nil {
-		delete(res.Metadata, protocol.ServiceError)
-	}
-
-	return nil
+	fmt.Println(resData)
 }
 
 func splitErrorStr(errMsg string) string {

+ 1 - 1
opms_parent/app/handler/contract/ctr_contract.go

@@ -117,7 +117,7 @@ func (c *CtrContract) Commit(ctx context.Context, req *model.CtrContractCommitRe
 
 type CtrContractHandler struct{}
 
-func (h *CtrContractHandler) CommitWithFile(ctx context.Context, args *multipart.MultipartFile, rsp *comm_def.CommonMsg) error {
+func (h *CtrContractHandler) CommitWithFile(ctx context.Context, args *multipart.Form, rsp *comm_def.CommonMsg) error {
 	g.Log().Infof("CtrContractHandler.CommitWithFile request %#v ", *args)
 	s, err := service.NewCtrContractService(ctx)
 	if err != nil {

+ 19 - 0
opms_parent/app/handler/dingtalk/ding_event.go

@@ -183,6 +183,25 @@ func (h *DingHandler) handleBpmsInstanceChange(msg *message.MixMessage, ctx *din
 			return err.Error()
 		}
 		return "success"
+	case model.ProjectCreate:
+		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
+			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.BusinessCreatedNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+		}
+		err = s.Update(instance, msg)
+		if err != nil {
+			glog.Error(err)
+			return err.Error()
+		}
+		return "success"
 	case model.ProjectUpGrade:
 		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
 			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)

+ 13 - 14
opms_parent/app/handler/proj/business.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"dashoo.cn/opms_libary/multipart"
 	"dashoo.cn/opms_libary/myerrors"
-	"fmt"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/util/gconv"
 	"github.com/gogf/gf/util/gvalid"
@@ -177,25 +176,27 @@ func (p *BusinessHandler) BusinessUpgrade(ctx context.Context, req *projModel.Bu
 	return nil
 }
 
-// BusinessUpgradeA 项目升级A类
+// BusinessUpgradeAorB 项目升级A类或B类
 // Swagger:Business 项目 项目升级
-func (p *BusinessHandler) BusinessUpgradeA(ctx context.Context, args *multipart.MultipartFile, rsp *comm_def.CommonMsg) error {
+func (p *BusinessHandler) BusinessUpgradeAorB(ctx context.Context, formData *multipart.Form, rsp *comm_def.CommonMsg) error {
 	req := new(projModel.BusinessUpgradeReq)
-	if err := gconv.Struct(args.Meta, req); err != nil {
+	if err := gconv.Struct(formData.Value, req); err != nil {
 		return err
 	}
 	if req.NboType != projSrv.StatusC && req.NboBudget <= 0 {
 		return myerrors.TipsError("项目预算不能小于0")
 	}
-	if req.NboType == projSrv.StatusA && req.IsAdoptDashoo == "10" {
-		if args.FileName == "" {
-			return fmt.Errorf("文件名称不能为空")
+	if req.NboType == projSrv.StatusA || req.NboType == projSrv.StatusB {
+		if len(formData.File) == 0 {
+			return myerrors.TipsError("请上传报价单文件")
 		}
-		if args.File == nil {
-			return fmt.Errorf("文件不能为空")
+		if _, ok := formData.File["quotationFile"]; !ok {
+			return myerrors.TipsError("请上传报价单文件")
 		}
-		if args.File.Name() == "" {
-			return fmt.Errorf("文件路径不能为空")
+	}
+	if req.NboType == projSrv.StatusA && req.IsAdoptDashoo == "10" && len(formData.File) > 0 {
+		if _, ok := formData.File["dashooParamFile"]; !ok {
+			return myerrors.TipsError("请上传大数技术参数文件")
 		}
 	}
 	// 参数校验
@@ -206,10 +207,8 @@ func (p *BusinessHandler) BusinessUpgradeA(ctx context.Context, args *multipart.
 	if err != nil {
 		return err
 	}
-	err = businessService.BusinessUpgrade(req, args)
+	err = businessService.BusinessUpgrade(req, formData.File)
 	if err != nil {
-		rsp.Code = 500
-		rsp.Msg = "系统异常"
 		return err
 	}
 	rsp.Code = 200

+ 13 - 7
opms_parent/app/handler/work/work_order.go

@@ -93,17 +93,17 @@ func (w *WorkOrderHandler) CreateWorkOrder(ctx context.Context, req *model.WorkO
 }
 
 // 创建上传文件工单
-func (w *WorkOrderHandler) CreateUploadFileOrder(ctx context.Context, args *multipart.MultipartFile, rsp *comm_def.CommonMsg) error {
+func (w *WorkOrderHandler) CreateUploadFileOrder(ctx context.Context, formData *multipart.Form, rsp *comm_def.CommonMsg) error {
 	orderService, err := workSrv.NewOrderService(ctx)
 	if err != nil {
 		return err
 	}
 	req := new(model.WorkOrderReq)
-	if err := gconv.Struct(args.Meta, req); err != nil {
+	if err := gconv.Struct(formData.Value, req); err != nil {
 		return err
 	}
 	itemDatas := make([]model.DingTalkFormItemData, 0)
-	data := gconv.Maps(args.Meta["dingTalkFormData"])
+	data := gconv.Maps(formData.Value["dingTalkFormData"])
 	if err := gconv.Structs(data, &itemDatas); err != nil {
 		return err
 	}
@@ -113,17 +113,23 @@ func (w *WorkOrderHandler) CreateUploadFileOrder(ctx context.Context, args *mult
 	if err := gvalid.CheckStruct(ctx, req, nil); err != nil {
 		return err
 	}
-	if args.FileName == "" {
+	if len(formData.File) == 0 {
+		return myerrors.TipsError("文件不能为空")
+	}
+	if _, ok := formData.File["file"]; !ok {
+		return myerrors.TipsError("文件不能为空")
+	}
+	if formData.File["file"].FileName == "" {
 		return myerrors.TipsError("文件名称不能为空")
 	}
-	if args.File == nil {
+	if formData.File["file"].File == nil {
 		return myerrors.TipsError("文件不能为空")
 	}
-	if args.File.Name() == "" {
+	if formData.File["file"].File.Name() == "" {
 		return myerrors.TipsError("文件路径不能为空")
 	}
 
-	err = orderService.CreateWorkOrder(req, args)
+	err = orderService.CreateWorkOrder(req, formData)
 	if err != nil {
 		rsp.Code = 500
 		rsp.Msg = "系统异常"

+ 21 - 1
opms_parent/app/service/base.go

@@ -146,6 +146,10 @@ type GetDictReq struct {
 	DictType     string `p:"dictType" v:"required#字典类型不能为空"`
 	DefaultValue string `p:"defaultValue"`
 }
+type GetDictLabelByTypeAndValueReq struct {
+	DictType  string `p:"dictType"`  //字典类型
+	DictValue string `p:"dictValue"` //字典标签
+}
 
 func baseGetDictDataByType(ctx context.Context, typ string) ([]interface{}, error) {
 	srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth")
@@ -189,6 +193,22 @@ func GetDictDataTreeByType(ctx context.Context, typ string) (*gmap.ListMap, erro
 	return res, nil
 }
 
+// 根据字典类型和字典值获取字典明细名称
+func GetDictLabelByTypeAndValue(ctx context.Context, dictType, value string) (string, error) {
+	srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth")
+	defer srv.Close()
+	resp := &comm_def.CommonMsg{}
+	err := srv.Call(ctx, "GetDictLabelByTypeAndValue", GetDictLabelByTypeAndValueReq{
+		DictType:  dictType,
+		DictValue: value,
+	}, resp)
+	if err != nil {
+		g.Log().Error(err)
+		return value, nil
+	}
+	return gconv.String(resp.Data), nil
+}
+
 func StringSlicecontains(s []string, ele string) bool {
 	for _, i := range s {
 		if i == ele {
@@ -280,7 +300,7 @@ func GetUsersByRoleCode(ctx context.Context, roleCode []string, pageSize ...int)
 	return res, nil
 }
 
-//跟进发送邮件消息
+// 跟进发送邮件消息
 func GSendMail(msg g.MapStrStr) error {
 	srv := micro_srv.InitMicroSrvClient("Message", "micro_srv.auth")
 	defer srv.Close()

+ 35 - 2
opms_parent/app/service/base_test.go

@@ -1,7 +1,10 @@
 package service
 
 import (
+	dao "dashoo.cn/micro/app/dao/proj"
+	"fmt"
 	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/util/gconv"
 	"testing"
 )
 
@@ -11,11 +14,41 @@ func TestCreateSystemMessage(t *testing.T) {
 		"msgContent":  "<p>111111111</p>",
 		"msgType":     "20",
 		"msgStatus":   "10",
-		"recvUserIds": "1",
-		"recvUser":    "系统管理员",
+		"recvUserIds": "1,2,4",
 		"sendType":    "10,20,30",
 	}
 	if err := CreateSystemMessage(msg); err != nil {
 		t.Errorf("CreateSystemMessage() error = %v", err)
 	}
 }
+func TestCreateSystem(t *testing.T) {
+	dd := dao.NewProjBusinessDynamicsDao("8b9ec443")
+	data, err := dd.WhereLike("opn_type", "4%").WhereNotIn("bus_id", []int{114, 118, 176, 177, 190, 198, 301, 339, 346, 372, 443, 446, 457, 485, 486, 492, 506, 507, 524, 559, 612, 629}).
+		Order("bus_id ASC, opn_date DESC").All()
+	if err != nil {
+		fmt.Println(err)
+	}
+	var id int
+	var count int
+	for _, v := range data {
+		fmt.Println(*v)
+		if v.OpnType == "41" && count == 0 {
+			if id == 0 {
+				id = v.Id
+			} else {
+				id = 0
+			}
+		}
+		count++
+		if v.OpnType == "40" && id != 0 && count == 2 {
+			context := gconv.Map(v.OpnContent)
+			_, err = dd.Data("remark", g.Map{"nboType": context["nboType"], "origNboType": context["origNboType"]}).WherePri(id).Update()
+			if err != nil {
+				fmt.Println(err)
+			}
+			id = 0
+			count = 0
+		}
+	}
+
+}

+ 18 - 12
opms_parent/app/service/contract/ctr_contract.go

@@ -536,38 +536,44 @@ func (s CtrContractService) Commit(ctx context.Context, req *model.CtrContractCo
 
 var spaceId = "21077726250"
 
-func (s CtrContractService) CommitWithFile(ctx context.Context, args *multipart.MultipartFile) error {
+func (s CtrContractService) CommitWithFile(ctx context.Context, formData *multipart.Form) error {
 	if s.userInfo.DingtalkUid == "" {
 		return fmt.Errorf("该用户钉钉 uid 为空")
 	}
-	if args.FileName == "" {
+	if len(formData.File) == 0 {
+		return myerrors.TipsError("文件不能为空")
+	}
+	if _, ok := formData.File["file"]; !ok {
+		return myerrors.TipsError("文件不能为空")
+	}
+	if formData.File["file"].FileName == "" {
 		return fmt.Errorf("文件名称不能为空")
 	}
-	if args.File == nil {
+	if formData.File["file"].File == nil {
 		return fmt.Errorf("文件不能为空")
 	}
-	if args.File.Name() == "" {
+	if formData.File["file"].File.Name() == "" {
 		return fmt.Errorf("文件路径不能为空")
 	}
-	contractId, err := strconv.Atoi(args.Meta["contractId"])
+	contractId, err := strconv.Atoi(formData.Value["contractId"])
 	if err != nil {
-		return fmt.Errorf("合同 Id 不合法 %s", args.Meta["contractId"])
+		return fmt.Errorf("合同 Id 不合法 %s", formData.Value["contractId"])
 	}
 
-	fmt.Println(args.File.Name(), args.FileName, args.FileSize, args.Meta)
-	fmt.Println(spaceId, s.userInfo.DingtalkId, args.FileName, args.File.Name())
+	//fmt.Println(args.File.Name(), args.FileName, args.FileSize, args.Meta)
+	//fmt.Println(spaceId, s.userInfo.DingtalkId, args.FileName, args.File.Name())
 	// resp, err := s.UploadFile("21042518430", "8xljy04PZiS9iPxp5PhDnUzQiEiE", "引物导入模板-000000.xlsx", "/Users/chengjian/Downloads/引物导入模板.xlsx")
 
-	resp, err := dingtalk.Client.GetStorage().UploadFile(spaceId, s.userInfo.DingtalkId, args.FileName, args.File.Name())
+	resp, err := dingtalk.Client.GetStorage().UploadFile(spaceId, s.userInfo.DingtalkId, formData.File["file"].FileName, formData.File["file"].File.Name())
 	if err != nil {
 		return fmt.Errorf("钉钉上传文件异常 %s", err.Error())
 	}
 
 	_, err = s.Commit(ctx, &model.CtrContractCommitReq{
 		Id:            contractId,
-		ContractModel: args.Meta["contractModel"],
-		Terms:         args.Meta["terms"],
-		PayTerms:      args.Meta["payTerms"],
+		ContractModel: formData.Value["contractModel"],
+		Terms:         formData.Value["terms"],
+		PayTerms:      formData.Value["payTerms"],
 		File: []model.DingFileInfo{
 			{
 				SpaceId:  resp.Dentry.SpaceId,

+ 1 - 1
opms_parent/app/service/home/report.go

@@ -745,7 +745,7 @@ func (s *HomeService) QuerySalesEngineerFollowUpNum(day *gtime.Time) (interface{
 		followUpMonthData = append(followUpMonthData, data)
 	}
 	// 409022238
-	userList, err := service.GetUsersByRoleCode(s.Ctx, []string{"SalesEngineer", "ProductLineManager"})
+	userList, err := service.GetUsersByRoleCode(s.Ctx, []string{"SalesEngineer", "ProductLineManager"}, 100)
 	if err != nil {
 		return nil, err
 	}

+ 251 - 45
opms_parent/app/service/proj/business.go

@@ -9,11 +9,11 @@ import (
 	model "dashoo.cn/micro/app/model/proj"
 	workflowModel "dashoo.cn/micro/app/model/workflow"
 	workflowService "dashoo.cn/micro/app/service/workflow"
+	"dashoo.cn/opms_libary/plugin/dingtalk"
 
 	"dashoo.cn/micro/app/service"
 	"dashoo.cn/opms_libary/multipart"
 	"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"
 	"dashoo.cn/opms_libary/utils"
@@ -193,28 +193,33 @@ func (p *businessService) Create(req *model.AddProjBusinessReq) (err error) {
 		return err
 	}
 	// 初始化项目信息
-	businessData := new(model.ProjBusiness)
-	if err = gconv.Struct(req, businessData); err != nil {
+	business := new(model.ProjBusiness)
+	if err = gconv.Struct(req, business); err != nil {
 		return
 	}
-	businessData.NboCode = nboCode
-	//businessData.NboStatus = StatusOK
-	businessData.NboType = StatusC
-	businessData.ApproStatus = ApprovalNotSubmit
-	businessData.EstTransPrice = totalPrice
-	businessData.CustProvinceId = customer.CustProvinceId
-	businessData.CustProvince = customer.CustProvince
-	businessData.CustCityId = customer.CustCityId
-	businessData.CustCity = customer.CustCity
-	businessData.CustRegionId = customer.CustRegionId
-	businessData.CustRegion = customer.CustRegion
-	businessData.DeptId = p.GetCxtUserDeptId()
-	service.SetCreatedInfo(businessData, p.GetCxtUserId(), p.GetCxtUserName())
-	businessData.FilingTime = businessData.CreatedTime
+	business.NboCode = nboCode
+	//business.NboStatus = StatusOK
+	business.NboType = StatusC
+	business.ApproStatus = ApprovalWaiting
+	business.EstTransPrice = totalPrice
+	business.CustProvinceId = customer.CustProvinceId
+	business.CustProvince = customer.CustProvince
+	business.CustCityId = customer.CustCityId
+	business.CustCity = customer.CustCity
+	business.CustRegionId = customer.CustRegionId
+	business.CustRegion = customer.CustRegion
+	business.DeptId = p.GetCxtUserDeptId()
+	service.SetCreatedInfo(business, p.GetCxtUserId(), p.GetCxtUserName())
+	business.FilingTime = business.CreatedTime
+
+	productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
+	nboSource, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "proj_nbo_source", business.NboSource)
+	salesModel, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "proj_sales_model", business.SalesModel)
+
 	// 事务
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
 		// 添加项目
-		lastId, err := p.Dao.TX(tx).InsertAndGetId(businessData)
+		lastId, err := p.Dao.TX(tx).InsertAndGetId(business)
 		if err != nil {
 			return err
 		}
@@ -238,15 +243,118 @@ func (p *businessService) Create(req *model.AddProjBusinessReq) (err error) {
 		dynamics := model.ProjBusinessDynamics{
 			BusId:   int(lastId),
 			OpnType: OpnCreate,
-			Remark:  businessData.Remark,
+			Remark:  business.Remark,
+		}
+		_, err = p.CreateProjBusinessDynamics(tx, dynamics, business)
+		// 审批流
+		workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
+		// OMS项目转移 审批
+		bizCode := business.NboCode + ":" + gconv.String(lastId)
+		_, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectCreate, "", &workflow.StartProcessInstanceRequest{
+			ProcessCode: &BusinessCreateRequestProcessCode,
+			FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
+				{
+					Id:    utils.String("TextField-K2AD4O5B"),
+					Name:  utils.String("项目编码"),
+					Value: utils.String(business.NboCode),
+				},
+				{
+					Id:    utils.String("TextField_BDLSECETVSG0"),
+					Name:  utils.String("项目名称"),
+					Value: utils.String(business.NboName),
+				},
+				{
+					Id:    utils.String("DDSelectField_213JKZA1OUO00"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
+				{
+					Id:    utils.String("TextField_1J9BJMOZ18F40"),
+					Name:  utils.String("客户名称"),
+					Value: utils.String(business.CustName),
+				},
+				{
+					Id:    utils.String("TextField_VZ64Y44LXFK0"),
+					Name:  utils.String("主要联系人"),
+					Value: utils.String(business.ContactName),
+				},
+				{
+					Id:    utils.String("DDSelectField_6CQD451D3800"),
+					Name:  utils.String("项目来源"),
+					Value: utils.String(nboSource),
+				},
+				{
+					Id:    utils.String("TextField_AEUWH63LJ0O0"),
+					Name:  utils.String("销售工程师"),
+					Value: utils.String(business.SaleName),
+				},
+				{
+					Id:    utils.String("DDSelectField_34QSUGHO2SO0"),
+					Name:  utils.String("销售模式"),
+					Value: utils.String(salesModel),
+				},
+				{
+					Id:    utils.String("TextField_1PWK6WHMGITC0"),
+					Name:  utils.String("经销商/代理商"),
+					Value: utils.String(business.DistributorName),
+				},
+				{
+					Id:    utils.String("DDSelectField_5R11VVM6GI00"),
+					Name:  utils.String("是否为大项目"),
+					Value: utils.String(yesOrNoType[business.IsBig]),
+				},
+				{
+					Id:    utils.String("TextareaField_1GEL8JJL3H5S0"),
+					Name:  utils.String("备注"),
+					Value: utils.String(business.Remark),
+				},
+			},
+		})
+		if err != nil {
+			g.Log().Error(err)
+			return err
 		}
-		_, err = p.CreateProjBusinessDynamics(tx, dynamics, businessData)
 		return err
 	})
 
 	return
 }
 
+// BusinessCreatedNotify 项目创建 审批结果通知
+func (p *businessService) BusinessCreatedNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	business, err := p.checkDingTalkNotify(flow, msg)
+	if err != nil {
+		return err
+	}
+
+	var data = g.Map{}
+	if msg.ProcessType == "terminate" {
+		data[p.Dao.C.ApproStatus] = ApprovalReturn
+	}
+	if msg.ProcessType == "finish" && msg.Result == "refuse" {
+		data[p.Dao.C.ApproStatus] = ApprovalRejection
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		data[p.Dao.C.ApproStatus] = ApprovalOK
+	}
+
+	// 项目修改
+	_, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
+	if err != nil {
+		return err
+	}
+	// 添加项目动态
+	dynamics := model.ProjBusinessDynamics{
+		BusId:   business.Id,
+		OpnType: OpnCreatedApproval,
+	}
+	_, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
+	if err != nil {
+		return err
+	}
+	return err
+}
+
 // setProductInfo 设置产品信息
 func (p *businessService) setProductInfo(busId int, productInfo []model.BusinessProduct) (total float64, products []*model.ProjBusinessProduct, err error) {
 	products = make([]*model.ProjBusinessProduct, len(productInfo))
@@ -358,6 +466,9 @@ func (p *businessService) BusinessTransfer(req *model.BusinessTransferReq) error
 	opnContent["saleId"] = req.UserId
 	opnContent["saleName"] = req.UserName
 	opnContent["remark"] = req.Remark
+
+	productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
+
 	// 审批流
 	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
@@ -408,6 +519,11 @@ func (p *businessService) BusinessTransfer(req *model.BusinessTransferReq) error
 					Name:  utils.String("所在市"),
 					Value: utils.String(business.CustCity),
 				},
+				{
+					Id:    utils.String("DDSelectField_6OMVO1JV0980"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("TextField_1E1WOYGKRTDS0"),
 					Name:  utils.String("项目级别"),
@@ -513,7 +629,7 @@ func (p *businessService) BusinessGradation(busId int, nboType, busType string)
 }
 
 // BusinessUpgrade 项目升级
-func (p *businessService) BusinessUpgrade(req *model.BusinessUpgradeReq, args *multipart.MultipartFile) error {
+func (p *businessService) BusinessUpgrade(req *model.BusinessUpgradeReq, fileMap map[string]*multipart.FileHeader) error {
 	business, err := p.BusinessGradation(req.Id, req.NboType, "up")
 	if err != nil {
 		return err
@@ -544,7 +660,7 @@ func (p *businessService) BusinessUpgrade(req *model.BusinessUpgradeReq, args *m
 		if err != nil {
 			return err
 		}
-		err = p.BusUpgradeDingEvent(business, req, args)
+		err = p.BusUpgradeDingEvent(business, req, fileMap)
 		return err
 	})
 	return err
@@ -572,11 +688,13 @@ func (p *businessService) getBusDingUpgradeType(dbNboType, reqNboType string) st
 }
 
 // BusUpgradeDingEvent 项目升级钉钉审批流调用
-func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req *model.BusinessUpgradeReq, args *multipart.MultipartFile) error {
+func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req *model.BusinessUpgradeReq, fileMap map[string]*multipart.FileHeader) error {
 	upgradeType := p.getBusDingUpgradeType(business.NboType, req.NboType)
 	if upgradeType == "" {
 		return myerrors.TipsError("错误的升级类型")
 	}
+	productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
+
 	// 审批流
 	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	// OMS项目升级 审批
@@ -598,6 +716,11 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 					Name:  utils.String("项目名称"),
 					Value: utils.String(business.NboName),
 				},
+				{
+					Id:    utils.String("DDSelectField_1MJU37HGJX4W0"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("DDSelectField_VSA3U380ZK00"),
 					Name:  utils.String("升级类型"),
@@ -622,6 +745,20 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 		}
 
 	case StatusB:
+		quotationFile := make([]contractModel.DingFileInfo, 0)
+		if len(fileMap) > 0 {
+			for k, files := range fileMap {
+				// 报价单
+				if k == "quotationFile" {
+					if quotationFile, err = p.txCreateBusinessDingTalkFile(business, k, files); err != nil {
+						return err
+					}
+				}
+			}
+		}
+		if len(quotationFile) == 0 {
+			return myerrors.TipsError("请上传报价单文件")
+		}
 		processCode := &BusinessUpgradeBRequestProcessCode
 		dingReq = &workflow.StartProcessInstanceRequest{
 			ProcessCode: processCode,
@@ -636,6 +773,11 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 					Name:  utils.String("项目名称"),
 					Value: utils.String(business.NboName),
 				},
+				{
+					Id:    utils.String("DDSelectField_213JKZA1OUO00"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("DDSelectField_VSA3U380ZK00"),
 					Name:  utils.String("升级类型"),
@@ -681,6 +823,11 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 					Name:  utils.String("是否我司参数"),
 					Value: utils.String(gconv.String(yesOrNoType[req.IsAdoptDashoo])),
 				},
+				{
+					Id:    utils.String("DDAttachment_KZPWZJS9GHO0"),
+					Name:  utils.String("上传报价单"),
+					Value: utils.String(gconv.String(quotationFile)),
+				},
 				{
 					Id:    utils.String("TextareaField_1GEL8JJL3H5S0"),
 					Name:  utils.String("备注"),
@@ -690,25 +837,27 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 		}
 
 	case StatusA:
-		var file []contractModel.DingFileInfo
-		if args != nil {
-			resp, err := dingtalk.Client.GetStorage().UploadFile(service.DingTalkSpaceId, p.GetCxtUserDingtalkId(), args.FileName, args.File.Name())
-			if err != nil {
-				return fmt.Errorf("钉钉上传文件异常 %s", err.Error())
-			}
-			g.Log().Info("项目转A类提交大数参数文件", resp)
-			file = []contractModel.DingFileInfo{{
-				SpaceId:  resp.Dentry.SpaceId,
-				FileId:   resp.Dentry.Id,
-				FileName: resp.Dentry.Name,
-				FileSize: resp.Dentry.Size,
-				FileType: resp.Dentry.Extension,
-			}}
-			err = p.txCreateBusinessFile(business.Id, file)
-			if err != nil {
-				return err
+		var dashooParamFile []contractModel.DingFileInfo
+		var quotationFile []contractModel.DingFileInfo
+		if len(fileMap) > 0 {
+			for k, files := range fileMap {
+				// 报价单
+				if k == "quotationFile" {
+					if quotationFile, err = p.txCreateBusinessDingTalkFile(business, k, files); err != nil {
+						return err
+					}
+				}
+				// 大数参数文件
+				if k == "dashooParamFile" {
+					if dashooParamFile, err = p.txCreateBusinessDingTalkFile(business, k, files); err != nil {
+						return err
+					}
+				}
 			}
 		}
+		if len(quotationFile) == 0 {
+			return myerrors.TipsError("请上传报价单文件")
+		}
 		processCode := &BusinessUpgradeARequestProcessCode
 		dingReq = &workflow.StartProcessInstanceRequest{
 			ProcessCode: processCode,
@@ -723,6 +872,11 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 					Name:  utils.String("项目名称"),
 					Value: utils.String(business.NboName),
 				},
+				{
+					Id:    utils.String("DDSelectField_L4CSUVLU1NK"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("DDSelectField_VSA3U380ZK00"),
 					Name:  utils.String("升级类型"),
@@ -771,7 +925,12 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 				{
 					Id:    utils.String("DDAttachment_11Q7DBRKE6HC0"),
 					Name:  utils.String("附件"),
-					Value: utils.String(gconv.String(file)),
+					Value: utils.String(gconv.String(dashooParamFile)),
+				},
+				{
+					Id:    utils.String("DDAttachment_19Y01ZRBFWXS0"),
+					Name:  utils.String("上传报价单"),
+					Value: utils.String(gconv.String(quotationFile)),
 				},
 				{
 					Id:    utils.String("TextareaField_1GEL8JJL3H5S0"),
@@ -792,14 +951,46 @@ func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req
 	return nil
 }
 
+// 项目上传文件至钉钉
+func (p *businessService) txCreateBusinessDingTalkFile(business *model.ProjBusiness, fileType string, file *multipart.FileHeader) ([]contractModel.DingFileInfo, error) {
+	dingTalkFiles := make([]contractModel.DingFileInfo, 0)
+	//for _, file := range files {
+	resp, err := dingtalk.Client.GetStorage().UploadFile(service.DingTalkSpaceId, p.GetCxtUserDingtalkId(), file.FileName, file.File.Name())
+	if err != nil {
+		g.Log().Error(err)
+		return nil, myerrors.TipsError("钉钉上传文件异常")
+	}
+	typ := "项目转" + nboType[business.NboType] + "类"
+	if fileType == "quotationFile" {
+		typ += "上传报价单文件"
+	}
+	if fileType == "dashooParamFile" {
+		typ += "上传大数技术参数文件"
+	}
+	g.Log().Info(typ, resp)
+	dingTalkFiles = append(dingTalkFiles, contractModel.DingFileInfo{
+		SpaceId:  resp.Dentry.SpaceId,
+		FileId:   resp.Dentry.Id,
+		FileName: resp.Dentry.Name,
+		FileSize: resp.Dentry.Size,
+		FileType: resp.Dentry.Extension,
+	})
+	//}
+	err = p.txCreateBusinessFile(business.Id, typ, dingTalkFiles)
+	if err != nil {
+		return nil, err
+	}
+	return dingTalkFiles, nil
+}
+
 // 采用大数参数文件记录
-func (p *businessService) txCreateBusinessFile(busId int, files []contractModel.DingFileInfo) error {
+func (p *businessService) txCreateBusinessFile(busId int, fileSource string, files []contractModel.DingFileInfo) error {
 	dataList := make([]*model.ProjBusinessFile, 0)
 	for _, v := range files {
 		data := new(model.ProjBusinessFile)
 		data.BusId = busId
 		data.FileName = v.FileName
-		data.FileSource = "项目转为A类采用大数参数文件"
+		data.FileSource = fileSource
 		data.FileSize = gconv.String(v.FileSize)
 		data.FileUrl = strings.Join([]string{"dingtalk", v.SpaceId, v.FileId}, ":")
 		service.SetCreatedInfo(data, p.GetCxtUserId(), p.GetCxtUserName())
@@ -899,6 +1090,8 @@ func (p *businessService) BusinessDowngrade(req *model.BusinessDowngradeReq) err
 	opnContent["approStatus"] = ApprovalWaiting
 	service.SetUpdatedInfo(opnContent, p.GetCxtUserId(), p.GetCxtUserName())
 
+	productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
+
 	// 审批流
 	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
@@ -952,6 +1145,11 @@ func (p *businessService) BusinessDowngrade(req *model.BusinessDowngradeReq) err
 					Name:  utils.String("降级类型"),
 					Value: utils.String(downgradeType),
 				},
+				{
+					Id:    utils.String("DDSelectField_1UCNHJ0P8C5C0"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("TextField_X4D3QGARU7K0"),
 					Name:  utils.String("支持内容"),
@@ -1130,6 +1328,9 @@ func (p *businessService) ConvertToReserve(req *model.BusinessToReserveReq) erro
 	if business == nil {
 		return myerrors.TipsError("项目已提交审批任务,无法重复提交。")
 	}
+
+	productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
+
 	// 审批流
 	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
@@ -1181,6 +1382,11 @@ func (p *businessService) ConvertToReserve(req *model.BusinessToReserveReq) erro
 					Name:  utils.String("项目级别"),
 					Value: utils.String(convertToReserveType[business.NboType]),
 				},
+				{
+					Id:    utils.String("DDSelectField_1UVBB1LZHIJK0"),
+					Name:  utils.String("产品线"),
+					Value: utils.String(productLine),
+				},
 				{
 					Id:    utils.String("TextField_1NDD3TY8KJB40"),
 					Name:  utils.String("销售工程师"),
@@ -1242,12 +1448,12 @@ func (p *businessService) ConvertToReserveNotify(flow *workflowModel.PlatWorkflo
 func (p *businessService) checkDingTalkNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) (*model.ProjBusiness, error) {
 	bizCode := strings.Split(flow.BizCode, ":")
 	if len(bizCode) != 2 {
-		return nil, fmt.Errorf("项目转储备审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
+		return nil, fmt.Errorf("项目审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
 	}
 	nboCode := bizCode[0]
 	busId, err := strconv.Atoi(bizCode[1])
 	if err != nil {
-		return nil, fmt.Errorf("项目转储备审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
+		return nil, fmt.Errorf("项目审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
 	}
 	if msg.ProcessType != "finish" && msg.ProcessType != "terminate" {
 		return nil, fmt.Errorf("无法识别的 ProcessType :%s", msg.ProcessType)

+ 3 - 1
opms_parent/app/service/proj/const.go

@@ -5,6 +5,7 @@ import "github.com/gogf/gf/frame/g"
 // 项目动态类型
 const (
 	OpnCreate            = "10" // 创建动态
+	OpnCreatedApproval   = "11" // 创建审批动态
 	OpnUpdate            = "20" // 更新动态
 	OpnStatus            = "30" // 更新项目状态动态
 	OpnUpgrade           = "40" // 升级动态
@@ -40,6 +41,7 @@ const (
 
 // 钉钉审批流 Code
 var (
+	BusinessCreateRequestProcessCode    = "PROC-8FDE2780-CE5A-4148-B9ED-941FBB2B9106" // 项目创建
 	BusinessUpgradeCRequestProcessCode  = "PROC-A1B1C9EF-EDB8-4F77-8058-06B60452574F" // 项目升级 转C
 	BusinessUpgradeBRequestProcessCode  = "PROC-2D7A7F90-8E86-495C-A332-18690A0F0109" // 项目升级 转B
 	BusinessUpgradeARequestProcessCode  = "PROC-D0425E06-F8AA-4B50-A253-376BC40CCE17" // 项目升级 转A
@@ -53,8 +55,8 @@ var nboType = g.MapStrStr{
 	StatusA:       "A",
 	StatusB:       "B",
 	StatusC:       "C",
-	StatusDeal:    "成交",
 	StatusReserve: "储备",
+	StatusDeal:    "成交",
 }
 
 // 钉钉 转储备类型

+ 3 - 3
opms_parent/app/service/work/work_order.go

@@ -160,7 +160,7 @@ func (s *OrderService) UpdateById(req *model.UpdateWorkOrderReq) error {
 	return nil
 }
 
-func (s *OrderService) CreateWorkOrder(req *model.WorkOrderReq, args *multipart.MultipartFile) (err error) {
+func (s *OrderService) CreateWorkOrder(req *model.WorkOrderReq, args *multipart.Form) (err error) {
 	data := new(model.WorkOrder)
 	if err = gconv.Struct(req, data); err != nil {
 		return
@@ -171,7 +171,7 @@ func (s *OrderService) CreateWorkOrder(req *model.WorkOrderReq, args *multipart.
 	if args != nil {
 		for k, v := range req.FormData {
 			if v.ComponentName == "DDAttachment" {
-				file, err := s.UploadFile(args)
+				file, err := s.UploadFile(args.File["file"])
 				if err != nil {
 					return err
 				}
@@ -212,7 +212,7 @@ func (s *OrderService) CreateWorkOrder(req *model.WorkOrderReq, args *multipart.
 	return
 }
 
-func (s *OrderService) UploadFile(args *multipart.MultipartFile) ([]contractModel.DingFileInfo, error) {
+func (s *OrderService) UploadFile(args *multipart.FileHeader) ([]contractModel.DingFileInfo, error) {
 	resp, err := dingtalk.Client.GetStorage().UploadFile(service.DingTalkSpaceId, s.GetCxtUserDingtalkId(), args.FileName, args.File.Name())
 	if err != nil {
 		return nil, myerrors.TipsError(fmt.Sprintf("钉钉上传文件异常 %s", err.Error()))