diff --git a/app/admin/apis/gdydmanage/gdyd_service.go b/app/admin/apis/gdydmanage/gdyd_service.go new file mode 100644 index 0000000..431e9b0 --- /dev/null +++ b/app/admin/apis/gdydmanage/gdyd_service.go @@ -0,0 +1,204 @@ +package gdydmanage + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/logger" + "go-admin/app/admin/models" + "go-admin/common/apis" + "go-admin/tools/app" + "net/http" +) + +type GDYDDeployService struct { + apis.Api +} + +// CreateOrder 商品订单生成 +// @Summary 商品订单生成 +// @Tags 2025-广东移动 +// @Produce json +// @Accept json +// @Param request body models.CreateProductOrderCKCommIDReq true "商品订单生成" +// @Success 200 {object} models.CommonResponse +// @Router /api/v1/mmAdWeb/create_order [post] +func (e GDYDDeployService) CreateOrder(c *gin.Context) { + fmt.Println("CreateOrder-start") + logger.Info("CreateOrder-start") + + err := e.MakeContext(c).MakeOrm().Errors + if err != nil { + e.Logger.Error(err) + app.Error(c, http.StatusInternalServerError, err, "初始化失败") + return + } + + // 绑定请求体 + var req models.CreateProductOrderCKCommIDReq + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("请求参数绑定失败:", err) + app.Error(c, http.StatusBadRequest, err, "参数错误") + return + } + + resp, err := models.DoSecurePostRequest(models.CreateOrderUrl, req.UserInfo.ServerNum, &req) + if err != nil { + logger.Error("CreateOrder error:", err) + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + //resp, err := models.SendCreateProductOrderCKCommIDRequest(&req) + //if err != nil { + // logger.Error("CreateOrder error:", err) + // app.Error(c, http.StatusBadRequest, err, err.Error()) + // return + //} + + fmt.Println("CreateOrder-end") + logger.Info("CreateOrder-end") + app.MiGuOK(c, resp) +} + +// ApplySmsCode 申请短信验证码 +// @Summary 申请短信验证码 +// @Tags 2025-广东移动 +// @Produce json +// @Accept json +// @Param request body models.ApplySmsCodeReq true "申请短信验证码" +// @Success 200 {object} models.CommonResponse +// @Router /api/v1/mmAdWeb/apply_sms_code [post] +func (e GDYDDeployService) ApplySmsCode(c *gin.Context) { + logger.Info("ApplySmsCode-start") + fmt.Println("ApplySmsCode-start") + + err := e.MakeContext(c).MakeOrm().Errors + if err != nil { + logger.Error("Init error:", err) + app.Error(c, http.StatusInternalServerError, err, "初始化失败") + return + } + + // 绑定请求体 + var req models.ApplySmsCodeReq + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("请求参数绑定失败:", err) + app.Error(c, http.StatusBadRequest, err, "参数错误") + return + } + + // 设置默认 OrderID 为 "0" 如果未指定 + if req.OrderID == "" { + req.OrderID = "0" + } + + //// 发起请求 + //resp, err := models.SendApplySmsCodeRequest(&req) + //if err != nil { + // logger.Error("SendApplySmsCodeRequest error:", err) + // app.Error(c, http.StatusBadRequest, err, "短信验证码申请失败") + // return + //} + + resp, err := models.DoSecurePostRequest(models.ApplySmsCodeUrl, req.MobileNo, &req) + if err != nil { + logger.Error("CreateOrder error:", err) + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + fmt.Println("ApplySmsCode-end") + logger.Info("ApplySmsCode-end") + + app.MiGuOK(c, resp) +} + +// CheckSmsCodeAndCommitOrder 短信验证及订单提交 +// @Summary 短信验证及订单提交 +// @Tags 2025-广东移动 +// @Produce json +// @Accept json +// @Param request body models.CheckSmsCodeAndCommitOrderReq true "短信验证及订单提交" +// @Success 200 {object} models.CommonResponse +// @Router /api/v1/mmAdWeb/commit_order [post] +func (e GDYDDeployService) CheckSmsCodeAndCommitOrder(c *gin.Context) { + logger.Info("CheckSmsCodeAndCommitOrder-start") + fmt.Println("CheckSmsCodeAndCommitOrder-start") + + err := e.MakeContext(c).MakeOrm().Errors + if err != nil { + logger.Error("初始化失败:", err) + app.Error(c, http.StatusInternalServerError, err, "初始化失败") + return + } + + var req models.CheckSmsCodeAndCommitOrderReq + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("请求参数解析失败:", err) + app.Error(c, http.StatusBadRequest, err, "请求参数错误") + return + } + + //resp, err := models.SendCheckSmsCodeAndCommitOrderRequest(&req) + //if err != nil { + // logger.Error("SendCheckSmsCodeAndCommitOrderRequest error:", err) + // app.Error(c, http.StatusBadRequest, err, "短信校验提交失败") + // return + //} + + resp, err := models.DoSecurePostRequest(models.CheckSmsCodeCommitOrderUrl, req.ServerNum, &req) + if err != nil { + logger.Error("CreateOrder error:", err) + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + fmt.Println("CheckSmsCodeAndCommitOrder-end") + logger.Infof("CheckSmsCodeAndCommitOrder-end") + app.MiGuOK(c, resp) +} + +// QueryOrder 查询订单状态 +// @Summary 查询订单状态 +// @Tags 2025-广东移动 +// @Produce json +// @Accept json +// @Param request body models.QueryOrderReq true "查询订单状态" +// @Success 200 {object} models.CommonResponse +// @Router /api/v1/mmAdWeb/query_order [post] +func (e GDYDDeployService) QueryOrder(c *gin.Context) { + logger.Info("QueryOrder - start") + fmt.Println("QueryOrder - start") + + err := e.MakeContext(c).MakeOrm().Errors + if err != nil { + logger.Error("初始化失败:", err) + app.Error(c, http.StatusInternalServerError, err, "初始化失败") + return + } + + var req models.QueryOrderReq + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("请求参数解析失败:", err) + app.Error(c, http.StatusBadRequest, err, "请求参数错误") + return + } + + //resp, err := models.SendQueryOrderRequest(&req) + //if err != nil { + // logger.Error("SendQueryOrderRequest error:", err) + // app.Error(c, http.StatusBadRequest, err, "订单状态查询失败") + // return + //} + + resp, err := models.DoSecurePostRequest(models.QueryOrderUrl, req.ServerNum, &req) + if err != nil { + logger.Error("CreateOrder error:", err) + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + fmt.Println("QueryOrder - end") + logger.Infof("QueryOrder - end") + app.MiGuOK(c, resp) +} diff --git a/app/admin/models/gdyd_model.go b/app/admin/models/gdyd_model.go new file mode 100644 index 0000000..b280b2d --- /dev/null +++ b/app/admin/models/gdyd_model.go @@ -0,0 +1,444 @@ +package models + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "github.com/google/uuid" + "io" + "net/http" + "sort" + "strings" + "time" +) + +const ( + AppId = "114320" + PrivateKeyPEM = `-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCoqhTbIPDpg8OzUDsJ8Po+UthsUWlugC+Ti7UCLHxp1Eask8UBOloOGWO9IUHS03y80SEWM+oy94Vb/g2QIe7Jk5QdfJzxa0cnptIzVxIRpyCFNlaSheNwCD4wjoZvXKXEoqb1J2C5U4ks0Jd9dYuUa7aLtwHBYLb2QL7hN9v7GyP4YOPU65pnHW6nrIDk6s+FZWkjdw6nT+dwCO3dl/l5MNbp0oaH+73xgxElOgABBStcelDEPc0YOwSPXlfwl68Ozd4cxwU5SGRH/zj1h7YBP+mwEOFUE62EO2mgc3JIF5YpaLsMHF960/VkM6j4qBM0Hds/WmxtJ1COXhVzZTWbAgMBAAECggEAYf8gSwlisGrMhBzzkJ0g6KE9+gF7Xqa//dxIeVDboKmjvpXE+yeqN1LtLnBqTFJwwUxJCxty0dYa+A4uVzZABYLnphJHJcYM+67jpszKRNN0A7JErrF4Khm/+Hp3BbEw54URuJL+ke9FXnJ78nsfdEb5M0hLjs3gwEdyIG1SNRzoI0VpcWxP430esn1vXTxfyWedLPhIhfdgVtzwLnaOrpRy5Qd4JiZacoSxCHnV3zsT6pp5QD1RwClg1UJbiH0B2TiUbBiyl5GJgMvVtOjj2yX80c8JbpiRxYMujIbHcmEjzqvbkCX5/q/WjxPkR5Fk4MlDAlogr68pOF3rL0H0oQKBgQDY5aARizxt6NABaZJtNElUqrjNBxQCaLMt7nMRGOjb5o7LKPRhwRcqUoTYvDIn4qKN0V8lLnvRJjT089WRwBHWqwJNfp14z3HqfJMWqLIFWnp1CaJCCusc6zdjTqu8KaztCyjlxlp0usZXfCw1SgKmSnziFOSRkxt1X0HFn/0WGQKBgQDHEmSoPH7MpqkrCWRvSysbbcdIbpYiBoru8+irdy0EVxzu5s9mGb6IncZ2Y41f+/T0cpPuNlcrJQfQ0tEKo0uDjpPmiKQa3AVlOElOJI9H/KOZQHHM835STSxjsOb5RjMdFBYbutzO5h7EAaQQEFWNfcNsbaSPQlXNttdWH8XX0wKBgQCr8z83KV868zsUI5IGKVGJYd8oC9h9IGwMmeF3SHwy+VFzFoDHjsDCuLDA8lIA9NdR/w6i93sJkHSjTTufVNnPibtFnH9S64KwFxq0+ABJ5jT23DBakzVZs9AxVoknnxKMyjAeGWZU7E2ZxcN2a7o2Aw+GXHHoRuuZ3W7TMcb+4QKBgQCdHTssPHKm+nJRcRw/akgfYckCtaTwPdGxPffIPErfPhGry6asomzqTfuwvGl789MkirmOLH0npBZDDd/GUZLrxb+dFwLN4BCyDnZsohYjbpWAAojOhO6R7i62j4v7+RemP5AjWpui/6QQdmsR8pJTFYsDLJXQKz6lGUVix7jR2QKBgQCztD1gFG2rMVvSiXqMbGfqjAvZjVygzBvpTidRB/ZKPcfXSdhrvEv1pYmrYoBjQ/oBM2HncyI7EsQsIed17n8r9tart4VMGCQfpQw3mneq4TZIjzqkpYP0qLY+mDS9v8l+FotRfVQtyOnff6xsTnWw3S9fTF5oSe5Yc9dnpxCCAw== +-----END PRIVATE KEY-----` + + CreateOrderUrl = "https://221.179.11.204/eaop/rest/BSS/commodity/create_productorder_ckcommid/v1.1.1" + ApplySmsCodeUrl = "https://221.179.11.204/eaop/rest/BSS/service/smscodeapply/v1.1.1" + CheckSmsCodeCommitOrderUrl = "https://221.179.11.204/eaop/rest/BSS/commodity/smscodechkodcommitorder/v1.1.1" + QueryOrderUrl = "https://221.179.11.204/eaop/rest/BSS/commodity/odqryorderbaseinfo_orderid/v1.1.1" +) + +var GdYdCodeMessageMap = map[string]string{ + "0": "成功", + "500": "数据错误", + "600": "业务失败", + "999": "系统内部失败", + "1009999999": "默认异常编码", + "1009999000": "系统内部错误", + "1000010001": "请求IP缺失", + "1000010002": "请求IP在黑名单中", + "1000010003": "请求IP不在白名单中", + "1000010009": "解析能力请求报文出错", + "1000010010": "缺失APPID参数", + "1000010011": "应用不存在", + "1000010012": "应用状态不合法", + "1000010013": "应用关联不到有效商户", + "1000010031": "能力不存在", + "1000010035": "传入参数错误", + "1000010043": "缺少签名参数", + "1000010047": "数字签名验证不通过", + "1000010049": "时间戳和系统时间隔太大", + "1000010060": "无访问能力权限", + "1000020001": "流量控制超流量后停止服务", + "1000020002": "配额控制未找到配额规则", + "1000020003": "配额控制超配额后停止服务", + "1000030001": "能力不支持此协议", + "1000030002": "能力不支持此报文格式", + "1000030004": "能力参数未配置", + "1000030005": "请求参数为空", + "1000030007": "缺少必选参数", + "1000030009": "非法的数据格式,参数值与字段类型定义不符", + "1000030015": "获取服务参数信息失败", + "1000030016": "服务返回报文格式错误", + "1000030017": "参数模糊化错误", + "1000040001": "模拟应答编码缺失", + "1000040002": "环境标识不合法", + "1000050001": "服务流程模板调用出错", + "1000050002": "能力回调出错", + "1000050003": "反向能力调用出错", + "1000050004": "服务调用超时", + "1000050005": "调用服务失败", + "1000050006": "调用服务返回结果不完整", + "1000050007": "调用服务返回结果为空", + "1000050008": "根据服务id获取流程模板出错", + "1000050010": "本地自服务调用失败", + "1000060001": "获取路由关键信息失败", + "1000060002": "服务路由失败", +} + +// CommonParams 公共参数 +type CommonParams struct { + AppID string `json:"appId"` // 必选,开放平台分配给应用的唯一标识 + Timestamp string `json:"timestamp"` // 必选,请求时间戳,格式:yyyyMMddHHmmssSSS,需重新生成,服务器时间差不得超5分钟 + BusiSerial string `json:"busiSerial"` // 必选,32位UUID(去掉4个减号)作为请求流水号 + Sign string `json:"sign"` // 必选,数字签名 + Nonce string `json:"nonce"` // 必选,32位数字+大写字母组成的随机字符串 + AuthCode string `json:"authCode,omitempty"` // 可选,用户授权调用的验证码 + OperatorID string `json:"operatorid,omitempty"` // 可选,操作员工号 + ComFlowCode string `json:"comflowcode,omitempty"` // 可选,通信流程编号 + InstanceID string `json:"instanceid,omitempty"` // 可选,流程实例唯一标识 + RouteType string `json:"route_type,omitempty"` // 可选,路由类型:0=地市,1=号码 + RouteValue string `json:"route_value,omitempty"` // 可选,路由字段值(手机号码或区号) + UnitID string `json:"unitid,omitempty"` // 可选,子渠道ID +} + +// GenerateSignature 通用签名函数 +func GenerateSignature(publicParams map[string]string, bizJson string, privateKeyPEM string) (string, error) { + // 删除 sign 字段(如果存在) + delete(publicParams, "sign") + + // 1. 排序参数 + keys := make([]string, 0, len(publicParams)) + for k := range publicParams { + keys = append(keys, k) + } + sort.Strings(keys) + + // 2. 拼接参数 + var sb strings.Builder + for i, k := range keys { + if i > 0 { + sb.WriteString("&") + } + sb.WriteString(fmt.Sprintf("%s=%s", k, publicParams[k])) + } + sb.WriteString(bizJson) + + signContent := sb.String() + + // 3. SHA256withRSA签名 + signature, err := rsaSignSHA256([]byte(signContent), privateKeyPEM) + if err != nil { + return "", err + } + + return signature, nil +} + +// 签名逻辑:SHA256withRSA + Base64 +func rsaSignSHA256(data []byte, privateKeyPEM string) (string, error) { + block, _ := pem.Decode([]byte(privateKeyPEM)) + if block == nil { + return "", fmt.Errorf("invalid private key PEM") + } + + priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return "", fmt.Errorf("parse private key error: %v", err) + } + + rsaPriv, ok := priv.(*rsa.PrivateKey) + if !ok { + return "", fmt.Errorf("not RSA private key") + } + + hash := sha256.Sum256(data) + signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPriv, crypto.SHA256, hash[:]) + if err != nil { + return "", fmt.Errorf("sign error: %v", err) + } + + return base64.StdEncoding.EncodeToString(signature), nil +} + +// CommonResponse 通用返回结构体 +type CommonResponse struct { + RespCode string `json:"respcode"` + RespDesc string `json:"respdesc"` + RespType string `json:"resptype"` + Result json.RawMessage `json:"result,omitempty"` +} + +// 32位由数字+大写字母组成的随机字符串,每次请求必须重新生成 +func generateNonce(n int) string { + const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, n) + for i := range b { + b[i] = charset[int(time.Now().UnixNano()+int64(i))%len(charset)] + } + return string(b) +} + +// 请求报文流水号(UUID去掉其中的四个减号) +func generateUUID() string { + return strings.ReplaceAll(uuid.New().String(), "-", "") +} + +// DoSecurePostRequest 发送签名后的通用 POST 请求 +func DoSecurePostRequest(url, phone string, bizPayload interface{}) (*CommonResponse, error) { + fmt.Println("enter DoSecurePostRequest") + fmt.Println("请求地址(URL):", url) + // Marshal 业务参数 + bizJSON, err := json.Marshal(bizPayload) + if err != nil { + return nil, fmt.Errorf("marshal biz payload failed: %w", err) + } + fmt.Println("请求体(业务参数 bizPayload):", string(bizJSON)) + + // 生成公共参数 + publicParams := map[string]string{ + "appId": AppId, + "busiSerial": generateUUID(), + "nonce": generateNonce(32), + "route_value": phone, + "route_type": "1", + "timestamp": time.Now().Format("20060102150405") + fmt.Sprintf("%03d", time.Now().Nanosecond()/1e6), // 精确到毫秒 + } + fmt.Println("publicParams is:", publicParams) + + // 生成签名 + signature, err := GenerateSignature(publicParams, string(bizJSON), PrivateKeyPEM) + if err != nil { + return nil, fmt.Errorf("sign failed: %w", err) + } + fmt.Println("signature is:", signature) + + // 添加签名 + publicParams["sign"] = signature + + // 准备请求 + req, err := http.NewRequest("POST", url, bytes.NewBuffer(bizJSON)) + if err != nil { + return nil, fmt.Errorf("create request failed: %w", err) + } + + req.Header.Set("Content-Type", "application/json") + + // 设置公共参数为 Header + for k, v := range publicParams { + req.Header.Set(k, v) + } + + // 打印请求头 + fmt.Println("请求头信息:") + for k, v := range req.Header { + fmt.Printf(" %s: %s\n", k, strings.Join(v, ",")) + } + + // 忽略 TLS 校验 + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{ + Timeout: 10 * time.Second, + Transport: tr, + } + + // 发送请求 + //client := http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("http request failed: %w", err) + } + defer resp.Body.Close() + + // 读取响应 + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read response failed: %w", err) + } + fmt.Println("响应内容(Response Body):", string(body)) + + // 解析返回体 + var result CommonResponse + if err = json.Unmarshal(body, &result); err != nil { + fmt.Println("unmarshal response failed, err is:", err.Error()) + return nil, fmt.Errorf("unmarshal response failed: %w", err) + } + + fmt.Println("leave DoSecurePostRequest") + return &result, nil +} + +// CreateProductOrderCKCommIDReq 商品订单生成 - 请求结构体(JSON) +type CreateProductOrderCKCommIDReq struct { + UserInfo struct { + ServerNum string `json:"servernum"` // 手机号码 + Area string `json:"area,omitempty"` // 地市 + Brand string `json:"brand,omitempty"` // 品牌 + } `json:"userinfo"` + MoreCommOrder string `json:"morecommorder"` // 多商品订购:0 或 1 + ProductInfo struct { + ProductID string `json:"productid"` // 产品编号 + ProductGroup string `json:"productgroup"` // 产品组 + ProductType string `json:"producttype"` // 产品类别 + ProductName string `json:"productname,omitempty"` // 产品名称 + OrderType string `json:"ordertype"` // 订购类型:1=办理 2=取消 3=修改 + } `json:"productinfo"` +} + +// CreateProductOrderCKCommIDResp 商品订单生成 - 响应结构体 +type CreateProductOrderCKCommIDResp struct { + MsgBody struct { + OrderInfo struct { + OrderID string `json:"orderid"` // CRM订单号 + OrderDQ string `json:"orderdq"` // 电渠订单号 + } `json:"orderinfo"` + } `json:"msgbody"` +} + +// SendCreateProductOrderCKCommIDRequest 商品订单生成请求接口 +func SendCreateProductOrderCKCommIDRequest(payload *CreateProductOrderCKCommIDReq) (*CreateProductOrderCKCommIDResp, error) { + // 发送通用 POST 请求 + commonResp, err := DoSecurePostRequest(CreateOrderUrl, payload.UserInfo.ServerNum, payload) + if err != nil { + return nil, err + } + + // 检查返回是否成功 + if commonResp == nil || commonResp.Result == nil { + fmt.Println("commonResp == nil || commonResp.Result == nil") + return nil, errors.New(fmt.Sprintf("%s", commonResp.RespDesc)) + } + + if commonResp.RespCode != "0" { + return nil, errors.New(fmt.Sprintf("%s", commonResp.RespDesc)) + } + + // 反序列化 Data 字段为目标响应结构 + var resp CreateProductOrderCKCommIDResp + dataBytes, err := json.Marshal(commonResp.Result) // 先转成 JSON 字节 + if err != nil { + fmt.Println("marshal CommonResponse.Data failed, err is:", err) + return nil, fmt.Errorf("marshal CommonResponse.Data failed: %v", err) + } + + err = json.Unmarshal(dataBytes, &resp) + if err != nil { + fmt.Println("unmarshal to CreateProductOrderCKCommIDResp failed, err is:", err) + return nil, fmt.Errorf("unmarshal to CreateProductOrderCKCommIDResp failed: %v", err) + } + + return &resp, nil +} + +// ApplySmsCodeReq 短信验证码申请 - 请求结构体 +type ApplySmsCodeReq struct { + Rectype string `json:"rectype,omitempty"` // 可选 + OrderID string `json:"orderid"` // 固定为 "0" 时表示仅申请验证码 + MobileNo string `json:"mobileno"` // 手机号 + RectypeExtInfoList []ApplySmsCodeExtAttr `json:"rectypeextinfolist,omitempty"` // 可选 +} + +// ApplySmsCodeExtAttr 扩展属性 +type ApplySmsCodeExtAttr struct { + ExtAttrID string `json:"extattrid,omitempty"` + ExtAttrValue string `json:"extattrvalue,omitempty"` +} + +// ApplySmsCodeResp 短信验证码申请 - 响应结构体 +type ApplySmsCodeResp struct { + MsgBody struct { + SmsSeq string `json:"smsseq"` // 短信流水 + } `json:"msgbody"` +} + +func SendApplySmsCodeRequest(payload *ApplySmsCodeReq) (*ApplySmsCodeResp, error) { + resp, err := DoSecurePostRequest(ApplySmsCodeUrl, payload.MobileNo, payload) + if err != nil { + return nil, err + } + + if resp == nil || resp.Result == nil { + return nil, errors.New("empty response from smscodeapply") + } + + var result ApplySmsCodeResp + raw, err := json.Marshal(resp.Result) + if err != nil { + return nil, fmt.Errorf("marshal ApplySmsCodeResp.Data failed: %v", err) + } + if err := json.Unmarshal(raw, &result); err != nil { + return nil, fmt.Errorf("unmarshal to ApplySmsCodeResp failed: %v", err) + } + + return &result, nil +} + +// CheckSmsCodeAndCommitOrderReq 短信验证及订单提交 - 请求结构体 +type CheckSmsCodeAndCommitOrderReq struct { + OrderID string `json:"orderid"` // 订单编码 + ServerNum string `json:"servernum"` // 手机号 + SmsSeq string `json:"smsseq"` // 短信流水 + SmsCode string `json:"smscode"` // 短信验证码 +} + +// CheckSmsCodeAndCommitOrderResp 响应结构体 +type CheckSmsCodeAndCommitOrderResp struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func SendCheckSmsCodeAndCommitOrderRequest(payload *CheckSmsCodeAndCommitOrderReq) (*CheckSmsCodeAndCommitOrderResp, error) { + resp, err := DoSecurePostRequest(CheckSmsCodeCommitOrderUrl, payload.ServerNum, payload) + if err != nil { + return nil, err + } + if resp == nil || resp.Result == nil { + return nil, errors.New("empty response from CheckSmsCodeAndCommitOrder") + } + + var result CheckSmsCodeAndCommitOrderResp + raw, err := json.Marshal(resp.Result) + if err != nil { + return nil, fmt.Errorf("marshal response data failed: %v", err) + } + if err := json.Unmarshal(raw, &result); err != nil { + return nil, fmt.Errorf("unmarshal to CheckSmsCodeAndCommitOrderResp failed: %v", err) + } + + return &result, nil +} + +// QueryOrderReq 查询订单状态 - 请求结构体 +type QueryOrderReq struct { + ServerNum string `json:"servernum"` // 手机号 + OrderID string `json:"orderid"` // CRM订单编码 +} + +// QueryOrderResp 查询订单状态 - 响应结构体 +type QueryOrderResp struct { + MsgBody struct { + OrderInfoList []struct { + OrderID string `json:"orderid"` // 订单编号 + RecDate string `json:"recdate"` // 订单产生时间 + Status string `json:"status"` // 订单状态码 + } `json:"orderinfolist"` + } `json:"msgbody"` +} + +func SendQueryOrderRequest(payload *QueryOrderReq) (*QueryOrderResp, error) { + resp, err := DoSecurePostRequest(QueryOrderUrl, payload.ServerNum, payload) + if err != nil { + return nil, err + } + if resp == nil || resp.Result == nil { + return nil, errors.New("empty response from QueryOrder") + } + + var result QueryOrderResp + raw, err := json.Marshal(resp.Result) + if err != nil { + return nil, fmt.Errorf("marshal response data failed: %v", err) + } + if err := json.Unmarshal(raw, &result); err != nil { + return nil, fmt.Errorf("unmarshal to QueryOrderResp failed: %v", err) + } + + return &result, nil +} diff --git a/app/admin/router/gdyd_router.go b/app/admin/router/gdyd_router.go new file mode 100644 index 0000000..8230a5a --- /dev/null +++ b/app/admin/router/gdyd_router.go @@ -0,0 +1,18 @@ +package router + +import ( + "github.com/gin-gonic/gin" + "go-admin/app/admin/apis/gdydmanage" +) + +// registerGDYDControlManageUnAuthRouter 无需认证的路由代码 +func registerGDYDControlManageUnAuthRouter(v1 *gin.RouterGroup) { + apiGd := gdydmanage.GDYDDeployService{} + api := v1.Group("/mmAdWeb") + { + api.POST("create_order", apiGd.CreateOrder) // 商品订单生成 + api.POST("apply_sms_code", apiGd.ApplySmsCode) // 申请短信验证码 + api.POST("commit_order", apiGd.CheckSmsCodeAndCommitOrder) // 短信验证及订单提交 + api.POST("query_order", apiGd.QueryOrder) // 查询订单状态 + } +} diff --git a/app/admin/router/router.go b/app/admin/router/router.go index 785047a..566ac3a 100644 --- a/app/admin/router/router.go +++ b/app/admin/router/router.go @@ -31,6 +31,9 @@ func examplesNoCheckRoleRouter(r *gin.Engine) { } registerMiGuControlManageUnAuthRouter(v1) + + // 广东省移动渠道接口 + registerGDYDControlManageUnAuthRouter(v1) } // 需要认证的路由示例 @@ -42,4 +45,5 @@ func examplesCheckRoleRouter(r *gin.Engine, authMiddleware *jwtauth.GinJWTMiddle } registerMiGuControlManageRouter(v1, authMiddleware) + }