Files
ycc-proxy-server/app/main/api/internal/logic/agent/offlinefeaturelogic.go
2026-02-01 19:15:52 +08:00

171 lines
5.0 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 agent
import (
"context"
"encoding/hex"
"encoding/json"
"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) {
// 1. 验证参数
if err := l.validateRequest(req); err != nil {
return nil, err
}
// 2. 获取用户ID并验证代理权限任意等级代理均可下架
userID, err := l.verifyAgent()
if err != nil {
return nil, err
}
// 3. 获取查询记录和身份证号
queryModel, idCard, err := l.getQueryInfo(req.QueryId)
if err != nil {
return nil, err
}
_ = queryModel // 避免未使用变量警告
// 4. 调用 WhitelistService 统一下架处理
needPay, amount, whitelistCreated, err := l.svcCtx.WhitelistService.ProcessOfflineFeature(
l.ctx,
nil, // 不使用事务,因为可能只是检查
idCard,
req.FeatureApiId,
userID,
req.QueryId,
)
if err != nil {
return nil, err
}
// 5. 如果已创建白名单,需要删除报告数据
if whitelistCreated {
if err := l.deleteQueryData(req.QueryId, req.FeatureApiId); err != nil {
// 删除报告数据失败不影响主流程,只记录日志
logx.Errorf("下架模块后删除报告数据失败:查询记录 %s模块 %s错误%v", req.QueryId, req.FeatureApiId, err)
}
}
return &types.OfflineFeatureResp{
Success: whitelistCreated,
NeedPay: needPay,
Amount: amount,
}, nil
}
// validateRequest 验证请求参数
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
}
// verifyAgent 验证是否为代理并返回用户ID任意等级代理均可下架
func (l *OfflineFeatureLogic) verifyAgent() (string, error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
}
_, err = l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
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
}
// getQueryInfo 获取查询记录和身份证号
func (l *OfflineFeatureLogic) getQueryInfo(queryId string) (*model.Query, string, error) {
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, queryId)
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)
}
// 解密 QueryParams 获取 idCard
idCard, err := l.extractIdCardFromQueryParams(queryModel)
if err != nil {
return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取身份证号失败, %v", err)
}
if idCard == "" {
return nil, "", errors.Wrapf(xerr.NewErrMsg("查询参数中缺少身份证号"), "")
}
return queryModel, idCard, nil
}
// extractIdCardFromQueryParams 从 QueryParams 中提取身份证号
func (l *OfflineFeatureLogic) extractIdCardFromQueryParams(queryModel *model.Query) (string, error) {
if queryModel.QueryParams == "" {
return "", errors.New("查询参数为空")
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return "", errors.Wrap(decodeErr, "获取AES密钥失败")
}
decryptedParams, decryptErr := crypto.AesDecrypt(queryModel.QueryParams, key)
if decryptErr != nil {
return "", errors.Wrap(decryptErr, "解密查询参数失败")
}
var params map[string]interface{}
unmarshalErr := json.Unmarshal(decryptedParams, &params)
if unmarshalErr != nil {
return "", errors.Wrap(unmarshalErr, "解析查询参数失败")
}
idCard, ok := params["id_card"].(string)
if !ok || idCard == "" {
return "", errors.New("查询参数中缺少 id_card 或 id_card 为空")
}
return idCard, nil
}
// deleteQueryData 删除报告数据
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)
})
}