addf
This commit is contained in:
@@ -1,103 +0,0 @@
|
|||||||
syntax = "v1"
|
|
||||||
|
|
||||||
info (
|
|
||||||
title: "后台白名单管理服务"
|
|
||||||
desc: "后台用户模块白名单管理相关接口"
|
|
||||||
version: "v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
@server (
|
|
||||||
prefix: /api/v1/admin/whitelist
|
|
||||||
group: admin_whitelist
|
|
||||||
middleware: AdminAuthInterceptor
|
|
||||||
)
|
|
||||||
service main {
|
|
||||||
// 获取白名单列表
|
|
||||||
@handler AdminGetWhitelistList
|
|
||||||
get /list (AdminGetWhitelistListReq) returns (AdminGetWhitelistListResp)
|
|
||||||
|
|
||||||
// 手动添加白名单
|
|
||||||
@handler AdminCreateWhitelist
|
|
||||||
post /create (AdminCreateWhitelistReq) returns (AdminCreateWhitelistResp)
|
|
||||||
|
|
||||||
// 批量添加白名单
|
|
||||||
@handler AdminBatchCreateWhitelist
|
|
||||||
post /batch-create (AdminBatchCreateWhitelistReq) returns (AdminBatchCreateWhitelistResp)
|
|
||||||
|
|
||||||
// 更新白名单(状态/备注金额)
|
|
||||||
@handler AdminUpdateWhitelist
|
|
||||||
put /update/:id (AdminUpdateWhitelistReq) returns (AdminUpdateWhitelistResp)
|
|
||||||
|
|
||||||
// 删除白名单(软删除)
|
|
||||||
@handler AdminDeleteWhitelist
|
|
||||||
delete /delete/:id (AdminDeleteWhitelistReq) returns (AdminDeleteWhitelistResp)
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
AdminGetWhitelistListReq {
|
|
||||||
Page int64 `form:"page"`
|
|
||||||
PageSize int64 `form:"pageSize"`
|
|
||||||
IdCard *string `form:"id_card,optional"`
|
|
||||||
FeatureApiId *string `form:"feature_api_id,optional"`
|
|
||||||
Status *int64 `form:"status,optional"`
|
|
||||||
}
|
|
||||||
AdminWhitelistListItem {
|
|
||||||
Id string `json:"id"`
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
FeatureApiId string `json:"feature_api_id"`
|
|
||||||
FeatureName string `json:"feature_name"`
|
|
||||||
UserId string `json:"user_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Status int64 `json:"status"`
|
|
||||||
StatusText string `json:"status_text"`
|
|
||||||
CreateTime string `json:"create_time"`
|
|
||||||
UpdateTime string `json:"update_time"`
|
|
||||||
}
|
|
||||||
AdminGetWhitelistListResp {
|
|
||||||
Total int64 `json:"total"`
|
|
||||||
Items []AdminWhitelistListItem `json:"items"`
|
|
||||||
}
|
|
||||||
AdminCreateWhitelistReq {
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
}
|
|
||||||
AdminCreateWhitelistResp {
|
|
||||||
Id string `json:"id"`
|
|
||||||
}
|
|
||||||
AdminBatchCreateWhitelistReq {
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureIds []string `json:"feature_ids"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
}
|
|
||||||
AdminBatchCreateWhitelistResultItem {
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
FeatureApiId string `json:"feature_api_id"`
|
|
||||||
FeatureName string `json:"feature_name"`
|
|
||||||
Action string `json:"action"`
|
|
||||||
Message string `json:"message,optional"`
|
|
||||||
}
|
|
||||||
AdminBatchCreateWhitelistResp {
|
|
||||||
SuccessCount int64 `json:"success_count"`
|
|
||||||
SkipCount int64 `json:"skip_count"`
|
|
||||||
FailCount int64 `json:"fail_count"`
|
|
||||||
Items []AdminBatchCreateWhitelistResultItem `json:"items"`
|
|
||||||
}
|
|
||||||
AdminUpdateWhitelistReq {
|
|
||||||
Id string `path:"id"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
}
|
|
||||||
AdminUpdateWhitelistResp {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
AdminDeleteWhitelistReq {
|
|
||||||
Id string `path:"id"`
|
|
||||||
}
|
|
||||||
AdminDeleteWhitelistResp {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -24,7 +24,6 @@ import "./admin/platform_user.api"
|
|||||||
import "./admin/notification.api"
|
import "./admin/notification.api"
|
||||||
import "./admin/admin_product.api"
|
import "./admin/admin_product.api"
|
||||||
import "./admin/admin_feature.api"
|
import "./admin/admin_feature.api"
|
||||||
import "./admin/admin_whitelist.api"
|
|
||||||
import "./admin/admin_query_whitelist.api"
|
import "./admin/admin_query_whitelist.api"
|
||||||
import "./admin/admin_query.api"
|
import "./admin/admin_query.api"
|
||||||
import "./admin/admin_agent.api"
|
import "./admin/admin_agent.api"
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
"ycc-server/app/main/api/internal/logic/admin_whitelist"
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/common/result"
|
|
||||||
"ycc-server/pkg/lzkit/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdminBatchCreateWhitelistHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.AdminBatchCreateWhitelistReq
|
|
||||||
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_whitelist.NewAdminBatchCreateWhitelistLogic(r.Context(), svcCtx)
|
|
||||||
resp, err := l.AdminBatchCreateWhitelist(&req)
|
|
||||||
result.HttpResult(r, w, resp, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
"ycc-server/app/main/api/internal/logic/admin_whitelist"
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/common/result"
|
|
||||||
"ycc-server/pkg/lzkit/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdminCreateWhitelistHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.AdminCreateWhitelistReq
|
|
||||||
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_whitelist.NewAdminCreateWhitelistLogic(r.Context(), svcCtx)
|
|
||||||
resp, err := l.AdminCreateWhitelist(&req)
|
|
||||||
result.HttpResult(r, w, resp, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
"ycc-server/app/main/api/internal/logic/admin_whitelist"
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/common/result"
|
|
||||||
"ycc-server/pkg/lzkit/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdminDeleteWhitelistHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.AdminDeleteWhitelistReq
|
|
||||||
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_whitelist.NewAdminDeleteWhitelistLogic(r.Context(), svcCtx)
|
|
||||||
resp, err := l.AdminDeleteWhitelist(&req)
|
|
||||||
result.HttpResult(r, w, resp, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
"ycc-server/app/main/api/internal/logic/admin_whitelist"
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/common/result"
|
|
||||||
"ycc-server/pkg/lzkit/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdminGetWhitelistListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.AdminGetWhitelistListReq
|
|
||||||
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_whitelist.NewAdminGetWhitelistListLogic(r.Context(), svcCtx)
|
|
||||||
resp, err := l.AdminGetWhitelistList(&req)
|
|
||||||
result.HttpResult(r, w, resp, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
"ycc-server/app/main/api/internal/logic/admin_whitelist"
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/common/result"
|
|
||||||
"ycc-server/pkg/lzkit/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdminUpdateWhitelistHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.AdminUpdateWhitelistReq
|
|
||||||
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_whitelist.NewAdminUpdateWhitelistLogic(r.Context(), svcCtx)
|
|
||||||
resp, err := l.AdminUpdateWhitelist(&req)
|
|
||||||
result.HttpResult(r, w, resp, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
admin_role "ycc-server/app/main/api/internal/handler/admin_role"
|
admin_role "ycc-server/app/main/api/internal/handler/admin_role"
|
||||||
admin_role_api "ycc-server/app/main/api/internal/handler/admin_role_api"
|
admin_role_api "ycc-server/app/main/api/internal/handler/admin_role_api"
|
||||||
admin_user "ycc-server/app/main/api/internal/handler/admin_user"
|
admin_user "ycc-server/app/main/api/internal/handler/admin_user"
|
||||||
admin_whitelist "ycc-server/app/main/api/internal/handler/admin_whitelist"
|
|
||||||
agent "ycc-server/app/main/api/internal/handler/agent"
|
agent "ycc-server/app/main/api/internal/handler/agent"
|
||||||
app "ycc-server/app/main/api/internal/handler/app"
|
app "ycc-server/app/main/api/internal/handler/app"
|
||||||
auth "ycc-server/app/main/api/internal/handler/auth"
|
auth "ycc-server/app/main/api/internal/handler/auth"
|
||||||
@@ -655,40 +654,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
rest.WithPrefix("/api/v1/admin/user"),
|
rest.WithPrefix("/api/v1/admin/user"),
|
||||||
)
|
)
|
||||||
|
|
||||||
server.AddRoutes(
|
|
||||||
rest.WithMiddlewares(
|
|
||||||
[]rest.Middleware{serverCtx.AdminAuthInterceptor},
|
|
||||||
[]rest.Route{
|
|
||||||
{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
Path: "/batch-create",
|
|
||||||
Handler: admin_whitelist.AdminBatchCreateWhitelistHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
Path: "/create",
|
|
||||||
Handler: admin_whitelist.AdminCreateWhitelistHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Method: http.MethodDelete,
|
|
||||||
Path: "/delete/:id",
|
|
||||||
Handler: admin_whitelist.AdminDeleteWhitelistHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Method: http.MethodGet,
|
|
||||||
Path: "/list",
|
|
||||||
Handler: admin_whitelist.AdminGetWhitelistListHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Method: http.MethodPut,
|
|
||||||
Path: "/update/:id",
|
|
||||||
Handler: admin_whitelist.AdminUpdateWhitelistHandler(serverCtx),
|
|
||||||
},
|
|
||||||
}...,
|
|
||||||
),
|
|
||||||
rest.WithPrefix("/api/v1/admin/whitelist"),
|
|
||||||
)
|
|
||||||
|
|
||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
rest.WithMiddlewares(
|
rest.WithMiddlewares(
|
||||||
[]rest.Middleware{serverCtx.AdminAuthInterceptor},
|
[]rest.Middleware{serverCtx.AdminAuthInterceptor},
|
||||||
|
|||||||
@@ -2,10 +2,17 @@ package admin_query
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
"ycc-server/app/main/api/internal/svc"
|
||||||
"ycc-server/app/main/api/internal/types"
|
"ycc-server/app/main/api/internal/types"
|
||||||
|
"ycc-server/app/main/model"
|
||||||
|
"ycc-server/common/ctxdata"
|
||||||
"ycc-server/common/xerr"
|
"ycc-server/common/xerr"
|
||||||
|
"ycc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
@@ -27,7 +34,6 @@ func NewAdminDeleteQueryFeatureDataLogic(ctx context.Context, svcCtx *svc.Servic
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *AdminDeleteQueryFeatureDataLogic) AdminDeleteQueryFeatureData(req *types.AdminDeleteQueryFeatureDataReq) (resp *types.AdminDeleteQueryFeatureDataResp, err error) {
|
func (l *AdminDeleteQueryFeatureDataLogic) AdminDeleteQueryFeatureData(req *types.AdminDeleteQueryFeatureDataReq) (resp *types.AdminDeleteQueryFeatureDataResp, err error) {
|
||||||
// 基本参数校验
|
|
||||||
if req.QueryId == "" {
|
if req.QueryId == "" {
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("QueryId 不能为空"), "")
|
return nil, errors.Wrapf(xerr.NewErrMsg("QueryId 不能为空"), "")
|
||||||
}
|
}
|
||||||
@@ -35,8 +41,56 @@ func (l *AdminDeleteQueryFeatureDataLogic) AdminDeleteQueryFeatureData(req *type
|
|||||||
return nil, errors.Wrapf(xerr.NewErrMsg("feature_api_id 不能为空"), "")
|
return nil, errors.Wrapf(xerr.NewErrMsg("feature_api_id 不能为空"), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用事务调用 WhitelistService.DeleteFeatureFromQueryData,保持与其它删除逻辑一致
|
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, req.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, err := decryptQueryParams(l.svcCtx, queryModel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取查询参数失败, %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
idCard, _ := queryParams["id_card"].(string)
|
||||||
|
if idCard == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("查询参数中缺少身份证号,无法添加白名单"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
name, _ := queryParams["name"].(string)
|
||||||
|
if strings.TrimSpace(name) == "" {
|
||||||
|
name = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
adminUserID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取管理员信息失败, %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
remark := fmt.Sprintf("后台删除报告模块自动同步 query_id=%s feature=%s", req.QueryId, feature.ApiId)
|
||||||
|
l.svcCtx.QueryWhitelistSyncService.TrySync(
|
||||||
|
l.ctx,
|
||||||
|
name,
|
||||||
|
idCard,
|
||||||
|
[]string{feature.ApiId},
|
||||||
|
remark,
|
||||||
|
)
|
||||||
|
|
||||||
err = l.svcCtx.QueryModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
err = l.svcCtx.QueryModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||||
|
if wlErr := l.svcCtx.WhitelistService.EnsureFreeWhitelist(ctx, session, idCard, feature, adminUserID, req.QueryId); wlErr != nil {
|
||||||
|
return wlErr
|
||||||
|
}
|
||||||
return l.svcCtx.WhitelistService.DeleteFeatureFromQueryData(ctx, session, req.QueryId, req.FeatureApiId)
|
return l.svcCtx.WhitelistService.DeleteFeatureFromQueryData(ctx, session, req.QueryId, req.FeatureApiId)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,6 +100,37 @@ func (l *AdminDeleteQueryFeatureDataLogic) AdminDeleteQueryFeatureData(req *type
|
|||||||
|
|
||||||
return &types.AdminDeleteQueryFeatureDataResp{
|
return &types.AdminDeleteQueryFeatureDataResp{
|
||||||
Success: true,
|
Success: true,
|
||||||
Message: "删除成功(如果原本不存在该模块数据,则视为已删除)",
|
Message: "删除成功,已同步本地白名单并尽力同步天远查询白名单(若原本不存在该模块数据,则视为已删除)",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractMainApiId(featureApiId string) string {
|
||||||
|
if idx := strings.Index(featureApiId, "_"); idx > 0 {
|
||||||
|
return featureApiId[:idx]
|
||||||
|
}
|
||||||
|
return featureApiId
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptQueryParams(svcCtx *svc.ServiceContext, queryModel *model.Query) (map[string]interface{}, error) {
|
||||||
|
if queryModel.QueryParams == "" {
|
||||||
|
return nil, errors.New("查询参数为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
secretKey := svcCtx.Config.Encrypt.SecretKey
|
||||||
|
key, decodeErr := hex.DecodeString(secretKey)
|
||||||
|
if decodeErr != nil {
|
||||||
|
return nil, errors.Wrap(decodeErr, "获取AES密钥失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptedParams, decryptErr := crypto.AesDecrypt(queryModel.QueryParams, key)
|
||||||
|
if decryptErr != nil {
|
||||||
|
return nil, errors.Wrap(decryptErr, "解密查询参数失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
var params map[string]interface{}
|
||||||
|
if unmarshalErr := json.Unmarshal(decryptedParams, ¶ms); unmarshalErr != nil {
|
||||||
|
return nil, errors.Wrap(unmarshalErr, "解析查询参数失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,6 +53,17 @@ func buildQueryWhitelistPayload(name, idCard string, apiCodes []string, remark s
|
|||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SyncQueryWhitelistToTianyuan 将产品编码同步到天远查询白名单(先追加,规则不存在则创建)
|
||||||
|
func SyncQueryWhitelistToTianyuan(
|
||||||
|
ctx context.Context,
|
||||||
|
svcCtx *svc.ServiceContext,
|
||||||
|
name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
) error {
|
||||||
|
return svcCtx.QueryWhitelistSyncService.Sync(ctx, name, idCard, apiCodes, remark)
|
||||||
|
}
|
||||||
|
|
||||||
func callQueryWhitelistMgmt(
|
func callQueryWhitelistMgmt(
|
||||||
svcCtx *svc.ServiceContext,
|
svcCtx *svc.ServiceContext,
|
||||||
apiPath string,
|
apiPath string,
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/ctxdata"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdminBatchCreateWhitelistLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdminBatchCreateWhitelistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminBatchCreateWhitelistLogic {
|
|
||||||
return &AdminBatchCreateWhitelistLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminBatchCreateWhitelistLogic) AdminBatchCreateWhitelist(req *types.AdminBatchCreateWhitelistReq) (resp *types.AdminBatchCreateWhitelistResp, err error) {
|
|
||||||
if req.IdCard == "" {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("身份证号不能为空"), "")
|
|
||||||
}
|
|
||||||
if len(req.FeatureIds) == 0 {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("请至少选择一个模块"), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取管理员信息失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
amount := 0.0
|
|
||||||
if req.Amount != nil {
|
|
||||||
amount = *req.Amount
|
|
||||||
}
|
|
||||||
status, err := parseWhitelistStatus(req.Status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp = &types.AdminBatchCreateWhitelistResp{
|
|
||||||
Items: make([]types.AdminBatchCreateWhitelistResultItem, 0, len(req.FeatureIds)),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, featureId := range req.FeatureIds {
|
|
||||||
item := types.AdminBatchCreateWhitelistResultItem{
|
|
||||||
FeatureId: featureId,
|
|
||||||
}
|
|
||||||
|
|
||||||
feature, findErr := l.svcCtx.FeatureModel.FindOne(l.ctx, featureId)
|
|
||||||
if findErr != nil {
|
|
||||||
if errors.Is(findErr, model.ErrNotFound) {
|
|
||||||
item.Action = "failed"
|
|
||||||
item.Message = "模块不存在"
|
|
||||||
resp.FailCount++
|
|
||||||
} else {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询模块失败, %v", findErr)
|
|
||||||
}
|
|
||||||
resp.Items = append(resp.Items, item)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result, createErr := createOrReactivateWhitelist(l.ctx, l.svcCtx, userID, req.IdCard, feature, amount, status)
|
|
||||||
if createErr != nil {
|
|
||||||
item.FeatureApiId = feature.ApiId
|
|
||||||
item.FeatureName = feature.Name
|
|
||||||
item.Action = "failed"
|
|
||||||
item.Message = createErr.Error()
|
|
||||||
resp.FailCount++
|
|
||||||
resp.Items = append(resp.Items, item)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
item.FeatureApiId = result.FeatureApiId
|
|
||||||
item.FeatureName = result.FeatureName
|
|
||||||
item.Action = result.Action
|
|
||||||
item.Message = result.Message
|
|
||||||
switch result.Action {
|
|
||||||
case whitelistActionSkipped:
|
|
||||||
resp.SkipCount++
|
|
||||||
case whitelistActionCreated, whitelistActionReactivated:
|
|
||||||
resp.SuccessCount++
|
|
||||||
}
|
|
||||||
resp.Items = append(resp.Items, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/ctxdata"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdminCreateWhitelistLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdminCreateWhitelistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateWhitelistLogic {
|
|
||||||
return &AdminCreateWhitelistLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminCreateWhitelistLogic) AdminCreateWhitelist(req *types.AdminCreateWhitelistReq) (resp *types.AdminCreateWhitelistResp, err error) {
|
|
||||||
if req.IdCard == "" {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("身份证号不能为空"), "")
|
|
||||||
}
|
|
||||||
if req.FeatureId == "" {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("模块不能为空"), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取管理员信息失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
feature, err := l.svcCtx.FeatureModel.FindOne(l.ctx, req.FeatureId)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
amount := 0.0
|
|
||||||
if req.Amount != nil {
|
|
||||||
amount = *req.Amount
|
|
||||||
}
|
|
||||||
status, err := parseWhitelistStatus(req.Status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := createOrReactivateWhitelist(l.ctx, l.svcCtx, userID, req.IdCard, feature, amount, status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result.Action == whitelistActionSkipped {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("该身份证号已存在生效的白名单记录"), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.AdminCreateWhitelistResp{Id: result.Id}, nil
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdminDeleteWhitelistLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdminDeleteWhitelistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteWhitelistLogic {
|
|
||||||
return &AdminDeleteWhitelistLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminDeleteWhitelistLogic) AdminDeleteWhitelist(req *types.AdminDeleteWhitelistReq) (resp *types.AdminDeleteWhitelistResp, err error) {
|
|
||||||
record, err := l.svcCtx.UserFeatureWhitelistModel.FindOne(l.ctx, req.Id)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = l.svcCtx.UserFeatureWhitelistModel.DeleteSoft(l.ctx, nil, record); err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除白名单记录失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.AdminDeleteWhitelistResp{Success: true}, nil
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdminGetWhitelistListLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdminGetWhitelistListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetWhitelistListLogic {
|
|
||||||
return &AdminGetWhitelistListLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminGetWhitelistListLogic) AdminGetWhitelistList(req *types.AdminGetWhitelistListReq) (resp *types.AdminGetWhitelistListResp, err error) {
|
|
||||||
builder := l.svcCtx.UserFeatureWhitelistModel.SelectBuilder()
|
|
||||||
|
|
||||||
if req.IdCard != nil && *req.IdCard != "" {
|
|
||||||
builder = builder.Where("id_card LIKE ?", "%"+*req.IdCard+"%")
|
|
||||||
}
|
|
||||||
if req.FeatureApiId != nil && *req.FeatureApiId != "" {
|
|
||||||
builder = builder.Where("feature_api_id LIKE ?", "%"+*req.FeatureApiId+"%")
|
|
||||||
}
|
|
||||||
if req.Status != nil {
|
|
||||||
builder = builder.Where("status = ?", *req.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
total, err := l.svcCtx.UserFeatureWhitelistModel.FindCount(l.ctx, builder, "id")
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询白名单总数失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
list, err := l.svcCtx.UserFeatureWhitelistModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询白名单列表失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
featureNameMap := l.buildFeatureNameMap(list)
|
|
||||||
|
|
||||||
items := make([]types.AdminWhitelistListItem, 0, len(list))
|
|
||||||
for _, w := range list {
|
|
||||||
items = append(items, types.AdminWhitelistListItem{
|
|
||||||
Id: w.Id,
|
|
||||||
IdCard: w.IdCard,
|
|
||||||
FeatureId: w.FeatureId,
|
|
||||||
FeatureApiId: w.FeatureApiId,
|
|
||||||
FeatureName: featureNameMap[w.FeatureId],
|
|
||||||
UserId: w.UserId,
|
|
||||||
Amount: w.Amount,
|
|
||||||
Status: w.Status,
|
|
||||||
StatusText: whitelistStatusText(w.Status),
|
|
||||||
CreateTime: w.CreateTime.Format("2006-01-02 15:04:05"),
|
|
||||||
UpdateTime: w.UpdateTime.Format("2006-01-02 15:04:05"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.AdminGetWhitelistListResp{
|
|
||||||
Total: total,
|
|
||||||
Items: items,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminGetWhitelistListLogic) buildFeatureNameMap(list []*model.UserFeatureWhitelist) map[string]string {
|
|
||||||
featureNameMap := make(map[string]string)
|
|
||||||
if len(list) == 0 {
|
|
||||||
return featureNameMap
|
|
||||||
}
|
|
||||||
|
|
||||||
featureIds := make([]string, 0, len(list))
|
|
||||||
seen := make(map[string]struct{}, len(list))
|
|
||||||
for _, w := range list {
|
|
||||||
if _, ok := seen[w.FeatureId]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[w.FeatureId] = struct{}{}
|
|
||||||
featureIds = append(featureIds, w.FeatureId)
|
|
||||||
}
|
|
||||||
|
|
||||||
featureBuilder := l.svcCtx.FeatureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIds})
|
|
||||||
features, err := l.svcCtx.FeatureModel.FindAll(l.ctx, featureBuilder, "")
|
|
||||||
if err != nil {
|
|
||||||
l.Errorf("批量查询模块名称失败: %v", err)
|
|
||||||
return featureNameMap
|
|
||||||
}
|
|
||||||
for _, f := range features {
|
|
||||||
featureNameMap[f.Id] = f.Name
|
|
||||||
}
|
|
||||||
return featureNameMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func whitelistStatusText(status int64) string {
|
|
||||||
if status == 1 {
|
|
||||||
return "生效"
|
|
||||||
}
|
|
||||||
return "已失效"
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/api/internal/types"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdminUpdateWhitelistLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdminUpdateWhitelistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateWhitelistLogic {
|
|
||||||
return &AdminUpdateWhitelistLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AdminUpdateWhitelistLogic) AdminUpdateWhitelist(req *types.AdminUpdateWhitelistReq) (resp *types.AdminUpdateWhitelistResp, err error) {
|
|
||||||
if req.Status == nil && req.Amount == nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("请至少提供一个更新字段"), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
record, err := l.svcCtx.UserFeatureWhitelistModel.FindOne(l.ctx, req.Id)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Status != nil {
|
|
||||||
if *req.Status != 1 && *req.Status != 2 {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("状态值无效,仅支持 1=生效 或 2=已失效"), "")
|
|
||||||
}
|
|
||||||
record.Status = *req.Status
|
|
||||||
}
|
|
||||||
if req.Amount != nil {
|
|
||||||
record.Amount = *req.Amount
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = l.svcCtx.UserFeatureWhitelistModel.UpdateWithVersion(l.ctx, nil, record); err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新白名单记录失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.AdminUpdateWhitelistResp{Success: true}, nil
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package admin_whitelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ycc-server/app/main/api/internal/svc"
|
|
||||||
"ycc-server/app/main/model"
|
|
||||||
"ycc-server/common/xerr"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
whitelistActionCreated = "created"
|
|
||||||
whitelistActionReactivated = "reactivated"
|
|
||||||
whitelistActionSkipped = "skipped"
|
|
||||||
)
|
|
||||||
|
|
||||||
type createWhitelistResult struct {
|
|
||||||
Id string
|
|
||||||
FeatureApiId string
|
|
||||||
FeatureName string
|
|
||||||
Action string
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func createOrReactivateWhitelist(
|
|
||||||
ctx context.Context,
|
|
||||||
svcCtx *svc.ServiceContext,
|
|
||||||
userID string,
|
|
||||||
idCard string,
|
|
||||||
feature *model.Feature,
|
|
||||||
amount float64,
|
|
||||||
status int64,
|
|
||||||
) (*createWhitelistResult, error) {
|
|
||||||
exists, err := svcCtx.WhitelistService.CheckWhitelistExists(ctx, idCard, feature.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
return &createWhitelistResult{
|
|
||||||
FeatureApiId: feature.ApiId,
|
|
||||||
FeatureName: feature.Name,
|
|
||||||
Action: whitelistActionSkipped,
|
|
||||||
Message: "已存在生效白名单",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
builder := svcCtx.UserFeatureWhitelistModel.SelectBuilder().
|
|
||||||
Where("id_card = ? AND feature_id = ?", idCard, feature.Id)
|
|
||||||
records, err := svcCtx.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询白名单记录失败, %v", err)
|
|
||||||
}
|
|
||||||
for _, record := range records {
|
|
||||||
if record.Status == 2 {
|
|
||||||
record.Status = status
|
|
||||||
record.Amount = amount
|
|
||||||
record.UserId = userID
|
|
||||||
if updateErr := svcCtx.UserFeatureWhitelistModel.UpdateWithVersion(ctx, nil, record); updateErr != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新白名单记录失败, %v", updateErr)
|
|
||||||
}
|
|
||||||
return &createWhitelistResult{
|
|
||||||
Id: record.Id,
|
|
||||||
FeatureApiId: feature.ApiId,
|
|
||||||
FeatureName: feature.Name,
|
|
||||||
Action: whitelistActionReactivated,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wl := &model.UserFeatureWhitelist{
|
|
||||||
Id: uuid.NewString(),
|
|
||||||
IdCard: idCard,
|
|
||||||
FeatureId: feature.Id,
|
|
||||||
FeatureApiId: feature.ApiId,
|
|
||||||
UserId: userID,
|
|
||||||
Amount: amount,
|
|
||||||
Status: status,
|
|
||||||
}
|
|
||||||
if _, err = svcCtx.UserFeatureWhitelistModel.Insert(ctx, nil, wl); err != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建白名单记录失败, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &createWhitelistResult{
|
|
||||||
Id: wl.Id,
|
|
||||||
FeatureApiId: feature.ApiId,
|
|
||||||
FeatureName: feature.Name,
|
|
||||||
Action: whitelistActionCreated,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseWhitelistStatus(status *int64) (int64, error) {
|
|
||||||
if status == nil {
|
|
||||||
return 1, nil
|
|
||||||
}
|
|
||||||
if *status != 1 && *status != 2 {
|
|
||||||
return 0, errors.Wrapf(xerr.NewErrMsg("状态值无效,仅支持 1=生效 或 2=已失效"), "")
|
|
||||||
}
|
|
||||||
return *status, nil
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"ycc-server/app/main/model"
|
"ycc-server/app/main/model"
|
||||||
"ycc-server/common/ctxdata"
|
"ycc-server/common/ctxdata"
|
||||||
"ycc-server/common/xerr"
|
"ycc-server/common/xerr"
|
||||||
@@ -33,28 +35,32 @@ func NewOfflineFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Of
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp *types.OfflineFeatureResp, err error) {
|
func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp *types.OfflineFeatureResp, err error) {
|
||||||
// 1. 验证参数
|
|
||||||
if err := l.validateRequest(req); err != nil {
|
if err := l.validateRequest(req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取用户ID并验证代理权限(任意等级代理均可下架)
|
|
||||||
userID, err := l.verifyAgent()
|
userID, err := l.verifyAgent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 获取查询记录和身份证号
|
queryModel, idCard, name, err := l.getQueryInfo(req.QueryId)
|
||||||
queryModel, idCard, err := l.getQueryInfo(req.QueryId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = queryModel // 避免未使用变量警告
|
|
||||||
|
|
||||||
// 4. 调用 WhitelistService 统一下架处理
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
needPay, amount, whitelistCreated, err := l.svcCtx.WhitelistService.ProcessOfflineFeature(
|
needPay, amount, whitelistCreated, err := l.svcCtx.WhitelistService.ProcessOfflineFeature(
|
||||||
l.ctx,
|
l.ctx,
|
||||||
nil, // 不使用事务,因为可能只是检查
|
nil,
|
||||||
idCard,
|
idCard,
|
||||||
req.FeatureApiId,
|
req.FeatureApiId,
|
||||||
userID,
|
userID,
|
||||||
@@ -64,14 +70,31 @@ func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 如果已创建白名单,需要删除报告数据
|
if needPay {
|
||||||
|
return &types.OfflineFeatureResp{
|
||||||
|
Success: false,
|
||||||
|
NeedPay: true,
|
||||||
|
Amount: amount,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
if whitelistCreated {
|
if whitelistCreated {
|
||||||
|
remark := fmt.Sprintf("代理下架自动同步 query_id=%s feature=%s", req.QueryId, feature.ApiId)
|
||||||
|
l.svcCtx.QueryWhitelistSyncService.TrySync(
|
||||||
|
l.ctx,
|
||||||
|
name,
|
||||||
|
idCard,
|
||||||
|
[]string{feature.ApiId},
|
||||||
|
remark,
|
||||||
|
)
|
||||||
|
|
||||||
if err := l.deleteQueryData(req.QueryId, req.FeatureApiId); err != nil {
|
if err := l.deleteQueryData(req.QueryId, req.FeatureApiId); err != nil {
|
||||||
// 删除报告数据失败不影响主流程,只记录日志
|
|
||||||
logx.Errorf("下架模块后删除报告数据失败:查询记录 %s,模块 %s,错误:%v", req.QueryId, req.FeatureApiId, err)
|
logx.Errorf("下架模块后删除报告数据失败:查询记录 %s,模块 %s,错误:%v", req.QueryId, req.FeatureApiId, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = queryModel
|
||||||
|
|
||||||
return &types.OfflineFeatureResp{
|
return &types.OfflineFeatureResp{
|
||||||
Success: whitelistCreated,
|
Success: whitelistCreated,
|
||||||
NeedPay: needPay,
|
NeedPay: needPay,
|
||||||
@@ -79,7 +102,6 @@ func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateRequest 验证请求参数
|
|
||||||
func (l *OfflineFeatureLogic) validateRequest(req *types.OfflineFeatureReq) error {
|
func (l *OfflineFeatureLogic) validateRequest(req *types.OfflineFeatureReq) error {
|
||||||
if req.QueryId == "" {
|
if req.QueryId == "" {
|
||||||
return errors.Wrapf(xerr.NewErrMsg("查询记录ID不能为空"), "")
|
return errors.Wrapf(xerr.NewErrMsg("查询记录ID不能为空"), "")
|
||||||
@@ -90,7 +112,6 @@ func (l *OfflineFeatureLogic) validateRequest(req *types.OfflineFeatureReq) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyAgent 验证是否为代理并返回用户ID(任意等级代理均可下架)
|
|
||||||
func (l *OfflineFeatureLogic) verifyAgent() (string, error) {
|
func (l *OfflineFeatureLogic) verifyAgent() (string, error) {
|
||||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -108,61 +129,67 @@ func (l *OfflineFeatureLogic) verifyAgent() (string, error) {
|
|||||||
return userID, nil
|
return userID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getQueryInfo 获取查询记录和身份证号
|
func (l *OfflineFeatureLogic) getQueryInfo(queryId string) (*model.Query, string, string, error) {
|
||||||
func (l *OfflineFeatureLogic) getQueryInfo(queryId string) (*model.Query, string, error) {
|
|
||||||
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, queryId)
|
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, queryId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, model.ErrNotFound) {
|
if errors.Is(err, model.ErrNotFound) {
|
||||||
return nil, "", errors.Wrapf(xerr.NewErrMsg("查询记录不存在"), "")
|
return nil, "", "", errors.Wrapf(xerr.NewErrMsg("查询记录不存在"), "")
|
||||||
}
|
}
|
||||||
return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询报告记录失败, %v", err)
|
return nil, "", "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询报告记录失败, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解密 QueryParams 获取 idCard
|
idCard, name, err := extractPersonInfoFromQueryParams(l.svcCtx, queryModel)
|
||||||
idCard, err := l.extractIdCardFromQueryParams(queryModel)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取身份证号失败, %v", err)
|
return nil, "", "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取查询参数失败, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if idCard == "" {
|
if idCard == "" {
|
||||||
return nil, "", errors.Wrapf(xerr.NewErrMsg("查询参数中缺少身份证号"), "")
|
return nil, "", "", errors.Wrapf(xerr.NewErrMsg("查询参数中缺少身份证号"), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryModel, idCard, nil
|
return queryModel, idCard, name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractIdCardFromQueryParams 从 QueryParams 中提取身份证号
|
func extractMainApiId(featureApiId string) string {
|
||||||
func (l *OfflineFeatureLogic) extractIdCardFromQueryParams(queryModel *model.Query) (string, error) {
|
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) {
|
||||||
if queryModel.QueryParams == "" {
|
if queryModel.QueryParams == "" {
|
||||||
return "", errors.New("查询参数为空")
|
return "", "", errors.New("查询参数为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
secretKey := svcCtx.Config.Encrypt.SecretKey
|
||||||
key, decodeErr := hex.DecodeString(secretKey)
|
key, decodeErr := hex.DecodeString(secretKey)
|
||||||
if decodeErr != nil {
|
if decodeErr != nil {
|
||||||
return "", errors.Wrap(decodeErr, "获取AES密钥失败")
|
return "", "", errors.Wrap(decodeErr, "获取AES密钥失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptedParams, decryptErr := crypto.AesDecrypt(queryModel.QueryParams, key)
|
decryptedParams, decryptErr := crypto.AesDecrypt(queryModel.QueryParams, key)
|
||||||
if decryptErr != nil {
|
if decryptErr != nil {
|
||||||
return "", errors.Wrap(decryptErr, "解密查询参数失败")
|
return "", "", errors.Wrap(decryptErr, "解密查询参数失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
var params map[string]interface{}
|
var params map[string]interface{}
|
||||||
unmarshalErr := json.Unmarshal(decryptedParams, ¶ms)
|
if unmarshalErr := json.Unmarshal(decryptedParams, ¶ms); unmarshalErr != nil {
|
||||||
if unmarshalErr != nil {
|
return "", "", errors.Wrap(unmarshalErr, "解析查询参数失败")
|
||||||
return "", errors.Wrap(unmarshalErr, "解析查询参数失败")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idCard, ok := params["id_card"].(string)
|
idCardValue, ok := params["id_card"].(string)
|
||||||
if !ok || idCard == "" {
|
if !ok || idCardValue == "" {
|
||||||
return "", errors.New("查询参数中缺少 id_card 或 id_card 为空")
|
return "", "", errors.New("查询参数中缺少 id_card 或 id_card 为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
return idCard, nil
|
nameValue, _ := params["name"].(string)
|
||||||
|
if strings.TrimSpace(nameValue) == "" {
|
||||||
|
nameValue = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
return idCardValue, nameValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteQueryData 删除报告数据
|
|
||||||
func (l *OfflineFeatureLogic) deleteQueryData(queryId, featureApiId string) error {
|
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.QueryModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||||
return l.svcCtx.WhitelistService.DeleteFeatureFromQueryData(ctx, session, queryId, featureApiId)
|
return l.svcCtx.WhitelistService.DeleteFeatureFromQueryData(ctx, session, queryId, featureApiId)
|
||||||
|
|||||||
@@ -172,6 +172,15 @@ func (l *AlipayCallbackLogic) handleWhitelistOrderPayment(w http.ResponseWriter,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if whitelistOrder.Status == 2 {
|
||||||
|
syncPaidWhitelistOrderToTianyuan(
|
||||||
|
l.ctx,
|
||||||
|
l.svcCtx,
|
||||||
|
whitelistOrder,
|
||||||
|
buildAgentPaidWhitelistSyncRemark(orderNo),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 6. 更新订单和白名单订单 + 创建白名单记录并删除报告数据
|
// 6. 更新订单和白名单订单 + 创建白名单记录并删除报告数据
|
||||||
err = l.svcCtx.WhitelistOrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
err = l.svcCtx.WhitelistOrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||||
// 6.1 更新订单状态
|
// 6.1 更新订单状态
|
||||||
|
|||||||
@@ -217,6 +217,13 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新白名单订单状态为已支付并处理白名单记录
|
// 更新白名单订单状态为已支付并处理白名单记录
|
||||||
|
syncPaidWhitelistOrderToTianyuan(
|
||||||
|
context.Background(),
|
||||||
|
l.svcCtx,
|
||||||
|
whitelistOrder,
|
||||||
|
buildAgentPaidWhitelistSyncRemark(paymentTypeResp.outTradeNo),
|
||||||
|
)
|
||||||
|
|
||||||
err := l.svcCtx.WhitelistOrderModel.Trans(context.Background(), func(transCtx context.Context, session sqlx.Session) error {
|
err := l.svcCtx.WhitelistOrderModel.Trans(context.Background(), func(transCtx context.Context, session sqlx.Session) error {
|
||||||
// 更新白名单订单状态为已支付
|
// 更新白名单订单状态为已支付
|
||||||
whitelistOrder.Status = 2 // 已支付
|
whitelistOrder.Status = 2 // 已支付
|
||||||
|
|||||||
@@ -166,6 +166,15 @@ func (l *WechatPayCallbackLogic) handleWhitelistOrderPayment(w http.ResponseWrit
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if whitelistOrder.Status == 2 {
|
||||||
|
syncPaidWhitelistOrderToTianyuan(
|
||||||
|
l.ctx,
|
||||||
|
l.svcCtx,
|
||||||
|
whitelistOrder,
|
||||||
|
buildAgentPaidWhitelistSyncRemark(orderNo),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 6. 更新订单和白名单订单 + 创建白名单记录并删除报告数据
|
// 6. 更新订单和白名单订单 + 创建白名单记录并删除报告数据
|
||||||
err := l.svcCtx.WhitelistOrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
err := l.svcCtx.WhitelistOrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||||
// 6.1 更新订单状态
|
// 6.1 更新订单状态
|
||||||
|
|||||||
28
app/main/api/internal/logic/pay/whitelist_sync_helper.go
Normal file
28
app/main/api/internal/logic/pay/whitelist_sync_helper.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package pay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"ycc-server/app/main/api/internal/svc"
|
||||||
|
"ycc-server/app/main/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func syncPaidWhitelistOrderToTianyuan(
|
||||||
|
ctx context.Context,
|
||||||
|
svcCtx *svc.ServiceContext,
|
||||||
|
whitelistOrder *model.WhitelistOrder,
|
||||||
|
remark string,
|
||||||
|
) {
|
||||||
|
itemBuilder := svcCtx.WhitelistOrderItemModel.SelectBuilder().
|
||||||
|
Where("order_id = ?", whitelistOrder.Id)
|
||||||
|
items, err := svcCtx.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
|
||||||
|
if err != nil || len(items) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
svcCtx.QueryWhitelistSyncService.TrySyncWhitelistOrder(ctx, whitelistOrder, items, remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAgentPaidWhitelistSyncRemark(orderNo string) string {
|
||||||
|
return fmt.Sprintf("代理付费下架自动同步 order_no=%s", orderNo)
|
||||||
|
}
|
||||||
303
app/main/api/internal/service/querywhitelistsync.go
Normal file
303
app/main/api/internal/service/querywhitelistsync.go
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ycc-server/app/main/api/internal/config"
|
||||||
|
tianyuanapi "ycc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||||
|
"ycc-server/app/main/model"
|
||||||
|
"ycc-server/common/ctxdata"
|
||||||
|
"ycc-server/common/xerr"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var queryWhitelistIdCardPattern = regexp.MustCompile(`^\d{17}[\dXx]$`)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tianyuanQueryWhitelistSuccessCode = 0
|
||||||
|
tianyuanQueryWhitelistExistsCode = 1013
|
||||||
|
tianyuanQueryWhitelistNotFoundCode = 1014
|
||||||
|
tianyuanQueryWhitelistLocalFailCode = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
// QueryWhitelistSyncService 天远查询白名单同步服务
|
||||||
|
type QueryWhitelistSyncService struct {
|
||||||
|
config config.Config
|
||||||
|
client *tianyuanapi.Client
|
||||||
|
opLogModel model.QueryWhitelistOpLogModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQueryWhitelistSyncService(
|
||||||
|
c config.Config,
|
||||||
|
client *tianyuanapi.Client,
|
||||||
|
opLogModel model.QueryWhitelistOpLogModel,
|
||||||
|
) *QueryWhitelistSyncService {
|
||||||
|
return &QueryWhitelistSyncService{
|
||||||
|
config: c,
|
||||||
|
client: client,
|
||||||
|
opLogModel: opLogModel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrySync 尽力同步天远查询白名单,失败仅记操作日志,不影响主流程
|
||||||
|
func (s *QueryWhitelistSyncService) TrySync(
|
||||||
|
ctx context.Context,
|
||||||
|
name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
) {
|
||||||
|
if err := s.Sync(ctx, name, idCard, apiCodes, remark); err != nil {
|
||||||
|
logx.WithContext(ctx).Errorf("天远查询白名单同步失败(不影响主流程): %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrySyncWhitelistOrder 尽力同步白名单订单中的模块到天远
|
||||||
|
func (s *QueryWhitelistSyncService) TrySyncWhitelistOrder(
|
||||||
|
ctx context.Context,
|
||||||
|
whitelistOrder *model.WhitelistOrder,
|
||||||
|
items []*model.WhitelistOrderItem,
|
||||||
|
remark string,
|
||||||
|
) {
|
||||||
|
if whitelistOrder == nil || len(items) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.TrySync(ctx, "*", whitelistOrder.IdCard, collectWhitelistOrderApiCodes(items), remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync 将产品编码同步到天远查询白名单(先追加,规则不存在则创建)
|
||||||
|
func (s *QueryWhitelistSyncService) Sync(
|
||||||
|
ctx context.Context,
|
||||||
|
name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
) error {
|
||||||
|
if err := validateQueryWhitelistSyncReq(idCard, apiCodes); err != nil {
|
||||||
|
s.recordOpLogFailure(ctx, "sync", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
appendResp, err := s.callMgmt(
|
||||||
|
"/api/v1/query-whitelist/entries/append",
|
||||||
|
name,
|
||||||
|
idCard,
|
||||||
|
apiCodes,
|
||||||
|
remark,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
s.recordOpLogFailure(ctx, "append", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isTianyuanQueryWhitelistSuccess(appendResp.Code) {
|
||||||
|
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, appendResp)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if appendResp.Code != tianyuanQueryWhitelistNotFoundCode {
|
||||||
|
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, appendResp)
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg(appendResp.Message), "天远查询白名单同步失败(code=%d)", appendResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.callMgmt(
|
||||||
|
"/api/v1/query-whitelist/entries",
|
||||||
|
name,
|
||||||
|
idCard,
|
||||||
|
apiCodes,
|
||||||
|
remark,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
s.recordOpLogFailure(ctx, "create", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isTianyuanQueryWhitelistSuccess(createResp.Code) {
|
||||||
|
s.recordOpLog(ctx, "create", name, idCard, apiCodes, remark, createResp)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if createResp.Code == tianyuanQueryWhitelistExistsCode {
|
||||||
|
retryResp, retryErr := s.callMgmt(
|
||||||
|
"/api/v1/query-whitelist/entries/append",
|
||||||
|
name,
|
||||||
|
idCard,
|
||||||
|
apiCodes,
|
||||||
|
remark,
|
||||||
|
)
|
||||||
|
if retryErr != nil {
|
||||||
|
s.recordOpLogFailure(ctx, "append", name, idCard, apiCodes, remark, retryErr.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||||
|
return retryErr
|
||||||
|
}
|
||||||
|
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, retryResp)
|
||||||
|
if isTianyuanQueryWhitelistSuccess(retryResp.Code) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg(retryResp.Message), "天远查询白名单同步失败(code=%d)", retryResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.recordOpLog(ctx, "create", name, idCard, apiCodes, remark, createResp)
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg(createResp.Message), "天远查询白名单同步失败(code=%d)", createResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectWhitelistOrderApiCodes(items []*model.WhitelistOrderItem) []string {
|
||||||
|
codes := make([]string, 0, len(items))
|
||||||
|
seen := make(map[string]bool, len(items))
|
||||||
|
for _, item := range items {
|
||||||
|
if item == nil || item.FeatureApiId == "" || seen[item.FeatureApiId] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[item.FeatureApiId] = true
|
||||||
|
codes = append(codes, item.FeatureApiId)
|
||||||
|
}
|
||||||
|
return codes
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateQueryWhitelistSyncReq(idCard string, apiCodes []string) error {
|
||||||
|
if strings.TrimSpace(idCard) == "" {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("身份证号不能为空"), "")
|
||||||
|
}
|
||||||
|
if !queryWhitelistIdCardPattern.MatchString(strings.TrimSpace(idCard)) {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("身份证号格式不正确,需为18位中国大陆身份证号"), "")
|
||||||
|
}
|
||||||
|
if len(apiCodes) == 0 {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("请至少选择一个产品编码"), "")
|
||||||
|
}
|
||||||
|
for _, code := range apiCodes {
|
||||||
|
if strings.TrimSpace(code) == "" {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("产品编码不能为空"), "")
|
||||||
|
}
|
||||||
|
if code == "*" {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("产品编码不支持通配符 *"), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *QueryWhitelistSyncService) callMgmt(
|
||||||
|
apiPath string,
|
||||||
|
name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
) (*tianyuanapi.QueryWhitelistMgmtResponse, error) {
|
||||||
|
mgmtKey := s.config.Tianyuanapi.WhitelistMgmtKey
|
||||||
|
if mgmtKey == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("查询白名单管理密钥未配置,请在服务端配置 Tianyuanapi.WhitelistMgmtKey"), "")
|
||||||
|
}
|
||||||
|
if s.client == nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("天远 API 客户端未初始化"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(name) == "" {
|
||||||
|
name = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
"id_card": strings.TrimSpace(idCard),
|
||||||
|
"api_codes": apiCodes,
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(remark) != "" {
|
||||||
|
payload["remark"] = strings.TrimSpace(remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.CallQueryWhitelistMgmt(apiPath, payload, mgmtKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *QueryWhitelistSyncService) recordOpLogFailure(
|
||||||
|
ctx context.Context,
|
||||||
|
action, name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark, message string,
|
||||||
|
code int64,
|
||||||
|
) {
|
||||||
|
s.insertOpLog(ctx, action, name, idCard, apiCodes, remark, code, message, "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *QueryWhitelistSyncService) recordOpLog(
|
||||||
|
ctx context.Context,
|
||||||
|
action, name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
apiResp *tianyuanapi.QueryWhitelistMgmtResponse,
|
||||||
|
) {
|
||||||
|
if apiResp == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.insertOpLog(ctx, action, name, idCard, apiCodes, remark, int64(apiResp.Code), apiResp.Message, apiResp.TransactionID, apiResp.Entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *QueryWhitelistSyncService) insertOpLog(
|
||||||
|
ctx context.Context,
|
||||||
|
action, name, idCard string,
|
||||||
|
apiCodes []string,
|
||||||
|
remark string,
|
||||||
|
tianyuanCode int64,
|
||||||
|
tianyuanMessage, transactionID string,
|
||||||
|
entry *tianyuanapi.QueryWhitelistEntry,
|
||||||
|
) {
|
||||||
|
if s.opLogModel == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
operatorUserId, err := ctxdata.GetUidFromCtx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: 获取操作人ID失败, %v", err)
|
||||||
|
operatorUserId = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
apiCodesJSON, marshalErr := json.Marshal(apiCodes)
|
||||||
|
if marshalErr != nil {
|
||||||
|
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: 序列化 api_codes 失败, %v", marshalErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log := &model.QueryWhitelistOpLog{
|
||||||
|
AdminUserId: operatorUserId,
|
||||||
|
Action: action,
|
||||||
|
Name: resolveQueryWhitelistName(name),
|
||||||
|
IdCard: strings.TrimSpace(idCard),
|
||||||
|
ApiCodes: string(apiCodesJSON),
|
||||||
|
TianyuanCode: tianyuanCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(remark) != "" {
|
||||||
|
log.Remark = sql.NullString{String: strings.TrimSpace(remark), Valid: true}
|
||||||
|
}
|
||||||
|
if tianyuanMessage != "" {
|
||||||
|
log.TianyuanMessage = sql.NullString{String: tianyuanMessage, Valid: true}
|
||||||
|
}
|
||||||
|
if transactionID != "" {
|
||||||
|
log.TransactionId = sql.NullString{String: transactionID, Valid: true}
|
||||||
|
}
|
||||||
|
if entry != nil {
|
||||||
|
if entry.IdCardMasked != "" {
|
||||||
|
log.IdCardMasked = sql.NullString{String: entry.IdCardMasked, Valid: true}
|
||||||
|
}
|
||||||
|
if entry.ID != "" {
|
||||||
|
log.EntryId = sql.NullString{String: entry.ID, Valid: true}
|
||||||
|
}
|
||||||
|
if entry.Status != "" {
|
||||||
|
log.EntryStatus = sql.NullString{String: entry.Status, Valid: true}
|
||||||
|
}
|
||||||
|
if len(entry.ApiCodes) > 0 {
|
||||||
|
entryCodesJSON, _ := json.Marshal(entry.ApiCodes)
|
||||||
|
log.EntryApiCodes = sql.NullString{String: string(entryCodesJSON), Valid: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, insertErr := s.opLogModel.Insert(ctx, nil, log); insertErr != nil {
|
||||||
|
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: %v", insertErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveQueryWhitelistName(name string) string {
|
||||||
|
if strings.TrimSpace(name) == "" {
|
||||||
|
return "*"
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTianyuanQueryWhitelistSuccess(code int) bool {
|
||||||
|
return code == tianyuanQueryWhitelistSuccessCode
|
||||||
|
}
|
||||||
@@ -100,7 +100,8 @@ type ServiceContext struct {
|
|||||||
WechatPayService *service.WechatPayService
|
WechatPayService *service.WechatPayService
|
||||||
ApplePayService *service.ApplePayService
|
ApplePayService *service.ApplePayService
|
||||||
ApiRequestService *service.ApiRequestService
|
ApiRequestService *service.ApiRequestService
|
||||||
WhitelistService *service.WhitelistService
|
WhitelistService *service.WhitelistService
|
||||||
|
QueryWhitelistSyncService *service.QueryWhitelistSyncService
|
||||||
AsynqServer *asynq.Server
|
AsynqServer *asynq.Server
|
||||||
AsynqService *service.AsynqService
|
AsynqService *service.AsynqService
|
||||||
VerificationService *service.VerificationService
|
VerificationService *service.VerificationService
|
||||||
@@ -315,12 +316,13 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
ComplaintAlipayTradeModel: complaintAlipayTradeModel,
|
ComplaintAlipayTradeModel: complaintAlipayTradeModel,
|
||||||
ComplaintManualModel: complaintManualModel,
|
ComplaintManualModel: complaintManualModel,
|
||||||
|
|
||||||
// 服务
|
// 服务
|
||||||
AlipayService: alipayService,
|
AlipayService: alipayService,
|
||||||
WechatPayService: wechatPayService,
|
WechatPayService: wechatPayService,
|
||||||
ApplePayService: applePayService,
|
ApplePayService: applePayService,
|
||||||
ApiRequestService: apiRequestService,
|
ApiRequestService: apiRequestService,
|
||||||
WhitelistService: whitelistService,
|
WhitelistService: whitelistService,
|
||||||
|
QueryWhitelistSyncService: service.NewQueryWhitelistSyncService(c, tianyuanapi, queryWhitelistOpLogModel),
|
||||||
AsynqServer: asynqServer,
|
AsynqServer: asynqServer,
|
||||||
AsynqService: asynqService,
|
AsynqService: asynqService,
|
||||||
VerificationService: verificationService,
|
VerificationService: verificationService,
|
||||||
|
|||||||
@@ -58,28 +58,6 @@ type AdminAuditWithdrawalResp struct {
|
|||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminBatchCreateWhitelistReq struct {
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureIds []string `json:"feature_ids"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminBatchCreateWhitelistResp struct {
|
|
||||||
SuccessCount int64 `json:"success_count"`
|
|
||||||
SkipCount int64 `json:"skip_count"`
|
|
||||||
FailCount int64 `json:"fail_count"`
|
|
||||||
Items []AdminBatchCreateWhitelistResultItem `json:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminBatchCreateWhitelistResultItem struct {
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
FeatureApiId string `json:"feature_api_id"`
|
|
||||||
FeatureName string `json:"feature_name"`
|
|
||||||
Action string `json:"action"`
|
|
||||||
Message string `json:"message,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminBatchUpdateApiStatusReq struct {
|
type AdminBatchUpdateApiStatusReq struct {
|
||||||
Ids []string `json:"ids"`
|
Ids []string `json:"ids"`
|
||||||
Status int64 `json:"status"`
|
Status int64 `json:"status"`
|
||||||
@@ -186,17 +164,6 @@ type AdminCreateUserResp struct {
|
|||||||
Id string `json:"id"` // 用户ID
|
Id string `json:"id"` // 用户ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminCreateWhitelistReq struct {
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminCreateWhitelistResp struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminAppendQueryWhitelistReq struct {
|
type AdminAppendQueryWhitelistReq struct {
|
||||||
Name string `json:"name,optional"`
|
Name string `json:"name,optional"`
|
||||||
IdCard string `json:"id_card"`
|
IdCard string `json:"id_card"`
|
||||||
@@ -335,14 +302,6 @@ type AdminDeleteUserResp struct {
|
|||||||
Success bool `json:"success"` // 是否成功
|
Success bool `json:"success"` // 是否成功
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminDeleteWhitelistReq struct {
|
|
||||||
Id string `path:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminDeleteWhitelistResp struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminDowngradeAgentReq struct {
|
type AdminDowngradeAgentReq struct {
|
||||||
AgentId string `json:"agent_id"` // 代理ID
|
AgentId string `json:"agent_id"` // 代理ID
|
||||||
ToLevel int64 `json:"to_level"` // 目标等级:1=普通,2=黄金,3=钻石(须低于当前等级)
|
ToLevel int64 `json:"to_level"` // 目标等级:1=普通,2=黄金,3=钻石(须低于当前等级)
|
||||||
@@ -867,19 +826,6 @@ type AdminGetUserListResp struct {
|
|||||||
Items []AdminUserListItem `json:"items"` // 列表
|
Items []AdminUserListItem `json:"items"` // 列表
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminGetWhitelistListReq struct {
|
|
||||||
Page int64 `form:"page"`
|
|
||||||
PageSize int64 `form:"pageSize"`
|
|
||||||
IdCard *string `form:"id_card,optional"`
|
|
||||||
FeatureApiId *string `form:"feature_api_id,optional"`
|
|
||||||
Status *int64 `form:"status,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminGetWhitelistListResp struct {
|
|
||||||
Total int64 `json:"total"`
|
|
||||||
Items []AdminWhitelistListItem `json:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminLoginReq struct {
|
type AdminLoginReq struct {
|
||||||
Username string `json:"username" validate:"required"`
|
Username string `json:"username" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
@@ -1177,16 +1123,6 @@ type AdminUpdateUserResp struct {
|
|||||||
Success bool `json:"success"` // 是否成功
|
Success bool `json:"success"` // 是否成功
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminUpdateWhitelistReq struct {
|
|
||||||
Id string `path:"id"`
|
|
||||||
Status *int64 `json:"status,optional"`
|
|
||||||
Amount *float64 `json:"amount,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminUpdateWhitelistResp struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdminUserInfoReq struct {
|
type AdminUserInfoReq struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1205,20 +1141,6 @@ type AdminUserListItem struct {
|
|||||||
RoleIds []string `json:"role_ids"` // 关联的角色ID列表
|
RoleIds []string `json:"role_ids"` // 关联的角色ID列表
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminWhitelistListItem struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
IdCard string `json:"id_card"`
|
|
||||||
FeatureId string `json:"feature_id"`
|
|
||||||
FeatureApiId string `json:"feature_api_id"`
|
|
||||||
FeatureName string `json:"feature_name"`
|
|
||||||
UserId string `json:"user_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Status int64 `json:"status"`
|
|
||||||
StatusText string `json:"status_text"`
|
|
||||||
CreateTime string `json:"create_time"`
|
|
||||||
UpdateTime string `json:"update_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentApplyReq struct {
|
type AgentApplyReq struct {
|
||||||
Region string `json:"region,optional"`
|
Region string `json:"region,optional"`
|
||||||
Mobile string `json:"mobile"`
|
Mobile string `json:"mobile"`
|
||||||
|
|||||||
Reference in New Issue
Block a user