2026-01-12 16:43:08 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"database/sql"
|
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
|
|
"ycc-server/app/main/api/internal/config"
|
|
|
|
|
|
"ycc-server/app/main/model"
|
2026-02-01 19:37:40 +08:00
|
|
|
|
"ycc-server/common/xerr"
|
2026-01-12 16:43:08 +08:00
|
|
|
|
"ycc-server/pkg/lzkit/crypto"
|
|
|
|
|
|
"ycc-server/pkg/lzkit/lzUtils"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
|
|
|
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 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)
|
2026-01-13 18:30:10 +08:00
|
|
|
|
if s == nil {
|
|
|
|
|
|
return result, nil
|
|
|
|
|
|
}
|
2026-01-12 16:43:08 +08:00
|
|
|
|
if 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 统一下架处理:处理免费下架或检查付费下架
|
|
|
|
|
|
// 返回:needPay(是否需要支付), amount(金额), whitelistCreated(是否已创建白名单)
|
|
|
|
|
|
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) {
|
|
|
|
|
|
// 1. 提取主模块ID并查询feature信息
|
|
|
|
|
|
mainApiId := s.extractMainApiId(featureApiId)
|
|
|
|
|
|
feature, err := s.getFeatureByApiId(ctx, mainApiId)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, 0, false, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 19:37:40 +08:00
|
|
|
|
// 2. 不支持下架的模块:whitelist_price < 0 表示该模块不开放下架功能
|
|
|
|
|
|
if feature.WhitelistPrice < 0 {
|
|
|
|
|
|
return false, 0, false, errors.Wrapf(xerr.NewErrMsg("该模块不支持下架"), "")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 检查是否已有白名单
|
2026-01-12 16:43:08 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
2026-02-01 19:37:40 +08:00
|
|
|
|
// 4. 免费下架:直接创建白名单记录(whitelist_price = 0)
|
2026-01-12 16:43:08 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 19:37:40 +08:00
|
|
|
|
// 5. 付费下架:检查是否已有支付成功的订单
|
2026-01-12 16:43:08 +08:00
|
|
|
|
paidOrderId, err := s.findPaidWhitelistOrder(ctx, userId, idCard, feature.Id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, 0, false, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 19:37:40 +08:00
|
|
|
|
// 6. 如果已有支付成功订单,补创建白名单记录
|
2026-01-12 16:43:08 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 19:37:40 +08:00
|
|
|
|
// 7. 需要支付
|
2026-01-12 16:43:08 +08:00
|
|
|
|
return true, price, false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// extractMainApiId 提取主模块ID(去掉下划线后的部分)
|
|
|
|
|
|
func (s *WhitelistService) extractMainApiId(featureApiId string) string {
|
|
|
|
|
|
if idx := strings.Index(featureApiId, "_"); idx > 0 {
|
|
|
|
|
|
return featureApiId[:idx]
|
|
|
|
|
|
}
|
|
|
|
|
|
return featureApiId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getFeatureByApiId 根据API ID查询feature信息
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// findPaidWhitelistOrder 查找已支付的白名单订单中是否包含指定feature
|
|
|
|
|
|
// 返回:paidOrderId(如果找到已支付订单),error
|
|
|
|
|
|
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) // 2表示已支付
|
|
|
|
|
|
orders, err := s.WhitelistOrderModel.FindAll(ctx, orderBuilder, "")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", errors.Wrap(err, "查询白名单订单失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查找已支付订单中是否包含该feature
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// createWhitelistFromPaidOrder 根据已支付订单创建白名单记录
|
|
|
|
|
|
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 从报告数据中删除指定模块的数据
|
|
|
|
|
|
// queryId: 查询记录ID(Query表的ID)
|
|
|
|
|
|
// featureApiId: 要删除的模块API标识
|
|
|
|
|
|
func (s *WhitelistService) DeleteFeatureFromQueryData(
|
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
|
session sqlx.Session,
|
|
|
|
|
|
queryId string,
|
|
|
|
|
|
featureApiId string,
|
|
|
|
|
|
) error {
|
|
|
|
|
|
// 1. 获取查询记录
|
|
|
|
|
|
queryModel, err := s.getQueryModel(ctx, queryId)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
if queryModel == nil {
|
|
|
|
|
|
// 报告不存在或数据为空,直接返回成功
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 解密并解析报告数据
|
|
|
|
|
|
mainApiId := s.extractMainApiId(featureApiId)
|
|
|
|
|
|
dataArray, key, err := s.decryptQueryData(queryModel)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 清空对应模块的数据(将 data 字段设置为 null)
|
|
|
|
|
|
modifiedArray, hasModified := s.clearFeatureData(dataArray, mainApiId)
|
|
|
|
|
|
if !hasModified {
|
|
|
|
|
|
logx.Infof("删除报告数据:查询记录 %s 中未找到模块 %s 的数据,跳过删除", queryId, featureApiId)
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 重新加密并更新数据库
|
|
|
|
|
|
if err := s.updateQueryData(ctx, session, queryModel, modifiedArray, key); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
logx.Infof("删除报告数据成功:查询记录 %s,模块 %s,已将对应模块的 data 字段设置为 null", queryId, featureApiId)
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getQueryModel 获取查询记录,如果不存在或数据为空则返回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) {
|
|
|
|
|
|
logx.Infof("删除报告数据:查询记录 %s 不存在,跳过删除", queryId)
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil, errors.Wrap(err, "查询报告记录失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果报告数据为空,直接返回
|
|
|
|
|
|
if !queryModel.QueryData.Valid || queryModel.QueryData.String == "" {
|
|
|
|
|
|
logx.Infof("删除报告数据:查询记录 %s 对应的报告数据为空,跳过删除", queryId)
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return queryModel, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// decryptQueryData 解密并解析报告数据
|
|
|
|
|
|
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, "解密报告数据失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析JSON数组
|
|
|
|
|
|
var dataArray []map[string]interface{}
|
|
|
|
|
|
unmarshalErr := json.Unmarshal(decryptedData, &dataArray)
|
|
|
|
|
|
if unmarshalErr != nil {
|
|
|
|
|
|
return nil, nil, errors.Wrap(unmarshalErr, "解析报告数据失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dataArray, key, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// clearFeatureData 清空指定模块的数据(将 data 字段设置为 null)
|
|
|
|
|
|
// 返回修改后的数组和是否进行了修改
|
|
|
|
|
|
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 {
|
|
|
|
|
|
// 深拷贝 item,避免修改原数据
|
|
|
|
|
|
newItem := make(map[string]interface{})
|
|
|
|
|
|
for k, v := range item {
|
|
|
|
|
|
newItem[k] = v
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
apiID, ok := item["apiID"].(string)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
// 如果apiID不存在或类型不对,保留原样
|
|
|
|
|
|
modifiedArray = append(modifiedArray, newItem)
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提取主模块ID进行比较
|
|
|
|
|
|
itemMainApiId := s.extractMainApiId(apiID)
|
|
|
|
|
|
|
|
|
|
|
|
// 如果主模块ID匹配,将 data 字段设置为 null
|
|
|
|
|
|
if itemMainApiId == mainApiId {
|
|
|
|
|
|
newItem["data"] = nil
|
|
|
|
|
|
hasModified = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
modifiedArray = append(modifiedArray, newItem)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return modifiedArray, hasModified
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// updateQueryData 重新加密并更新数据库
|
|
|
|
|
|
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,
|
|
|
|
|
|
}
|
|
|
|
|
|
updateErr := s.QueryModel.UpdateWithVersion(ctx, session, queryModel)
|
|
|
|
|
|
if updateErr != nil {
|
|
|
|
|
|
return errors.Wrap(updateErr, "更新报告数据失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckQueryDataContainsFeature 检查报告数据中是否包含指定的模块
|
|
|
|
|
|
// 返回 true 表示包含该模块,false 表示不包含(已删除)
|
|
|
|
|
|
func (s *WhitelistService) CheckQueryDataContainsFeature(
|
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
|
queryId string,
|
|
|
|
|
|
featureApiId string,
|
|
|
|
|
|
) (bool, error) {
|
|
|
|
|
|
// 1. 获取查询记录
|
|
|
|
|
|
queryModel, err := s.getQueryModel(ctx, queryId)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, err
|
|
|
|
|
|
}
|
|
|
|
|
|
if queryModel == nil {
|
|
|
|
|
|
// 报告不存在,认为数据已删除
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 解密并解析报告数据
|
|
|
|
|
|
mainApiId := s.extractMainApiId(featureApiId)
|
|
|
|
|
|
dataArray, _, err := s.decryptQueryData(queryModel)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 检查数据中是否包含该模块(且 data 不为 null)
|
|
|
|
|
|
for _, item := range dataArray {
|
|
|
|
|
|
apiID, ok := item["apiID"].(string)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
// 提取主模块ID进行比较
|
|
|
|
|
|
itemMainApiId := s.extractMainApiId(apiID)
|
|
|
|
|
|
if itemMainApiId == mainApiId {
|
|
|
|
|
|
// 找到了该模块,检查 data 字段
|
|
|
|
|
|
dataValue, exists := item["data"]
|
|
|
|
|
|
if !exists || dataValue == nil {
|
|
|
|
|
|
// data 字段不存在或为 null,认为数据已删除
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
// data 字段存在且不为 null,认为数据存在
|
|
|
|
|
|
return true, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 未找到该模块的数据,说明已删除
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProcessPaidWhitelistOrder 处理已支付的白名单订单:创建白名单记录并删除报告数据
|
|
|
|
|
|
// order: 支付订单(Order表)
|
|
|
|
|
|
// whitelistOrder: 白名单订单(WhitelistOrder表)
|
|
|
|
|
|
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(""), // 查询订单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, "创建白名单记录失败")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试删除报告数据
|
|
|
|
|
|
// 注意:由于支付回调时可能不知道具体的查询订单ID,这里先尝试根据 id_card 查找
|
|
|
|
|
|
// 如果找不到对应的报告,就跳过删除步骤(不影响主流程)
|
|
|
|
|
|
// 实际的报告数据删除应该在 OfflineFeature 接口中完成(如果提供了 orderId)
|
|
|
|
|
|
// 这里暂时不删除,因为无法确定是哪个具体的查询订单
|
|
|
|
|
|
logx.Infof("白名单订单支付成功:订单 %s,模块 %s,已创建白名单记录。如需删除报告数据,请在 OfflineFeature 接口中提供查询订单ID", whitelistOrder.OrderNo, item.FeatureApiId)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|