diff --git a/apps/api/api.api b/apps/api/api.api index 884e059..3112d3b 100644 --- a/apps/api/api.api +++ b/apps/api/api.api @@ -157,4 +157,15 @@ service api-api { @handler JRZQ4AA8 post /JRZQ4AA8 (request) returns (string) -} \ No newline at end of file +} + +@server ( + group: COMB + prefix: /api/v1 + middleware: ApiAuthInterceptor +) +service api-api { + @handler COMB298Y + post /COMB298Y (request) returns (string) +} + diff --git a/apps/api/internal/handler/COMB/comb298yhandler.go b/apps/api/internal/handler/COMB/comb298yhandler.go new file mode 100644 index 0000000..542f8fc --- /dev/null +++ b/apps/api/internal/handler/COMB/comb298yhandler.go @@ -0,0 +1,31 @@ +package COMB + +import ( + "net/http" + + "tianyuan-api/apps/api/internal/logic/COMB" + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" + "tianyuan-api/pkg/errs" + "tianyuan-api/pkg/response" + + "github.com/zeromicro/go-zero/rest/httpx" +) + +func COMB298YHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.Request + if err := httpx.Parse(r, &req); err != nil { + response.Fail(r.Context(), w, errs.ErrParamValidation, nil) + return + } + + l := COMB.NewCOMB298YLogic(r.Context(), svcCtx) + resp, err := l.COMB298Y(&req) + if err != nil { + response.Fail(r.Context(), w, err, resp) + } else { + response.Success(r.Context(), w, resp) + } + } +} diff --git a/apps/api/internal/handler/routes.go b/apps/api/internal/handler/routes.go index 6115444..54a2ca7 100644 --- a/apps/api/internal/handler/routes.go +++ b/apps/api/internal/handler/routes.go @@ -6,6 +6,7 @@ package handler import ( "net/http" + COMB "tianyuan-api/apps/api/internal/handler/COMB" FLXG "tianyuan-api/apps/api/internal/handler/FLXG" IVYZ "tianyuan-api/apps/api/internal/handler/IVYZ" JRZQ "tianyuan-api/apps/api/internal/handler/JRZQ" @@ -17,6 +18,20 @@ import ( ) func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.ApiAuthInterceptor}, + []rest.Route{ + { + Method: http.MethodPost, + Path: "/COMB298Y", + Handler: COMB.COMB298YHandler(serverCtx), + }, + }..., + ), + rest.WithPrefix("/api/v1"), + ) + server.AddRoutes( rest.WithMiddlewares( []rest.Middleware{serverCtx.ApiAuthInterceptor}, diff --git a/apps/api/internal/logic/COMB/comb298ylogic.go b/apps/api/internal/logic/COMB/comb298ylogic.go new file mode 100644 index 0000000..2f385b1 --- /dev/null +++ b/apps/api/internal/logic/COMB/comb298ylogic.go @@ -0,0 +1,239 @@ +package COMB + +import ( + "context" + "encoding/hex" + "encoding/json" + "sync" + + "tianyuan-api/apps/api/internal/common" + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" + "tianyuan-api/apps/api/internal/validator" + "tianyuan-api/apps/api/internal/westmodel" + "tianyuan-api/pkg/crypto" + "tianyuan-api/pkg/errs" + + "github.com/zeromicro/go-zero/core/logx" +) + +type COMB298YLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// WestAPIRequest 定义西部API请求结构 +type APIRequest struct { + SourceId string + ServiceId string + Request map[string]interface{} + Mapping map[string]string + Wrap string + Service string +} + +// WestAPIResponse 定义西部API响应结构 +type APIResponse struct { + SourceId string + Resp []byte + Success bool +} + +// 将所有响应组装成JSON +type ResponseData struct { + Responses []struct { + ServiceId string `json:"api_code"` + Data json.RawMessage `json:"data"` + Success bool `json:"success"` + } `json:"responses"` +} + +func NewCOMB298YLogic(ctx context.Context, svcCtx *svc.ServiceContext) *COMB298YLogic { + return &COMB298YLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *COMB298YLogic) COMB298Y(req *types.Request) (resp string, err *errs.AppError) { + var status string + var charges bool + var remark = "" + secretKey, ok := l.ctx.Value("secretKey").(string) + if !ok { + return "", errs.ErrSystem + } + transactionID, ok := l.ctx.Value("transactionID").(string) + if !ok { + return "", errs.ErrSystem + } + userId, userIdOk := l.ctx.Value("userId").(int64) + if !userIdOk { + return "", errs.ErrSystem + } + productCode, productCodeOk := l.ctx.Value("productCode").(string) + if !productCodeOk || productCode == "" { + return "", errs.ErrSystem + } + + defer func() { + if err != nil { + status = "failed" + charges = false + } else { + status = "success" + charges = true + } + sendApiRequestMessageErr := l.svcCtx.ApiRequestMqsService.SendApiRequestMessage(l.ctx, transactionID, userId, productCode, status, charges, remark) + if sendApiRequestMessageErr != nil { + logx.Errorf("发送 API 请求消息失败: %v", err) + } + }() + // 1、解密 + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return "", errs.ErrSystem + } + decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key) + if aesDecryptErr != nil || len(decryptData) == 0 { + return "", errs.ErrParamDecryption + } + + // 2、校验 + var data validator.COMB298YRequest + if validatorErr := validator.ValidateAndParse(decryptData, &data); validatorErr != nil { + return "", errs.ErrParamValidation + } + + // 3、西部加密 + westConfig := l.svcCtx.Config.WestConfig + encryptedFields, encryptStructFieldsErr := common.EncryptStructFields(data, westConfig.Key) + if encryptStructFieldsErr != nil { + logx.Errorf("西部加密错误:%v", encryptStructFieldsErr) + return "", errs.ErrSystem + } + + // 4、发送请求到西部 + logx.Infof("交易号:%s", transactionID) + + // 准备并发请求 + apiRequests := []APIRequest{ + {SourceId: "YYSY09CD", ServiceId: "G16BJ02", Mapping: westmodel.YYSY09CDFieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "JRZQ0A03", ServiceId: "G27BJ05", Mapping: westmodel.JRZQ0A03FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "JRZQ8203", ServiceId: "G28BJ05", Mapping: westmodel.JRZQ8203FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "FLXG3D56", ServiceId: "G26BJ05", Mapping: westmodel.FLXG3D56FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "FLXGCA3D", ServiceId: "G22SC01", Mapping: westmodel.FLXGCA3DFieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "JRZQ4AA8", ServiceId: "G29BJ05", Mapping: westmodel.JRZQ4AA8FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "FLXGC9D1", ServiceId: "G30BJ05", Mapping: westmodel.FLXGC9D1FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "FLXG162A", ServiceId: "G32BJ05", Mapping: westmodel.FLXG162AFieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "FLXG54F5", ServiceId: "G03HZ01", Mapping: westmodel.FLXG54F5FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "IVYZ5733", ServiceId: "G09XM02", Mapping: westmodel.IVYZ5733FieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "IVYZ9A2B", ServiceId: "G11BJ06", Mapping: westmodel.IVYZ9A2BFieldMapping, Wrap: "data", Service: "west"}, + {SourceId: "QYGLB4C0", ServiceId: "G05HZ01", Mapping: westmodel.QYGLB4C0FieldMapping, Wrap: "", Service: "west"}, + {SourceId: "FLXG8UI0", ServiceId: "RIS031", Mapping: westmodel.FLXG8UI0FieldMapping, Wrap: "data", Service: "yushan"}, + } + + // 为每个请求构建对应的请求参数 + for i := range apiRequests { + apiRequests[i].Request = common.MapStructToAPIRequest(encryptedFields, apiRequests[i].Mapping, apiRequests[i].Wrap) + } + + // 创建响应通道 + responseChan := make(chan APIResponse, len(apiRequests)) + var wg sync.WaitGroup + + // 并发处理请求 + for _, apiReq := range apiRequests { + wg.Add(1) + go func(req APIRequest) { + defer wg.Done() + success := true + var westResp string + var callAPIErr *errs.AppError + + // 根据服务类型选择不同的调用方式 + switch req.Service { + case "west": + respData, err := l.svcCtx.WestDexService.CallAPI(req.SourceId, req.Request, l.svcCtx.Config.WestConfig.SecretId) + if err != nil { + callAPIErr = err + } else { + westResp = string(respData) + } + case "yushan": + respData, err := l.svcCtx.YushanService.Request(req.SourceId, req.Request) + if err != nil { + if appErr, ok := err.(*errs.AppError); ok { + callAPIErr = appErr + } else { + callAPIErr = errs.ErrSystem + } + } else { + westResp = string(respData) + } + default: + success = false + logx.Errorf("未知的服务类型:%s", req.Service) + } + + if callAPIErr != nil { + success = false + } + + responseChan <- APIResponse{ + SourceId: req.ServiceId, + Resp: []byte(westResp), + Success: success, + } + }(apiReq) + } + + // 等待所有请求完成 + go func() { + wg.Wait() + close(responseChan) + }() + + // 处理响应 + var responses []APIResponse + for resp := range responseChan { + responses = append(responses, resp) + } + + responseData := ResponseData{ + Responses: make([]struct { + ServiceId string `json:"api_code"` + Data json.RawMessage `json:"data"` + Success bool `json:"success"` + }, len(responses)), + } + + for i, resp := range responses { + responseData.Responses[i] = struct { + ServiceId string `json:"api_code"` + Data json.RawMessage `json:"data"` + Success bool `json:"success"` + }{ + ServiceId: resp.SourceId, + Data: resp.Resp, + Success: resp.Success, + } + } + + // 将响应数据转换为JSON + jsonData, marshalErr := json.Marshal(responseData) + if marshalErr != nil { + logx.Errorf("JSON编码错误:%v", marshalErr) + return "", errs.ErrSystem + } + + // 加密JSON数据 + encryptData, aesEncrypt := crypto.AesEncrypt(jsonData, key) + if aesEncrypt != nil { + return "", errs.ErrSystem + } + + return string(encryptData), nil +} diff --git a/apps/api/internal/validator/structs.go b/apps/api/internal/validator/structs.go index b101458..470ebaa 100644 --- a/apps/api/internal/validator/structs.go +++ b/apps/api/internal/validator/structs.go @@ -162,3 +162,9 @@ type IVYZ9A2BRequest struct { IDCard string `json:"id_card" validate:"required,validIDCard"` Name string `json:"name" validate:"required,min=1,validName"` } + +type COMB298YRequest struct { + IDCard string `json:"id_card" validate:"required,validIDCard"` + Name string `json:"name" validate:"required,min=1,validName"` + MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"` +} diff --git a/apps/api/internal/westmodel/fieldMapping.go b/apps/api/internal/westmodel/fieldMapping.go index 0b1635e..7e96b71 100644 --- a/apps/api/internal/westmodel/fieldMapping.go +++ b/apps/api/internal/westmodel/fieldMapping.go @@ -50,6 +50,11 @@ var FLXGDEC7FieldMapping = map[string]string{ "IDCard": "id_card", "Name": "name", } +var FLXG8UI0FieldMapping = map[string]string{ + "IDCard": "id", + "Name": "name", + "MobileNo": "cell", +} var IVYZ385EFieldMapping = map[string]string{ "IDCard": "gmsfzhm", "Name": "xm", @@ -112,6 +117,7 @@ var QYGL8271FieldMapping = map[string]string{ var QYGLB4C0FieldMapping = map[string]string{ "IDCard": "pid", } + var YYSY4B37FieldMapping = map[string]string{ "MobileNo": "phone", }