refactor: RBAC权限系统重构 + UI组件拆分 + 测试修复 + 架构文档
Some checks failed
CI / build-deploy (push) Has been cancelled
Some checks failed
CI / build-deploy (push) Has been cancelled
- RBAC: 新增30个权限点、DataScope行级权限、requirePermission守卫,所有57+ Server Action接入权限校验 - UI拆分: exam-form(1623行→11文件)、textbook-reader(744行→7文件),均降至300行以内 - 测试: 新增5个单元测试文件(19用例),修复4个集成测试文件(38用例全部通过) - 架构文档: 新增架构影响地图(004/005)、标准功能清单(006)、差距审计报告(007) - 项目规则: 架构图优先规则,改码必同步图 - 安全: rehype-sanitize净化、AES加密API Key、权限路由守卫 - 无障碍: skip-link、aria-label、prefers-reduced-motion - 性能: next/font优化、next/image、代码分割
This commit is contained in:
@@ -13,6 +13,7 @@ import { Label } from "@/shared/components/ui/label"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/components/ui/select"
|
||||
import { Textarea } from "@/shared/components/ui/textarea"
|
||||
import { cn } from "@/shared/lib/utils"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
|
||||
type Role = "student" | "teacher" | "parent" | "admin"
|
||||
|
||||
@@ -27,7 +28,6 @@ export function OnboardingGate() {
|
||||
const router = useRouter()
|
||||
const { status, data: session, update } = useSession()
|
||||
const [required, setRequired] = useState(false)
|
||||
const [currentRole, setCurrentRole] = useState<Role>("student")
|
||||
const [open, setOpen] = useState(false)
|
||||
const [step, setStep] = useState(0)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
@@ -53,7 +53,6 @@ export function OnboardingGate() {
|
||||
const required = Boolean(json.required)
|
||||
const role = String(json.role ?? "student") as Role
|
||||
setRequired(required)
|
||||
setCurrentRole(role)
|
||||
setRole(role === "admin" ? "admin" : role)
|
||||
setName(String(session?.user?.name ?? "").trim())
|
||||
if (required) {
|
||||
@@ -88,6 +87,12 @@ export function OnboardingGate() {
|
||||
const canNextFromStep0 = role.length > 0
|
||||
const canNextFromStep1 = name.trim().length > 0 && phone.trim().length > 0
|
||||
|
||||
const permissions = (session?.user?.permissions ?? []) as string[]
|
||||
const isAdmin = permissions.includes(Permissions.SETTINGS_ADMIN)
|
||||
const isTeacher = permissions.includes(Permissions.EXAM_CREATE)
|
||||
const isStudent = permissions.includes(Permissions.HOMEWORK_SUBMIT) && !permissions.includes(Permissions.EXAM_CREATE)
|
||||
const isParent = !permissions.includes(Permissions.EXAM_CREATE) && !permissions.includes(Permissions.HOMEWORK_SUBMIT) && permissions.includes(Permissions.EXAM_READ)
|
||||
|
||||
const onNext = async () => {
|
||||
if (step === 0) {
|
||||
if (!canNextFromStep0) return
|
||||
@@ -99,7 +104,7 @@ export function OnboardingGate() {
|
||||
toast.error("请填写姓名与电话")
|
||||
return
|
||||
}
|
||||
if (role === "admin") {
|
||||
if (isAdmin) {
|
||||
setStep(3)
|
||||
} else {
|
||||
setStep(2)
|
||||
@@ -181,7 +186,7 @@ export function OnboardingGate() {
|
||||
{step === 0 ? (
|
||||
<div className="grid gap-2">
|
||||
<Label>Role</Label>
|
||||
{currentRole === "admin" ? (
|
||||
{isAdmin ? (
|
||||
<div className="rounded-md border px-3 py-2 text-sm">admin</div>
|
||||
) : (
|
||||
<Select value={role} onValueChange={(v) => setRole(v as Role)}>
|
||||
@@ -217,7 +222,7 @@ export function OnboardingGate() {
|
||||
|
||||
{step === 2 ? (
|
||||
<div className="grid gap-4">
|
||||
{role === "teacher" ? (
|
||||
{isTeacher ? (
|
||||
<>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="onb_codes_teacher">班级代码(可多个)</Label>
|
||||
@@ -242,7 +247,7 @@ export function OnboardingGate() {
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{role === "student" ? (
|
||||
{isStudent ? (
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="onb_codes_student">班级代码</Label>
|
||||
<Textarea
|
||||
@@ -254,7 +259,7 @@ export function OnboardingGate() {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{role === "parent" ? (
|
||||
{isParent ? (
|
||||
<div className="rounded-md border px-3 py-2 text-sm text-muted-foreground">
|
||||
家长角色暂不需要配置,可跳过
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user