From 228767dba072198bdde501a5da88b7add4c16064 Mon Sep 17 00:00:00 2001 From: Mrxs <18278715334@163.com> Date: Thu, 18 Jun 2026 17:49:30 +0800 Subject: [PATCH] add --- app/main/api/desc/admin/admin_whitelist.api | 103 ++++++++++++++++ app/main/api/desc/main.api | 1 + .../adminbatchcreatewhitelisthandler.go | 29 +++++ .../admincreatewhitelisthandler.go | 29 +++++ .../admindeletewhitelisthandler.go | 29 +++++ .../admingetwhitelistlisthandler.go | 29 +++++ .../adminupdatewhitelisthandler.go | 29 +++++ app/main/api/internal/handler/routes.go | 35 ++++++ .../adminbatchcreatewhitelistlogic.go | 99 ++++++++++++++++ .../admincreatewhitelistlogic.go | 69 +++++++++++ .../admindeletewhitelistlogic.go | 43 +++++++ .../admingetwhitelistlistlogic.go | 111 ++++++++++++++++++ .../adminupdatewhitelistlogic.go | 57 +++++++++ .../whitelist_create_helper.go | 102 ++++++++++++++++ app/main/api/internal/types/types.go | 78 ++++++++++++ deploy/sql/admin_whitelist_menu_migration.sql | 69 +++++++++++ 16 files changed, 912 insertions(+) create mode 100644 app/main/api/desc/admin/admin_whitelist.api create mode 100644 app/main/api/internal/handler/admin_whitelist/adminbatchcreatewhitelisthandler.go create mode 100644 app/main/api/internal/handler/admin_whitelist/admincreatewhitelisthandler.go create mode 100644 app/main/api/internal/handler/admin_whitelist/admindeletewhitelisthandler.go create mode 100644 app/main/api/internal/handler/admin_whitelist/admingetwhitelistlisthandler.go create mode 100644 app/main/api/internal/handler/admin_whitelist/adminupdatewhitelisthandler.go create mode 100644 app/main/api/internal/logic/admin_whitelist/adminbatchcreatewhitelistlogic.go create mode 100644 app/main/api/internal/logic/admin_whitelist/admincreatewhitelistlogic.go create mode 100644 app/main/api/internal/logic/admin_whitelist/admindeletewhitelistlogic.go create mode 100644 app/main/api/internal/logic/admin_whitelist/admingetwhitelistlistlogic.go create mode 100644 app/main/api/internal/logic/admin_whitelist/adminupdatewhitelistlogic.go create mode 100644 app/main/api/internal/logic/admin_whitelist/whitelist_create_helper.go create mode 100644 deploy/sql/admin_whitelist_menu_migration.sql diff --git a/app/main/api/desc/admin/admin_whitelist.api b/app/main/api/desc/admin/admin_whitelist.api new file mode 100644 index 0000000..12402fc --- /dev/null +++ b/app/main/api/desc/admin/admin_whitelist.api @@ -0,0 +1,103 @@ +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"` + } +) diff --git a/app/main/api/desc/main.api b/app/main/api/desc/main.api index d63545b..e349c43 100644 --- a/app/main/api/desc/main.api +++ b/app/main/api/desc/main.api @@ -24,6 +24,7 @@ import "./admin/platform_user.api" import "./admin/notification.api" import "./admin/admin_product.api" import "./admin/admin_feature.api" +import "./admin/admin_whitelist.api" import "./admin/admin_query.api" import "./admin/admin_agent.api" import "./admin/admin_api.api" diff --git a/app/main/api/internal/handler/admin_whitelist/adminbatchcreatewhitelisthandler.go b/app/main/api/internal/handler/admin_whitelist/adminbatchcreatewhitelisthandler.go new file mode 100644 index 0000000..0c93374 --- /dev/null +++ b/app/main/api/internal/handler/admin_whitelist/adminbatchcreatewhitelisthandler.go @@ -0,0 +1,29 @@ +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) + } +} diff --git a/app/main/api/internal/handler/admin_whitelist/admincreatewhitelisthandler.go b/app/main/api/internal/handler/admin_whitelist/admincreatewhitelisthandler.go new file mode 100644 index 0000000..128bd47 --- /dev/null +++ b/app/main/api/internal/handler/admin_whitelist/admincreatewhitelisthandler.go @@ -0,0 +1,29 @@ +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) + } +} diff --git a/app/main/api/internal/handler/admin_whitelist/admindeletewhitelisthandler.go b/app/main/api/internal/handler/admin_whitelist/admindeletewhitelisthandler.go new file mode 100644 index 0000000..6414f7b --- /dev/null +++ b/app/main/api/internal/handler/admin_whitelist/admindeletewhitelisthandler.go @@ -0,0 +1,29 @@ +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) + } +} diff --git a/app/main/api/internal/handler/admin_whitelist/admingetwhitelistlisthandler.go b/app/main/api/internal/handler/admin_whitelist/admingetwhitelistlisthandler.go new file mode 100644 index 0000000..ce67eaf --- /dev/null +++ b/app/main/api/internal/handler/admin_whitelist/admingetwhitelistlisthandler.go @@ -0,0 +1,29 @@ +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) + } +} diff --git a/app/main/api/internal/handler/admin_whitelist/adminupdatewhitelisthandler.go b/app/main/api/internal/handler/admin_whitelist/adminupdatewhitelisthandler.go new file mode 100644 index 0000000..53bf7fe --- /dev/null +++ b/app/main/api/internal/handler/admin_whitelist/adminupdatewhitelisthandler.go @@ -0,0 +1,29 @@ +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) + } +} diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index 62b533c..9c5ceff 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -19,6 +19,7 @@ import ( 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_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" app "ycc-server/app/main/api/internal/handler/app" auth "ycc-server/app/main/api/internal/handler/auth" @@ -653,6 +654,40 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { 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( []rest.Route{ { diff --git a/app/main/api/internal/logic/admin_whitelist/adminbatchcreatewhitelistlogic.go b/app/main/api/internal/logic/admin_whitelist/adminbatchcreatewhitelistlogic.go new file mode 100644 index 0000000..d5b937e --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/adminbatchcreatewhitelistlogic.go @@ -0,0 +1,99 @@ +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 +} diff --git a/app/main/api/internal/logic/admin_whitelist/admincreatewhitelistlogic.go b/app/main/api/internal/logic/admin_whitelist/admincreatewhitelistlogic.go new file mode 100644 index 0000000..66a50ec --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/admincreatewhitelistlogic.go @@ -0,0 +1,69 @@ +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 +} diff --git a/app/main/api/internal/logic/admin_whitelist/admindeletewhitelistlogic.go b/app/main/api/internal/logic/admin_whitelist/admindeletewhitelistlogic.go new file mode 100644 index 0000000..86aae08 --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/admindeletewhitelistlogic.go @@ -0,0 +1,43 @@ +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 +} diff --git a/app/main/api/internal/logic/admin_whitelist/admingetwhitelistlistlogic.go b/app/main/api/internal/logic/admin_whitelist/admingetwhitelistlistlogic.go new file mode 100644 index 0000000..e768d4c --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/admingetwhitelistlistlogic.go @@ -0,0 +1,111 @@ +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 "已失效" +} diff --git a/app/main/api/internal/logic/admin_whitelist/adminupdatewhitelistlogic.go b/app/main/api/internal/logic/admin_whitelist/adminupdatewhitelistlogic.go new file mode 100644 index 0000000..05b00b0 --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/adminupdatewhitelistlogic.go @@ -0,0 +1,57 @@ +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 +} diff --git a/app/main/api/internal/logic/admin_whitelist/whitelist_create_helper.go b/app/main/api/internal/logic/admin_whitelist/whitelist_create_helper.go new file mode 100644 index 0000000..76083ca --- /dev/null +++ b/app/main/api/internal/logic/admin_whitelist/whitelist_create_helper.go @@ -0,0 +1,102 @@ +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 +} diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index ec15f0e..358a53f 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -58,6 +58,28 @@ type AdminAuditWithdrawalResp struct { 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 { Ids []string `json:"ids"` Status int64 `json:"status"` @@ -164,6 +186,17 @@ type AdminCreateUserResp struct { 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 AdminDeleteApiReq struct { Id string `path:"id"` } @@ -230,6 +263,14 @@ type AdminDeleteUserResp struct { Success bool `json:"success"` // 是否成功 } +type AdminDeleteWhitelistReq struct { + Id string `path:"id"` +} + +type AdminDeleteWhitelistResp struct { + Success bool `json:"success"` +} + type AdminDowngradeAgentReq struct { AgentId string `json:"agent_id"` // 代理ID ToLevel int64 `json:"to_level"` // 目标等级:1=普通,2=黄金,3=钻石(须低于当前等级) @@ -754,6 +795,19 @@ type AdminGetUserListResp struct { 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 { Username string `json:"username" validate:"required"` Password string `json:"password" validate:"required"` @@ -1051,6 +1105,16 @@ type AdminUpdateUserResp struct { 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 { } @@ -1069,6 +1133,20 @@ type AdminUserListItem struct { 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 { Region string `json:"region,optional"` Mobile string `json:"mobile"` diff --git a/deploy/sql/admin_whitelist_menu_migration.sql b/deploy/sql/admin_whitelist_menu_migration.sql new file mode 100644 index 0000000..216016a --- /dev/null +++ b/deploy/sql/admin_whitelist_menu_migration.sql @@ -0,0 +1,69 @@ +-- ============================================ +-- 模块白名单 - 后台菜单插入 SQL +-- 数据库:ycc +-- 父菜单:产品管理 (48d0e129-a141-4a74-b519-7adc38d22d27) +-- 超级管理员:741b7a39-a95d-4b9d-8dc0-84ee664d5fef +-- ============================================ + +-- 1. 插入「模块白名单」菜单(已存在则跳过) +INSERT INTO `admin_menu` ( + `id`, `pid`, `name`, `path`, `component`, `redirect`, `meta`, + `status`, `type`, `sort`, `del_state`, `version` +) +SELECT + 'c01e094d-6af8-11f1-bd31-dec53e82fe74', + '48d0e129-a141-4a74-b519-7adc38d22d27', + 'whitelist', + '/product-manage/whitelist/list', + '/product-manage/whitelist/list', + NULL, + JSON_OBJECT('icon', 'lucide:shield-check', 'title', '模块白名单'), + 1, + 1, + 0, + 0, + 0 +FROM DUAL +WHERE NOT EXISTS ( + SELECT 1 FROM `admin_menu` + WHERE `path` = '/product-manage/whitelist/list' AND `del_state` = 0 +); + +-- 2. 给「超级管理员」授权(关键:没有这一步菜单不会显示) +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/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 + ); + +-- 3. 给所有已拥有「模块列表」权限的角色同步授权 +INSERT INTO `admin_role_menu` (`id`, `role_id`, `menu_id`, `del_state`, `version`) +SELECT + UUID(), + arm.`role_id`, + m.`id`, + 0, + 0 +FROM `admin_role_menu` arm +JOIN `admin_menu` m ON m.`path` = '/product-manage/whitelist/list' AND m.`del_state` = 0 +WHERE arm.`menu_id` = '7ef2b1d3-4578-4884-a735-915f60c87e13' + AND arm.`del_state` = 0 + AND NOT EXISTS ( + SELECT 1 FROM `admin_role_menu` x + WHERE x.`role_id` = arm.`role_id` + AND x.`menu_id` = m.`id` + AND x.`del_state` = 0 + ); + +-- 执行后请重新登录管理后台