feat(admin): 引入细粒度权限组管理

- 新增权限目录、系统权限组与用户权限组分配,后台路由改为按权限粒度控制。
- 支持创建、编辑、查看和删除自定义权限组,并为用户绑定权限组。
- 前端后台界面按权限动态展示菜单与操作项,补充用户/权限组相关类型与交互。
This commit is contained in:
LanQin_
2026-06-22 14:31:10 +08:00
parent e35b0985ee
commit 31435c1e97
15 changed files with 1915 additions and 157 deletions
+30 -1
View File
@@ -115,6 +115,22 @@ func (a *App) migrate(ctx context.Context) error {
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`,
`CREATE TABLE IF NOT EXISTS permission_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
description TEXT NOT NULL DEFAULT '',
permissions_json TEXT NOT NULL DEFAULT '[]',
system INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`,
`CREATE TABLE IF NOT EXISTS user_permission_groups (
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
group_id TEXT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
created_at TEXT NOT NULL,
PRIMARY KEY(user_id, group_id)
)`,
`CREATE INDEX IF NOT EXISTS idx_user_permission_groups_group ON user_permission_groups(group_id, user_id)`,
`CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
@@ -327,6 +343,9 @@ func (a *App) migrate(ctx context.Context) error {
if err := a.migrateLegacyBootstrapMailbox(ctx); err != nil {
return err
}
if err := a.ensureDefaultPermissionGroups(ctx); err != nil {
return err
}
return nil
}
@@ -679,7 +698,7 @@ func (a *App) seed(ctx context.Context) error {
return err
}
if count > 0 {
return nil
return a.ensureConfiguredAdminSuperAdmin(ctx)
}
adminPassword := a.cfg.AdminPassword
@@ -736,6 +755,16 @@ func (a *App) seed(ctx context.Context) error {
return nil
}
func (a *App) ensureConfiguredAdminSuperAdmin(ctx context.Context) error {
adminEmail := normalizeEmail(a.cfg.AdminEmail)
if adminEmail == "" || !strings.Contains(adminEmail, "@") {
return nil
}
_, err := a.db.ExecContext(ctx, `UPDATE users SET role='admin', disabled=0, updated_at=? WHERE email=?`,
a.now().UTC().Format(time.RFC3339Nano), adminEmail)
return err
}
func (a *App) createDomainTx(ctx context.Context, tx *sql.Tx, name string) (string, error) {
name = normalizeDomain(name)
if name == "" || !strings.Contains(name, ".") {