下架白名单补充支付回调删除数据以及后台运维补充删除

This commit is contained in:
2026-03-16 14:37:35 +08:00
parent a63e4a9dbb
commit 0b87a39c41
10 changed files with 142 additions and 21 deletions

View File

@@ -28,6 +28,10 @@ service main {
@handler AdminGetQueryCleanupConfigList
get /cleanup/configs (AdminGetQueryCleanupConfigListReq) returns (AdminGetQueryCleanupConfigListResp)
@doc "按 QueryId+FeatureApiId 补删单条查询的某个模块数据(仅内部运维使用)"
@handler AdminDeleteQueryFeatureData
post /cleanup/delete/feature (AdminDeleteQueryFeatureDataReq) returns (AdminDeleteQueryFeatureDataResp)
@doc "更新清理配置"
@handler AdminUpdateQueryCleanupConfig
put /cleanup/config (AdminUpdateQueryCleanupConfigReq) returns (AdminUpdateQueryCleanupConfigResp)
@@ -131,3 +135,14 @@ type AdminGetQueryCleanupConfigListResp {
type AdminUpdateQueryCleanupConfigResp {
Success bool `json:"success"` // 是否成功
}
// 运维补删接口:按 QueryId+FeatureApiId 删除单条查询中的指定模块数据
type AdminDeleteQueryFeatureDataReq {
QueryId string `json:"query_id"` // 查询IDQuery表ID
FeatureApiId string `json:"feature_api_id"` // 模块API标识与前台 OfflineFeature 一致)
}
type AdminDeleteQueryFeatureDataResp {
Success bool `json:"success"` // 是否删除成功(或数据本就不存在)
Message string `json:"message"` // 结果说明
}

View File

@@ -288,7 +288,7 @@ service main {
@handler CheckFeatureWhitelistStatus
get /whitelist/check (CheckFeatureWhitelistStatusReq) returns (CheckFeatureWhitelistStatusResp)
// 下架单个模块(创建订单并支付
// 下架单个模块(统一入口:创建/补充白名单并根据 QueryId 删除本次报告中的模块数据
@handler OfflineFeature
post /whitelist/offline (OfflineFeatureReq) returns (OfflineFeatureResp)

View File

@@ -0,0 +1,29 @@
package admin_query
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"ycc-server/app/main/api/internal/logic/admin_query"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"ycc-server/common/result"
"ycc-server/pkg/lzkit/validator"
)
func AdminDeleteQueryFeatureDataHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AdminDeleteQueryFeatureDataReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := admin_query.NewAdminDeleteQueryFeatureDataLogic(r.Context(), svcCtx)
resp, err := l.AdminDeleteQueryFeatureData(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -490,6 +490,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/cleanup/configs",
Handler: admin_query.AdminGetQueryCleanupConfigListHandler(serverCtx),
},
{
// 按 QueryId+FeatureApiId 补删单条查询的某个模块数据(仅内部运维使用)
Method: http.MethodPost,
Path: "/cleanup/delete/feature",
Handler: admin_query.AdminDeleteQueryFeatureDataHandler(serverCtx),
},
{
// 获取清理详情列表
Method: http.MethodGet,

View File

@@ -0,0 +1,30 @@
package admin_query
import (
"context"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminDeleteQueryFeatureDataLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminDeleteQueryFeatureDataLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteQueryFeatureDataLogic {
return &AdminDeleteQueryFeatureDataLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminDeleteQueryFeatureDataLogic) AdminDeleteQueryFeatureData(req *types.AdminDeleteQueryFeatureDataReq) (resp *types.AdminDeleteQueryFeatureDataResp, err error) {
// todo: add your logic here and delete this line
return
}

View File

@@ -6,6 +6,7 @@ import (
"ycc-server/app/main/model"
"ycc-server/common/ctxdata"
"ycc-server/common/xerr"
"ycc-server/pkg/lzkit/lzUtils"
"github.com/google/uuid"
"github.com/pkg/errors"
@@ -123,6 +124,7 @@ func (l *CreateWhitelistOrderLogic) CreateWhitelistOrder(req *types.CreateWhitel
Id: uuid.NewString(),
OrderNo: orderNo,
UserId: userID,
OrderId: lzUtils.StringToNullString(req.OrderId), // 关联的查询订单ID可选用于后续支付回调精确删除报告
IdCard: req.IdCard,
TotalAmount: totalAmount,
Status: 1, // 待支付

View File

@@ -71,6 +71,8 @@ func (s *WhitelistService) EnsureFreeWhitelist(
}
}
// 约定OrderId 字段在白名单表中用于记录“触发本次白名单的查询记录IDQueryId
// 这里的 orderId 即为 OfflineFeature 请求中传入的 QueryId
wl := &model.UserFeatureWhitelist{
Id: uuid.NewString(),
IdCard: idCard,
@@ -198,6 +200,8 @@ func (s *WhitelistService) ProcessOfflineFeature(
}
// 3. 检查是否已有白名单
// 约定:只要调用 OfflineFeature下架成功包含“之前已存在白名单”的情况都应删除“当前这一次查询”的报告数据
// 因此,对于“已存在生效白名单”的场景,这里依然返回 whitelistCreated = true触发上层 OfflineFeatureLogic 删除本次 QueryId 的模块数据
exists, err := s.CheckWhitelistExists(ctx, idCard, feature.Id)
if err != nil {
return false, 0, false, err
@@ -297,6 +301,8 @@ func (s *WhitelistService) createWhitelistFromPaidOrder(
paidOrderId string,
price float64,
) error {
// 约定OrderId 字段在白名单表中用于记录“触发本次白名单的查询记录IDQueryId
// 这里的 orderId 即为 OfflineFeature 请求中传入的 QueryId
wl := &model.UserFeatureWhitelist{
Id: uuid.NewString(),
IdCard: idCard,
@@ -517,7 +523,7 @@ func (s *WhitelistService) CheckQueryDataContainsFeature(
return false, nil
}
// ProcessPaidWhitelistOrder 处理已支付的白名单订单:创建白名单记录并删除报告数据
// ProcessPaidWhitelistOrder 处理已支付的白名单订单:创建白名单记录,并在可精确定位时删除对应报告数据
// order: 支付订单Order表
// whitelistOrder: 白名单订单WhitelistOrder表
func (s *WhitelistService) ProcessPaidWhitelistOrder(
@@ -539,8 +545,31 @@ func (s *WhitelistService) ProcessPaidWhitelistOrder(
return errors.Wrap(err, "查询白名单订单明细失败")
}
// 为每个明细创建白名单记录并删除报告数据
// 为每个明细创建白名单记录,并在能够精确定位 Query 时删除对应报告数据
for _, item := range items {
var queryId string
// 如果白名单订单绑定了查询订单IDorder_id尝试通过 Query.order_id 精确找到对应的查询记录
if whitelistOrder.OrderId.Valid && whitelistOrder.OrderId.String != "" {
queryModel, qErr := s.QueryModel.FindOneByOrderId(ctx, whitelistOrder.OrderId.String)
if qErr != nil {
if errors.Is(qErr, model.ErrNotFound) {
logx.Infof("白名单订单支付成功:订单 %s 绑定的查询订单 %s 未找到对应查询记录,跳过报告删除", whitelistOrder.OrderNo, whitelistOrder.OrderId.String)
} else {
return errors.Wrap(qErr, "根据白名单订单的查询订单ID查找查询记录失败")
}
} else {
queryId = queryModel.Id
// 精确删除该查询下当前模块的数据
if delErr := s.DeleteFeatureFromQueryData(ctx, session, queryId, item.FeatureApiId); delErr != nil {
// 删除报告数据失败不影响白名单记录创建,只记录错误日志
logx.Errorf("白名单订单支付后删除报告数据失败:查询记录 %s模块 %s错误%v", queryId, item.FeatureApiId, delErr)
} else {
logx.Infof("白名单订单支付后删除报告数据成功:查询记录 %s模块 %s", queryId, item.FeatureApiId)
}
}
}
// 创建白名单记录
wl := &model.UserFeatureWhitelist{
Id: uuid.NewString(),
@@ -548,7 +577,9 @@ func (s *WhitelistService) ProcessPaidWhitelistOrder(
FeatureId: item.FeatureId,
FeatureApiId: item.FeatureApiId,
UserId: whitelistOrder.UserId,
OrderId: lzUtils.StringToNullString(""), // 查询订单ID如果有的话会在后续步骤中设置
// 约定UserFeatureWhitelist.OrderId 记录触发本次白名单的查询记录IDQueryId
// 对于支付回调场景,如果成功通过 order_id 找到 Query则将 QueryId 回写到白名单记录中,便于后续审计
OrderId: lzUtils.StringToNullString(queryId),
WhitelistOrderId: lzUtils.StringToNullString(whitelistOrder.Id),
Amount: item.Price,
Status: 1, // 生效
@@ -556,13 +587,10 @@ func (s *WhitelistService) ProcessPaidWhitelistOrder(
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)
// 如果无法通过 order_id 找到 Query仅创建白名单记录不删除任何报告数据避免误删历史记录
if !whitelistOrder.OrderId.Valid || whitelistOrder.OrderId.String == "" || queryId == "" {
logx.Infof("白名单订单支付成功:订单 %s模块 %s已创建白名单记录。由于缺少可用的查询订单ID或对应查询记录未删除任何报告数据", whitelistOrder.OrderNo, item.FeatureApiId)
}
}
return nil

View File

@@ -212,6 +212,16 @@ type AdminDeleteProductResp struct {
Success bool `json:"success"` // 是否成功
}
type AdminDeleteQueryFeatureDataReq struct {
QueryId string `json:"query_id"` // 查询IDQuery表ID
FeatureApiId string `json:"feature_api_id"` // 模块API标识与前台 OfflineFeature 一致)
}
type AdminDeleteQueryFeatureDataResp struct {
Success bool `json:"success"` // 是否删除成功(或数据本就不存在)
Message string `json:"message"` // 结果说明
}
type AdminDeleteUserReq struct {
Id string `path:"id"` // 用户ID
}
@@ -2040,8 +2050,8 @@ type ProductListItem struct {
ProductEn string `json:"product_en"` // 英文名
Description string `json:"description"` // 描述
Notes string `json:"notes"` // 备注
CostPrice float64 `json:"cost_price"` // 成本价(由功能成本累加得出)
SellPrice float64 `json:"sell_price"` // 售价
CostPrice float64 `json:"cost_price"` // 成本价(由功能成本累加得出)
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
}

View File

@@ -66,6 +66,7 @@ type (
Version int64 `db:"version"` // 版本号(乐观锁)
OrderNo string `db:"order_no"` // 订单号(唯一)
UserId string `db:"user_id"` // 用户ID代理的user_id
OrderId sql.NullString `db:"order_id"` // 关联的查询订单IDQuery 表对应的订单ID一般为 order.id
IdCard string `db:"id_card"` // 身份证号(查询对象标识)
TotalAmount float64 `db:"total_amount"` // 总金额(单位:元)
Status int64 `db:"status"` // 订单状态1=待支付2=已支付3=已取消
@@ -89,11 +90,11 @@ func (m *defaultWhitelistOrderModel) Insert(ctx context.Context, session sqlx.Se
yccWhitelistOrderIdKey := fmt.Sprintf("%s%v", cacheYccWhitelistOrderIdPrefix, data.Id)
yccWhitelistOrderOrderNoKey := fmt.Sprintf("%s%v", cacheYccWhitelistOrderOrderNoPrefix, data.OrderNo)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, whitelistOrderRowsExpectAutoSet)
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, whitelistOrderRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.OrderNo, data.UserId, data.IdCard, data.TotalAmount, data.Status, data.PaymentMethod, data.PaymentPlatform, data.PlatformOrderId, data.PayTime)
return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.OrderNo, data.UserId, data.OrderId, data.IdCard, data.TotalAmount, data.Status, data.PaymentMethod, data.PaymentPlatform, data.PlatformOrderId, data.PayTime)
}
return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.OrderNo, data.UserId, data.IdCard, data.TotalAmount, data.Status, data.PaymentMethod, data.PaymentPlatform, data.PlatformOrderId, data.PayTime)
return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.OrderNo, data.UserId, data.OrderId, data.IdCard, data.TotalAmount, data.Status, data.PaymentMethod, data.PaymentPlatform, data.PlatformOrderId, data.PayTime)
}, yccWhitelistOrderIdKey, yccWhitelistOrderOrderNoKey)
}
func (m *defaultWhitelistOrderModel) insertUUID(data *WhitelistOrder) {
@@ -160,9 +161,9 @@ func (m *defaultWhitelistOrderModel) Update(ctx context.Context, session sqlx.Se
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, whitelistOrderRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id)
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.OrderId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id)
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.OrderId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id)
}, yccWhitelistOrderIdKey, yccWhitelistOrderOrderNoKey)
}
@@ -183,9 +184,9 @@ func (m *defaultWhitelistOrderModel) UpdateWithVersion(ctx context.Context, sess
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, whitelistOrderRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id, oldVersion)
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.OrderId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id, oldVersion)
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.OrderNo, newData.UserId, newData.OrderId, newData.IdCard, newData.TotalAmount, newData.Status, newData.PaymentMethod, newData.PaymentPlatform, newData.PlatformOrderId, newData.PayTime, newData.Id, oldVersion)
}, yccWhitelistOrderIdKey, yccWhitelistOrderOrderNoKey)
if err != nil {
return err

View File

@@ -58,11 +58,11 @@ $tables = @(
# "query_cleanup_log",
# "user",
# "user_auth"
# "whitelist_order",
"whitelist_order"
# "whitelist_order_item",
# "user_feature_whitelist"
# "complaint_main",
"complaint_alipay"
# "complaint_alipay"
# "complaint_alipay_trade",
# "complaint_manual"
# "tianyuanapi_call_log"