Files
ycc-proxy-server/app/main/api/internal/logic/agent/offlinefeaturelogic.go

198 lines
5.4 KiB
Go
Raw Normal View History

2026-01-12 16:43:08 +08:00
package agent
import (
"context"
"encoding/hex"
"encoding/json"
2026-06-20 15:13:58 +08:00
"fmt"
"strings"
2026-01-12 16:43:08 +08:00
"ycc-server/app/main/model"
"ycc-server/common/ctxdata"
"ycc-server/common/xerr"
"ycc-server/pkg/lzkit/crypto"
"github.com/pkg/errors"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type OfflineFeatureLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewOfflineFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OfflineFeatureLogic {
return &OfflineFeatureLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp *types.OfflineFeatureResp, err error) {
if err := l.validateRequest(req); err != nil {
return nil, err
}
2026-02-01 19:15:52 +08:00
userID, err := l.verifyAgent()
2026-01-12 16:43:08 +08:00
if err != nil {
return nil, err
}
2026-06-20 15:13:58 +08:00
queryModel, idCard, name, err := l.getQueryInfo(req.QueryId)
2026-01-12 16:43:08 +08:00
if err != nil {
return nil, err
}
2026-06-20 15:13:58 +08:00
mainApiId := extractMainApiId(req.FeatureApiId)
feature, err := l.svcCtx.FeatureModel.FindOneByApiId(l.ctx, mainApiId)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrMsg("模块不存在"), "")
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询模块信息失败, %v", err)
}
2026-01-12 16:43:08 +08:00
needPay, amount, whitelistCreated, err := l.svcCtx.WhitelistService.ProcessOfflineFeature(
l.ctx,
2026-06-20 15:13:58 +08:00
nil,
2026-01-12 16:43:08 +08:00
idCard,
req.FeatureApiId,
userID,
req.QueryId,
)
if err != nil {
return nil, err
}
2026-06-20 15:13:58 +08:00
if needPay {
return &types.OfflineFeatureResp{
Success: false,
NeedPay: true,
Amount: amount,
}, nil
}
2026-01-12 16:43:08 +08:00
if whitelistCreated {
2026-06-20 15:13:58 +08:00
remark := fmt.Sprintf("代理下架自动同步 query_id=%s feature=%s", req.QueryId, feature.ApiId)
l.svcCtx.QueryWhitelistSyncService.TrySync(
l.ctx,
name,
idCard,
[]string{feature.ApiId},
remark,
)
2026-01-12 16:43:08 +08:00
if err := l.deleteQueryData(req.QueryId, req.FeatureApiId); err != nil {
logx.Errorf("下架模块后删除报告数据失败:查询记录 %s模块 %s错误%v", req.QueryId, req.FeatureApiId, err)
}
}
2026-06-20 15:13:58 +08:00
_ = queryModel
2026-01-12 16:43:08 +08:00
return &types.OfflineFeatureResp{
Success: whitelistCreated,
NeedPay: needPay,
Amount: amount,
}, nil
}
func (l *OfflineFeatureLogic) validateRequest(req *types.OfflineFeatureReq) error {
if req.QueryId == "" {
return errors.Wrapf(xerr.NewErrMsg("查询记录ID不能为空"), "")
}
if req.FeatureApiId == "" {
return errors.Wrapf(xerr.NewErrMsg("模块API标识不能为空"), "")
}
return nil
}
2026-02-01 19:15:52 +08:00
func (l *OfflineFeatureLogic) verifyAgent() (string, error) {
2026-01-12 16:43:08 +08:00
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
}
2026-02-01 19:15:52 +08:00
_, err = l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
2026-01-12 16:43:08 +08:00
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return "", errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
}
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
}
return userID, nil
}
2026-06-20 15:13:58 +08:00
func (l *OfflineFeatureLogic) getQueryInfo(queryId string) (*model.Query, string, string, error) {
2026-01-12 16:43:08 +08:00
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, queryId)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
2026-06-20 15:13:58 +08:00
return nil, "", "", errors.Wrapf(xerr.NewErrMsg("查询记录不存在"), "")
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
return nil, "", "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询报告记录失败, %v", err)
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
idCard, name, err := extractPersonInfoFromQueryParams(l.svcCtx, queryModel)
2026-01-12 16:43:08 +08:00
if err != nil {
2026-06-20 15:13:58 +08:00
return nil, "", "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取查询参数失败, %v", err)
2026-01-12 16:43:08 +08:00
}
if idCard == "" {
2026-06-20 15:13:58 +08:00
return nil, "", "", errors.Wrapf(xerr.NewErrMsg("查询参数中缺少身份证号"), "")
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
return queryModel, idCard, name, nil
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
func extractMainApiId(featureApiId string) string {
if idx := strings.Index(featureApiId, "_"); idx > 0 {
return featureApiId[:idx]
}
return featureApiId
}
func extractPersonInfoFromQueryParams(svcCtx *svc.ServiceContext, queryModel *model.Query) (idCard, name string, err error) {
2026-01-12 16:43:08 +08:00
if queryModel.QueryParams == "" {
2026-06-20 15:13:58 +08:00
return "", "", errors.New("查询参数为空")
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
secretKey := svcCtx.Config.Encrypt.SecretKey
2026-01-12 16:43:08 +08:00
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
2026-06-20 15:13:58 +08:00
return "", "", errors.Wrap(decodeErr, "获取AES密钥失败")
2026-01-12 16:43:08 +08:00
}
decryptedParams, decryptErr := crypto.AesDecrypt(queryModel.QueryParams, key)
if decryptErr != nil {
2026-06-20 15:13:58 +08:00
return "", "", errors.Wrap(decryptErr, "解密查询参数失败")
2026-01-12 16:43:08 +08:00
}
var params map[string]interface{}
2026-06-20 15:13:58 +08:00
if unmarshalErr := json.Unmarshal(decryptedParams, &params); unmarshalErr != nil {
return "", "", errors.Wrap(unmarshalErr, "解析查询参数失败")
}
idCardValue, ok := params["id_card"].(string)
if !ok || idCardValue == "" {
return "", "", errors.New("查询参数中缺少 id_card 或 id_card 为空")
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
nameValue, _ := params["name"].(string)
if strings.TrimSpace(nameValue) == "" {
nameValue = "*"
2026-01-12 16:43:08 +08:00
}
2026-06-20 15:13:58 +08:00
return idCardValue, nameValue, nil
2026-01-12 16:43:08 +08:00
}
func (l *OfflineFeatureLogic) deleteQueryData(queryId, featureApiId string) error {
return l.svcCtx.QueryModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
return l.svcCtx.WhitelistService.DeleteFeatureFromQueryData(ctx, session, queryId, featureApiId)
})
}