diff --git a/app/main/api/internal/logic/query/queryexamplelogic.go b/app/main/api/internal/logic/query/queryexamplelogic.go index d299362..902fb9b 100644 --- a/app/main/api/internal/logic/query/queryexamplelogic.go +++ b/app/main/api/internal/logic/query/queryexamplelogic.go @@ -3,10 +3,12 @@ package query import ( "context" "encoding/hex" + "encoding/json" "sim-server/app/main/api/internal/svc" "sim-server/app/main/api/internal/types" "sim-server/common/xerr" "sim-server/pkg/lzkit/crypto" + "strings" "github.com/bytedance/sonic" "github.com/pkg/errors" @@ -14,6 +16,14 @@ import ( "github.com/zeromicro/go-zero/core/logx" ) +// comboExampleDataItem 组合包示例 Content 解密后的单条结构,与 APIResponseData 一致,便于按模块展开 +type comboExampleDataItem struct { + ApiID string `json:"apiID"` + Data json.RawMessage `json:"data"` + Success bool `json:"success"` + Timestamp string `json:"timestamp"` +} + type QueryExampleLogic struct { logx.Logger ctx context.Context @@ -68,14 +78,49 @@ func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp strin // 根据特性ID查找示例数据 example, err := l.svcCtx.ExampleModel.FindOneByFeatureId(l.ctx, pf.FeatureId) if err != nil { - logx.Infof("示例报告, 特性ID %d 无示例数据: %v", pf.FeatureId, err) + logx.Infof("示例报告, 特性ID %s 无示例数据: %v", pf.FeatureId, err) continue // 如果没有示例数据就跳过 } // 获取对应的Feature信息 feature, err := l.svcCtx.FeatureModel.FindOne(l.ctx, pf.FeatureId) if err != nil { - logx.Infof("示例报告, 无法获取特性ID %d 的信息: %v", pf.FeatureId, err) + logx.Infof("示例报告, 无法获取特性ID %s 的信息: %v", pf.FeatureId, err) + continue + } + + // 组合包(api_id 前四位为 COMB):示例 Content 为多条 APIResponseData 的 JSON 数组,按子模块展开为多个 Tab + if strings.HasPrefix(feature.ApiId, "COMB") { + if example.Content == "000" { + continue + } + decryptedData, decryptErr := crypto.AesDecrypt(example.Content, key) + if decryptErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 组合包解密失败: %v", decryptErr) + } + var comboItems []comboExampleDataItem + if err := sonic.Unmarshal([]byte(decryptedData), &comboItems); err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 组合包示例解析失败: %v", err) + } + for i, item := range comboItems { + subFeature, subErr := l.svcCtx.FeatureModel.FindOneByApiId(l.ctx, item.ApiID) + featureName := item.ApiID + if subErr == nil && subFeature != nil { + featureName = subFeature.Name + } + query.QueryData = append(query.QueryData, types.QueryItem{ + Feature: map[string]interface{}{ + "featureName": featureName, + "sort": pf.Sort*1000 + int64(i), // 保持组合包整体顺序,子项按索引排 + }, + Data: map[string]interface{}{ + "apiID": item.ApiID, + "data": item.Data, + "success": item.Success, + "timestamp": item.Timestamp, + }, + }) + } continue } diff --git a/app/main/api/internal/service/apirequestService.go b/app/main/api/internal/service/apirequestService.go index feb2734..5009d0f 100644 --- a/app/main/api/internal/service/apirequestService.go +++ b/app/main/api/internal/service/apirequestService.go @@ -57,6 +57,18 @@ type APIResponseData struct { Error string `json:"error,omitempty"` } +// ComboPackageResponseItem 组合包接口返回的单个子项 +type ComboPackageResponseItem struct { + ApiCode string `json:"api_code"` + Success bool `json:"success"` + Data json.RawMessage `json:"data"` +} + +// ComboPackageResponse 组合包接口返回结构 +type ComboPackageResponse struct { + Responses []ComboPackageResponseItem `json:"responses"` +} + // ProcessRequests 处理请求 func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]byte, error) { var ctx, cancel = context.WithCancel(context.Background()) @@ -85,6 +97,13 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([] if len(featureList) == 0 { return nil, errors.New("处理请求错误,产品无对应接口功能") } + // 若产品包含组合包(api_id 前四位为 COMB),则只调用该组合包,不再并发请求其他 feature + for _, f := range featureList { + if strings.HasPrefix(f.ApiId, "COMB") { + featureList = []*model.Feature{f} + break + } + } var ( wg sync.WaitGroup resultsCh = make(chan APIResponseData, len(featureList)) @@ -153,10 +172,20 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([] close(resultsCh) close(errorsCh) }() - // 收集所有结果并合并z + // 收集所有结果并合并;组合包(api_id 前四位为 COMB)返回的是多条 APIResponseData,需展开 var responseData []APIResponseData for result := range resultsCh { - responseData = append(responseData, result) + if strings.HasPrefix(result.ApiID, "COMB") { + var comboItems []APIResponseData + if err := json.Unmarshal(result.Data, &comboItems); err != nil { + logx.WithContext(ctx).Errorf("组合包响应解析失败: %v", err) + responseData = append(responseData, result) + continue + } + responseData = append(responseData, comboItems...) + } else { + responseData = append(responseData, result) + } } if atomic.LoadInt32(&errorCount) >= int32(errorLimit) { var allErrors []error @@ -208,6 +237,9 @@ var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, err "JRZQ7F1A": (*ApiRequestService).ProcessJRZQ7F1ARequest, "IVYZ3P9M": (*ApiRequestService).ProcessIVYZ3P9MRequest, "JRZQ6F2A": (*ApiRequestService).ProcessJRZQ6F2ARequest, + "COMBCZGR": (*ApiRequestService).ProcessCOMBCZGRRequest, + "COMBCZDQ": (*ApiRequestService).ProcessCOMBCZDQRequest, + "COMBCZQY": (*ApiRequestService).ProcessCOMBCZQYRequest, } // PreprocessRequestApi 调用指定的请求处理函数 @@ -1601,3 +1633,112 @@ func (a *ApiRequestService) ProcessJRZQ6F2ARequest(params []byte) ([]byte, error return convertTianyuanResponse(resp) } + +// ProcessCOMBCZGRRequest 组合包 COMBCZGR:一次请求返回多个模块数据。必传 authorization_url, id_card, name, mobile_no +func (a *ApiRequestService) ProcessCOMBCZGRRequest(params []byte) ([]byte, error) { + authorizationURL := gjson.GetBytes(params, "authorization_url") + idCard := gjson.GetBytes(params, "id_card") + name := gjson.GetBytes(params, "name") + mobileNo := gjson.GetBytes(params, "mobile_no") + if !mobileNo.Exists() { + mobileNo = gjson.GetBytes(params, "mobile") + } + if !authorizationURL.Exists() || authorizationURL.String() == "" || + !idCard.Exists() || !name.Exists() || !mobileNo.Exists() { + return nil, errors.New("api请求, COMBCZGR, 缺少必填参数: authorization_url / id_card / name / mobile_no(mobile)") + } + + reqParams := map[string]interface{}{ + "authorization_url": authorizationURL.String(), + "id_card": idCard.String(), + "name": name.String(), + "mobile_no": mobileNo.String(), + } + + resp, err := a.tianyuanapi.CallInterface("COMBCZGR", reqParams) + if err != nil { + return nil, err + } + return a.comboResponseToAPIResponseData(resp) +} + +// ProcessCOMBCZDQRequest 组合包 COMBCZDQ:一次请求返回多个模块数据。必传 name, mobile_no, authorization_url, authorized, id_card +func (a *ApiRequestService) ProcessCOMBCZDQRequest(params []byte) ([]byte, error) { + name := gjson.GetBytes(params, "name") + mobileNo := gjson.GetBytes(params, "mobile_no") + if !mobileNo.Exists() { + mobileNo = gjson.GetBytes(params, "mobile") + } + authorizationURL := gjson.GetBytes(params, "authorization_url") + authorized := gjson.GetBytes(params, "authorized") + idCard := gjson.GetBytes(params, "id_card") + if !name.Exists() || !mobileNo.Exists() || !authorizationURL.Exists() || authorizationURL.String() == "" || + !authorized.Exists() || authorized.String() == "" || !idCard.Exists() { + return nil, errors.New("api请求, COMBCZDQ, 缺少必填参数: name / mobile_no(mobile) / authorization_url / authorized / id_card") + } + + reqParams := map[string]interface{}{ + "name": name.String(), + "mobile_no": mobileNo.String(), + "authorization_url": authorizationURL.String(), + "authorized": authorized.String(), + "id_card": idCard.String(), + } + + resp, err := a.tianyuanapi.CallInterface("COMBCZDQ", reqParams) + if err != nil { + return nil, err + } + return a.comboResponseToAPIResponseData(resp) +} + +// ProcessCOMBCZQYRequest 组合包 COMBCZQY:一次请求返回多个模块数据。必传 name, mobile_no, authorization_url, id_card +func (a *ApiRequestService) ProcessCOMBCZQYRequest(params []byte) ([]byte, error) { + name := gjson.GetBytes(params, "name") + mobileNo := gjson.GetBytes(params, "mobile_no") + if !mobileNo.Exists() { + mobileNo = gjson.GetBytes(params, "mobile") + } + authorizationURL := gjson.GetBytes(params, "authorization_url") + idCard := gjson.GetBytes(params, "id_card") + if !name.Exists() || !mobileNo.Exists() || !authorizationURL.Exists() || authorizationURL.String() == "" || + !idCard.Exists() { + return nil, errors.New("api请求, COMBCZQY, 缺少必填参数: name / mobile_no(mobile) / authorization_url / id_card") + } + + reqParams := map[string]interface{}{ + "name": name.String(), + "mobile_no": mobileNo.String(), + "authorization_url": authorizationURL.String(), + "id_card": idCard.String(), + } + + resp, err := a.tianyuanapi.CallInterface("COMBCZQY", reqParams) + if err != nil { + return nil, err + } + return a.comboResponseToAPIResponseData(resp) +} + +// comboResponseToAPIResponseData 将组合包接口解密后的 Data 转为 []APIResponseData 并返回 JSON +func (a *ApiRequestService) comboResponseToAPIResponseData(resp *tianyuanapi.Response) ([]byte, error) { + dataBytes, err := json.Marshal(resp.Data) + if err != nil { + return nil, fmt.Errorf("组合包响应序列化失败: %w", err) + } + var combo ComboPackageResponse + if err := json.Unmarshal(dataBytes, &combo); err != nil { + return nil, fmt.Errorf("组合包响应解析失败: %w", err) + } + timestamp := time.Now().Format("2006-01-02 15:04:05") + out := make([]APIResponseData, 0, len(combo.Responses)) + for _, item := range combo.Responses { + out = append(out, APIResponseData{ + ApiID: item.ApiCode, + Data: item.Data, + Success: item.Success, + Timestamp: timestamp, + }) + } + return json.Marshal(out) +}