From 0d9feccf1d555b1e0c91def5ca7c769b14e2c918 Mon Sep 17 00:00:00 2001 From: Mrxs <18278715334@163.com> Date: Fri, 19 Jun 2026 12:15:17 +0800 Subject: [PATCH] f --- .../api/desc/admin/admin_query_whitelist.api | 92 ++++ app/main/api/desc/main.api | 4 +- app/main/api/etc/main.dev.yaml | 1 + app/main/api/etc/main.yaml | 1 + app/main/api/internal/config/config.go | 9 +- .../adminquerywhitelistappendhandler.go | 29 ++ .../adminquerywhitelistcreatehandler.go | 29 ++ .../adminquerywhitelistoploglisthandler.go | 29 ++ app/main/api/internal/handler/routes.go | 55 ++- .../adminquerywhitelistappendlogic.go | 37 ++ .../adminquerywhitelistcreatelogic.go | 31 ++ .../adminquerywhitelistoploglistlogic.go | 75 ++++ .../logic/admin_query_whitelist/op_helper.go | 141 +++++++ .../service/tianyuanapi_sdk/client.go | 29 +- .../tianyuanapi_sdk/query_whitelist.go | 148 +++++++ app/main/api/internal/svc/servicecontext.go | 14 +- app/main/api/internal/types/types.go | 170 +++++--- app/main/model/queryWhitelistOpLogModel.go | 27 ++ .../model/queryWhitelistOpLogModel_gen.go | 398 ++++++++++++++++++ deploy/sql/query_whitelist_migration.sql | 118 ++++++ 20 files changed, 1344 insertions(+), 93 deletions(-) create mode 100644 app/main/api/desc/admin/admin_query_whitelist.api create mode 100644 app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistappendhandler.go create mode 100644 app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistcreatehandler.go create mode 100644 app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistoploglisthandler.go create mode 100644 app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistappendlogic.go create mode 100644 app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistcreatelogic.go create mode 100644 app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistoploglistlogic.go create mode 100644 app/main/api/internal/logic/admin_query_whitelist/op_helper.go create mode 100644 app/main/api/internal/service/tianyuanapi_sdk/query_whitelist.go create mode 100644 app/main/model/queryWhitelistOpLogModel.go create mode 100644 app/main/model/queryWhitelistOpLogModel_gen.go create mode 100644 deploy/sql/query_whitelist_migration.sql diff --git a/app/main/api/desc/admin/admin_query_whitelist.api b/app/main/api/desc/admin/admin_query_whitelist.api new file mode 100644 index 0000000..d63f8a6 --- /dev/null +++ b/app/main/api/desc/admin/admin_query_whitelist.api @@ -0,0 +1,92 @@ +syntax = "v1" + +info ( + title: "查询白名单管理" + desc: "代理天远查询白名单接口,并记录操作日志" + version: "v1" +) + +@server ( + prefix: /api/v1/admin/query-whitelist + group: admin_query_whitelist + middleware: AdminAuthInterceptor +) +service main { + @doc "创建查询白名单规则" + @handler AdminQueryWhitelistCreate + post /create (AdminQueryWhitelistCreateReq) returns (AdminQueryWhitelistOpResp) + + @doc "追加查询白名单产品编码" + @handler AdminQueryWhitelistAppend + post /append (AdminQueryWhitelistAppendReq) returns (AdminQueryWhitelistOpResp) + + @doc "查询白名单操作记录列表" + @handler AdminQueryWhitelistOpLogList + get /op-log/list (AdminQueryWhitelistOpLogListReq) returns (AdminQueryWhitelistOpLogListResp) +} + +type ( + AdminQueryWhitelistCreateReq { + Name string `json:"name"` // 姓名,* 表示仅按身份证匹配 + IdCard string `json:"id_card"` // 身份证号 + ApiCodes []string `json:"api_codes"` // 产品编码列表 + Remark string `json:"remark,optional"` // 备注 + } + + AdminQueryWhitelistAppendReq { + Name string `json:"name"` // 姓名,* 表示仅按身份证匹配 + IdCard string `json:"id_card"` // 身份证号 + ApiCodes []string `json:"api_codes"` // 产品编码列表 + Remark string `json:"remark,optional"` // 备注 + } + + AdminQueryWhitelistEntryItem { + Id string `json:"id"` + Name string `json:"name"` + IdCardMasked string `json:"id_card_masked"` + ApiCodes []string `json:"api_codes"` + Status string `json:"status"` + Remark string `json:"remark"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } + + AdminQueryWhitelistOpResp { + TianyuanCode int `json:"tianyuan_code"` // 天远业务码 + TianyuanMessage string `json:"tianyuan_message"` // 天远返回描述 + TransactionId string `json:"transaction_id,optional"` // 天远流水号 + Entry *AdminQueryWhitelistEntryItem `json:"entry,optional"` // 成功时规则详情 + } + + AdminQueryWhitelistOpLogListReq { + Page int64 `form:"page,default=1"` + PageSize int64 `form:"page_size,default=20"` + IdCard *string `form:"id_card,optional"` // 身份证号 + Action *string `form:"action,optional"` // create / append + TianyuanCode *int64 `form:"tianyuan_code,optional"` // 天远业务码,0=成功 + } + + AdminQueryWhitelistOpLogItem { + Id string `json:"id"` + AdminUserId string `json:"admin_user_id"` + AdminUserName string `json:"admin_user_name"` + Action string `json:"action"` + Name string `json:"name"` + IdCard string `json:"id_card"` + IdCardMasked string `json:"id_card_masked"` + ApiCodes []string `json:"api_codes"` + Remark string `json:"remark"` + TianyuanCode int `json:"tianyuan_code"` + TianyuanMessage string `json:"tianyuan_message"` + TransactionId string `json:"transaction_id"` + EntryId string `json:"entry_id"` + EntryStatus string `json:"entry_status"` + EntryApiCodes []string `json:"entry_api_codes"` + CreateTime string `json:"create_time"` + } + + AdminQueryWhitelistOpLogListResp { + Total int64 `json:"total"` + Items []AdminQueryWhitelistOpLogItem `json:"items"` + } +) diff --git a/app/main/api/desc/main.api b/app/main/api/desc/main.api index 3d72214..dd15817 100644 --- a/app/main/api/desc/main.api +++ b/app/main/api/desc/main.api @@ -31,6 +31,4 @@ import "./admin/admin_query.api" import "./admin/admin_agent.api" import "./admin/admin_api.api" import "./admin/admin_role_api.api" - - - +import "./admin/admin_query_whitelist.api" diff --git a/app/main/api/etc/main.dev.yaml b/app/main/api/etc/main.dev.yaml index e42dafe..2f208fc 100644 --- a/app/main/api/etc/main.dev.yaml +++ b/app/main/api/etc/main.dev.yaml @@ -103,6 +103,7 @@ Tianyuanapi: Key: "04c6b4c559be6d5ba5351c04c8713a64" BaseURL: "https://api.tianyuanapi.com" Timeout: 60 + WhitelistMgmtKey: "2R12TmEc1e8P3p69RdIoN5Ykjk%H@4orPy7DZv7MXpGByoEL" tianxingjuhe: url: "https://apis.tianapi.com" key: "4ceffb1ffb95b83230b9a9c9df2467e1" diff --git a/app/main/api/etc/main.yaml b/app/main/api/etc/main.yaml index 3fb17b4..1a80da4 100644 --- a/app/main/api/etc/main.yaml +++ b/app/main/api/etc/main.yaml @@ -85,6 +85,7 @@ Tianyuanapi: Key: "04c6b4c559be6d5ba5351c04c8713a64" BaseURL: "https://api.tianyuanapi.com" Timeout: 60 + WhitelistMgmtKey: "2R12TmEc1e8P3p69RdIoN5Ykjk%H@4orPy7DZv7MXpGByoEL" tianxingjuhe: url: "https://apis.tianapi.com" key: "4ceffb1ffb95b83230b9a9c9df2467e1" diff --git a/app/main/api/internal/config/config.go b/app/main/api/internal/config/config.go index b767524..b1d1a2f 100644 --- a/app/main/api/internal/config/config.go +++ b/app/main/api/internal/config/config.go @@ -123,10 +123,11 @@ type TaxConfig struct { TaxExemptionAmount float64 } type TianyuanapiConfig struct { - AccessID string - Key string - BaseURL string - Timeout int64 + AccessID string + Key string + BaseURL string + Timeout int64 + WhitelistMgmtKey string } type AuthorizationConfig struct { diff --git a/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistappendhandler.go b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistappendhandler.go new file mode 100644 index 0000000..8709a51 --- /dev/null +++ b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistappendhandler.go @@ -0,0 +1,29 @@ +package admin_query_whitelist + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/admin_query_whitelist" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func AdminQueryWhitelistAppendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.AdminQueryWhitelistAppendReq + 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_whitelist.NewAdminQueryWhitelistAppendLogic(r.Context(), svcCtx) + resp, err := l.AdminQueryWhitelistAppend(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistcreatehandler.go b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistcreatehandler.go new file mode 100644 index 0000000..eddfadc --- /dev/null +++ b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistcreatehandler.go @@ -0,0 +1,29 @@ +package admin_query_whitelist + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/admin_query_whitelist" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func AdminQueryWhitelistCreateHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.AdminQueryWhitelistCreateReq + 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_whitelist.NewAdminQueryWhitelistCreateLogic(r.Context(), svcCtx) + resp, err := l.AdminQueryWhitelistCreate(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistoploglisthandler.go b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistoploglisthandler.go new file mode 100644 index 0000000..4faa393 --- /dev/null +++ b/app/main/api/internal/handler/admin_query_whitelist/adminquerywhitelistoploglisthandler.go @@ -0,0 +1,29 @@ +package admin_query_whitelist + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/admin_query_whitelist" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func AdminQueryWhitelistOpLogListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.AdminQueryWhitelistOpLogListReq + 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_whitelist.NewAdminQueryWhitelistOpLogListLogic(r.Context(), svcCtx) + resp, err := l.AdminQueryWhitelistOpLogList(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index a67dc75..a7c83df 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -15,6 +15,7 @@ import ( admin_platform_user "qnc-server/app/main/api/internal/handler/admin_platform_user" admin_product "qnc-server/app/main/api/internal/handler/admin_product" admin_query "qnc-server/app/main/api/internal/handler/admin_query" + admin_query_whitelist "qnc-server/app/main/api/internal/handler/admin_query_whitelist" admin_role "qnc-server/app/main/api/internal/handler/admin_role" admin_role_api "qnc-server/app/main/api/internal/handler/admin_role_api" admin_user "qnc-server/app/main/api/internal/handler/admin_user" @@ -368,18 +369,18 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/retry-agent-process/:id", Handler: admin_order.AdminRetryAgentProcessHandler(serverCtx), }, - { - // xpay补发货(查微信单并到账) - Method: http.MethodPost, - Path: "/xpay-deliver/:id", - Handler: admin_order.AdminXpayDeliverHandler(serverCtx), - }, { // 更新订单 Method: http.MethodPut, Path: "/update/:id", Handler: admin_order.AdminUpdateOrderHandler(serverCtx), }, + { + // xpay补发货(查微信单并到账) + Method: http.MethodPost, + Path: "/xpay-deliver/:id", + Handler: admin_order.AdminXpayDeliverHandler(serverCtx), + }, }..., ), rest.WithPrefix("/api/v1/admin/order"), @@ -508,6 +509,33 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithPrefix("/api/v1/admin/query"), ) + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.AdminAuthInterceptor}, + []rest.Route{ + { + // 追加查询白名单产品编码 + Method: http.MethodPost, + Path: "/append", + Handler: admin_query_whitelist.AdminQueryWhitelistAppendHandler(serverCtx), + }, + { + // 创建查询白名单规则 + Method: http.MethodPost, + Path: "/create", + Handler: admin_query_whitelist.AdminQueryWhitelistCreateHandler(serverCtx), + }, + { + // 查询白名单操作记录列表 + Method: http.MethodGet, + Path: "/op-log/list", + Handler: admin_query_whitelist.AdminQueryWhitelistOpLogListHandler(serverCtx), + }, + }..., + ), + rest.WithPrefix("/api/v1/admin/query-whitelist"), + ) + server.AddRoutes( rest.WithMiddlewares( []rest.Middleware{serverCtx.AdminAuthInterceptor}, @@ -851,13 +879,13 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, { Method: http.MethodGet, - Path: "/app/version", - Handler: app.GetAppVersionHandler(serverCtx), + Path: "/app/home/dynamic", + Handler: app.GetHomeDynamicDataHandler(serverCtx), }, { Method: http.MethodGet, - Path: "/app/home/dynamic", - Handler: app.GetHomeDynamicDataHandler(serverCtx), + Path: "/app/version", + Handler: app.GetAppVersionHandler(serverCtx), }, { // 心跳检测接口 @@ -945,12 +973,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, { Method: http.MethodGet, - Path: "/pay/xpay/push", - Handler: pay.XpayPushHandler(serverCtx), - }, - { - Method: http.MethodPost, - Path: "/pay/xpay/push", + Path: "/pay/xpay/pushpost/pay/xpay/push", Handler: pay.XpayPushHandler(serverCtx), }, }, diff --git a/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistappendlogic.go b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistappendlogic.go new file mode 100644 index 0000000..e8cf42f --- /dev/null +++ b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistappendlogic.go @@ -0,0 +1,37 @@ +package admin_query_whitelist + +import ( + "context" + + tianyuanapi "qnc-server/app/main/api/internal/service/tianyuanapi_sdk" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type AdminQueryWhitelistAppendLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAdminQueryWhitelistAppendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminQueryWhitelistAppendLogic { + return &AdminQueryWhitelistAppendLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AdminQueryWhitelistAppendLogic) AdminQueryWhitelistAppend(req *types.AdminQueryWhitelistAppendReq) (resp *types.AdminQueryWhitelistOpResp, err error) { + createReq := &types.AdminQueryWhitelistCreateReq{ + Name: req.Name, + IdCard: req.IdCard, + ApiCodes: req.ApiCodes, + Remark: req.Remark, + } + return executeQueryWhitelistOp(l.ctx, l.svcCtx, "append", createReq, func(client *tianyuanapi.Client, payload tianyuanapi.QueryWhitelistRequest) *tianyuanapi.QueryWhitelistResult { + return client.AppendQueryWhitelistEntry(payload) + }) +} diff --git a/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistcreatelogic.go b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistcreatelogic.go new file mode 100644 index 0000000..3e671ab --- /dev/null +++ b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistcreatelogic.go @@ -0,0 +1,31 @@ +package admin_query_whitelist + +import ( + "context" + + tianyuanapi "qnc-server/app/main/api/internal/service/tianyuanapi_sdk" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type AdminQueryWhitelistCreateLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAdminQueryWhitelistCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminQueryWhitelistCreateLogic { + return &AdminQueryWhitelistCreateLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AdminQueryWhitelistCreateLogic) AdminQueryWhitelistCreate(req *types.AdminQueryWhitelistCreateReq) (resp *types.AdminQueryWhitelistOpResp, err error) { + return executeQueryWhitelistOp(l.ctx, l.svcCtx, "create", req, func(client *tianyuanapi.Client, payload tianyuanapi.QueryWhitelistRequest) *tianyuanapi.QueryWhitelistResult { + return client.CreateQueryWhitelistEntry(payload) + }) +} diff --git a/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistoploglistlogic.go b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistoploglistlogic.go new file mode 100644 index 0000000..ebce7e1 --- /dev/null +++ b/app/main/api/internal/logic/admin_query_whitelist/adminquerywhitelistoploglistlogic.go @@ -0,0 +1,75 @@ +package admin_query_whitelist + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/app/main/model" + "qnc-server/common/globalkey" + "qnc-server/common/xerr" + + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/mr" +) + +type AdminQueryWhitelistOpLogListLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAdminQueryWhitelistOpLogListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminQueryWhitelistOpLogListLogic { + return &AdminQueryWhitelistOpLogListLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AdminQueryWhitelistOpLogListLogic) AdminQueryWhitelistOpLogList(req *types.AdminQueryWhitelistOpLogListReq) (resp *types.AdminQueryWhitelistOpLogListResp, err error) { + builder := l.svcCtx.QueryWhitelistOpLogModel.SelectBuilder(). + Where("del_state = ?", globalkey.DelStateNo) + + if req.IdCard != nil && *req.IdCard != "" { + builder = builder.Where("id_card = ?", *req.IdCard) + } + if req.Action != nil && *req.Action != "" { + builder = builder.Where("action = ?", *req.Action) + } + if req.TianyuanCode != nil { + builder = builder.Where("tianyuan_code = ?", *req.TianyuanCode) + } + + var total int64 + var logs []*model.QueryWhitelistOpLog + err = mr.Finish(func() error { + count, countErr := l.svcCtx.QueryWhitelistOpLogModel.FindCount(l.ctx, builder, "id") + if countErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询操作记录总数失败: %v", countErr) + } + total = count + return nil + }, func() error { + list, listErr := l.svcCtx.QueryWhitelistOpLogModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "create_time DESC") + if listErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询操作记录列表失败: %v", listErr) + } + logs = list + return nil + }) + if err != nil { + return nil, err + } + + resp = &types.AdminQueryWhitelistOpLogListResp{ + Total: total, + Items: make([]types.AdminQueryWhitelistOpLogItem, 0, len(logs)), + } + for _, log := range logs { + resp.Items = append(resp.Items, buildOpLogListItem(l.ctx, l.svcCtx, log)) + } + + return resp, nil +} diff --git a/app/main/api/internal/logic/admin_query_whitelist/op_helper.go b/app/main/api/internal/logic/admin_query_whitelist/op_helper.go new file mode 100644 index 0000000..28f0296 --- /dev/null +++ b/app/main/api/internal/logic/admin_query_whitelist/op_helper.go @@ -0,0 +1,141 @@ +package admin_query_whitelist + +import ( + "context" + "database/sql" + "encoding/json" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + tianyuanapi "qnc-server/app/main/api/internal/service/tianyuanapi_sdk" + "qnc-server/app/main/model" + "qnc-server/common/ctxdata" + "qnc-server/common/xerr" + + "github.com/pkg/errors" +) + +func executeQueryWhitelistOp( + ctx context.Context, + svcCtx *svc.ServiceContext, + action string, + req *types.AdminQueryWhitelistCreateReq, + callFn func(client *tianyuanapi.Client, payload tianyuanapi.QueryWhitelistRequest) *tianyuanapi.QueryWhitelistResult, +) (*types.AdminQueryWhitelistOpResp, error) { + adminUserId, err := ctxdata.GetUidFromCtx(ctx) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "获取管理员信息失败: %v", err) + } + + if svcCtx.TianyuanapiClient == nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "天远API客户端未初始化") + } + + name := req.Name + if name == "" { + name = "*" + } + + payload := tianyuanapi.QueryWhitelistRequest{ + Name: name, + IdCard: req.IdCard, + ApiCodes: req.ApiCodes, + Remark: req.Remark, + } + + result := callFn(svcCtx.TianyuanapiClient, payload) + + apiCodesJSON, _ := json.Marshal(req.ApiCodes) + opLog := &model.QueryWhitelistOpLog{ + AdminUserId: adminUserId, + Action: action, + Name: name, + IdCard: req.IdCard, + ApiCodes: string(apiCodesJSON), + TianyuanCode: int64(result.Code), + } + if req.Remark != "" { + opLog.Remark = sql.NullString{String: req.Remark, Valid: true} + } + if result.Message != "" { + opLog.TianyuanMessage = sql.NullString{String: result.Message, Valid: true} + } + if result.TransactionID != "" { + opLog.TransactionId = sql.NullString{String: result.TransactionID, Valid: true} + } + if result.Entry != nil { + opLog.IdCardMasked = sql.NullString{String: result.Entry.IdCardMasked, Valid: result.Entry.IdCardMasked != ""} + opLog.EntryId = sql.NullString{String: result.Entry.Id, Valid: result.Entry.Id != ""} + opLog.EntryStatus = sql.NullString{String: result.Entry.Status, Valid: result.Entry.Status != ""} + if len(result.Entry.ApiCodes) > 0 { + entryApiCodesJSON, _ := json.Marshal(result.Entry.ApiCodes) + opLog.EntryApiCodes = sql.NullString{String: string(entryApiCodesJSON), Valid: true} + } + } + + if _, insertErr := svcCtx.QueryWhitelistOpLogModel.Insert(ctx, nil, opLog); insertErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "保存操作记录失败: %v", insertErr) + } + + resp := &types.AdminQueryWhitelistOpResp{ + TianyuanCode: result.Code, + TianyuanMessage: result.Message, + TransactionId: result.TransactionID, + } + if result.Entry != nil { + resp.Entry = &types.AdminQueryWhitelistEntryItem{ + Id: result.Entry.Id, + Name: result.Entry.Name, + IdCardMasked: result.Entry.IdCardMasked, + ApiCodes: result.Entry.ApiCodes, + Status: result.Entry.Status, + Remark: result.Entry.Remark, + CreatedAt: result.Entry.CreatedAt, + UpdatedAt: result.Entry.UpdatedAt, + } + } + + return resp, nil +} + +func buildOpLogListItem(ctx context.Context, svcCtx *svc.ServiceContext, log *model.QueryWhitelistOpLog) types.AdminQueryWhitelistOpLogItem { + item := types.AdminQueryWhitelistOpLogItem{ + Id: log.Id, + AdminUserId: log.AdminUserId, + Action: log.Action, + Name: log.Name, + IdCard: log.IdCard, + IdCardMasked: log.IdCardMasked.String, + Remark: log.Remark.String, + TianyuanCode: int(log.TianyuanCode), + TianyuanMessage: log.TianyuanMessage.String, + TransactionId: log.TransactionId.String, + EntryId: log.EntryId.String, + EntryStatus: log.EntryStatus.String, + CreateTime: log.CreateTime.Format("2006-01-02 15:04:05"), + } + + if log.ApiCodes != "" { + var apiCodes []string + if json.Unmarshal([]byte(log.ApiCodes), &apiCodes) == nil { + item.ApiCodes = apiCodes + } + } + if log.EntryApiCodes.Valid && log.EntryApiCodes.String != "" { + var entryApiCodes []string + if json.Unmarshal([]byte(log.EntryApiCodes.String), &entryApiCodes) == nil { + item.EntryApiCodes = entryApiCodes + } + } + + if log.AdminUserId != "" { + if adminUser, err := svcCtx.AdminUserModel.FindOne(ctx, log.AdminUserId); err == nil { + item.AdminUserName = adminUser.RealName + if item.AdminUserName == "" { + item.AdminUserName = adminUser.Username + } + } + } + + return item +} diff --git a/app/main/api/internal/service/tianyuanapi_sdk/client.go b/app/main/api/internal/service/tianyuanapi_sdk/client.go index fcbfa74..1c05597 100644 --- a/app/main/api/internal/service/tianyuanapi_sdk/client.go +++ b/app/main/api/internal/service/tianyuanapi_sdk/client.go @@ -58,19 +58,21 @@ type ApiCallOptions struct { // Client 天元API客户端 type Client struct { - accessID string - key string - baseURL string - timeout time.Duration - client *http.Client + accessID string + key string + baseURL string + whitelistMgmtKey string + timeout time.Duration + client *http.Client } // Config 客户端配置 type Config struct { - AccessID string // 访问ID - Key string // AES密钥(16进制) - BaseURL string // API基础URL - Timeout time.Duration // 超时时间 + AccessID string // 访问ID + Key string // AES密钥(16进制) + BaseURL string // API基础URL + WhitelistMgmtKey string // 查询白名单管理密钥 + Timeout time.Duration // 超时时间 } // Request 请求参数 @@ -122,10 +124,11 @@ func NewClient(config Config) (*Client, error) { } return &Client{ - accessID: config.AccessID, - key: config.Key, - baseURL: config.BaseURL, - timeout: config.Timeout, + accessID: config.AccessID, + key: config.Key, + baseURL: config.BaseURL, + whitelistMgmtKey: config.WhitelistMgmtKey, + timeout: config.Timeout, client: &http.Client{ Timeout: config.Timeout, }, diff --git a/app/main/api/internal/service/tianyuanapi_sdk/query_whitelist.go b/app/main/api/internal/service/tianyuanapi_sdk/query_whitelist.go new file mode 100644 index 0000000..1021aa0 --- /dev/null +++ b/app/main/api/internal/service/tianyuanapi_sdk/query_whitelist.go @@ -0,0 +1,148 @@ +package tianyuanapi + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// QueryWhitelistRequest 查询白名单请求参数(加密前明文) +type QueryWhitelistRequest struct { + Name string `json:"name"` + IdCard string `json:"id_card"` + ApiCodes []string `json:"api_codes"` + Remark string `json:"remark,omitempty"` +} + +// QueryWhitelistEntry 查询白名单规则(解密后 data) +type QueryWhitelistEntry struct { + Id string `json:"id"` + Name string `json:"name"` + IdCardMasked string `json:"id_card_masked"` + ApiCodes []string `json:"api_codes"` + Status string `json:"status"` + Remark string `json:"remark"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +// QueryWhitelistResult 查询白名单接口调用结果(保留天远原始业务码) +type QueryWhitelistResult struct { + Code int `json:"code"` + Message string `json:"message"` + TransactionID string `json:"transaction_id"` + Entry *QueryWhitelistEntry `json:"entry,omitempty"` + RequestError string `json:"request_error,omitempty"` +} + +// CreateQueryWhitelistEntry 创建查询白名单规则 +func (c *Client) CreateQueryWhitelistEntry(req QueryWhitelistRequest) *QueryWhitelistResult { + return c.callQueryWhitelist("query-whitelist/entries", req) +} + +// AppendQueryWhitelistEntry 向已有规则追加产品编码 +func (c *Client) AppendQueryWhitelistEntry(req QueryWhitelistRequest) *QueryWhitelistResult { + return c.callQueryWhitelist("query-whitelist/entries/append", req) +} + +func (c *Client) callQueryWhitelist(path string, payload QueryWhitelistRequest) *QueryWhitelistResult { + if c.whitelistMgmtKey == "" { + return &QueryWhitelistResult{ + Code: 1010, + Message: "缺少管理密钥", + } + } + + jsonData, err := json.Marshal(payload) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("参数序列化失败: %v", err), + } + } + + encryptedData, err := c.encrypt(string(jsonData)) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("数据加密失败: %v", err), + } + } + + requestBody := map[string]interface{}{ + "data": encryptedData, + } + requestBodyBytes, err := json.Marshal(requestBody) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("请求体序列化失败: %v", err), + } + } + + url := fmt.Sprintf("%s/api/v1/%s", c.baseURL, path) + httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBodyBytes)) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("创建HTTP请求失败: %v", err), + } + } + + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set("Access-Id", c.accessID) + httpReq.Header.Set("Whitelist-Mgmt-Key", c.whitelistMgmtKey) + httpReq.Header.Set("User-Agent", "TianyuanAPI-Go-SDK/1.0.0") + + resp, err := c.client.Do(httpReq) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: err.Error(), + } + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("读取响应失败: %v", err), + } + } + + var apiResp ApiResponse + if err := json.Unmarshal(body, &apiResp); err != nil { + return &QueryWhitelistResult{ + Code: 1001, + Message: "接口异常", + RequestError: fmt.Sprintf("响应解析失败: %v", err), + } + } + + result := &QueryWhitelistResult{ + Code: apiResp.Code, + Message: apiResp.Message, + TransactionID: apiResp.TransactionID, + } + + if apiResp.Data != "" { + decryptedData, err := c.decrypt(apiResp.Data) + if err == nil { + var entry QueryWhitelistEntry + if json.Unmarshal([]byte(decryptedData), &entry) == nil { + result.Entry = &entry + } + } + } + + return result +} diff --git a/app/main/api/internal/svc/servicecontext.go b/app/main/api/internal/svc/servicecontext.go index 03223cd..aff0f09 100644 --- a/app/main/api/internal/svc/servicecontext.go +++ b/app/main/api/internal/svc/servicecontext.go @@ -83,9 +83,11 @@ type ServiceContext struct { GlobalNotificationsModel model.GlobalNotificationsModel AuthorizationDocumentModel model.AuthorizationDocumentModel InquiryRecordModel model.InquiryRecordModel + QueryWhitelistOpLogModel model.QueryWhitelistOpLogModel // 第三方服务 TianyuanapiCallLogService *service.TianyuanapiCallLogService + TianyuanapiClient *tianyuanapi.Client // 服务 AlipayService *service.AliPayService @@ -175,14 +177,16 @@ func NewServiceContext(c config.Config) *ServiceContext { globalNotificationsModel := model.NewGlobalNotificationsModel(db, cacheConf) authorizationDocumentModel := model.NewAuthorizationDocumentModel(db, cacheConf) inquiryRecordModel := model.NewInquiryRecordModel(db, cacheConf) + queryWhitelistOpLogModel := model.NewQueryWhitelistOpLogModel(db, cacheConf) tianyuanapiCallLogModel := model.NewTianyuanapiCallLogModel(db, cacheConf) // ============================== 第三方服务初始化 ============================== tianyuanapi, err := tianyuanapi.NewClient(tianyuanapi.Config{ - AccessID: c.Tianyuanapi.AccessID, - Key: c.Tianyuanapi.Key, - BaseURL: c.Tianyuanapi.BaseURL, - Timeout: time.Duration(c.Tianyuanapi.Timeout) * time.Second, + AccessID: c.Tianyuanapi.AccessID, + Key: c.Tianyuanapi.Key, + BaseURL: c.Tianyuanapi.BaseURL, + WhitelistMgmtKey: c.Tianyuanapi.WhitelistMgmtKey, + Timeout: time.Duration(c.Tianyuanapi.Timeout) * time.Second, }) if err != nil { logx.Errorf("初始化天远API失败: %+v", err) @@ -302,9 +306,11 @@ func NewServiceContext(c config.Config) *ServiceContext { GlobalNotificationsModel: globalNotificationsModel, AuthorizationDocumentModel: authorizationDocumentModel, InquiryRecordModel: inquiryRecordModel, + QueryWhitelistOpLogModel: queryWhitelistOpLogModel, // 第三方服务 TianyuanapiCallLogService: tianyuanapiCallLogService, + TianyuanapiClient: tianyuanapi, // 服务 AlipayService: alipayService, diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index 99d4076..82e7afa 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -230,6 +230,10 @@ type AdminGenerateDiamondInviteCodeResp struct { Codes []string `json:"codes"` // 生成的邀请码列表 } +type AdminGenerateQueryShareLinkReq struct { + OrderId string `json:"order_id"` +} + type AdminGetAgentCommissionListReq struct { Page int64 `form:"page"` // 页码 PageSize int64 `form:"pageSize"` // 每页数量 @@ -676,10 +680,6 @@ type AdminGetQueryDetailByOrderIdReq struct { OrderId string `path:"order_id"` } -type AdminGenerateQueryShareLinkReq struct { - OrderId string `json:"order_id"` -} - type AdminGetQueryDetailByOrderIdResp struct { Id string `json:"id"` // 主键ID OrderId string `json:"order_id"` // 订单ID @@ -776,6 +776,70 @@ type AdminQueryItem struct { Data interface{} `json:"data"` // 这里可以是 map 或 具体的 struct } +type AdminQueryWhitelistAppendReq struct { + Name string `json:"name"` // 姓名,* 表示仅按身份证匹配 + IdCard string `json:"id_card"` // 身份证号 + ApiCodes []string `json:"api_codes"` // 产品编码列表 + Remark string `json:"remark,optional"` // 备注 +} + +type AdminQueryWhitelistCreateReq struct { + Name string `json:"name"` // 姓名,* 表示仅按身份证匹配 + IdCard string `json:"id_card"` // 身份证号 + ApiCodes []string `json:"api_codes"` // 产品编码列表 + Remark string `json:"remark,optional"` // 备注 +} + +type AdminQueryWhitelistEntryItem struct { + Id string `json:"id"` + Name string `json:"name"` + IdCardMasked string `json:"id_card_masked"` + ApiCodes []string `json:"api_codes"` + Status string `json:"status"` + Remark string `json:"remark"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type AdminQueryWhitelistOpLogItem struct { + Id string `json:"id"` + AdminUserId string `json:"admin_user_id"` + AdminUserName string `json:"admin_user_name"` + Action string `json:"action"` + Name string `json:"name"` + IdCard string `json:"id_card"` + IdCardMasked string `json:"id_card_masked"` + ApiCodes []string `json:"api_codes"` + Remark string `json:"remark"` + TianyuanCode int `json:"tianyuan_code"` + TianyuanMessage string `json:"tianyuan_message"` + TransactionId string `json:"transaction_id"` + EntryId string `json:"entry_id"` + EntryStatus string `json:"entry_status"` + EntryApiCodes []string `json:"entry_api_codes"` + CreateTime string `json:"create_time"` +} + +type AdminQueryWhitelistOpLogListReq struct { + Page int64 `form:"page,default=1"` + PageSize int64 `form:"page_size,default=20"` + IdCard *string `form:"id_card,optional"` // 身份证号 + Action *string `form:"action,optional"` // create / append + TianyuanCode *int64 `form:"tianyuan_code,optional"` // 天远业务码,0=成功 +} + +type AdminQueryWhitelistOpLogListResp struct { + Total int64 `json:"total"` + Items []AdminQueryWhitelistOpLogItem `json:"items"` +} + +type AdminQueryWhitelistOpResp struct { + TianyuanCode int `json:"tianyuan_code"` // 天远业务码 + TianyuanMessage string `json:"tianyuan_message"` // 天远返回描述 + TransactionId string `json:"transaction_id,optional"` // 天远流水号 + Entry *AdminQueryWhitelistEntryItem `json:"entry,optional"` // 成功时规则详情 +} + type AdminRefundOrderReq struct { Id string `path:"id"` // 订单ID RefundAmount float64 `json:"refund_amount"` // 退款金额 @@ -816,18 +880,6 @@ type AdminRetryAgentProcessResp struct { ProcessedAt string `json:"processed_at"` // 处理时间 } -type AdminXpayDeliverReq struct { - Id string `path:"id"` // 订单ID -} - -type AdminXpayDeliverResp struct { - Credited bool `json:"credited"` - Notified bool `json:"notified"` - WechatDetail string `json:"wechat_detail"` - Errors []string `json:"errors"` - Message string `json:"message"` -} - type AdminRevenueStatistics struct { TodayAmount float64 `json:"today_amount"` // 今日营收 MonthAmount float64 `json:"month_amount"` // 当月营收 @@ -1034,6 +1086,18 @@ type AdminUserListItem struct { RoleIds []string `json:"role_ids"` // 关联的角色ID列表 } +type AdminXpayDeliverReq struct { + Id string `path:"id"` // 订单ID +} + +type AdminXpayDeliverResp struct { + Credited bool `json:"credited"` + Notified bool `json:"notified"` + WechatDetail string `json:"wechat_detail"` + Errors []string `json:"errors"` + Message string `json:"message"` +} + type AgentApplyReq struct { Region string `json:"region,optional"` Mobile string `json:"mobile"` @@ -1764,6 +1828,13 @@ type IapCallbackReq struct { TransactionReceipt string `json:"transaction_receipt" validate:"required"` } +type InquiryRecordItem struct { + Id int64 `json:"id"` + Tag string `json:"tag"` + Vin string `json:"vin"` + Model string `json:"model"` +} + type InviteCodeItem struct { Id string `json:"id"` // 记录ID Code string `json:"code"` // 邀请码 @@ -1935,25 +2006,6 @@ type PaymentCheckResp struct { WxOrderDetail string `json:"wx_order_detail,optional"` // query_order 原始 order 摘要(排查用) } -type XpayClientEventReq struct { - OrderNo string `json:"order_no,optional"` - Stage string `json:"stage" validate:"required"` // prepay_ok, invoke, success, fail, check - EventType string `json:"event_type" validate:"required,oneof=info tip fail success"` - Message string `json:"message,optional"` // 微信/Apple 展示给用户的话术 - ErrMsg string `json:"err_msg,optional"` - ErrCode int `json:"err_code,optional"` - Errno int `json:"errno,optional"` - SignData string `json:"sign_data,optional"` - Device string `json:"device,optional"` - Extra string `json:"extra,optional"` -} - -type XpayClientEventResp struct { - WxOrderStatus int `json:"wx_order_status,optional"` - WxOrderDetail string `json:"wx_order_detail,optional"` - WxSyncError string `json:"wx_sync_error,optional"` -} - type PaymentReq struct { Id string `json:"id"` PayMethod string `json:"pay_method"` // 支付方式: wechat, alipay, appleiap, test(仅开发环境), test_empty(仅开发环境-空报告模式) @@ -2226,6 +2278,11 @@ type RegisterByInviteCodeResp struct { AgentCode int64 `json:"agent_code"` } +type ReviewItem struct { + Name string `json:"name"` + Content string `json:"content"` +} + type RoleListItem struct { Id string `json:"id"` // 角色ID RoleName string `json:"role_name"` // 角色名称 @@ -2460,6 +2517,25 @@ type WithdrawalItem struct { CreateTime string `json:"create_time"` // 创建时间 } +type XpayClientEventReq struct { + OrderNo string `json:"order_no,optional"` + Stage string `json:"stage" validate:"required"` // prepay_ok, invoke, success, fail, check + EventType string `json:"event_type" validate:"required,oneof=info tip fail success"` + Message string `json:"message,optional"` // 微信/Apple 展示给用户的话术(非 HTTP 报错) + ErrMsg string `json:"err_msg,optional"` + ErrCode int `json:"err_code,optional"` + Errno int `json:"errno,optional"` + SignData string `json:"sign_data,optional"` + Device string `json:"device,optional"` + Extra string `json:"extra,optional"` +} + +type XpayClientEventResp struct { + WxOrderStatus int `json:"wx_order_status,optional"` + WxOrderDetail string `json:"wx_order_detail,optional"` + WxSyncError string `json:"wx_sync_error,optional"` +} + type GetAppConfigResp struct { QueryRetentionDays int64 `json:"query_retention_days"` } @@ -2469,29 +2545,17 @@ type GetAppVersionResp struct { WgtUrl string `json:"wgtUrl"` } -type SendSmsReq struct { - Mobile string `json:"mobile" validate:"required,mobile"` - ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"` - CaptchaVerifyParam string `json:"captchaVerifyParam,optional"` -} - type GetHomeDynamicDataReq struct { LastId int64 `form:"lastId,optional"` } -type InquiryRecordItem struct { - Id int64 `json:"id"` - Tag string `json:"tag"` - Vin string `json:"vin"` - Model string `json:"model"` -} - -type ReviewItem struct { - Name string `json:"name"` - Content string `json:"content"` -} - type GetHomeDynamicDataResp struct { Cases []InquiryRecordItem `json:"cases"` Reviews []ReviewItem `json:"reviews"` } + +type SendSmsReq struct { + Mobile string `json:"mobile" validate:"required,mobile"` + ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"` + CaptchaVerifyParam string `json:"captchaVerifyParam,optional"` +} diff --git a/app/main/model/queryWhitelistOpLogModel.go b/app/main/model/queryWhitelistOpLogModel.go new file mode 100644 index 0000000..992256d --- /dev/null +++ b/app/main/model/queryWhitelistOpLogModel.go @@ -0,0 +1,27 @@ +package model + +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ QueryWhitelistOpLogModel = (*customQueryWhitelistOpLogModel)(nil) + +type ( + // QueryWhitelistOpLogModel is an interface to be customized, add more methods here, + // and implement the added methods in customQueryWhitelistOpLogModel. + QueryWhitelistOpLogModel interface { + queryWhitelistOpLogModel + } + + customQueryWhitelistOpLogModel struct { + *defaultQueryWhitelistOpLogModel + } +) + +// NewQueryWhitelistOpLogModel returns a model for the database table. +func NewQueryWhitelistOpLogModel(conn sqlx.SqlConn, c cache.CacheConf) QueryWhitelistOpLogModel { + return &customQueryWhitelistOpLogModel{ + defaultQueryWhitelistOpLogModel: newQueryWhitelistOpLogModel(conn, c), + } +} diff --git a/app/main/model/queryWhitelistOpLogModel_gen.go b/app/main/model/queryWhitelistOpLogModel_gen.go new file mode 100644 index 0000000..c80102b --- /dev/null +++ b/app/main/model/queryWhitelistOpLogModel_gen.go @@ -0,0 +1,398 @@ +// Code generated by goctl. DO NOT EDIT! + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "reflect" + "time" + + "github.com/Masterminds/squirrel" + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + "qnc-server/common/globalkey" +) + +var ( + queryWhitelistOpLogFieldNames = builder.RawFieldNames(&QueryWhitelistOpLog{}) + queryWhitelistOpLogRows = strings.Join(queryWhitelistOpLogFieldNames, ",") + queryWhitelistOpLogRowsExpectAutoSet = strings.Join(stringx.Remove(queryWhitelistOpLogFieldNames, "`create_time`", "`update_time`"), ",") + queryWhitelistOpLogRowsWithPlaceHolder = strings.Join(stringx.Remove(queryWhitelistOpLogFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" + + cacheQueryWhitelistOpLogIdPrefix = "cache:queryWhitelistOpLog:id:" +) + +type ( + queryWhitelistOpLogModel interface { + Insert(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) (sql.Result, error) + FindOne(ctx context.Context, id string) (*QueryWhitelistOpLog, error) + Update(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) (sql.Result, error) + UpdateWithVersion(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) error + Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error + SelectBuilder() squirrel.SelectBuilder + DeleteSoft(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) error + FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error) + FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error) + FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*QueryWhitelistOpLog, error) + FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryWhitelistOpLog, error) + FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryWhitelistOpLog, int64, error) + FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*QueryWhitelistOpLog, error) + FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*QueryWhitelistOpLog, error) + Delete(ctx context.Context, session sqlx.Session, id string) error + } + + defaultQueryWhitelistOpLogModel struct { + sqlc.CachedConn + table string + } + + QueryWhitelistOpLog struct { + Id string `db:"id"` // UUID主键 + CreateTime time.Time `db:"create_time"` // 创建时间 + UpdateTime time.Time `db:"update_time"` // 更新时间 + DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 + DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除 + Version int64 `db:"version"` // 版本号(乐观锁) + AdminUserId string `db:"admin_user_id"` // 操作管理员ID + Action string `db:"action"` // 操作类型:create=创建规则,append=追加接口 + Name string `db:"name"` // 姓名规则 + IdCard string `db:"id_card"` // 身份证号(明文,供后台审计) + IdCardMasked sql.NullString `db:"id_card_masked"` // 天远返回的脱敏身份证号 + ApiCodes string `db:"api_codes"` // 本次提交的产品编码(JSON数组) + Remark sql.NullString `db:"remark"` // 备注 + TianyuanCode int64 `db:"tianyuan_code"` // 天远 API 业务码 + TianyuanMessage sql.NullString `db:"tianyuan_message"` // 天远 API 返回描述 + TransactionId sql.NullString `db:"transaction_id"` // 天远 API 流水号 + EntryId sql.NullString `db:"entry_id"` // 天远规则ID(成功时) + EntryStatus sql.NullString `db:"entry_status"` // 规则状态(成功时) + EntryApiCodes sql.NullString `db:"entry_api_codes"` // 规则当前产品编码列表(JSON数组,成功时) + } +) + +func newQueryWhitelistOpLogModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultQueryWhitelistOpLogModel { + return &defaultQueryWhitelistOpLogModel{ + CachedConn: sqlc.NewConn(conn, c), + table: "`query_whitelist_op_log`", + } +} + +func (m *defaultQueryWhitelistOpLogModel) Insert(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) (sql.Result, error) { + data.DelState = globalkey.DelStateNo + m.insertUUID(data) + queryWhitelistOpLogIdKey := fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, data.Id) + 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, queryWhitelistOpLogRowsExpectAutoSet) + if session != nil { + return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes) + } + return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes) + }, queryWhitelistOpLogIdKey) +} +func (m *defaultQueryWhitelistOpLogModel) insertUUID(data *QueryWhitelistOpLog) { + t := reflect.TypeOf(data).Elem() + v := reflect.ValueOf(data).Elem() + for i := 0; i < t.NumField(); i++ { + sf := t.Field(i) + if sf.Tag.Get("db") == "id" { + f := v.Field(i) + if f.IsValid() && f.CanSet() && f.Kind() == reflect.String { + if f.String() == "" { + f.SetString(uuid.NewString()) + } + } + break + } + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindOne(ctx context.Context, id string) (*QueryWhitelistOpLog, error) { + queryWhitelistOpLogIdKey := fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, id) + var resp QueryWhitelistOpLog + err := m.QueryRowCtx(ctx, &resp, queryWhitelistOpLogIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", queryWhitelistOpLogRows, m.table) + return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo) + }) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) Update(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) (sql.Result, error) { + queryWhitelistOpLogIdKey := fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, data.Id) + 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, queryWhitelistOpLogRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes, data.Id) + } + return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes, data.Id) + }, queryWhitelistOpLogIdKey) +} + +func (m *defaultQueryWhitelistOpLogModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) error { + + oldVersion := data.Version + data.Version += 1 + + var sqlResult sql.Result + var err error + + queryWhitelistOpLogIdKey := fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, data.Id) + 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, queryWhitelistOpLogRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes, data.Id, oldVersion) + } + return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.AdminUserId, data.Action, data.Name, data.IdCard, data.IdCardMasked, data.ApiCodes, data.Remark, data.TianyuanCode, data.TianyuanMessage, data.TransactionId, data.EntryId, data.EntryStatus, data.EntryApiCodes, data.Id, oldVersion) + }, queryWhitelistOpLogIdKey) + if err != nil { + return err + } + updateCount, err := sqlResult.RowsAffected() + if err != nil { + return err + } + if updateCount == 0 { + return ErrNoRowsUpdate + } + + return nil +} + +func (m *defaultQueryWhitelistOpLogModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *QueryWhitelistOpLog) error { + data.DelState = globalkey.DelStateYes + data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true} + if err := m.UpdateWithVersion(ctx, session, data); err != nil { + return errors.Wrapf(errors.New("delete soft failed "), "QueryWhitelistOpLogModel delete err : %+v", err) + } + return nil +} + +func (m *defaultQueryWhitelistOpLogModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field") + } + + builder = builder.Columns("IFNULL(SUM(" + field + "),0)") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp float64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field") + } + + builder = builder.Columns("COUNT(" + field + ")") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp int64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*QueryWhitelistOpLog, error) { + + builder = builder.Columns(queryWhitelistOpLogRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryWhitelistOpLog + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryWhitelistOpLog, error) { + + builder = builder.Columns(queryWhitelistOpLogRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryWhitelistOpLog + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryWhitelistOpLog, int64, error) { + + total, err := m.FindCount(ctx, builder, "id") + if err != nil { + return nil, 0, err + } + + builder = builder.Columns(queryWhitelistOpLogRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, total, err + } + + var resp []*QueryWhitelistOpLog + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, total, nil + default: + return nil, total, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*QueryWhitelistOpLog, error) { + + builder = builder.Columns(queryWhitelistOpLogRows) + + if preMinId > 0 { + builder = builder.Where(" id < ? ", preMinId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryWhitelistOpLog + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*QueryWhitelistOpLog, error) { + + builder = builder.Columns(queryWhitelistOpLogRows) + + if preMaxId > 0 { + builder = builder.Where(" id > ? ", preMaxId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryWhitelistOpLog + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryWhitelistOpLogModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error { + + return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error { + return fn(ctx, session) + }) + +} + +func (m *defaultQueryWhitelistOpLogModel) SelectBuilder() squirrel.SelectBuilder { + return squirrel.Select().From(m.table) +} +func (m *defaultQueryWhitelistOpLogModel) Delete(ctx context.Context, session sqlx.Session, id string) error { + queryWhitelistOpLogIdKey := fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, id) + _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + if session != nil { + return session.ExecCtx(ctx, query, id) + } + return conn.ExecCtx(ctx, query, id) + }, queryWhitelistOpLogIdKey) + return err +} +func (m *defaultQueryWhitelistOpLogModel) formatPrimary(primary interface{}) string { + return fmt.Sprintf("%s%v", cacheQueryWhitelistOpLogIdPrefix, primary) +} +func (m *defaultQueryWhitelistOpLogModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", queryWhitelistOpLogRows, m.table) + return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo) +} + +func (m *defaultQueryWhitelistOpLogModel) tableName() string { + return m.table +} diff --git a/deploy/sql/query_whitelist_migration.sql b/deploy/sql/query_whitelist_migration.sql new file mode 100644 index 0000000..bdb6e0c --- /dev/null +++ b/deploy/sql/query_whitelist_migration.sql @@ -0,0 +1,118 @@ +-- ============================================ +-- 查询白名单:操作记录表 + 菜单 + API 权限 +-- 数据库:qnc +-- ============================================ + +-- 1. 创建操作记录表 +CREATE TABLE IF NOT EXISTS `query_whitelist_op_log` ( + `id` CHAR(36) NOT NULL COMMENT 'UUID主键', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `delete_time` datetime DEFAULT NULL COMMENT '删除时间', + `del_state` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态:0=未删除,1=已删除', + `version` bigint NOT NULL DEFAULT '0' COMMENT '版本号(乐观锁)', + + `admin_user_id` CHAR(36) NOT NULL COMMENT '操作管理员ID', + `action` varchar(20) NOT NULL COMMENT '操作类型:create=创建规则,append=追加接口', + `name` varchar(50) NOT NULL DEFAULT '*' COMMENT '姓名规则', + `id_card` varchar(50) NOT NULL COMMENT '身份证号(明文,供后台审计)', + `id_card_masked` varchar(50) DEFAULT NULL COMMENT '天远返回的脱敏身份证号', + `api_codes` varchar(2000) NOT NULL COMMENT '本次提交的产品编码(JSON数组)', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `tianyuan_code` int NOT NULL DEFAULT 0 COMMENT '天远 API 业务码', + `tianyuan_message` varchar(500) DEFAULT NULL COMMENT '天远 API 返回描述', + `transaction_id` varchar(64) DEFAULT NULL COMMENT '天远 API 流水号', + `entry_id` varchar(64) DEFAULT NULL COMMENT '天远规则ID(成功时)', + `entry_status` varchar(20) DEFAULT NULL COMMENT '规则状态(成功时)', + `entry_api_codes` varchar(2000) DEFAULT NULL COMMENT '规则当前产品编码列表(JSON数组,成功时)', + + PRIMARY KEY (`id`), + KEY `idx_admin_user_id` (`admin_user_id`), + KEY `idx_id_card` (`id_card`), + KEY `idx_action` (`action`), + KEY `idx_tianyuan_code` (`tianyuan_code`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='查询白名单操作记录表'; + +-- 2. 菜单:新增「查询白名单」 +INSERT INTO `admin_menu` ( + `id`, `pid`, `name`, `path`, `component`, `redirect`, `meta`, + `status`, `type`, `sort`, `del_state`, `version` +) +SELECT + 'd02e094d-6af8-11f1-bd31-dec53e82fe75', + '48d0e129-a141-4a74-b519-7adc38d22d27', + 'queryWhitelist', + '/product-manage/query-whitelist/list', + '/product-manage/query-whitelist/list', + NULL, + JSON_OBJECT('icon', 'lucide:shield-off', 'title', '查询白名单'), + 1, + 1, + 0, + 0, + 0 +FROM DUAL +WHERE NOT EXISTS ( + SELECT 1 FROM `admin_menu` + WHERE `path` = '/product-manage/query-whitelist/list' AND `del_state` = 0 +); + +-- 3. 给超级管理员授权菜单 +INSERT INTO `admin_role_menu` (`id`, `role_id`, `menu_id`, `del_state`, `version`) +SELECT + UUID(), + '741b7a39-a95d-4b9d-8dc0-84ee664d5fef', + m.`id`, + 0, + 0 +FROM `admin_menu` m +WHERE m.`path` = '/product-manage/query-whitelist/list' + AND m.`del_state` = 0 + AND NOT EXISTS ( + SELECT 1 FROM `admin_role_menu` rm + WHERE rm.`role_id` = '741b7a39-a95d-4b9d-8dc0-84ee664d5fef' + AND rm.`menu_id` = m.`id` + AND rm.`del_state` = 0 + ); + +-- 4. 注册后台 API 权限 +INSERT INTO `admin_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `name`, `code`, `method`, `url`, `status`, `description`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '查询白名单-创建', 'post__api_v1_admin_query-whitelist_create', 'POST', '/api/v1/admin/query-whitelist/create', 1, '创建查询白名单规则' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `admin_api` WHERE `url` = '/api/v1/admin/query-whitelist/create' AND `method` = 'POST' AND `del_state` = 0); + +INSERT INTO `admin_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `name`, `code`, `method`, `url`, `status`, `description`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '查询白名单-追加', 'post__api_v1_admin_query-whitelist_append', 'POST', '/api/v1/admin/query-whitelist/append', 1, '追加查询白名单产品编码' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `admin_api` WHERE `url` = '/api/v1/admin/query-whitelist/append' AND `method` = 'POST' AND `del_state` = 0); + +INSERT INTO `admin_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `name`, `code`, `method`, `url`, `status`, `description`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '查询白名单-操作记录', 'get__api_v1_admin_query-whitelist_op-log_list', 'GET', '/api/v1/admin/query-whitelist/op-log/list', 1, '查询白名单操作记录列表' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `admin_api` WHERE `url` = '/api/v1/admin/query-whitelist/op-log/list' AND `method` = 'GET' AND `del_state` = 0); + +-- 5. 给超级管理员授权 API +INSERT INTO `admin_role_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `role_id`, `api_id`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '741b7a39-a95d-4b9d-8dc0-84ee664d5fef', a.`id` +FROM `admin_api` a +WHERE a.`url` = '/api/v1/admin/query-whitelist/create' AND a.`method` = 'POST' AND a.`del_state` = 0 + AND NOT EXISTS ( + SELECT 1 FROM `admin_role_api` ra + WHERE ra.`role_id` = '741b7a39-a95d-4b9d-8dc0-84ee664d5fef' AND ra.`api_id` = a.`id` AND ra.`del_state` = 0 + ); + +INSERT INTO `admin_role_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `role_id`, `api_id`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '741b7a39-a95d-4b9d-8dc0-84ee664d5fef', a.`id` +FROM `admin_api` a +WHERE a.`url` = '/api/v1/admin/query-whitelist/append' AND a.`method` = 'POST' AND a.`del_state` = 0 + AND NOT EXISTS ( + SELECT 1 FROM `admin_role_api` ra + WHERE ra.`role_id` = '741b7a39-a95d-4b9d-8dc0-84ee664d5fef' AND ra.`api_id` = a.`id` AND ra.`del_state` = 0 + ); + +INSERT INTO `admin_role_api` (`id`, `create_time`, `update_time`, `delete_time`, `del_state`, `version`, `role_id`, `api_id`) +SELECT UUID(), NOW(), NOW(), NULL, 0, 0, '741b7a39-a95d-4b9d-8dc0-84ee664d5fef', a.`id` +FROM `admin_api` a +WHERE a.`url` = '/api/v1/admin/query-whitelist/op-log/list' AND a.`method` = 'GET' AND a.`del_state` = 0 + AND NOT EXISTS ( + SELECT 1 FROM `admin_role_api` ra + WHERE ra.`role_id` = '741b7a39-a95d-4b9d-8dc0-84ee664d5fef' AND ra.`api_id` = a.`id` AND ra.`del_state` = 0 + );