feat: update frontend for four-tier role system

Add Student Admin and Teacher Admin roles to constants, types, store,
permissions, routes, and admin UI. Teacher Admin sees contests and
problemsets in sidebar; Student Admin sees only problems.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 18:13:39 -06:00
parent 8444d6e21a
commit 2fbcbd07c5
11 changed files with 112 additions and 52 deletions

View File

@@ -166,7 +166,7 @@ const menus = computed<MenuOption[]>(() => [
label: () =>
h(
RouterLink,
{ to: userStore.isTheAdmin ? "/admin/problem/list" : "/admin" },
{ to: userStore.isSuperAdmin ? "/admin" : "/admin/problem/list" },
{ default: () => "后台" },
),
show: userStore.isAdminRole,

View File

@@ -19,8 +19,8 @@ const options = computed<MenuOption[]>(() => {
},
]
// admin 可以访问的功能
if (userStore.isTheAdmin) {
// Student Admin: only problems
if (userStore.isStudentAdmin) {
baseOptions.push({
label: () =>
h(RouterLink, { to: "/admin/problem/list" }, { default: () => "题目" }),
@@ -28,7 +28,40 @@ const options = computed<MenuOption[]>(() => {
})
}
// super_admin 可以访问的功能
// Teacher Admin: problems + contests + problemsets
if (userStore.isTeacherAdmin) {
baseOptions.push(
{
label: () =>
h(
RouterLink,
{ to: "/admin/problem/list" },
{ default: () => "题目" },
),
key: "admin problem list",
},
{
label: () =>
h(
RouterLink,
{ to: "/admin/contest/list" },
{ default: () => "比赛" },
),
key: "admin contest list",
},
{
label: () =>
h(
RouterLink,
{ to: "/admin/problemset/list" },
{ default: () => "题单" },
),
key: "admin problemset list",
},
)
}
// Super Admin: everything
if (userStore.isSuperAdmin) {
baseOptions.push(
{

View File

@@ -13,10 +13,21 @@ export const useUserStore = defineStore("user", () => {
const isAuthed = computed(() => !!user.value?.email)
const isAdminRole = computed(
() =>
user.value?.admin_type === USER_TYPE.ADMIN ||
user.value?.admin_type === USER_TYPE.STUDENT_ADMIN ||
user.value?.admin_type === USER_TYPE.TEACHER_ADMIN ||
user.value?.admin_type === USER_TYPE.SUPER_ADMIN,
)
const isStudentAdmin = computed(
() => user.value?.admin_type === USER_TYPE.STUDENT_ADMIN,
)
const isTeacherAdmin = computed(
() => user.value?.admin_type === USER_TYPE.TEACHER_ADMIN,
)
const isTeacherOrAbove = computed(
() =>
user.value?.admin_type === USER_TYPE.TEACHER_ADMIN ||
user.value?.admin_type === USER_TYPE.SUPER_ADMIN,
)
const isTheAdmin = computed(() => user.value?.admin_type === USER_TYPE.ADMIN)
const isSuperAdmin = computed(
() => user.value?.admin_type === USER_TYPE.SUPER_ADMIN,
)
@@ -47,7 +58,9 @@ export const useUserStore = defineStore("user", () => {
isFinished,
user,
isAdminRole,
isTheAdmin,
isStudentAdmin,
isTeacherAdmin,
isTeacherOrAbove,
isSuperAdmin,
hasProblemPermission,
isAuthed,