diff --git a/config.go b/config.go index 655c4e5..ffd5607 100644 --- a/config.go +++ b/config.go @@ -2,84 +2,76 @@ package l_msg_api // 业务系统和模板配置 type ( - Base struct { + base struct { ServerIndex string `json:"server_index"` // 业务系统 TempIndex string `json:"temp_index"` // 配置模板 } - accessTokenResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data struct { - AccessToken string `json:"accessToken"` // 授权token - AccessExpire int `json:"accessExpire"` // 过期时间 - } `json:"data"` + responseBody struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` } - OACreatePurchaseResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data struct { - IsSuccess bool `json:"is_success"` // 是否成功 true 成功 false 失败 - Msg string `json:"msg"` - InstanceId string `json:"instance_id"` // 审批实例id - } `json:"data"` + accessTokenResponse struct { + AccessToken string `json:"accessToken"` // 授权token + AccessExpire int `json:"accessExpire"` // 过期时间 + } + + OAResponse struct { + IsSuccess bool `json:"is_success"` // 是否成功 true 成功 false 失败 + Msg string `json:"msg"` + InstanceId string `json:"instance_id"` // 审批实例id } // 封装上游采购审批表单数据 formDataRequest struct { - Base Base `json:"base"` - formsData + Base base `json:"base"` + FormsData } - formsData struct { - FormBase - FormComponentValues []formComponentValues `json:"form_component_values"` // 审批表单数据 + + FormsData struct { + formBase + FormComponentValues []FormComponentValues `json:"form_component_values"` // 审批表单数据 + Finance *Finance `json:"finance"` // 财务模块调用 } - formComponentValues struct { // 审批表单数据 + + FormComponentValues struct { // 审批表单数据 Name string `json:"name"` Value string `json:"value"` ComponentType string `json:"component_type,omitempty"` ExtValue string `json:"extValue,omitempty"` } + Finance struct { + CheckUserId string `json:"checkUserId"` //审核人 + Sync int64 `json:"sync"` //是否是异步,如果为异步,付款申请和业务申请是同时进行 + Amount string `json:"amount"` //金额 + GoodsInfo string `json:"goodsInfo"` //商品信息 + PaymentAccount string `json:"payment_account"` //付款方账户 + TaxAmount string `json:"tax_amount"` //税率 + CallbackUrl string `json:"callback_url"` //回调地址 + Remark string `json:"remark"` //备注 + BankInfo BankInfo `json:"bankInfo"` + } + + BankInfo struct { + ResellerName string `json:"resellerName"` //供应商名称 + BankName string `json:"bankName"` //银行名称 + AccountBankName string `json:"accountBankName"` //开户行名称 + SubjectName string `json:"subjectName"` //户名 + BankAccount string `json:"bankAccount"` //银行卡号 + } + // 创建OA基础数据 - FormBase struct { + formBase struct { OutTradeNo string `json:"out_trade_no"` // 流水号 OriginatorUserId string `json:"originator_user_id"` // 钉钉申请人id } - // 创建采购审批表单数据 - CreatePurchaseForm struct { - FormBase - PurchaseNum string // 采购单号 - SupplierName string //供应商名称 - TotalCount string //采购总数量 - TotalAmount string //采购总金额 - WarehouseName string //入库仓库 - ExpectArrivalTime string //预计到货时间 - - Remark string //采购备注 - PurchaseType string //采购类型 - PayType string //支付类型 - TotalAmountUpperCase string //总金额大写 - SupplierSettlementBank string //结算账户开户行 - SupplierSettlementAccount string //结算账户 - - PurchaseInGoodsList []PurchaseInGoods - } - - // 采购单商品列表 - PurchaseInGoods struct { - GoodsCode string `json:"goods_code"` // 商品编码 - GoodsName string `json:"goods_name"` // 商品名称 - Count string `json:"count"` // 数量 - Price string `json:"price"` // 单价 - Total string `json:"total"` // 总价 - } - // 获取审批实列详情 请求数据 oAGetDetailRequest struct { - Base Base `json:"base"` + Base base `json:"base"` OutTradeNo string `json:"out_trade_no"` // 流水号 ProcessInstanceId string `json:"process_instance_id"` // 审批实例id } @@ -95,93 +87,56 @@ type ( CreateTime string `json:"createTime"` // 审批创建时间 UpdateTime string `json:"updateTime"` // 审批更新时间 } - OAGetDetailResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data OAGetDetailData `json:"data"` - } - // 创建客户充值审批表单数据 - CreateCustomerRechargeForm struct { - FormBase - Initiator string //发起人 - CustomerName string //客户名称 - RecipientAccountName string //收款账户名称 - RechargeType string //充值类型 - RechargeAmount string //充值金额 - Voucher string //充值凭证 - Remark string //备注 - CreatedAt string //创建时间 - } - - // 创建供应商充值审批表单数据 - CreateSupplierRechargeForm struct { - FormBase - Initiator string //发起人 - SupplierName string //供应商名称 - RecipientAccountName string //收款账户名称 - RechargeType string //充值类型 - RechargeAmount string //充值金额 - Voucher string //充值凭证 - Remark string //备注 - CreatedAt string //创建时间 - } - - /* - OaNotifyData 回调通知数据 - Method: POST - {"content-type": "application/json; charset=utf-8"}, - */ - OaNotifyData struct { - OutTradeNo string `json:"out_trade_no"` // 下游流水号 - ProcessInstanceId string `json:"process_instance_id"` // 创建审批任务返回的 审批实例id - Title string `json:"title"` // 实例标题 - StaffId string `json:"staff_id"` // 当前任务的审批人userId,操作转交动作的用户userId - Result int32 `json:"result"` // 审批结果,(1:同意,2:拒绝) - Type string `json:"type"` // 任务状态变更类型,start:审批任务开始,finish:审批任务正常结束(完成或转交),comment:审批任务评论,cancel:说明当前节点有多个审批人并且是或签,其中一个人执行了审批,其他审批人会推送cancel类型事件 - Remark string `json:"remark"` // 操作时写的评论内容 - CreatedAt string `json:"created_at"` // 创建时间 - UpdatedAt string `json:"updated_at"` // 结束时间 - } - - SmsRequest struct { - Base Base `json:"base"` + smsRequest struct { + Base base `json:"base"` Param string `json:"param"` // 短信模板变量对应的实际值 Tels string `json:"tels"` } - SmsSendRes struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data SmsSend `json:"data"` - } SmsSend struct { - SendList []SmsSendResView `json:"send_list"` + SendList []smsSendResView `json:"send_list"` } - SmsSendResView struct { + smsSendResView struct { Tel string `json:"tel"` IsSuccess uint32 `json:"is_success"` } - DingTalkBlackBoardSendReq struct { - Base Base `json:"base"` - BlackboardReceiver BlackboardReceiverView `json:"blackboard_receiver"` //公告接收人。 + dingTalkBlackBoardSendReq struct { + Base base `json:"base"` + BlackboardReceiver blackboardReceiverView `json:"blackboard_receiver"` //公告接收人。 Title string `json:"title,default=公告"` //公告标题 Content string `json:"content,default=大家好"` //公告内容 } - BlackboardReceiverView struct { + blackboardReceiverView struct { DeptidList []int `json:"deptid_list"` //接收部门ID列表,最大的列表长度为20。 UseridList []string `json:"userid_list"` //接收部用户ID列表,最大的列表长度为20。 } - DefaultRes struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data Default `json:"data"` - } Default struct { IsSuccess bool `json:"is_success,default=false"` Msg string `json:"msg,default=ok"` } + + oACommentRequest struct { + Base base `json:"base"` + OutTradeNo string `json:"out_trade_no"` // 流水号 + Text string `json:"text"` //评论的内容 + CommentUserId string `json:"commentUserId,optional"` //评论的内容 + File DingOACommentReqFile `json:"file,optional"` //文件 + } + + DingOACommentReqFile struct { + Photos []string `json:"photos,optional"` //图片URL地址 + Attachments []DingOACommentReqFileAttachments `json:"attachments,optional"` //图片URL地址 + } + + DingOACommentReqFileAttachments struct { + SpaceId string `json:"spaceId,optional"` //钉盘空间ID。 + FileSize string `json:"fileSize,optional"` //文件大小。 + FileId string `json:"fileId,optional"` //文件ID。 + FileName string `json:"fileName,optional"` //文件名称。 + FileType string `json:"fileType,optional"` //文件类型。 + } ) diff --git a/const.go b/const.go index 4f25542..fd66466 100644 --- a/const.go +++ b/const.go @@ -1,8 +1,8 @@ package l_msg_api const ( - ServerHost = "http://121.199.38.107:8000" - TimeOut = 60 + ServerHost = "http://127.0.0.1:8001" + TimeOut = 80000000 ) const ( @@ -14,8 +14,9 @@ const ( ) const ( - PathAccessToken = "/oauth/v1/accesstoken" - PathOaCreat = "/msg/v1/dingtalk/oa/create" - PathOaGet = "/msg/v1/dingtalk/oa/create" - SendSms = "/msg/v1//sms/send" + AccessToken = "/oauth/v1/accesstoken" + OaCreat = "/msg/v1/dingtalk/oa/create" + OaGet = "/msg/v1/dingtalk/oa/get" + OaComment = "/msg/v1/dingtalk/oa/comment" + SendSms = "/msg/v1/sms/send" ) diff --git a/httpclient/fasthttp.go b/httpclient/fasthttp.go index ccca12e..4ebb4d7 100644 --- a/httpclient/fasthttp.go +++ b/httpclient/fasthttp.go @@ -9,12 +9,13 @@ import ( func FastHttpPost(url string, header map[string]string, body []byte, timeout int) ([]byte, error) { req := fasthttp.AcquireRequest() defer fasthttp.ReleaseRequest(req) // 用完需要释放资源 - // 默认是application/x-www-form-urlencoded + req.Header.SetMethod("POST") for k, v := range header { req.Header.Set(k, v) } req.SetRequestURI(url) + req.SetTimeout(time.Duration(timeout) * time.Second) req.SetBody(body) resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(resp) // 用完需要释放资源 @@ -29,7 +30,6 @@ func FastHttpPost(url string, header map[string]string, body []byte, timeout int } } b := resp.Body() - //fmt.Println(string(b),"http请求") return b, nil } diff --git a/msg.go b/msg.go index 5174a23..9591b30 100644 --- a/msg.go +++ b/msg.go @@ -2,11 +2,6 @@ package l_msg_api import ( "encoding/json" - "errors" - "fmt" - "gitea.cdlsxd.cn/self-tools/l_msg_api/cache" - "gitea.cdlsxd.cn/self-tools/l_msg_api/httpclient" - "strings" ) type MessageCenter struct { @@ -14,139 +9,93 @@ type MessageCenter struct { ClientKey string // 客户端id,获取授权token需要 ClientSecret string header map[string]string - Base + base } -func NewMessageCenter(clientKey, clientSecret, serverIndex, tempIndex string) (*MessageCenter, error) { +func NewMessageCenter(host, clientKey, clientSecret, serverIndex, tempIndex string) (*MessageCenter, error) { msg := &MessageCenter{ - Host: ServerHost, + Host: host, ClientKey: clientKey, ClientSecret: clientSecret, - Base: Base{ + base: base{ ServerIndex: serverIndex, TempIndex: tempIndex, }, } + msg.header = map[string]string{"content-type": "application/json; charset=utf-8"} accessToken, err := msg.getAccessToken() msg.header = map[string]string{"Authorization": accessToken, "content-type": "application/json; charset=utf-8"} + return msg, err } -/* -获取授权token -AccessExpire 有效期内可缓存起来使用 -*/ -func (m *MessageCenter) getAccessToken() (string, error) { - if tokenInterface, exist := cache.InstanceCacheMap().Get(m.ClientKey); exist { - return tokenInterface.(string), nil - } - var data accessTokenResponse - url := fmt.Sprintf("%s%s", m.Host, PathAccessToken) - var authParam, _ = json.Marshal(map[string]string{"client_key": m.ClientKey, "client_secret": m.ClientSecret}) - res, err := httpclient.FastHttpPost(url, m.header, authParam, TimeOut) - if err != nil { - return "", err - } - err = json.Unmarshal(res, &data) - if data.Code != 0 { - return "", errors.New(data.Msg) - } - cache.InstanceCacheMap().Put(m.ClientKey, data.Data.AccessToken) - return data.Data.AccessToken, err -} - -// 采购单OA审批 -func (m *MessageCenter) OACreate(dTalkUserId, treadNo string, checkForm []formComponentValues) (data OACreatePurchaseResponse, err error) { - res, err := httpclient.FastHttpPost( - fmt.Sprintf("%s%s", m.Host, PathOaCreat), - m.header, - m.parseOACreateParam(dTalkUserId, treadNo, checkForm), - TimeOut) +// OACreate 发起OA审批 +func (m *MessageCenter) OACreate(dTalkUserId, treadNo string, formModel *FormsData) (data OAResponse, err error) { + formModel.formBase.OutTradeNo = treadNo + formModel.formBase.OriginatorUserId = dTalkUserId + err = m.post(OaCreat, m.parseOACreateParam(formModel), &data) if err != nil { return } - err = json.Unmarshal(res, &data) - return -} - -func (m *MessageCenter) parseOACreateParam(dTalkUserId, treadNo string, checkForm []formComponentValues) (out []byte) { - req := formDataRequest{ - Base: m.Base, - } - req.FormBase = FormBase{ - OutTradeNo: treadNo, - OriginatorUserId: dTalkUserId, - } - req.FormComponentValues = checkForm - out, _ = json.Marshal(req) return } +// OAGetDetail OA详情 func (m *MessageCenter) OAGetDetail(outTradeNo string) (data OAGetDetailData, err error) { param, _ := json.Marshal(oAGetDetailRequest{ - Base: m.Base, + Base: m.base, OutTradeNo: outTradeNo, }) - res, err := httpclient.FastHttpPost(fmt.Sprintf("%s%s", m.Host, PathOaGet), m.header, param, TimeOut) + err = m.post(OaGet, param, &data) if err != nil { return } - // 解析响应参数 - body := OAGetDetailResponse{} - err = json.Unmarshal(res, &body) - if err != nil { - return - } - if body.Code != 0 { - err = errors.New(body.Msg) - return - } - return body.Data, nil + return } -// 采购单OA审批 -func (m *MessageCenter) SendSms(tels []string, jsonParam string) (data SmsSendRes, err error) { +// SendSms 短信 +func (m *MessageCenter) SendSms(tels []string, jsonParam string) (data SmsSend, err error) { param := m.parseSmsSendParam(tels, jsonParam) - res, err := httpclient.FastHttpPost( - fmt.Sprintf("%s%s", m.Host, SendSms), - m.header, - param, - TimeOut) + err = m.post(SendSms, param, &data) if err != nil { return } - err = json.Unmarshal(res, &data) return } -func (m *MessageCenter) parseSmsSendParam(tels []string, jsonParam string) (out []byte) { - out, _ = json.Marshal(SmsRequest{ - Base: m.Base, - Tels: strings.Join(tels, ","), - Param: jsonParam, - }) - return -} +// BlackboardReceiverView struct { -func (m *MessageCenter) SendBlackBoard(title, content string, receiver BlackboardReceiverView) (data DefaultRes, err error) { - res, err := httpclient.FastHttpPost( - fmt.Sprintf("%s%s", m.Host, SendSms), - m.header, - m.parseSendBlackBoardParam(title, content, receiver), - TimeOut) +// } +// SendBlackBoard 钉钉公告 +// deptidList //接收部门ID列表,最大的列表长度为20。 +// UseridList //接收部用户ID列表,最大的列表长度为20。 +func (m *MessageCenter) SendBlackBoard(title, content string, deptidList []int, useridList []string) (data Default, err error) { + receiver := blackboardReceiverView{ + deptidList, useridList, + } + err = m.post(SendSms, m.parseSendBlackBoardParam(title, content, receiver), &data) if err != nil { return } - err = json.Unmarshal(res, &data) return } -func (m *MessageCenter) parseSendBlackBoardParam(title, content string, receiver BlackboardReceiverView) (out []byte) { - out, _ = json.Marshal(DingTalkBlackBoardSendReq{ - Base: m.Base, - Content: content, - Title: title, - BlackboardReceiver: receiver, - }) +// OAComment OA评论,CommentUserId为空则默认审核发起人评论 +func (m *MessageCenter) OAComment(outTradeNo, text, commentUserId string, file *DingOACommentReqFile) (data OAResponse, err error) { + req := &oACommentRequest{ + Base: m.base, + OutTradeNo: outTradeNo, + Text: text, + CommentUserId: commentUserId, + } + if file != nil { + req.File = *file + } + param, _ := json.Marshal(req) + + err = m.post(OaComment, param, &data) + if err != nil { + return + } return } diff --git a/paramset.go b/paramset.go new file mode 100644 index 0000000..bd78477 --- /dev/null +++ b/paramset.go @@ -0,0 +1,102 @@ +package l_msg_api + +import ( + "encoding/json" + "fmt" + "gitea.cdlsxd.cn/self-tools/l_msg_api/cache" + "gitea.cdlsxd.cn/self-tools/l_msg_api/httpclient" + "strings" +) + +func (m *MessageCenter) parseOACreateParam(formModel *FormsData) (out []byte) { + req := formDataRequest{ + Base: m.base, + } + req.FormComponentValues = formModel.FormComponentValues + req.Finance = formModel.Finance + req.formBase = formModel.formBase + out, _ = json.Marshal(req) + return +} + +func (m *MessageCenter) parseSmsSendParam(tels []string, jsonParam string) (out []byte) { + out, _ = json.Marshal(smsRequest{ + Base: m.base, + Tels: strings.Join(tels, ","), + Param: jsonParam, + }) + return +} +func (m *MessageCenter) parseSendBlackBoardParam(title, content string, receiver blackboardReceiverView) (out []byte) { + out, _ = json.Marshal(dingTalkBlackBoardSendReq{ + Base: m.base, + Content: content, + Title: title, + BlackboardReceiver: receiver, + }) + return +} + +func (m *MessageCenter) getAccessToken() (string, error) { + + if tokenInterface, exist := cache.InstanceCacheMap().Get(m.ClientKey); exist { + return tokenInterface.(string), nil + } + var data accessTokenResponse + + var authParam, _ = json.Marshal(map[string]string{"client_key": m.ClientKey, "client_secret": m.ClientSecret}) + err := m.accessPost(AccessToken, authParam, &data) + if err != nil { + return "", err + } + cache.InstanceCacheMap().Put(m.ClientKey, data.AccessToken) + return data.AccessToken, err +} + +func (m *MessageCenter) post(path string, data []byte, resReflect interface{}) (err error) { + var body responseBody + res, err := httpclient.FastHttpPost(fmt.Sprintf("%s%s", m.Host, path), m.header, data, TimeOut) + if err != nil { + return + } + if err = json.Unmarshal(res, &body); err != nil { + return fmt.Errorf("请求失败:%s", string(res)) + } + if body.Code != 0 { + return fmt.Errorf("请求失败:%s", body.Msg) + } + + dataByte, err := json.Marshal(body.Data) + if err != nil { + return fmt.Errorf("未知的返回格式:%s", string(dataByte)) + } + if err = json.Unmarshal(dataByte, &resReflect); err != nil { + return fmt.Errorf("未知的返回格式:%s", string(dataByte)) + } + + return +} + +func (m *MessageCenter) accessPost(path string, data []byte, resReflect interface{}) (err error) { + var body responseBody + res, err := httpclient.FastHttpPost(fmt.Sprintf("%s%s", m.Host, path), m.header, data, TimeOut) + if err != nil { + return + } + if err = json.Unmarshal(res, &body); err != nil { + return fmt.Errorf("请求失败:%s", string(res)) + } + if body.Code != 0 { + return fmt.Errorf("请求失败:%s", body.Msg) + } + + dataByte, err := json.Marshal(body.Data) + if err != nil { + return fmt.Errorf("未知的返回格式:%s", string(dataByte)) + } + if err = json.Unmarshal(dataByte, &resReflect); err != nil { + return fmt.Errorf("未知的返回格式:%s", string(dataByte)) + } + + return +} diff --git a/test/msg_test.go b/test/msg_test.go index 578b29d..e8645e1 100644 --- a/test/msg_test.go +++ b/test/msg_test.go @@ -6,12 +6,63 @@ import ( "testing" ) -func TestBase(t *testing.T) { - msg, err := l_msg_api.NewMessageCenter("", "", "sms", "cron_sms") +const ( + ClientKey = "ymt" + ClientSecret = "ymt" +) + +func TestSms(t *testing.T) { + msg, err := l_msg_api.NewMessageCenter(ClientKey, ClientSecret, "smssass", "sasssms") if err != nil { panic(err) } - res, err := msg.SendSms([]string{"15082245122"}, `{"content": "测试"}`) + res, err := msg.SendSms([]string{"15082245107"}, `{"content": "测试"}`) + fmt.Println(res, err) + +} + +func TestOaCreate(t *testing.T) { + msg, err := l_msg_api.NewMessageCenter(ClientKey, ClientSecret, "sw_oa", "sw_oa_purchase") + if err != nil { + panic(err) + } + form := []l_msg_api.FormComponentValues{ + {Name: "采购单号", Value: "123456789123"}, + {Name: "供应商", Value: "测试供应商"}, + {Name: "采购总数量", Value: "1"}, + {Name: "入库仓库", Value: "测试仓库"}, + {Name: "采购总金额", Value: "11.22"}, + {Name: "预计到货时间", Value: "2025-03-21"}, + } + res, err := msg.OACreate("17101201090101570", "123456789123bgff", &l_msg_api.FormsData{ + FormComponentValues: form, + Finance: &l_msg_api.Finance{ + Amount: "11.22", + CheckUserId: "17109839571135417", + GoodsInfo: "实物系统测试商品", + PaymentAccount: "1312312321", + TaxAmount: "1", + CallbackUrl: "www.baidu.com", + Remark: "测试备注", + Sync: 1, + BankInfo: l_msg_api.BankInfo{ + BankName: "中国银行", + BankAccount: "43243243434", + AccountBankName: "中国银行成都分行", + ResellerName: "张三", + SubjectName: "张三", + }, + }, + }) + fmt.Println(res, err) +} + +func TestOaComment(t *testing.T) { + msg, err := l_msg_api.NewMessageCenter(ClientKey, ClientSecret, "sw_oa", "sw_oa_purchase") + if err != nil { + panic(err) + } + res, err := msg.OAComment("P24110515152043136-20250318181554", "sdk测试", "", nil) fmt.Println(res, err) }