2026-07-14 17:12:39 +08:00

634 lines
41 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"hyapp-admin-server/internal/config"
"hyapp-admin-server/internal/model"
"hyapp-admin-server/internal/security"
"gorm.io/gorm"
)
var defaultPermissions = []model.Permission{
{Name: "总览查看", Code: "overview:view", Kind: "menu"},
{Name: "用户查看", Code: "user:view", Kind: "menu"},
{Name: "用户创建", Code: "user:create", Kind: "button"},
{Name: "用户更新", Code: "user:update", Kind: "button"},
{Name: "用户状态", Code: "user:status", Kind: "button"},
{Name: "用户重置密码", Code: "user:reset-password", Kind: "button"},
{Name: "用户导出", Code: "user:export", Kind: "button"},
{Name: "团队查看", Code: "team:view", Kind: "menu"},
{Name: "团队创建", Code: "team:create", Kind: "button"},
{Name: "团队更新", Code: "team:update", Kind: "button"},
{Name: "App 用户查看", Code: "app-user:view", Kind: "menu"},
{Name: "App 用户更新", Code: "app-user:update", Kind: "button"},
{Name: "App 用户等级调整", Code: "app-user:level", Kind: "button"},
{Name: "App 用户导出", Code: "app-user:export", Kind: "button"},
{Name: "App 用户状态", Code: "app-user:status", Kind: "button"},
{Name: "App 用户设置密码", Code: "app-user:password", Kind: "button"},
{Name: "App 用户获取 Token", Code: "app-user:token", Kind: "button"},
{Name: "等级配置查看", Code: "level-config:view", Kind: "menu"},
{Name: "等级配置更新", Code: "level-config:update", Kind: "button"},
{Name: "靓号管理查看", Code: "pretty-id:view", Kind: "menu"},
{Name: "靓号池更新", Code: "pretty-id:update", Kind: "button"},
{Name: "靓号批量生成", Code: "pretty-id:generate", Kind: "button"},
{Name: "靓号后台发放", Code: "pretty-id:grant", Kind: "button"},
{Name: "风控配置查看", Code: "risk-config:view", Kind: "menu"},
{Name: "风控配置更新", Code: "risk-config:update", Kind: "button"},
{Name: "地区屏蔽查看", Code: "region-block:view", Kind: "menu"},
{Name: "地区屏蔽更新", Code: "region-block:update", Kind: "button"},
{Name: "房间查看", Code: "room:view", Kind: "menu"},
{Name: "房间更新", Code: "room:update", Kind: "button"},
{Name: "房间删除", Code: "room:delete", Kind: "button"},
{Name: "房间置顶查看", Code: "room-pin:view", Kind: "menu"},
{Name: "房间置顶创建", Code: "room-pin:create", Kind: "button"},
{Name: "房间置顶取消", Code: "room-pin:cancel", Kind: "button"},
{Name: "房间配置查看", Code: "room-config:view", Kind: "menu"},
{Name: "房间配置更新", Code: "room-config:update", Kind: "button"},
{Name: "房间白名单查看", Code: "room-whitelist:view", Kind: "menu"},
{Name: "房间白名单更新", Code: "room-whitelist:update", Kind: "button"},
{Name: "机器人房间查看", Code: "room-robot:view", Kind: "menu"},
{Name: "机器人房间创建", Code: "room-robot:create", Kind: "button"},
{Name: "机器人房间更新", Code: "room-robot:update", Kind: "button"},
{Name: "APP 配置查看", Code: "app-config:view", Kind: "menu"},
{Name: "APP 配置更新", Code: "app-config:update", Kind: "button"},
{Name: "版本管理查看", Code: "app-version:view", Kind: "menu"},
{Name: "版本管理创建", Code: "app-version:create", Kind: "button"},
{Name: "版本管理更新", Code: "app-version:update", Kind: "button"},
{Name: "版本管理删除", Code: "app-version:delete", Kind: "button"},
{Name: "资源查看", Code: "resource:view", Kind: "menu"},
{Name: "资源创建", Code: "resource:create", Kind: "button"},
{Name: "资源更新", Code: "resource:update", Kind: "button"},
{Name: "资源删除", Code: "resource:delete", Kind: "button"},
{Name: "道具商店查看", Code: "resource-shop:view", Kind: "menu"},
{Name: "道具商店更新", Code: "resource-shop:update", Kind: "button"},
{Name: "资源组查看", Code: "resource-group:view", Kind: "menu"},
{Name: "资源组创建", Code: "resource-group:create", Kind: "button"},
{Name: "资源组更新", Code: "resource-group:update", Kind: "button"},
{Name: "资源赠送查看", Code: "resource-grant:view", Kind: "menu"},
{Name: "资源赠送创建", Code: "resource-grant:create", Kind: "button"},
{Name: "资源赠送撤销", Code: "resource-grant:revoke", Kind: "button"},
{Name: "礼物查看", Code: "gift:view", Kind: "menu"},
{Name: "礼物创建", Code: "gift:create", Kind: "button"},
{Name: "礼物更新", Code: "gift:update", Kind: "button"},
{Name: "礼物状态", Code: "gift:status", Kind: "button"},
{Name: "礼物删除", Code: "gift:delete", Kind: "button"},
{Name: "表情包查看", Code: "emoji-pack:view", Kind: "menu"},
{Name: "表情包创建", Code: "emoji-pack:create", Kind: "button"},
{Name: "国家查看", Code: "country:view", Kind: "menu"},
{Name: "国家创建", Code: "country:create", Kind: "button"},
{Name: "国家更新", Code: "country:update", Kind: "button"},
{Name: "国家状态", Code: "country:status", Kind: "button"},
{Name: "区域查看", Code: "region:view", Kind: "menu"},
{Name: "区域创建", Code: "region:create", Kind: "button"},
{Name: "区域更新", Code: "region:update", Kind: "button"},
{Name: "区域状态", Code: "region:status", Kind: "button"},
{Name: "主播查看", Code: "host:view", Kind: "menu"},
{Name: "主播代理工资政策查看", Code: "host-agency-policy:view", Kind: "menu"},
{Name: "主播代理工资政策创建", Code: "host-agency-policy:create", Kind: "button"},
{Name: "主播代理工资政策更新", Code: "host-agency-policy:update", Kind: "button"},
{Name: "主播代理工资政策删除", Code: "host-agency-policy:delete", Kind: "button"},
{Name: "主播代理工资政策发布", Code: "host-agency-policy:publish", Kind: "button"},
{Name: "BD/Admin 工资政策查看", Code: "team-salary-policy:view", Kind: "button"},
{Name: "BD/Admin 工资政策创建", Code: "team-salary-policy:create", Kind: "button"},
{Name: "BD/Admin 工资政策更新", Code: "team-salary-policy:update", Kind: "button"},
{Name: "BD/Admin 工资政策删除", Code: "team-salary-policy:delete", Kind: "button"},
{Name: "工资结算查看", Code: "host-salary-settlement:view", Kind: "menu"},
{Name: "工资手动结算", Code: "host-salary-settlement:settle", Kind: "button"},
{Name: "Agency 查看", Code: "agency:view", Kind: "menu"},
{Name: "Agency 创建", Code: "agency:create", Kind: "button"},
{Name: "Agency 状态", Code: "agency:status", Kind: "button"},
{Name: "Agency 删除", Code: "agency:delete", Kind: "button"},
{Name: "BD 查看", Code: "bd:view", Kind: "menu"},
{Name: "BD 创建", Code: "bd:create", Kind: "button"},
{Name: "BD 更新", Code: "bd:update", Kind: "button"},
{Name: "币商查看", Code: "coin-seller:view", Kind: "menu"},
{Name: "币商创建", Code: "coin-seller:create", Kind: "button"},
{Name: "币商更新", Code: "coin-seller:update", Kind: "button"},
{Name: "币商进货", Code: "coin-seller:stock-credit", Kind: "button"},
{Name: "币商工资兑换比例", Code: "coin-seller:exchange-rate", Kind: "button"},
{Name: "子币商申请查看", Code: "coin-seller-sub-application:view", Kind: "menu"},
{Name: "子币商申请审核", Code: "coin-seller-sub-application:audit", Kind: "button"},
{Name: "金币流水查看", Code: "coin-ledger:view", Kind: "menu"},
{Name: "币商流水查看", Code: "coin-seller-ledger:view", Kind: "menu"},
{Name: "主播提现查看", Code: "host-withdrawal:view", Kind: "menu"},
{Name: "币商提现白名单查看", Code: "point-withdrawal-config:view", Kind: "menu"},
{Name: "币商提现白名单编辑", Code: "point-withdrawal-config:update", Kind: "button"},
{Name: "金币增减查看", Code: "coin-adjustment:view", Kind: "menu"},
{Name: "金币增减创建", Code: "coin-adjustment:create", Kind: "button"},
{Name: "举报列表查看", Code: "report:view", Kind: "menu"},
{Name: "礼物钻石查看", Code: "gift-diamond:view", Kind: "menu"},
{Name: "礼物钻石更新", Code: "gift-diamond:update", Kind: "button"},
{Name: "收益政策模板查看", Code: "policy-template:view", Kind: "menu"},
{Name: "收益政策模板创建", Code: "policy-template:create", Kind: "button"},
{Name: "收益政策实例创建", Code: "policy-instance:create", Kind: "button"},
{Name: "收益政策实例更新", Code: "policy-instance:update", Kind: "button"},
{Name: "收益政策实例发布", Code: "policy-instance:publish", Kind: "button"},
{Name: "系统消息推送查看", Code: "full-server-notice:view", Kind: "menu"},
{Name: "系统消息推送发送", Code: "full-server-notice:send", Kind: "button"},
{Name: "支付账单查看", Code: "payment-bill:view", Kind: "menu"},
{Name: "支付账单导出", Code: "payment-bill:export", Kind: "button"},
{Name: "支付账单刷新", Code: "payment-bill:refresh", Kind: "button"},
{Name: "三方支付查看", Code: "payment-third-party:view", Kind: "menu"},
{Name: "三方支付更新", Code: "payment-third-party:update", Kind: "button", Description: "兼容旧角色的三方支付写权限"},
{Name: "三方支付方式更新", Code: "payment-third-party:update-method", Kind: "button"},
{Name: "三方支付方式同步", Code: "payment-third-party:sync-methods", Kind: "button"},
{Name: "三方支付汇率编辑", Code: "payment-third-party:update-rate", Kind: "button"},
{Name: "三方支付汇率同步", Code: "payment-third-party:sync-rates", Kind: "button"},
{Name: "三方临时支付链接查看", Code: "payment-temporary-link:view", Kind: "menu"},
{Name: "三方临时支付链接创建", Code: "payment-temporary-link:create", Kind: "button"},
{Name: "财务范围查看", Code: "finance:view", Kind: "menu"},
{Name: "币商充值订单查看", Code: "finance-order:coin-seller-recharge:view", Kind: "menu"},
{Name: "币商充值订单创建", Code: "finance-order:coin-seller-recharge:create", Kind: "button"},
{Name: "币商充值订单校验", Code: "finance-order:coin-seller-recharge:verify", Kind: "button"},
{Name: "币商充值订单发放", Code: "finance-order:coin-seller-recharge:grant", Kind: "button"},
{Name: "用户提现申请查看", Code: "finance-withdrawal:view", Kind: "menu"},
{Name: "用户提现申请审核", Code: "finance-withdrawal:audit", Kind: "button"},
{Name: "内购配置查看", Code: "payment-product:view", Kind: "menu"},
{Name: "内购配置创建", Code: "payment-product:create", Kind: "button"},
{Name: "内购配置更新", Code: "payment-product:update", Kind: "button"},
{Name: "内购配置删除", Code: "payment-product:delete", Kind: "button"},
{Name: "游戏查看", Code: "game:view", Kind: "menu", Description: "兼容旧角色的游戏管理查看权限"},
{Name: "游戏创建", Code: "game:create", Kind: "button", Description: "兼容旧角色的游戏管理创建权限"},
{Name: "游戏更新", Code: "game:update", Kind: "button", Description: "兼容旧角色的游戏管理更新权限"},
{Name: "游戏状态", Code: "game:status", Kind: "button", Description: "兼容旧角色的游戏管理状态权限"},
{Name: "游戏删除", Code: "game:delete", Kind: "button", Description: "兼容旧角色的游戏管理删除权限"},
{Name: "游戏列表查看", Code: "game-catalog:view", Kind: "menu"},
{Name: "游戏平台配置", Code: "game-catalog:platform", Kind: "button"},
{Name: "游戏列表创建", Code: "game-catalog:create", Kind: "button"},
{Name: "游戏列表更新", Code: "game-catalog:update", Kind: "button"},
{Name: "游戏列表状态", Code: "game-catalog:status", Kind: "button"},
{Name: "游戏列表删除", Code: "game-catalog:delete", Kind: "button"},
{Name: "自研游戏查看", Code: "self-game:view", Kind: "menu"},
{Name: "自研游戏配置", Code: "self-game:update", Kind: "button"},
{Name: "全站机器人查看", Code: "game-robot:view", Kind: "menu"},
{Name: "全站机器人创建", Code: "game-robot:create", Kind: "button"},
{Name: "全站机器人更新", Code: "game-robot:update", Kind: "button"},
{Name: "全站机器人删除", Code: "game-robot:delete", Kind: "button"},
{Name: "房内猜拳配置查看", Code: "room-rps-config:view", Kind: "menu"},
{Name: "房内猜拳配置更新", Code: "room-rps-config:update", Kind: "button"},
{Name: "房内猜拳订单查看", Code: "room-rps-order:view", Kind: "menu"},
{Name: "房内猜拳订单更新", Code: "room-rps-order:update", Kind: "button"},
{Name: "每日任务查看", Code: "daily-task:view", Kind: "menu"},
{Name: "每日任务创建", Code: "daily-task:create", Kind: "button"},
{Name: "每日任务更新", Code: "daily-task:update", Kind: "button"},
{Name: "每日任务状态", Code: "daily-task:status", Kind: "button"},
{Name: "成就配置查看", Code: "achievement:view", Kind: "menu"},
{Name: "成就配置创建", Code: "achievement:create", Kind: "button"},
{Name: "成就配置更新", Code: "achievement:update", Kind: "button"},
{Name: "注册奖励查看", Code: "registration-reward:view", Kind: "menu"},
{Name: "注册奖励更新", Code: "registration-reward:update", Kind: "button"},
{Name: "首充礼包查看", Code: "first-recharge-reward:view", Kind: "menu"},
{Name: "首充礼包更新", Code: "first-recharge-reward:update", Kind: "button"},
{Name: "累充奖励查看", Code: "cumulative-recharge-reward:view", Kind: "menu"},
{Name: "累充奖励更新", Code: "cumulative-recharge-reward:update", Kind: "button"},
{Name: "邀请活动查看", Code: "invite-activity-reward:view", Kind: "menu"},
{Name: "邀请活动更新", Code: "invite-activity-reward:update", Kind: "button"},
{Name: "七日签到查看", Code: "seven-day-checkin:view", Kind: "menu"},
{Name: "七日签到更新", Code: "seven-day-checkin:update", Kind: "button"},
{Name: "幸运礼物查看", Code: "lucky-gift:view", Kind: "menu"},
{Name: "幸运礼物更新", Code: "lucky-gift:update", Kind: "button"},
{Name: "转盘抽奖查看", Code: "wheel:view", Kind: "menu"},
{Name: "转盘抽奖更新", Code: "wheel:update", Kind: "button"},
{Name: "房间火箭查看", Code: "room-rocket:view", Kind: "menu"},
{Name: "房间火箭更新", Code: "room-rocket:update", Kind: "button"},
{Name: "房间流水奖励查看", Code: "room-turnover-reward:view", Kind: "menu"},
{Name: "房间流水奖励更新", Code: "room-turnover-reward:update", Kind: "button"},
{Name: "房间流水奖励重试", Code: "room-turnover-reward:retry", Kind: "button"},
{Name: "用户榜单查看", Code: "user-leaderboard:view", Kind: "menu"},
{Name: "红包配置查看", Code: "red-packet:view", Kind: "menu"},
{Name: "红包配置更新", Code: "red-packet:update", Kind: "button"},
{Name: "CP 配置查看", Code: "cp-config:view", Kind: "menu"},
{Name: "CP 配置更新", Code: "cp-config:update", Kind: "button"},
{Name: "CP 排行活动查看", Code: "cp-weekly-rank:view", Kind: "menu"},
{Name: "CP 排行活动更新", Code: "cp-weekly-rank:update", Kind: "button"},
{Name: "VIP 配置查看", Code: "vip-config:view", Kind: "menu"},
{Name: "VIP 配置更新", Code: "vip-config:update", Kind: "button"},
{Name: "VIP 赠送", Code: "vip-config:grant", Kind: "button"},
{Name: "周星配置查看", Code: "weekly-star:view", Kind: "menu"},
{Name: "周星配置创建", Code: "weekly-star:create", Kind: "button"},
{Name: "周星配置更新", Code: "weekly-star:update", Kind: "button"},
{Name: "周星结算查看", Code: "weekly-star:settle", Kind: "button"},
{Name: "代理开业活动查看", Code: "agency-opening:view", Kind: "menu"},
{Name: "代理开业活动创建", Code: "agency-opening:create", Kind: "button"},
{Name: "代理开业活动更新", Code: "agency-opening:update", Kind: "button"},
{Name: "角色查看", Code: "role:view", Kind: "menu"},
{Name: "角色创建", Code: "role:create", Kind: "button"},
{Name: "角色更新", Code: "role:update", Kind: "button"},
{Name: "角色删除", Code: "role:delete", Kind: "button"},
{Name: "角色授权", Code: "role:permission", Kind: "button"},
{Name: "角色数据权限", Code: "role:data-scope", Kind: "button"},
{Name: "角色管理", Code: "role:manage", Kind: "button", Description: "兼容旧版本的角色管理权限"},
{Name: "权限查看", Code: "permission:view", Kind: "menu"},
{Name: "权限创建", Code: "permission:create", Kind: "button"},
{Name: "权限更新", Code: "permission:update", Kind: "button"},
{Name: "权限删除", Code: "permission:delete", Kind: "button"},
{Name: "权限同步", Code: "permission:sync", Kind: "button"},
{Name: "菜单查看", Code: "menu:view", Kind: "menu"},
{Name: "菜单创建", Code: "menu:create", Kind: "button"},
{Name: "菜单更新", Code: "menu:update", Kind: "button"},
{Name: "菜单删除", Code: "menu:delete", Kind: "button"},
{Name: "菜单排序", Code: "menu:sort", Kind: "button"},
{Name: "菜单显隐", Code: "menu:visible", Kind: "button"},
{Name: "日志查看", Code: "log:view", Kind: "menu"},
{Name: "日志导出", Code: "log:export", Kind: "button"},
{Name: "任务查看", Code: "job:view", Kind: "menu"},
{Name: "任务取消", Code: "job:cancel", Kind: "button"},
{Name: "导出任务创建", Code: "export:create", Kind: "button"},
{Name: "文件上传", Code: "upload:create", Kind: "button"},
}
var deprecatedPermissionCodes = []string{
"service:view", "service:create", "service:update", "service:operate",
"notification:view", "notification:read", "notification:read-all", "notification:delete",
"money:view", "money:payment-link:create",
}
var deprecatedMenuCodes = []string{"services", "notifications", "jobs"}
func (s *Store) seedPermissions() error {
return s.syncDefaultPermissions(s.db)
}
func (s *Store) seedMenus() error {
systemID := uint(0)
geoID := uint(0)
hostOrgID := uint(0)
appUsersID := uint(0)
appConfigID := uint(0)
resourceID := uint(0)
operationsID := uint(0)
roomsID := uint(0)
paymentID := uint(0)
activityID := uint(0)
gameID := uint(0)
menus := []model.Menu{
{Title: "总览", Code: "overview", Path: "/overview", Icon: "dashboard", PermissionCode: "overview:view", Sort: 10, Visible: true},
{Title: "用户管理", Code: "app-users", Path: "", Icon: "users", PermissionCode: "", Sort: 20, Visible: true},
{Title: "团队管理", Code: "host-org", Path: "", Icon: "network", PermissionCode: "", Sort: 30, Visible: true},
{Title: "房间管理", Code: "rooms", Path: "", Icon: "room", PermissionCode: "", Sort: 40, Visible: true},
{Title: "APP配置", Code: "app-config", Path: "", Icon: "settings", PermissionCode: "", Sort: 50, Visible: true},
{Title: "资源管理", Code: "resources", Path: "", Icon: "inventory", PermissionCode: "", Sort: 60, Visible: true},
{Title: "运营管理", Code: "operations", Path: "", Icon: "operations", PermissionCode: "", Sort: 70, Visible: true},
{Title: "支付管理", Code: "payment", Path: "", Icon: "wallet", PermissionCode: "", Sort: 80, Visible: true},
{Title: "活动管理", Code: "activities", Path: "", Icon: "campaign", PermissionCode: "", Sort: 90, Visible: true},
{Title: "游戏管理", Code: "games", Path: "", Icon: "sports_esports", PermissionCode: "", Sort: 100, Visible: true},
{Title: "地区管理", Code: "geo", Path: "", Icon: "map", PermissionCode: "", Sort: 110, Visible: true},
{Title: "后台设置", Code: "system", Path: "", Icon: "settings", PermissionCode: "", Sort: 120, Visible: true},
{Title: "日志审计", Code: "logs", Path: "", Icon: "history", PermissionCode: "", Sort: 130, Visible: false},
}
for _, menu := range menus {
syncedMenu, err := s.syncDefaultMenu(s.db, menu)
if err != nil {
return err
}
if syncedMenu.Code == "system" {
systemID = syncedMenu.ID
}
if syncedMenu.Code == "geo" {
geoID = syncedMenu.ID
}
if syncedMenu.Code == "host-org" {
hostOrgID = syncedMenu.ID
}
if syncedMenu.Code == "app-users" {
appUsersID = syncedMenu.ID
}
if syncedMenu.Code == "app-config" {
appConfigID = syncedMenu.ID
}
if syncedMenu.Code == "resources" {
resourceID = syncedMenu.ID
}
if syncedMenu.Code == "operations" {
operationsID = syncedMenu.ID
}
if syncedMenu.Code == "rooms" {
roomsID = syncedMenu.ID
}
if syncedMenu.Code == "payment" {
paymentID = syncedMenu.ID
}
if syncedMenu.Code == "activities" {
activityID = syncedMenu.ID
}
if syncedMenu.Code == "games" {
gameID = syncedMenu.ID
}
}
children := []model.Menu{
{ParentID: &systemID, Title: "后台用户", Code: "system-users", Path: "/system/users", Icon: "users", PermissionCode: "user:view", Sort: 31, Visible: true},
{ParentID: &systemID, Title: "角色配置", Code: "system-roles", Path: "/system/roles", Icon: "shield", PermissionCode: "role:view", Sort: 32, Visible: true},
{ParentID: &systemID, Title: "菜单权限", Code: "system-menus", Path: "/system/menus", Icon: "menu", PermissionCode: "menu:view", Sort: 33, Visible: true},
{ParentID: &systemID, Title: "登录日志", Code: "logs-login", Path: "/logs/login", Icon: "login", PermissionCode: "log:view", Sort: 34, Visible: true},
{ParentID: &systemID, Title: "操作日志", Code: "logs-operations", Path: "/logs/operations", Icon: "receipt", PermissionCode: "log:view", Sort: 35, Visible: true},
{ParentID: &systemID, Title: "团队配置", Code: "system-teams", Path: "/system/teams", Icon: "team", PermissionCode: "team:view", Sort: 36, Visible: true},
{ParentID: &appUsersID, Title: "用户列表", Code: "app-user-list", Path: "/app/users", Icon: "users", PermissionCode: "app-user:view", Sort: 60, Visible: true},
{ParentID: &appUsersID, Title: "封禁列表", Code: "app-user-bans", Path: "/app/users/bans", Icon: "block", PermissionCode: "app-user:view", Sort: 61, Visible: true},
{ParentID: &appUsersID, Title: "登录日志", Code: "app-user-login-logs", Path: "/app/users/login-logs", Icon: "login", PermissionCode: "app-user:view", Sort: 62, Visible: true},
{ParentID: &appUsersID, Title: "等级配置", Code: "app-user-level-config", Path: "/app/users/level-config", Icon: "military_tech", PermissionCode: "level-config:view", Sort: 63, Visible: true},
{ParentID: &appUsersID, Title: "靓号管理", Code: "app-user-pretty-ids", Path: "/app/users/pretty-ids", Icon: "tag", PermissionCode: "pretty-id:view", Sort: 64, Visible: true},
{ParentID: &appUsersID, Title: "风控管理", Code: "app-user-risk-config", Path: "/app/users/risk-config", Icon: "shield", PermissionCode: "risk-config:view", Sort: 65, Visible: true},
{ParentID: &appUsersID, Title: "地区屏蔽", Code: "app-user-region-blocks", Path: "/app/users/region-blocks", Icon: "public", PermissionCode: "region-block:view", Sort: 66, Visible: true},
{ParentID: &roomsID, Title: "房间列表", Code: "room-list", Path: "/rooms", Icon: "room", PermissionCode: "room:view", Sort: 65, Visible: true},
{ParentID: &roomsID, Title: "房间置顶", Code: "room-pins", Path: "/rooms/pins", Icon: "push_pin", PermissionCode: "room-pin:view", Sort: 66, Visible: true},
{ParentID: &roomsID, Title: "房间配置", Code: "room-config", Path: "/rooms/config", Icon: "settings", PermissionCode: "room-config:view", Sort: 67, Visible: true},
{ParentID: &roomsID, Title: "房间白名单", Code: "room-whitelist", Path: "/rooms/whitelist", Icon: "shield", PermissionCode: "room-whitelist:view", Sort: 68, Visible: true},
{ParentID: &roomsID, Title: "机器人房间", Code: "room-robots", Path: "/rooms/robots", Icon: "team", PermissionCode: "room-robot:view", Sort: 69, Visible: true},
{ParentID: &appConfigID, Title: "H5配置", Code: "app-config-h5", Path: "/app-config/h5", Icon: "settings", PermissionCode: "app-config:view", Sort: 66, Visible: true},
{ParentID: &appConfigID, Title: "BANNER配置", Code: "app-config-banners", Path: "/app-config/banners", Icon: "image", PermissionCode: "app-config:view", Sort: 67, Visible: true},
{ParentID: &appConfigID, Title: "开屏配置", Code: "app-config-splash-screens", Path: "/app-config/splash-screens", Icon: "image", PermissionCode: "app-config:view", Sort: 68, Visible: true},
{ParentID: &appConfigID, Title: "弹窗配置", Code: "app-config-popups", Path: "/app-config/popups", Icon: "image", PermissionCode: "app-config:view", Sort: 69, Visible: true},
{ParentID: &appConfigID, Title: "Explore配置", Code: "app-config-explore", Path: "/app-config/explore", Icon: "explore", PermissionCode: "app-config:view", Sort: 70, Visible: true},
{ParentID: &appConfigID, Title: "版本管理", Code: "app-config-versions", Path: "/app-config/versions", Icon: "settings", PermissionCode: "app-version:view", Sort: 72, Visible: true},
{ParentID: &appConfigID, Title: "系统消息推送", Code: "operation-full-server-notice", Path: "/app-config/system-message-push", Icon: "campaign", PermissionCode: "full-server-notice:view", Sort: 73, Visible: true},
{ParentID: &resourceID, Title: "资源列表", Code: "resource-list", Path: "/resources", Icon: "inventory", PermissionCode: "resource:view", Sort: 67, Visible: true},
{ParentID: &resourceID, Title: "道具商店", Code: "resource-shop-list", Path: "/resource-shop", Icon: "storefront", PermissionCode: "resource-shop:view", Sort: 68, Visible: true},
{ParentID: &resourceID, Title: "资源组列表", Code: "resource-group-list", Path: "/resource-groups", Icon: "category", PermissionCode: "resource-group:view", Sort: 69, Visible: true},
{ParentID: &resourceID, Title: "礼物列表", Code: "gift-list", Path: "/gifts", Icon: "gift", PermissionCode: "gift:view", Sort: 70, Visible: true},
{ParentID: &resourceID, Title: "资源赠送", Code: "resource-grant-list", Path: "/resource-grants", Icon: "send", PermissionCode: "resource-grant:view", Sort: 71, Visible: true},
{ParentID: &resourceID, Title: "表情包列表", Code: "emoji-pack-list", Path: "/emoji-packs", Icon: "image", PermissionCode: "emoji-pack:view", Sort: 72, Visible: true},
{ParentID: &operationsID, Title: "金币流水", Code: "operation-coin-ledger", Path: "/operations/coin-ledger", Icon: "receipt", PermissionCode: "coin-ledger:view", Sort: 68, Visible: true},
{ParentID: &operationsID, Title: "币商流水", Code: "operation-coin-seller-ledger", Path: "/operations/coin-seller-ledger", Icon: "receipt", PermissionCode: "coin-seller-ledger:view", Sort: 69, Visible: true},
{ParentID: &operationsID, Title: "金币增减", Code: "operation-coin-adjustment", Path: "/operations/coin-adjustments", Icon: "wallet", PermissionCode: "coin-adjustment:view", Sort: 70, Visible: true},
{ParentID: &operationsID, Title: "幸运礼物", Code: "lucky-gift", Path: "/operations/lucky-gift", Icon: "redeem", PermissionCode: "lucky-gift:view", Sort: 71, Visible: true},
{ParentID: &operationsID, Title: "举报列表", Code: "operation-reports", Path: "/operations/reports", Icon: "flag", PermissionCode: "report:view", Sort: 73, Visible: true},
{ParentID: &operationsID, Title: "礼物钻石", Code: "operation-gift-diamond", Path: "/operations/gift-diamonds", Icon: "diamond", PermissionCode: "gift-diamond:view", Sort: 74, Visible: true},
{ParentID: &operationsID, Title: "收益政策模板", Code: "policy-template", Path: "/policy/templates", Icon: "settings", PermissionCode: "policy-template:view", Sort: 88, Visible: true},
{ParentID: &paymentID, Title: "账单列表", Code: "payment-bill-list", Path: "/payment/bills", Icon: "receipt", PermissionCode: "payment-bill:view", Sort: 68, Visible: true},
{ParentID: &paymentID, Title: "三方支付", Code: "payment-third-party", Path: "/payment/third-party", Icon: "wallet", PermissionCode: "payment-third-party:view", Sort: 69, Visible: true},
{ParentID: &paymentID, Title: "三方临时支付链接", Code: "payment-temporary-links", Path: "/payment/temporary-links", Icon: "receipt", PermissionCode: "payment-temporary-link:view", Sort: 70, Visible: true},
{ParentID: &paymentID, Title: "支付内购商品", Code: "payment-recharge-products", Path: "/payment/recharge-products", Icon: "wallet", PermissionCode: "payment-product:view", Sort: 71, Visible: true},
{ParentID: &paymentID, Title: "币商充值订单", Code: "finance-coin-seller-recharge-orders", Path: "/finance/orders/coin-seller-recharges", Icon: "receipt", PermissionCode: "finance-order:coin-seller-recharge:view", Sort: 72, Visible: true},
{ParentID: &activityID, Title: "每日任务", Code: "daily-task-list", Path: "/activities/daily-tasks", Icon: "task", PermissionCode: "daily-task:view", Sort: 69, Visible: true},
{ParentID: &activityID, Title: "注册奖励", Code: "registration-reward", Path: "/activities/registration-reward", Icon: "gift", PermissionCode: "registration-reward:view", Sort: 70, Visible: true},
{ParentID: &activityID, Title: "成就配置", Code: "achievement-config", Path: "/activities/achievements", Icon: "military_tech", PermissionCode: "achievement:view", Sort: 71, Visible: true},
{ParentID: &activityID, Title: "七日签到", Code: "seven-day-checkin", Path: "/activities/seven-day-checkin", Icon: "event_available", PermissionCode: "seven-day-checkin:view", Sort: 72, Visible: true},
{ParentID: &activityID, Title: "房间火箭", Code: "room-rocket", Path: "/activities/room-rocket", Icon: "redeem", PermissionCode: "room-rocket:view", Sort: 73, Visible: true},
{ParentID: &activityID, Title: "用户榜单", Code: "user-leaderboard", Path: "/activities/user-leaderboards", Icon: "leaderboard", PermissionCode: "user-leaderboard:view", Sort: 74, Visible: true},
{ParentID: &activityID, Title: "红包配置", Code: "red-packet", Path: "/activities/red-packets", Icon: "redeem", PermissionCode: "red-packet:view", Sort: 75, Visible: true},
{ParentID: &activityID, Title: "CP配置", Code: "cp-config", Path: "/activities/cp-config", Icon: "favorite", PermissionCode: "cp-config:view", Sort: 76, Visible: true},
{ParentID: &activityID, Title: "CP排行活动", Code: "cp-weekly-rank", Path: "/activities/cp-weekly-rank", Icon: "leaderboard", PermissionCode: "cp-weekly-rank:view", Sort: 77, Visible: true},
{ParentID: &activityID, Title: "VIP配置", Code: "vip-config", Path: "/activities/vip-config", Icon: "workspace_premium", PermissionCode: "vip-config:view", Sort: 78, Visible: true},
{ParentID: &activityID, Title: "周星配置", Code: "weekly-star", Path: "/activities/weekly-star", Icon: "star", PermissionCode: "weekly-star:view", Sort: 79, Visible: true},
{ParentID: &activityID, Title: "代理开业活动", Code: "agency-opening", Path: "/activities/agency-opening", Icon: "workspace_premium", PermissionCode: "agency-opening:view", Sort: 80, Visible: true},
{ParentID: &activityID, Title: "转盘抽奖", Code: "wheel", Path: "/activities/wheel", Icon: "casino", PermissionCode: "wheel:view", Sort: 81, Visible: true},
{ParentID: &gameID, Title: "游戏列表", Code: "game-list", Path: "/games", Icon: "sports_esports", PermissionCode: "game-catalog:view", Sort: 70, Visible: true},
{ParentID: &gameID, Title: "自研游戏", Code: "self-games", Path: "/games/self-games", Icon: "settings", PermissionCode: "self-game:view", Sort: 80, Visible: true},
{ParentID: &gameID, Title: "全站机器人", Code: "game-robots", Path: "/games/robots", Icon: "team", PermissionCode: "game-robot:view", Sort: 90, Visible: true},
{ParentID: &gameID, Title: "房内猜拳配置", Code: "room-rps-config", Path: "/games/room-rps/config", Icon: "settings", PermissionCode: "room-rps-config:view", Sort: 100, Visible: true},
{ParentID: &gameID, Title: "房内猜拳订单", Code: "room-rps-challenges", Path: "/games/room-rps/challenges", Icon: "history", PermissionCode: "room-rps-order:view", Sort: 110, Visible: true},
{ParentID: &geoID, Title: "国家管理", Code: "host-org-countries", Path: "/host/countries", Icon: "public", PermissionCode: "country:view", Sort: 70, Visible: true},
{ParentID: &geoID, Title: "区域管理", Code: "host-org-regions", Path: "/host/regions", Icon: "map", PermissionCode: "region:view", Sort: 71, Visible: true},
{ParentID: &hostOrgID, Title: "经理列表", Code: "host-org-managers", Path: "/host/managers", Icon: "users", PermissionCode: "bd:view", Sort: 80, Visible: true},
{ParentID: &hostOrgID, Title: "Agency 列表", Code: "host-org-agencies", Path: "/host/agencies", Icon: "apartment", PermissionCode: "agency:view", Sort: 81, Visible: true},
{ParentID: &hostOrgID, Title: "BD Leader 列表", Code: "host-org-bd-leaders", Path: "/host/bd-leaders", Icon: "shield", PermissionCode: "bd:view", Sort: 82, Visible: true},
{ParentID: &hostOrgID, Title: "BD 列表", Code: "host-org-bds", Path: "/host/bds", Icon: "team", PermissionCode: "bd:view", Sort: 83, Visible: true},
{ParentID: &hostOrgID, Title: "Host 列表", Code: "host-org-hosts", Path: "/host/hosts", Icon: "users", PermissionCode: "host:view", Sort: 84, Visible: true},
{ParentID: &hostOrgID, Title: "工资政策", Code: "host-agency-policy", Path: "/host/salary-policies", Icon: "wallet", PermissionCode: "host-agency-policy:view", Sort: 85, Visible: true},
{ParentID: &hostOrgID, Title: "工资结算", Code: "host-salary-settlement", Path: "/host/salary-settlements", Icon: "receipt", PermissionCode: "host-salary-settlement:view", Sort: 86, Visible: true},
{ParentID: &hostOrgID, Title: "Coin Saller列表", Code: "host-org-coin-sellers", Path: "/host/coin-sellers", Icon: "wallet", PermissionCode: "coin-seller:view", Sort: 87, Visible: true},
{ParentID: &hostOrgID, Title: "Sub Coin Seller 申请列表", Code: "host-org-coin-seller-sub-applications", Path: "/host/coin-seller-sub-applications", Icon: "receipt", PermissionCode: "coin-seller-sub-application:view", Sort: 88, Visible: true},
{ParentID: &hostOrgID, Title: "主播提现", Code: "host-withdrawals", Path: "/host/withdrawals", Icon: "receipt", PermissionCode: "host-withdrawal:view", Sort: 89, Visible: true},
}
for _, menu := range children {
if _, err := s.syncDefaultMenu(s.db, menu); err != nil {
return err
}
}
return nil
}
func (s *Store) seedTeams() error {
teams := []model.Team{
{ID: model.TeamProductResearchID, Name: "产研团队", Description: "产品和研发后台用户", Sort: 1},
{ID: model.TeamOperationsID, Name: "运营团队", Description: "运营后台用户;运营人员接口固定读取该团队", Sort: 2},
}
for _, definition := range teams {
team := model.Team{}
// 团队 ID 是前端“运营人员=运营团队 ID 2”契约的一部分已存在时同步展示字段不改主键。
result := s.db.Where("id = ?", definition.ID).Limit(1).Find(&team)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
if err := s.db.Create(&definition).Error; err != nil {
return err
}
continue
}
if err := s.db.Model(&team).Updates(map[string]any{
"parent_id": nil,
"name": definition.Name,
"description": definition.Description,
"sort": definition.Sort,
}).Error; err != nil {
return err
}
}
operationsTeamID := model.TeamOperationsID
childTeams := []model.Team{
{ParentID: &operationsTeamID, Name: "运营一部", Description: "运营团队子部门", Sort: 1},
{ParentID: &operationsTeamID, Name: "运营二部", Description: "运营团队子部门", Sort: 2},
{ParentID: &operationsTeamID, Name: "运营三部", Description: "运营团队子部门", Sort: 3},
}
for _, definition := range childTeams {
team := model.Team{}
// 子部门不固定主键,按名称做幂等维护;这样既满足默认部门存在,也不会覆盖线上已自增出来的团队 ID。
result := s.db.Where("name = ?", definition.Name).Limit(1).Find(&team)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
if err := s.db.Create(&definition).Error; err != nil {
return err
}
continue
}
if err := s.db.Model(&team).Updates(map[string]any{
"parent_id": definition.ParentID,
"description": definition.Description,
"sort": definition.Sort,
}).Error; err != nil {
return err
}
}
if err := s.db.Model(&model.User{}).
Where("team_id = ?", model.TeamOperationsID).
Update("team", "运营团队").Error; err != nil {
return err
}
if err := s.db.Model(&model.User{}).
Where("team_id IS NULL AND TRIM(COALESCE(team, '')) IN ?", []string{"运营", "运营团队", "平台运营", "平台运营团队", "平台运维", "平台运维团队", "运维", "运维团队"}).
Updates(map[string]any{"team_id": model.TeamOperationsID, "team": "运营团队"}).Error; err != nil {
return err
}
return nil
}
func (s *Store) seedRoles() error {
var permissions []model.Permission
if err := s.db.Find(&permissions).Error; err != nil {
return err
}
for _, definition := range managedDefaultRoles {
role := model.Role{}
result := s.db.Where("code = ?", definition.Code).Limit(1).Find(&role)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
role = definition
if err := s.db.Create(&role).Error; err != nil {
return err
}
} else if err := s.db.Model(&role).Updates(map[string]any{
"name": definition.Name,
"description": definition.Description,
}).Error; err != nil {
return err
}
if role.Code == roleCodePlatformAdmin {
if err := s.db.Model(&role).Association("Permissions").Replace(permissions); err != nil {
return err
}
continue
}
// 显式 bootstrap 的职责是恢复产品确认的岗位模板;普通启动不会执行 Seed
// 因此这里可以精确替换固定岗位权限,同时不影响用户自行创建的其他角色。
if err := s.replaceRolePermissionsByCode(&role, defaultRolePermissionCodes(role.Code)); err != nil {
return err
}
}
return nil
}
func (s *Store) seedUsers(cfg config.Config) error {
var count int64
if err := s.db.Model(&model.User{}).Count(&count).Error; err != nil {
return err
}
if count > 0 {
return nil
}
if cfg.Bootstrap.Password == "" {
return nil
}
hash, err := security.HashPassword(cfg.Bootstrap.Password)
if err != nil {
return err
}
var role model.Role
if err := s.db.Where("code = ?", roleCodePlatformAdmin).First(&role).Error; err != nil {
return err
}
operationsTeamID := model.TeamOperationsID
user := model.User{
Username: cfg.Bootstrap.Username,
Name: cfg.Bootstrap.Name,
PasswordHash: hash,
Team: "运营团队",
TeamID: &operationsTeamID,
Status: model.UserStatusActive,
// 全新环境的唯一 bootstrap 管理员必须能进入 App 主站,后续仍可在用户编辑中改成 selected/none。
AppScopeMode: model.UserAppScopeModeAll,
MFAEnabled: false,
}
if err := s.db.Create(&user).Error; err != nil {
return err
}
return s.db.Model(&user).Association("Roles").Replace([]model.Role{role})
}
func (s *Store) pruneDeprecatedDefaults() error {
return s.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("code IN ? OR permission_code IN ?", deprecatedMenuCodes, deprecatedPermissionCodes).Delete(&model.Menu{}).Error; err != nil {
return err
}
var permissions []model.Permission
if err := tx.Where("code IN ?", deprecatedPermissionCodes).Find(&permissions).Error; err != nil {
return err
}
if len(permissions) == 0 {
return nil
}
permissionIDs := make([]uint, 0, len(permissions))
for _, permission := range permissions {
permissionIDs = append(permissionIDs, permission.ID)
}
if err := tx.Table("admin_role_permissions").Where("permission_id IN ?", permissionIDs).Delete(nil).Error; err != nil {
return err
}
return tx.Where("id IN ?", permissionIDs).Delete(&model.Permission{}).Error
})
}
func (s *Store) syncDefaultPermissions(tx *gorm.DB) error {
for _, definition := range defaultPermissions {
permission := model.Permission{}
// 权限种子是前后端契约来源;已存在时同步名称、类型和说明,避免按钮文案和授权页长期漂移。
result := tx.Where("code = ?", definition.Code).Limit(1).Find(&permission)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
if err := tx.Create(&definition).Error; err != nil {
return err
}
continue
}
if err := tx.Model(&permission).Updates(map[string]any{
"name": definition.Name,
"kind": definition.Kind,
"description": definition.Description,
}).Error; err != nil {
return err
}
}
return nil
}
func (s *Store) syncDefaultMenu(tx *gorm.DB, definition model.Menu) (model.Menu, error) {
menu := model.Menu{}
// 菜单种子同样是前后端契约来源;已存在时同步标题、路径和权限,避免后台菜单文案长期漂移。
result := tx.Where("code = ?", definition.Code).Limit(1).Find(&menu)
if result.Error != nil {
return model.Menu{}, result.Error
}
if result.RowsAffected == 0 {
if err := tx.Create(&definition).Error; err != nil {
return model.Menu{}, err
}
return definition, nil
}
if err := tx.Model(&menu).Updates(map[string]any{
"parent_id": definition.ParentID,
"title": definition.Title,
"path": definition.Path,
"icon": definition.Icon,
"permission_code": definition.PermissionCode,
"sort": definition.Sort,
"visible": definition.Visible,
}).Error; err != nil {
return model.Menu{}, err
}
return menu, nil
}
func (s *Store) replaceRolePermissionsByCode(role *model.Role, codes []string) error {
var permissions []model.Permission
if len(codes) > 0 {
if err := s.db.Where("code IN ?", codes).Find(&permissions).Error; err != nil {
return err
}
}
return s.db.Model(role).Association("Permissions").Replace(permissions)
}