新增几大中心功能

This commit is contained in:
Administrator
2026-04-23 15:29:07 +08:00
parent 5c2a146a44
commit c6354ee065
123 changed files with 13074 additions and 229 deletions

View File

@@ -2,7 +2,9 @@ package system
import (
"context"
"strings"
"git.echol.cn/loser/Go-Web-Template/server/global"
sysModel "git.echol.cn/loser/Go-Web-Template/server/model/system"
"git.echol.cn/loser/Go-Web-Template/server/service/system"
"github.com/pkg/errors"
@@ -13,9 +15,81 @@ type initApi struct{}
const initOrderApi = system.InitOrderSystem + 1
func registerApiDefaultMeta(entities []sysModel.SysApi) {
if global.GVA_API_DEFAULT_META == nil {
global.GVA_API_DEFAULT_META = make(map[string]struct {
ApiGroup string
Description string
}, len(entities))
}
for _, e := range entities {
key := strings.ToUpper(strings.TrimSpace(e.Method)) + " " + strings.TrimSpace(e.Path)
if _, ok := global.GVA_API_DEFAULT_META[key]; !ok {
global.GVA_API_DEFAULT_META[key] = struct {
ApiGroup string
Description string
}{ApiGroup: e.ApiGroup, Description: e.Description}
}
}
}
// auto run
func init() {
system.RegisterInit(initOrderApi, &initApi{})
// ensure default meta available even when db seed is skipped
if global.GVA_API_DEFAULT_META == nil {
global.GVA_API_DEFAULT_META = make(map[string]struct {
ApiGroup string
Description string
})
}
// 关键:即使跳过 SysApi 灌库,也要能在“同步路由”时预填分组与简介
// 这里只注册“我们新增/扩展过的接口”以及玩家端相关接口,避免 UI 再次手填。
registerApiDefaultMeta([]sysModel.SysApi{
{ApiGroup: "参数管理", Method: "GET", Path: "/sysParams/getChangeLogList", Description: "获取参数变更审计"},
{ApiGroup: "玩家管理", Method: "GET", Path: "/admin/app-users/:id", Description: "获取玩家详情"},
{ApiGroup: "玩家管理", Method: "GET", Path: "/admin/app-users/:id/overview", Description: "获取玩家聚合概览"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/reset-password", Description: "重置玩家密码"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/toggle-enable", Description: "启用/停用玩家"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/recharge", Description: "后台手动充值(账户余额/游戏币)"},
{ApiGroup: "玩家管理", Method: "DELETE", Path: "/admin/app-users/:id", Description: "软删除玩家"},
{ApiGroup: "玩家管理", Method: "PATCH", Path: "/admin/app-users/:id", Description: "编辑玩家(仅启用状态/欢迎词)"},
{ApiGroup: "玩家资产流水", Method: "GET", Path: "/admin/app-asset-transactions", Description: "获取玩家资产流水列表"},
{ApiGroup: "玩家资产流水", Method: "GET", Path: "/admin/app-asset-transactions/:id", Description: "获取玩家资产流水详情"},
{ApiGroup: "提现管理", Method: "GET", Path: "/admin/app-withdraw-orders", Description: "获取提现订单列表"},
{ApiGroup: "提现管理", Method: "GET", Path: "/admin/app-withdraw-orders/:id", Description: "获取提现订单详情"},
{ApiGroup: "提现管理", Method: "POST", Path: "/admin/app-withdraw-orders", Description: "后台创建提现订单(冻结账户余额)"},
{ApiGroup: "提现管理", Method: "POST", Path: "/admin/app-withdraw-orders/:id/approve", Description: "审核通过提现订单"},
{ApiGroup: "提现管理", Method: "POST", Path: "/admin/app-withdraw-orders/:id/reject", Description: "审核拒绝提现订单(解冻)"},
{ApiGroup: "提现管理", Method: "POST", Path: "/admin/app-withdraw-orders/:id/mark-paid", Description: "确认已打款(扣减余额并解冻)"},
{ApiGroup: "提现管理", Method: "POST", Path: "/admin/app-withdraw-orders/:id/mark-failed", Description: "标记打款失败(解冻)"},
{ApiGroup: "风控标签", Method: "GET", Path: "/admin/app-risk-tags", Description: "获取风险标签列表"},
{ApiGroup: "风控标签", Method: "POST", Path: "/admin/app-risk-tags", Description: "创建风险标签"},
{ApiGroup: "风控标签", Method: "PUT", Path: "/admin/app-risk-tags/:id", Description: "更新风险标签"},
{ApiGroup: "风控标签", Method: "DELETE", Path: "/admin/app-risk-tags/:id", Description: "删除风险标签"},
{ApiGroup: "风控标签", Method: "GET", Path: "/admin/app-users/:id/risk-tags", Description: "获取玩家风险标签"},
{ApiGroup: "风控标签", Method: "POST", Path: "/admin/app-users/:id/risk-tags", Description: "给玩家打标"},
{ApiGroup: "风控标签", Method: "DELETE", Path: "/admin/app-user-risk-tags/:id", Description: "移除玩家标签"},
{ApiGroup: "玩家登录日志", Method: "GET", Path: "/admin/app-login-logs", Description: "获取玩家登录日志列表"},
{ApiGroup: "邀请码管理", Method: "GET", Path: "/admin/app-invite-codes/:id", Description: "获取玩家邀请码详情"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/:id/revoke", Description: "作废玩家邀请码"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/issue", Description: "后台代用户生成邀请码"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/clear-unused", Description: "强制清空用户未使用邀请码"},
{ApiGroup: "玩家端-个人中心", Method: "GET", Path: "/app/me", Description: "获取当前玩家信息"},
{ApiGroup: "玩家端-邀请码", Method: "GET", Path: "/app/invite-code/current", Description: "获取当前未使用邀请码"},
{ApiGroup: "玩家端-邀请码", Method: "POST", Path: "/app/invite-code/generate", Description: "生成邀请码"},
{ApiGroup: "玩家端-注册登录", Method: "GET", Path: "/public/app/register/status", Description: "获取注册状态"},
{ApiGroup: "玩家端-注册登录", Method: "POST", Path: "/public/app/register", Description: "玩家注册"},
{ApiGroup: "玩家端-注册登录", Method: "POST", Path: "/public/app/login", Description: "玩家登录"},
})
}
func (i *initApi) InitializerName() string {
@@ -67,17 +141,31 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "系统用户", Method: "POST", Path: "/user/resetPassword", Description: "重置用户密码"},
{ApiGroup: "系统用户", Method: "PUT", Path: "/user/setSelfSetting", Description: "用户界面配置"},
{ApiGroup: "api", Method: "POST", Path: "/api/createApi", Description: "创建api"},
{ApiGroup: "api", Method: "POST", Path: "/api/deleteApi", Description: "删除Api"},
{ApiGroup: "api", Method: "POST", Path: "/api/updateApi", Description: "更新Api"},
{ApiGroup: "api", Method: "POST", Path: "/api/getApiList", Description: "获取api列表"},
{ApiGroup: "api", Method: "POST", Path: "/api/getAllApis", Description: "获取所有api"},
{ApiGroup: "api", Method: "POST", Path: "/api/getApiById", Description: "获取api详细信息"},
{ApiGroup: "api", Method: "DELETE", Path: "/api/deleteApisByIds", Description: "批量删除api"},
{ApiGroup: "api", Method: "GET", Path: "/api/syncApi", Description: "获取待同步API"},
{ApiGroup: "api", Method: "GET", Path: "/api/getApiGroups", Description: "获取路由组"},
{ApiGroup: "api", Method: "POST", Path: "/api/enterSyncApi", Description: "确认同步API"},
{ApiGroup: "api", Method: "POST", Path: "/api/ignoreApi", Description: "忽略API"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/createApi", Description: "创建api"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/deleteApi", Description: "删除Api"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/updateApi", Description: "更新Api"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/getApiList", Description: "获取api列表"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/getAllApis", Description: "获取所有api"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/getApiById", Description: "获取api详细信息"},
{ApiGroup: "API管理", Method: "DELETE", Path: "/api/deleteApisByIds", Description: "批量删除api"},
{ApiGroup: "API管理", Method: "GET", Path: "/api/syncApi", Description: "获取待同步API"},
{ApiGroup: "API管理", Method: "GET", Path: "/api/getApiGroups", Description: "获取路由组"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/enterSyncApi", Description: "确认同步API"},
{ApiGroup: "API管理", Method: "POST", Path: "/api/ignoreApi", Description: "忽略API"},
// 玩家端(登录态)
{ApiGroup: "玩家端-个人中心", Method: "GET", Path: "/app/me", Description: "获取当前玩家信息"},
{ApiGroup: "玩家端-邀请码", Method: "GET", Path: "/app/invite-code/current", Description: "获取当前未使用邀请码"},
{ApiGroup: "玩家端-邀请码", Method: "POST", Path: "/app/invite-code/generate", Description: "生成邀请码"},
// 玩家端(公开:注册/登录)
{ApiGroup: "玩家端-注册登录", Method: "GET", Path: "/public/app/register/status", Description: "获取注册状态"},
{ApiGroup: "玩家端-注册登录", Method: "POST", Path: "/public/app/register", Description: "玩家注册"},
{ApiGroup: "玩家端-注册登录", Method: "POST", Path: "/public/app/login", Description: "玩家登录"},
// 用户前端system/public
{ApiGroup: "用户前端-注册", Method: "GET", Path: "/public/auth/register/status", Description: "获取注册状态"},
{ApiGroup: "用户前端-注册", Method: "POST", Path: "/public/auth/register", Description: "账号注册"},
{ApiGroup: "角色", Method: "POST", Path: "/authority/copyAuthority", Description: "拷贝角色"},
{ApiGroup: "角色", Method: "POST", Path: "/authority/createAuthority", Description: "创建角色"},
@@ -115,6 +203,26 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "系统服务", Method: "POST", Path: "/system/getServerInfo", Description: "获取服务器信息"},
{ApiGroup: "系统服务", Method: "POST", Path: "/system/getSystemConfig", Description: "获取配置文件内容"},
{ApiGroup: "系统服务", Method: "POST", Path: "/system/setSystemConfig", Description: "设置配置文件内容"},
{ApiGroup: "运营大屏", Method: "GET", Path: "/admin/dashboard/stats", Description: "仪表盘统计数据"},
{ApiGroup: "邀请码", Method: "POST", Path: "/user/invite-code/generate", Description: "生成邀请码"},
{ApiGroup: "邀请码", Method: "GET", Path: "/user/invite-code/current", Description: "获取当前未使用邀请码"},
{ApiGroup: "玩家管理", Method: "GET", Path: "/admin/app-users", Description: "获取玩家列表"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users", Description: "手动新增玩家"},
{ApiGroup: "玩家管理", Method: "GET", Path: "/admin/app-users/:id", Description: "获取玩家详情"},
{ApiGroup: "玩家管理", Method: "GET", Path: "/admin/app-users/:id/overview", Description: "获取玩家聚合概览"},
{ApiGroup: "玩家管理", Method: "PATCH", Path: "/admin/app-users/:id", Description: "编辑玩家(仅启用状态/欢迎词)"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/reset-password", Description: "重置玩家密码"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/toggle-enable", Description: "启用/停用玩家"},
{ApiGroup: "玩家管理", Method: "DELETE", Path: "/admin/app-users/:id", Description: "软删除玩家"},
{ApiGroup: "玩家管理", Method: "POST", Path: "/admin/app-users/:id/recharge", Description: "后台手动充值(账户余额/游戏币)"},
{ApiGroup: "玩家资产流水", Method: "GET", Path: "/admin/app-asset-transactions", Description: "获取玩家资产流水列表"},
{ApiGroup: "玩家资产流水", Method: "GET", Path: "/admin/app-asset-transactions/:id", Description: "获取玩家资产流水详情"},
{ApiGroup: "玩家登录日志", Method: "GET", Path: "/admin/app-login-logs", Description: "获取玩家登录日志列表"},
{ApiGroup: "邀请码管理", Method: "GET", Path: "/admin/app-invite-codes", Description: "获取玩家邀请码列表"},
{ApiGroup: "邀请码管理", Method: "GET", Path: "/admin/app-invite-codes/:id", Description: "获取玩家邀请码详情"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/:id/revoke", Description: "作废玩家邀请码"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/issue", Description: "后台代用户生成邀请码"},
{ApiGroup: "邀请码管理", Method: "POST", Path: "/admin/app-invite-codes/clear-unused", Description: "强制清空用户未使用邀请码"},
{ApiGroup: "MCP管理", Method: "GET", Path: "/mcp/status", Description: "获取 MCP 独立服务状态"},
{ApiGroup: "MCP管理", Method: "POST", Path: "/mcp/start", Description: "启动 MCP 独立服务"},
@@ -174,10 +282,27 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "参数管理", Method: "GET", Path: "/sysParams/findSysParams", Description: "根据ID获取参数"},
{ApiGroup: "参数管理", Method: "GET", Path: "/sysParams/getSysParamsList", Description: "获取参数列表"},
{ApiGroup: "参数管理", Method: "GET", Path: "/sysParams/getSysParam", Description: "获取参数列表"},
{ApiGroup: "参数管理", Method: "GET", Path: "/sysParams/getChangeLogList", Description: "获取参数变更审计"},
{ApiGroup: "媒体库分类", Method: "GET", Path: "/attachmentCategory/getCategoryList", Description: "分类列表"},
{ApiGroup: "媒体库分类", Method: "POST", Path: "/attachmentCategory/addCategory", Description: "添加/编辑分类"},
{ApiGroup: "媒体库分类", Method: "POST", Path: "/attachmentCategory/deleteCategory", Description: "删除分类"},
}
// register default meta for SyncApi prefill (best-effort)
if global.GVA_API_DEFAULT_META == nil {
global.GVA_API_DEFAULT_META = make(map[string]struct {
ApiGroup string
Description string
}, len(entities))
}
for _, e := range entities {
key := strings.ToUpper(strings.TrimSpace(e.Method)) + " " + strings.TrimSpace(e.Path)
if _, ok := global.GVA_API_DEFAULT_META[key]; !ok {
global.GVA_API_DEFAULT_META[key] = struct {
ApiGroup string
Description string
}{ApiGroup: e.ApiGroup, Description: e.Description}
}
}
if err := db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, sysModel.SysApi{}.TableName()+"表数据初始化失败!")
}

View File

@@ -117,6 +117,38 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "888", V1: "/system/getSystemConfig", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/system/setSystemConfig", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/system/getServerInfo", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/dashboard/stats", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-users", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-users", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/overview", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id", V2: "PATCH"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/reset-password", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/toggle-enable", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id", V2: "DELETE"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/recharge", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-asset-transactions", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-asset-transactions/:id", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders/:id", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders/:id/approve", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders/:id/reject", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders/:id/mark-paid", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-withdraw-orders/:id/mark-failed", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-risk-tags", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-risk-tags", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-risk-tags/:id", V2: "PUT"},
{Ptype: "p", V0: "888", V1: "/admin/app-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/risk-tags", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-users/:id/risk-tags", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-user-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "888", V1: "/admin/app-login-logs", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-invite-codes", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-invite-codes/:id", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/admin/app-invite-codes/:id/revoke", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-invite-codes/issue", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/admin/app-invite-codes/clear-unused", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/mcp/status", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/mcp/start", V2: "POST"},
@@ -176,6 +208,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "888", V1: "/sysParams/findSysParams", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/sysParams/getSysParamsList", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/sysParams/getSysParam", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/sysParams/getChangeLogList", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/attachmentCategory/getCategoryList", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/attachmentCategory/addCategory", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/attachmentCategory/deleteCategory", V2: "POST"},
@@ -216,6 +249,39 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "8881", V1: "/system/getSystemConfig", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/system/setSystemConfig", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/user/getUserInfo", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/dashboard/stats", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/overview", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id", V2: "PATCH"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/reset-password", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/toggle-enable", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id", V2: "DELETE"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/recharge", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-asset-transactions", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-asset-transactions/:id", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders/:id", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders/:id/approve", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders/:id/reject", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders/:id/mark-paid", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-withdraw-orders/:id/mark-failed", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-risk-tags", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-risk-tags", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-risk-tags/:id", V2: "PUT"},
{Ptype: "p", V0: "8881", V1: "/admin/app-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/risk-tags", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-users/:id/risk-tags", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-user-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "8881", V1: "/admin/app-login-logs", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-invite-codes", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-invite-codes/:id", V2: "GET"},
{Ptype: "p", V0: "8881", V1: "/admin/app-invite-codes/:id/revoke", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-invite-codes/issue", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/admin/app-invite-codes/clear-unused", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/sysParams/getChangeLogList", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/user/admin_register", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/api/createApi", V2: "POST"},
@@ -260,7 +326,42 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "9528", V1: "/mcp/tools", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/mcp/test", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/mcp/createTool", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/user/invite-code/generate", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/user/invite-code/current", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/user/getUserInfo", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/dashboard/stats", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/overview", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id", V2: "PATCH"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/reset-password", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/toggle-enable", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id", V2: "DELETE"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/recharge", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-asset-transactions", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-asset-transactions/:id", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders/:id", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders/:id/approve", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders/:id/reject", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders/:id/mark-paid", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-withdraw-orders/:id/mark-failed", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-risk-tags", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-risk-tags", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-risk-tags/:id", V2: "PUT"},
{Ptype: "p", V0: "9528", V1: "/admin/app-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/risk-tags", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-users/:id/risk-tags", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-user-risk-tags/:id", V2: "DELETE"},
{Ptype: "p", V0: "9528", V1: "/admin/app-login-logs", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-invite-codes", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-invite-codes/:id", V2: "GET"},
{Ptype: "p", V0: "9528", V1: "/admin/app-invite-codes/:id/revoke", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-invite-codes/issue", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/admin/app-invite-codes/clear-unused", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/sysParams/getChangeLogList", V2: "GET"},
}
if err := db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, "Casbin 表 ("+i.InitializerName()+") 数据初始化失败!")

View File

@@ -0,0 +1,223 @@
package system
import (
"context"
. "git.echol.cn/loser/Go-Web-Template/server/model/system"
"git.echol.cn/loser/Go-Web-Template/server/service/system"
"github.com/pkg/errors"
"gorm.io/gorm"
)
// 该 initializer 用于把「菜单 DB 数据」与「前端文件路由」对齐:
// - 按 Name 精准匹配,幂等修正 path/parent/component避免出现“前端显示与实际路由不一致”的别名情况。
// - 若缺少必要父级/子级菜单,则补齐到目标结构。
//
// 注意:它不会删除菜单,只做修正/补齐,避免误伤线上已有配置。
const initOrderMenuRepair = initOrderMenu + 1
type menuRepair struct{}
func init() {
system.RegisterInit(initOrderMenuRepair, &menuRepair{})
}
func (m *menuRepair) InitializerName() string {
return "sys_base_menus_repair"
}
func (m *menuRepair) MigrateTable(ctx context.Context) (context.Context, error) {
// 仅修复数据,不建表
return ctx, nil
}
func (m *menuRepair) TableCreated(ctx context.Context) bool {
// 仅修复数据,不参与建表逻辑
return true
}
func (m *menuRepair) DataInserted(ctx context.Context) bool {
// 每次都允许运行(幂等修复),因此返回 false 以触发 InitializeData
return false
}
type menuSeed struct {
level uint
hidden bool
parentName string // 空表示根节点
path string
name string
component string
sort int
title string
icon string
}
func ensureMenu(tx *gorm.DB, seed menuSeed, parentID uint) (*SysBaseMenu, error) {
var menu SysBaseMenu
err := tx.Where("name = ?", seed.name).First(&menu).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
if errors.Is(err, gorm.ErrRecordNotFound) {
menu = SysBaseMenu{
MenuLevel: seed.level,
ParentId: parentID,
Path: seed.path,
Name: seed.name,
Hidden: seed.hidden,
Component: seed.component,
Sort: seed.sort,
Meta: Meta{
Title: seed.title,
Icon: seed.icon,
},
}
if err := tx.Create(&menu).Error; err != nil {
return nil, err
}
return &menu, nil
}
updates := map[string]any{
"menu_level": seed.level,
"parent_id": parentID,
"path": seed.path,
"component": seed.component,
}
if err := tx.Model(&menu).Updates(updates).Error; err != nil {
return nil, err
}
// 尽量不覆盖用户自定义标题/图标:仅在为空时补齐
metaUpdates := map[string]any{}
if menu.Meta.Title == "" && seed.title != "" {
metaUpdates["title"] = seed.title
}
if menu.Meta.Icon == "" && seed.icon != "" {
metaUpdates["icon"] = seed.icon
}
if len(metaUpdates) > 0 {
if err := tx.Model(&menu).Updates(metaUpdates).Error; err != nil {
return nil, err
}
}
return &menu, nil
}
func (m *menuRepair) InitializeData(ctx context.Context) (next context.Context, err error) {
db, ok := ctx.Value("db").(*gorm.DB)
if !ok {
return ctx, system.ErrMissingDBContext
}
seeds := []menuSeed{
// 父级(若不存在则补齐)
{
level: 0,
hidden: false,
path: "userCenter",
name: "userCenter",
component: "features/discovery/ModuleLandingPage:userCenter",
sort: 2,
title: "用户中心",
icon: "AppstoreOutlined",
},
{
level: 0,
hidden: false,
path: "opsConfig",
name: "opsConfig",
component: "features/discovery/ModuleLandingPage:opsConfig",
sort: 6,
title: "运营配置",
icon: "SettingOutlined",
},
{
level: 0,
hidden: false,
path: "common",
name: "common",
component: "features/discovery/ModuleLandingPage:common",
sort: 6,
title: "公共能力",
icon: "AppstoreOutlined",
},
// 子级(目标规范路径)
{
level: 1,
hidden: false,
parentName: "userCenter",
path: "appLoginLog",
name: "appLoginLog",
component: "features/appLoginLogs/AppLoginLogsPage",
sort: 99,
title: "登录日志",
icon: "FileTextOutlined",
},
{
level: 1,
hidden: false,
parentName: "opsConfig",
path: "sysParamChangeLog",
name: "sysParamChangeLog",
component: "features/params/SysParamChangeLogPage",
sort: 99,
title: "参数变更日志",
icon: "SettingOutlined",
},
{
level: 1,
hidden: false,
parentName: "common",
path: "upload",
name: "upload",
component: "features/media/MediaLibraryPage",
sort: 1,
title: "媒体库(上传下载)",
icon: "UploadOutlined",
},
}
err = db.Transaction(func(tx *gorm.DB) error {
byName := map[string]*SysBaseMenu{}
// 先确保父级存在(包含 common 也一起修正 component/path
for _, seed := range seeds {
if seed.level != 0 {
continue
}
menu, err := ensureMenu(tx, seed, 0)
if err != nil {
return errors.Wrap(err, "ensure parent menu failed")
}
byName[seed.name] = menu
}
// 再确保子级存在并挂载到父级
for _, seed := range seeds {
if seed.level == 0 {
continue
}
parent := byName[seed.parentName]
if parent == nil {
return errors.Errorf("missing parent menu %s for %s", seed.parentName, seed.name)
}
if _, err := ensureMenu(tx, seed, parent.ID); err != nil {
return errors.Wrap(err, "ensure child menu failed")
}
}
return nil
})
if err != nil {
return ctx, err
}
return ctx, nil
}

View File

@@ -2,6 +2,7 @@ package system
import (
"context"
sysModel "git.echol.cn/loser/Go-Web-Template/server/model/system"
"git.echol.cn/loser/Go-Web-Template/server/service/system"
"git.echol.cn/loser/Go-Web-Template/server/utils"
@@ -59,21 +60,21 @@ func (i *initUser) InitializeData(ctx context.Context) (next context.Context, er
UUID: uuid.New(),
Username: "admin",
Password: adminPassword,
NickName: "Mr.奇淼",
HeaderImg: "https://qmplusimg.henrongyi.top/gva_header.jpg",
NickName: "超级管理员",
HeaderImg: "https://gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y",
AuthorityId: 888,
Phone: "17611111111",
Email: "333333333@qq.com",
Phone: "13888888888",
Email: "admin@example.com",
},
{
UUID: uuid.New(),
Username: "a303176530",
Username: "JohnDoe",
Password: password,
NickName: "用户1",
HeaderImg: "https://qmplusimg.henrongyi.top/1572075907logo.png",
NickName: "测试用户",
HeaderImg: "https://gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y",
AuthorityId: 9528,
Phone: "17611111111",
Email: "333333333@qq.com"},
Phone: "13999999999",
Email: "test@example.com"},
}
if err = db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, sysModel.SysUser{}.TableName()+"表数据初始化失败!")