Files
sim-server/app/main/api/internal/logic/query/queryexamplelogic.go
2026-02-09 14:48:13 +08:00

204 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package query
import (
"bytes"
"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"
"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"`
}
// comboExampleRawResponse 组合包数据源原始返回格式:{ "responses": [ { "api_code", "success", "data" } ] }
type comboExampleRawResponse struct {
Responses []struct {
ApiCode string `json:"api_code"`
Success bool `json:"success"`
Data json.RawMessage `json:"data"`
} `json:"responses"`
}
type QueryExampleLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryExampleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryExampleLogic {
return &QueryExampleLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp string, err error) {
// 根据产品特性标识获取产品信息
product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, req.Feature)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 获取商品信息失败, %v", err)
}
secretKeyHex := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKeyHex)
if decodeErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 解析AES密钥失败, %v", decodeErr)
}
// 创建一个空的Query结构体来存储结果
query := types.Query{
Product: product.ProductEn,
ProductName: product.ProductName,
QueryData: make([]types.QueryItem, 0),
QueryParams: make(map[string]interface{}),
}
query.QueryParams = map[string]interface{}{
"id_card": "45000000000000000",
"mobile": "13700000000",
"name": "张老三",
}
// 查询ProductFeatureModel获取产品相关的功能列表
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().Where("product_id = ?", product.Id)
productFeatures, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "")
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 查询 ProductFeatureModel 错误: %v", err)
}
// 从每个启用的特性获取示例数据并合并
for _, pf := range productFeatures {
if pf.Enable != 1 {
continue // 跳过未启用的特性
}
// 根据特性ID查找示例数据
example, err := l.svcCtx.ExampleModel.FindOneByFeatureId(l.ctx, pf.FeatureId)
if err != nil {
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 %s 的信息: %v", pf.FeatureId, err)
continue
}
// 组合包api_id 前四位为 COMB示例 Content 支持两种格式,按子模块展开为多个 Tab
// 格式1[]comboExampleDataItem 即 [ { "apiID", "data", "success", "timestamp" }, ... ]
// 格式2数据源原始格式 { "responses": [ { "api_code", "success", "data" }, ... ] }
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)
}
decryptedBytes := decryptedData
type expandItem struct {
ApiID string
Data json.RawMessage
Success bool
Timestamp string
}
var itemsToExpand []expandItem
trimmed := bytes.TrimSpace(decryptedBytes)
if len(trimmed) > 0 && trimmed[0] == '[' {
var comboItems []comboExampleDataItem
if err := sonic.Unmarshal(decryptedBytes, &comboItems); err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 组合包示例解析失败: %v", err)
}
for _, item := range comboItems {
itemsToExpand = append(itemsToExpand, expandItem{item.ApiID, item.Data, item.Success, item.Timestamp})
}
} else {
var raw comboExampleRawResponse
if err := sonic.Unmarshal(decryptedBytes, &raw); err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 组合包示例解析失败(非数组且非responses格式): %v", err)
}
for _, r := range raw.Responses {
itemsToExpand = append(itemsToExpand, expandItem{r.ApiCode, r.Data, r.Success, ""})
}
}
for i, item := range itemsToExpand {
subFeature, subErr := l.svcCtx.FeatureModel.FindOneByApiId(l.ctx, item.ApiID)
featureName := item.ApiID
if subErr == nil && subFeature != nil {
featureName = subFeature.Name
}
ts := item.Timestamp
if ts == "" {
ts = "2020-01-01 00:00:00"
}
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": ts,
},
})
}
continue
}
var queryItem types.QueryItem
// 解密查询数据
// 解析示例内容
if example.Content == "000" {
queryItem.Data = example.Content
} else {
// 解密数据
decryptedData, decryptErr := crypto.AesDecrypt(example.Content, key)
if decryptErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 解密数据失败: %v", decryptErr)
}
err = sonic.Unmarshal([]byte(decryptedData), &queryItem.Data)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 解析示例内容失败: %v", err)
}
}
// 添加特性信息
queryItem.Feature = map[string]interface{}{
"featureName": feature.Name,
"sort": pf.Sort,
}
// 添加到查询数据中
query.QueryData = append(query.QueryData, queryItem)
}
queryBytes, marshalErr := sonic.Marshal(query)
if marshalErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 序列化查询结果失败: %v", marshalErr)
}
encryptedQuery, encryptErr := crypto.AesEncrypt(queryBytes, key)
if encryptErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 加密查询结果失败: %v", encryptErr)
}
return encryptedQuery, nil
}