feat(shared): update permissions system, i18n, hooks, and components

- Update permission-bitmap.ts, permissions.ts, resolve-action-error.ts

- Update types/permissions.ts

- Update rbac i18n messages (en, zh-CN)

- Update locale-switcher.tsx

- Update use-action-with-toast.ts hook
This commit is contained in:
SpecialX
2026-07-07 16:17:53 +08:00
parent b333cda8c5
commit 224740ad98
8 changed files with 36 additions and 9 deletions

View File

@@ -4,7 +4,7 @@ import * as React from "react"
import { useTransition } from "react"
import { useLocale, useTranslations } from "next-intl"
import { Check, Globe } from "lucide-react"
import { toast } from "sonner"
import { notify } from "@/shared/lib/notify"
import { Button } from "@/shared/components/ui/button"
import {
@@ -35,9 +35,9 @@ export function LocaleSwitcher({ compact = false }: { compact?: boolean }) {
startTransition(async () => {
const result = await setLocaleAction(next)
if (result.success) {
toast.success(t("switch"))
notify.success(t("switch"))
} else {
toast.error(t("switch"))
notify.error(t("switch"))
}
})
}

View File

@@ -1,7 +1,7 @@
"use client"
import { useTransition } from "react"
import { toast } from "sonner"
import { notify } from "@/shared/lib/notify"
import type { ActionState } from "@/shared/types/action-state"
export function useActionWithToast<T>() {
@@ -11,9 +11,9 @@ export function useActionWithToast<T>() {
startTransition(async () => {
const result = await action()
if (result.success) {
toast.success(result.message || "操作成功")
notify.success(result.message || "操作成功")
} else {
toast.error(result.message || "操作失败")
notify.error(result.message || "操作失败")
}
})
}

View File

@@ -173,7 +173,11 @@
},
"audit": {
"read": "Read Audit Logs",
"readDesc": "Allows viewing system audit logs"
"readDesc": "Allows viewing system audit logs",
"purge": "Purge Audit Logs",
"purgeDesc": "Physically delete expired audit logs (destructive, admin only)",
"retentionManage": "Manage Audit Retention",
"retentionManageDesc": "Configure audit log retention days and auto-cleanup rules"
},
"announcement": {
"manage": "Manage Announcements",

View File

@@ -173,7 +173,11 @@
},
"audit": {
"read": "查看审计日志",
"readDesc": "允许查看系统审计日志"
"readDesc": "允许查看系统审计日志",
"purge": "清理审计日志",
"purgeDesc": "物理删除过期审计日志(破坏性操作,仅管理员)",
"retentionManage": "管理审计保留策略",
"retentionManageDesc": "配置审计日志保留天数与自动清理规则"
},
"announcement": {
"manage": "管理公告",

View File

@@ -91,6 +91,8 @@ export const PERMISSION_BITMAP_ORDER: readonly Permission[] = [
Permissions.SETTINGS_ADMIN,
// Audit
Permissions.AUDIT_LOG_READ,
Permissions.AUDIT_LOG_PURGE,
Permissions.AUDIT_RETENTION_MANAGE,
// Announcement
Permissions.ANNOUNCEMENT_MANAGE,
Permissions.ANNOUNCEMENT_READ,

View File

@@ -48,6 +48,8 @@ export const ROLE_PERMISSIONS_SEED: Record<BuiltinRole, Permission[]> = {
Permissions.AI_CONFIGURE,
Permissions.SETTINGS_ADMIN,
Permissions.AUDIT_LOG_READ,
Permissions.AUDIT_LOG_PURGE,
Permissions.AUDIT_RETENTION_MANAGE,
Permissions.ANNOUNCEMENT_MANAGE,
Permissions.ANNOUNCEMENT_READ,
Permissions.GRADE_RECORD_MANAGE,

View File

@@ -15,7 +15,7 @@ import type { ActionState } from "@/shared/types/action-state"
* ```tsx
* const t = useTranslations("attendance")
* const msg = resolveActionError(result, t, t("errors.unexpected"))
* toast.error(msg)
* notify.error(msg)
* ```
*/
export function resolveActionError<T>(

View File

@@ -110,6 +110,10 @@ export const Permissions = {
// Audit
AUDIT_LOG_READ: "audit_log:read",
/** 审计日志清理(物理删除)—— 破坏性操作,仅 admin */
AUDIT_LOG_PURGE: "audit_log:purge",
/** 审计日志保留策略管理(配置保留天数、自动清理规则) */
AUDIT_RETENTION_MANAGE: "audit_retention:manage",
// Announcement
ANNOUNCEMENT_MANAGE: "announcement:manage",
@@ -210,6 +214,17 @@ export const Permissions = {
export type Permission = (typeof Permissions)[keyof typeof Permissions]
/** 所有合法的权限值列表(用于运行时校验) */
const PERMISSION_VALUES = Object.values(Permissions) as readonly string[]
/**
* 类型守卫:判断值是否为合法的 Permission。
* 用于从 string[] 安全收窄到 Permission[],替代 `as Permission[]` 断言。
*/
export function isPermission(value: unknown): value is Permission {
return typeof value === "string" && PERMISSION_VALUES.includes(value)
}
/**
* Data scope for row-level security.
*