f
This commit is contained in:
@@ -33,19 +33,33 @@ func generateAuthDateRange() string {
|
||||
}
|
||||
|
||||
type ApiRequestService struct {
|
||||
config config.Config
|
||||
featureModel model.FeatureModel
|
||||
productFeatureModel model.ProductFeatureModel
|
||||
tianyuanapi *tianyuanapi.Client
|
||||
config config.Config
|
||||
featureModel model.FeatureModel
|
||||
productFeatureModel model.ProductFeatureModel
|
||||
userFeatureWhitelistModel model.UserFeatureWhitelistModel
|
||||
whitelistService *WhitelistService
|
||||
tianyuanapi *tianyuanapi.Client
|
||||
tianyuanapiCallLogService *TianyuanapiCallLogService
|
||||
}
|
||||
|
||||
// NewApiRequestService 是一个构造函数,用于初始化 ApiRequestService
|
||||
func NewApiRequestService(c config.Config, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel, tianyuanapi *tianyuanapi.Client) *ApiRequestService {
|
||||
// NewApiRequestService 构造函数
|
||||
func NewApiRequestService(
|
||||
c config.Config,
|
||||
featureModel model.FeatureModel,
|
||||
productFeatureModel model.ProductFeatureModel,
|
||||
userFeatureWhitelistModel model.UserFeatureWhitelistModel,
|
||||
tianyuanapi *tianyuanapi.Client,
|
||||
tianyuanapiCallLogService *TianyuanapiCallLogService,
|
||||
whitelistService *WhitelistService,
|
||||
) *ApiRequestService {
|
||||
return &ApiRequestService{
|
||||
config: c,
|
||||
featureModel: featureModel,
|
||||
productFeatureModel: productFeatureModel,
|
||||
tianyuanapi: tianyuanapi,
|
||||
config: c,
|
||||
featureModel: featureModel,
|
||||
productFeatureModel: productFeatureModel,
|
||||
userFeatureWhitelistModel: userFeatureWhitelistModel,
|
||||
tianyuanapi: tianyuanapi,
|
||||
tianyuanapiCallLogService: tianyuanapiCallLogService,
|
||||
whitelistService: whitelistService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,23 +75,33 @@ type APIResponseData struct {
|
||||
func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]byte, error) {
|
||||
var ctx, cancel = context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productID,
|
||||
})
|
||||
|
||||
// 白名单:已下架模块直接返回占位成功,不调用天远 API
|
||||
idCard := gjson.GetBytes(params, "id_card").String()
|
||||
var whitelistedFeatureApiIds map[string]bool
|
||||
if a.whitelistService != nil {
|
||||
whitelistedFeatureApiIds, _ = a.whitelistService.GetWhitelistedFeatureApisByIdCard(ctx, idCard)
|
||||
} else {
|
||||
whitelistedFeatureApiIds = make(map[string]bool)
|
||||
}
|
||||
|
||||
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productID,
|
||||
})
|
||||
productFeatureList, findProductFeatureErr := a.productFeatureModel.FindAll(ctx, build, "")
|
||||
if findProductFeatureErr != nil {
|
||||
return nil, findProductFeatureErr
|
||||
}
|
||||
var featureIDs []string
|
||||
isImportantMap := make(map[string]int64, len(productFeatureList))
|
||||
var featureIDs []string
|
||||
isImportantMap := make(map[string]int64, len(productFeatureList))
|
||||
for _, pf := range productFeatureList {
|
||||
featureIDs = append(featureIDs, pf.FeatureId)
|
||||
isImportantMap[pf.FeatureId] = pf.IsImportant
|
||||
featureIDs = append(featureIDs, pf.FeatureId)
|
||||
isImportantMap[pf.FeatureId] = pf.IsImportant
|
||||
}
|
||||
if len(featureIDs) == 0 {
|
||||
return nil, errors.New("featureIDs 是空的")
|
||||
}
|
||||
builder := a.featureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIDs})
|
||||
builder := a.featureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIDs})
|
||||
featureList, findFeatureErr := a.featureModel.FindAll(ctx, builder, "")
|
||||
if findFeatureErr != nil {
|
||||
return nil, findFeatureErr
|
||||
@@ -109,12 +133,19 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]
|
||||
Success: false,
|
||||
}
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||
// 白名单:已下架模块直接返回占位成功
|
||||
if whitelistedFeatureApiIds[feature.ApiId] {
|
||||
result.Success = true
|
||||
result.Timestamp = timestamp
|
||||
result.Data = []byte("null")
|
||||
resultsCh <- result
|
||||
return
|
||||
}
|
||||
var (
|
||||
resp json.RawMessage
|
||||
preprocessErr error
|
||||
)
|
||||
// 若 isImportantMap[feature.ID] == 1,则表示需要在出错时重试
|
||||
isImportant := isImportantMap[feature.Id] == 1
|
||||
isImportant := isImportantMap[feature.Id] == 1
|
||||
tryCount := 0
|
||||
for {
|
||||
tryCount++
|
||||
|
||||
190
app/main/api/internal/service/tianyuanapiCallLogService.go
Normal file
190
app/main/api/internal/service/tianyuanapiCallLogService.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"qnc-server/app/main/model"
|
||||
)
|
||||
|
||||
// TianyuanapiCallLogService 天元API调用记录服务
|
||||
type TianyuanapiCallLogService struct {
|
||||
tianyuanapiCallLogModel model.TianyuanapiCallLogModel
|
||||
featureModel model.FeatureModel
|
||||
}
|
||||
|
||||
// NewTianyuanapiCallLogService 创建天元API调用记录服务
|
||||
func NewTianyuanapiCallLogService(
|
||||
tianyuanapiCallLogModel model.TianyuanapiCallLogModel,
|
||||
featureModel model.FeatureModel,
|
||||
) *TianyuanapiCallLogService {
|
||||
return &TianyuanapiCallLogService{
|
||||
tianyuanapiCallLogModel: tianyuanapiCallLogModel,
|
||||
featureModel: featureModel,
|
||||
}
|
||||
}
|
||||
|
||||
// CallLogOptions 调用记录选项
|
||||
type CallLogOptions struct {
|
||||
FeatureID string // 功能ID
|
||||
ApiID string // API标识(如:YYSYBE08)
|
||||
OrderID string // 订单ID(可选)
|
||||
QueryID string // 查询ID(可选)
|
||||
CallStatus int64 // 调用状态:0=失败,1=成功
|
||||
ResponseTime int64 // 响应耗时(毫秒)
|
||||
ErrorCode string // 错误码(失败时)
|
||||
ErrorMessage string // 错误信息(失败时)
|
||||
RequestParams interface{} // 请求参数(可选)
|
||||
ResponseData interface{} // 响应数据(可选)
|
||||
TransactionID string // 天元API流水号
|
||||
}
|
||||
|
||||
// RecordCall 记录天元API调用
|
||||
func (s *TianyuanapiCallLogService) RecordCall(ctx context.Context, opts CallLogOptions) error {
|
||||
// 1. 获取feature的成本价
|
||||
costPrice := 0.00
|
||||
if opts.CallStatus == 1 { // 只有成功才计算成本
|
||||
if opts.FeatureID == "" {
|
||||
logx.Infof("记录API调用时feature_id为空,api_id=%s,无法获取成本价", opts.ApiID)
|
||||
} else {
|
||||
feature, err := s.featureModel.FindOne(ctx, opts.FeatureID)
|
||||
if err == nil {
|
||||
costPrice = feature.CostPrice
|
||||
logx.Infof("记录API调用 - feature_id=%s, api_id=%s, cost_price=%f", opts.FeatureID, opts.ApiID, costPrice)
|
||||
} else {
|
||||
logx.Errorf("查询feature成本价失败,feature_id=%s, api_id=%s, err=%v", opts.FeatureID, opts.ApiID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 转换参数和响应为JSON字符串
|
||||
var requestParamsStr, responseDataStr *string
|
||||
if opts.RequestParams != nil {
|
||||
if bytes, err := json.Marshal(opts.RequestParams); err == nil {
|
||||
jsonStr := string(bytes)
|
||||
requestParamsStr = &jsonStr
|
||||
}
|
||||
}
|
||||
if opts.ResponseData != nil {
|
||||
if bytes, err := json.Marshal(opts.ResponseData); err == nil {
|
||||
jsonStr := string(bytes)
|
||||
if len(jsonStr) > 1000 {
|
||||
jsonStr = jsonStr[:1000] + "...[truncated]"
|
||||
}
|
||||
responseDataStr = &jsonStr
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 构建调用记录
|
||||
callTime := time.Now()
|
||||
deleteTime := sql.NullTime{}
|
||||
callLog := &model.TianyuanapiCallLog{
|
||||
FeatureId: opts.FeatureID,
|
||||
ApiId: opts.ApiID,
|
||||
OrderId: sql.NullString{},
|
||||
QueryId: sql.NullString{},
|
||||
CallStatus: opts.CallStatus,
|
||||
CallTime: callTime,
|
||||
ResponseTime: sql.NullInt64{},
|
||||
CostPrice: costPrice,
|
||||
ErrorCode: sql.NullString{},
|
||||
ErrorMessage: sql.NullString{},
|
||||
RequestParams: sql.NullString{},
|
||||
ResponseData: sql.NullString{},
|
||||
TransactionId: sql.NullString{},
|
||||
CreateTime: callTime,
|
||||
UpdateTime: callTime,
|
||||
DeleteTime: deleteTime,
|
||||
DelState: 0,
|
||||
Version: 0,
|
||||
}
|
||||
|
||||
if opts.OrderID != "" {
|
||||
callLog.OrderId = sql.NullString{String: opts.OrderID, Valid: true}
|
||||
}
|
||||
if opts.QueryID != "" {
|
||||
callLog.QueryId = sql.NullString{String: opts.QueryID, Valid: true}
|
||||
}
|
||||
if opts.ResponseTime > 0 {
|
||||
callLog.ResponseTime = sql.NullInt64{Int64: opts.ResponseTime, Valid: true}
|
||||
}
|
||||
if opts.ErrorCode != "" {
|
||||
callLog.ErrorCode = sql.NullString{String: opts.ErrorCode, Valid: true}
|
||||
}
|
||||
if opts.ErrorMessage != "" {
|
||||
callLog.ErrorMessage = sql.NullString{String: opts.ErrorMessage, Valid: true}
|
||||
}
|
||||
if requestParamsStr != nil {
|
||||
callLog.RequestParams = sql.NullString{String: *requestParamsStr, Valid: true}
|
||||
}
|
||||
if responseDataStr != nil {
|
||||
callLog.ResponseData = sql.NullString{String: *responseDataStr, Valid: true}
|
||||
}
|
||||
if opts.TransactionID != "" {
|
||||
callLog.TransactionId = sql.NullString{String: opts.TransactionID, Valid: true}
|
||||
}
|
||||
|
||||
_, err := s.tianyuanapiCallLogModel.Insert(ctx, nil, callLog)
|
||||
if err != nil {
|
||||
logx.Errorf("插入天元API调用记录失败,feature_id=%s, api_id=%s, err=%v", opts.FeatureID, opts.ApiID, err)
|
||||
return fmt.Errorf("插入调用记录失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StatisticsFilter 统计过滤条件
|
||||
type StatisticsFilter struct {
|
||||
FeatureID string
|
||||
ApiID string
|
||||
StartDate time.Time
|
||||
EndDate time.Time
|
||||
}
|
||||
|
||||
// Statistics 统计信息
|
||||
type Statistics struct {
|
||||
TotalCalls int64
|
||||
SuccessCalls int64
|
||||
FailedCalls int64
|
||||
TotalCost float64
|
||||
}
|
||||
|
||||
// GetStatistics 获取统计信息
|
||||
func (s *TianyuanapiCallLogService) GetStatistics(ctx context.Context, filter StatisticsFilter) (*Statistics, error) {
|
||||
builder := s.tianyuanapiCallLogModel.SelectBuilder()
|
||||
if filter.FeatureID != "" {
|
||||
builder = builder.Where(squirrel.Eq{"feature_id": filter.FeatureID})
|
||||
}
|
||||
if filter.ApiID != "" {
|
||||
builder = builder.Where(squirrel.Eq{"api_id": filter.ApiID})
|
||||
}
|
||||
if !filter.StartDate.IsZero() {
|
||||
builder = builder.Where(squirrel.GtOrEq{"call_time": filter.StartDate})
|
||||
}
|
||||
if !filter.EndDate.IsZero() {
|
||||
builder = builder.Where(squirrel.Lt{"call_time": filter.EndDate})
|
||||
}
|
||||
totalCalls, err := s.tianyuanapiCallLogModel.FindCount(ctx, builder, "id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计总调用次数失败: %w", err)
|
||||
}
|
||||
successBuilder := builder.Where(squirrel.Eq{"call_status": 1})
|
||||
successCalls, err := s.tianyuanapiCallLogModel.FindCount(ctx, successBuilder, "id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计成功次数失败: %w", err)
|
||||
}
|
||||
totalCost, err := s.tianyuanapiCallLogModel.FindSum(ctx, successBuilder, "cost_price")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计总成本失败: %w", err)
|
||||
}
|
||||
return &Statistics{
|
||||
TotalCalls: totalCalls,
|
||||
SuccessCalls: successCalls,
|
||||
FailedCalls: totalCalls - successCalls,
|
||||
TotalCost: totalCost,
|
||||
}, nil
|
||||
}
|
||||
450
app/main/api/internal/service/whitelistService.go
Normal file
450
app/main/api/internal/service/whitelistService.go
Normal file
@@ -0,0 +1,450 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/app/main/model"
|
||||
"qnc-server/common/xerr"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
)
|
||||
|
||||
// WhitelistService 白名单领域服务
|
||||
type WhitelistService struct {
|
||||
config config.Config
|
||||
UserFeatureWhitelistModel model.UserFeatureWhitelistModel
|
||||
WhitelistOrderModel model.WhitelistOrderModel
|
||||
WhitelistOrderItemModel model.WhitelistOrderItemModel
|
||||
QueryModel model.QueryModel
|
||||
FeatureModel model.FeatureModel
|
||||
}
|
||||
|
||||
// NewWhitelistService 创建白名单服务
|
||||
func NewWhitelistService(
|
||||
c config.Config,
|
||||
userFeatureWhitelistModel model.UserFeatureWhitelistModel,
|
||||
whitelistOrderModel model.WhitelistOrderModel,
|
||||
whitelistOrderItemModel model.WhitelistOrderItemModel,
|
||||
queryModel model.QueryModel,
|
||||
featureModel model.FeatureModel,
|
||||
) *WhitelistService {
|
||||
return &WhitelistService{
|
||||
config: c,
|
||||
UserFeatureWhitelistModel: userFeatureWhitelistModel,
|
||||
WhitelistOrderModel: whitelistOrderModel,
|
||||
WhitelistOrderItemModel: whitelistOrderItemModel,
|
||||
QueryModel: queryModel,
|
||||
FeatureModel: featureModel,
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureFreeWhitelist 免费下架:如果还没有生效白名单,则创建一条免费白名单记录
|
||||
func (s *WhitelistService) EnsureFreeWhitelist(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
idCard string,
|
||||
feature *model.Feature,
|
||||
userId string,
|
||||
orderId string,
|
||||
) error {
|
||||
builder := s.UserFeatureWhitelistModel.SelectBuilder().
|
||||
Where("id_card = ? AND feature_id = ?", idCard, feature.Id)
|
||||
records, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "查询白名单记录失败")
|
||||
}
|
||||
for _, r := range records {
|
||||
if r.Status == 1 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
wl := &model.UserFeatureWhitelist{
|
||||
Id: uuid.NewString(),
|
||||
IdCard: idCard,
|
||||
FeatureId: feature.Id,
|
||||
FeatureApiId: feature.ApiId,
|
||||
UserId: userId,
|
||||
OrderId: lzUtils.StringToNullString(orderId),
|
||||
WhitelistOrderId: lzUtils.StringToNullString(""),
|
||||
Amount: 0,
|
||||
Status: 1,
|
||||
}
|
||||
_, err = s.UserFeatureWhitelistModel.Insert(ctx, session, wl)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "创建免费白名单记录失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateWhitelistByPaidOrder 根据已支付的白名单订单,创建对应的白名单记录
|
||||
func (s *WhitelistService) CreateWhitelistByPaidOrder(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
order *model.Order,
|
||||
whitelistOrder *model.WhitelistOrder,
|
||||
) error {
|
||||
if whitelistOrder.Status != 2 {
|
||||
return nil
|
||||
}
|
||||
itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
|
||||
Where("order_id = ?", whitelistOrder.Id)
|
||||
items, err := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "查询白名单订单明细失败")
|
||||
}
|
||||
for _, item := range items {
|
||||
wl := &model.UserFeatureWhitelist{
|
||||
Id: uuid.NewString(),
|
||||
IdCard: whitelistOrder.IdCard,
|
||||
FeatureId: item.FeatureId,
|
||||
FeatureApiId: item.FeatureApiId,
|
||||
UserId: whitelistOrder.UserId,
|
||||
OrderId: lzUtils.StringToNullString(order.Id),
|
||||
WhitelistOrderId: lzUtils.StringToNullString(whitelistOrder.Id),
|
||||
Amount: item.Price,
|
||||
Status: 1,
|
||||
}
|
||||
if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
|
||||
return errors.Wrap(err, "创建白名单记录失败")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWhitelistedFeatureApisByIdCard 获取某个身份证号已下架的 feature_api_id 集合
|
||||
func (s *WhitelistService) GetWhitelistedFeatureApisByIdCard(
|
||||
ctx context.Context,
|
||||
idCard string,
|
||||
) (map[string]bool, error) {
|
||||
result := make(map[string]bool)
|
||||
if s == nil || idCard == "" {
|
||||
return result, nil
|
||||
}
|
||||
builder := s.UserFeatureWhitelistModel.SelectBuilder().
|
||||
Where("id_card = ? AND status = ?", idCard, 1)
|
||||
list, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "查询白名单失败")
|
||||
}
|
||||
for _, wl := range list {
|
||||
result[wl.FeatureApiId] = true
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckWhitelistExists 检查指定身份证号和模块是否已有生效的白名单记录
|
||||
func (s *WhitelistService) CheckWhitelistExists(
|
||||
ctx context.Context,
|
||||
idCard string,
|
||||
featureId string,
|
||||
) (bool, error) {
|
||||
if idCard == "" || featureId == "" {
|
||||
return false, nil
|
||||
}
|
||||
builder := s.UserFeatureWhitelistModel.SelectBuilder().
|
||||
Where("id_card = ? AND feature_id = ? AND status = ?", idCard, featureId, 1)
|
||||
list, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "查询白名单记录失败")
|
||||
}
|
||||
return len(list) > 0, nil
|
||||
}
|
||||
|
||||
// ProcessOfflineFeature 统一下架处理
|
||||
func (s *WhitelistService) ProcessOfflineFeature(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
idCard string,
|
||||
featureApiId string,
|
||||
userId string,
|
||||
orderId string,
|
||||
) (needPay bool, amount float64, whitelistCreated bool, err error) {
|
||||
mainApiId := s.extractMainApiId(featureApiId)
|
||||
feature, err := s.getFeatureByApiId(ctx, mainApiId)
|
||||
if err != nil {
|
||||
return false, 0, false, err
|
||||
}
|
||||
if feature.WhitelistPrice < 0 {
|
||||
return false, 0, false, errors.Wrapf(xerr.NewErrMsg("该模块不支持下架"), "")
|
||||
}
|
||||
exists, err := s.CheckWhitelistExists(ctx, idCard, feature.Id)
|
||||
if err != nil {
|
||||
return false, 0, false, err
|
||||
}
|
||||
if exists {
|
||||
return false, 0, true, nil
|
||||
}
|
||||
price := feature.WhitelistPrice
|
||||
if price <= 0 {
|
||||
if err := s.EnsureFreeWhitelist(ctx, session, idCard, feature, userId, orderId); err != nil {
|
||||
return false, 0, false, err
|
||||
}
|
||||
return false, 0, true, nil
|
||||
}
|
||||
paidOrderId, err := s.findPaidWhitelistOrder(ctx, userId, idCard, feature.Id)
|
||||
if err != nil {
|
||||
return false, 0, false, err
|
||||
}
|
||||
if paidOrderId != "" {
|
||||
if err := s.createWhitelistFromPaidOrder(ctx, session, idCard, feature, userId, orderId, paidOrderId, price); err != nil {
|
||||
return false, 0, false, err
|
||||
}
|
||||
return false, price, true, nil
|
||||
}
|
||||
return true, price, false, nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) extractMainApiId(featureApiId string) string {
|
||||
if idx := strings.Index(featureApiId, "_"); idx > 0 {
|
||||
return featureApiId[:idx]
|
||||
}
|
||||
return featureApiId
|
||||
}
|
||||
|
||||
func (s *WhitelistService) getFeatureByApiId(ctx context.Context, apiId string) (*model.Feature, error) {
|
||||
feature, err := s.FeatureModel.FindOneByApiId(ctx, apiId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrap(err, "模块不存在")
|
||||
}
|
||||
return nil, errors.Wrap(err, "查询模块信息失败")
|
||||
}
|
||||
return feature, nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) findPaidWhitelistOrder(
|
||||
ctx context.Context,
|
||||
userId string,
|
||||
idCard string,
|
||||
featureId string,
|
||||
) (string, error) {
|
||||
orderBuilder := s.WhitelistOrderModel.SelectBuilder().
|
||||
Where("user_id = ? AND id_card = ? AND status = ?", userId, idCard, 2)
|
||||
orders, err := s.WhitelistOrderModel.FindAll(ctx, orderBuilder, "")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "查询白名单订单失败")
|
||||
}
|
||||
for _, order := range orders {
|
||||
itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
|
||||
Where("order_id = ? AND feature_id = ?", order.Id, featureId)
|
||||
items, itemErr := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
|
||||
if itemErr != nil {
|
||||
return "", errors.Wrap(itemErr, "查询白名单订单明细失败")
|
||||
}
|
||||
if len(items) > 0 {
|
||||
return order.Id, nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) createWhitelistFromPaidOrder(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
idCard string,
|
||||
feature *model.Feature,
|
||||
userId string,
|
||||
orderId string,
|
||||
paidOrderId string,
|
||||
price float64,
|
||||
) error {
|
||||
wl := &model.UserFeatureWhitelist{
|
||||
Id: uuid.NewString(),
|
||||
IdCard: idCard,
|
||||
FeatureId: feature.Id,
|
||||
FeatureApiId: feature.ApiId,
|
||||
UserId: userId,
|
||||
OrderId: lzUtils.StringToNullString(orderId),
|
||||
WhitelistOrderId: lzUtils.StringToNullString(paidOrderId),
|
||||
Amount: price,
|
||||
Status: 1,
|
||||
}
|
||||
if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
|
||||
return errors.Wrap(err, "根据已支付订单创建白名单记录失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFeatureFromQueryData 从报告数据中删除指定模块的数据
|
||||
func (s *WhitelistService) DeleteFeatureFromQueryData(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
queryId string,
|
||||
featureApiId string,
|
||||
) error {
|
||||
queryModel, err := s.getQueryModel(ctx, queryId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if queryModel == nil {
|
||||
return nil
|
||||
}
|
||||
mainApiId := s.extractMainApiId(featureApiId)
|
||||
dataArray, key, err := s.decryptQueryData(queryModel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modifiedArray, hasModified := s.clearFeatureData(dataArray, mainApiId)
|
||||
if !hasModified {
|
||||
logx.Infof("删除报告数据:查询记录 %s 中未找到模块 %s 的数据,跳过删除", queryId, featureApiId)
|
||||
return nil
|
||||
}
|
||||
if err := s.updateQueryData(ctx, session, queryModel, modifiedArray, key); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) getQueryModel(ctx context.Context, queryId string) (*model.Query, error) {
|
||||
queryModel, err := s.QueryModel.FindOne(ctx, queryId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.Wrap(err, "查询报告记录失败")
|
||||
}
|
||||
if !queryModel.QueryData.Valid || queryModel.QueryData.String == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return queryModel, nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) decryptQueryData(queryModel *model.Query) ([]map[string]interface{}, []byte, error) {
|
||||
secretKey := s.config.Encrypt.SecretKey
|
||||
key, decodeErr := hex.DecodeString(secretKey)
|
||||
if decodeErr != nil {
|
||||
return nil, nil, errors.Wrap(decodeErr, "获取AES密钥失败")
|
||||
}
|
||||
decryptedData, decryptErr := crypto.AesDecrypt(queryModel.QueryData.String, key)
|
||||
if decryptErr != nil {
|
||||
return nil, nil, errors.Wrap(decryptErr, "解密报告数据失败")
|
||||
}
|
||||
var dataArray []map[string]interface{}
|
||||
if unmarshalErr := json.Unmarshal(decryptedData, &dataArray); unmarshalErr != nil {
|
||||
return nil, nil, errors.Wrap(unmarshalErr, "解析报告数据失败")
|
||||
}
|
||||
return dataArray, key, nil
|
||||
}
|
||||
|
||||
func (s *WhitelistService) clearFeatureData(dataArray []map[string]interface{}, mainApiId string) ([]map[string]interface{}, bool) {
|
||||
modifiedArray := make([]map[string]interface{}, 0, len(dataArray))
|
||||
hasModified := false
|
||||
for _, item := range dataArray {
|
||||
newItem := make(map[string]interface{})
|
||||
for k, v := range item {
|
||||
newItem[k] = v
|
||||
}
|
||||
apiID, ok := item["apiID"].(string)
|
||||
if !ok {
|
||||
modifiedArray = append(modifiedArray, newItem)
|
||||
continue
|
||||
}
|
||||
if s.extractMainApiId(apiID) == mainApiId {
|
||||
newItem["data"] = nil
|
||||
hasModified = true
|
||||
}
|
||||
modifiedArray = append(modifiedArray, newItem)
|
||||
}
|
||||
return modifiedArray, hasModified
|
||||
}
|
||||
|
||||
func (s *WhitelistService) updateQueryData(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
queryModel *model.Query,
|
||||
filteredArray []map[string]interface{},
|
||||
key []byte,
|
||||
) error {
|
||||
filteredBytes, marshalErr := json.Marshal(filteredArray)
|
||||
if marshalErr != nil {
|
||||
return errors.Wrap(marshalErr, "序列化过滤后的报告数据失败")
|
||||
}
|
||||
encryptedData, encryptErr := crypto.AesEncrypt(filteredBytes, key)
|
||||
if encryptErr != nil {
|
||||
return errors.Wrap(encryptErr, "加密过滤后的报告数据失败")
|
||||
}
|
||||
queryModel.QueryData = sql.NullString{String: encryptedData, Valid: true}
|
||||
if updateErr := s.QueryModel.UpdateWithVersion(ctx, session, queryModel); updateErr != nil {
|
||||
return errors.Wrap(updateErr, "更新报告数据失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckQueryDataContainsFeature 检查报告数据中是否包含指定的模块
|
||||
func (s *WhitelistService) CheckQueryDataContainsFeature(
|
||||
ctx context.Context,
|
||||
queryId string,
|
||||
featureApiId string,
|
||||
) (bool, error) {
|
||||
queryModel, err := s.getQueryModel(ctx, queryId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if queryModel == nil {
|
||||
return false, nil
|
||||
}
|
||||
mainApiId := s.extractMainApiId(featureApiId)
|
||||
dataArray, _, err := s.decryptQueryData(queryModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, item := range dataArray {
|
||||
apiID, ok := item["apiID"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if s.extractMainApiId(apiID) == mainApiId {
|
||||
dataValue, exists := item["data"]
|
||||
if !exists || dataValue == nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ProcessPaidWhitelistOrder 处理已支付的白名单订单
|
||||
func (s *WhitelistService) ProcessPaidWhitelistOrder(
|
||||
ctx context.Context,
|
||||
session sqlx.Session,
|
||||
order *model.Order,
|
||||
whitelistOrder *model.WhitelistOrder,
|
||||
) error {
|
||||
if whitelistOrder.Status != 2 {
|
||||
return nil
|
||||
}
|
||||
itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
|
||||
Where("order_id = ?", whitelistOrder.Id)
|
||||
items, err := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "查询白名单订单明细失败")
|
||||
}
|
||||
for _, item := range items {
|
||||
wl := &model.UserFeatureWhitelist{
|
||||
Id: uuid.NewString(),
|
||||
IdCard: whitelistOrder.IdCard,
|
||||
FeatureId: item.FeatureId,
|
||||
FeatureApiId: item.FeatureApiId,
|
||||
UserId: whitelistOrder.UserId,
|
||||
OrderId: lzUtils.StringToNullString(""),
|
||||
WhitelistOrderId: lzUtils.StringToNullString(whitelistOrder.Id),
|
||||
Amount: item.Price,
|
||||
Status: 1,
|
||||
}
|
||||
if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
|
||||
return errors.Wrap(err, "创建白名单记录失败")
|
||||
}
|
||||
logx.Infof("白名单订单支付成功:订单 %s,模块 %s,已创建白名单记录", whitelistOrder.OrderNo, item.FeatureApiId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user