diff --git a/src/admin/achievement/components/AchievementModal.vue b/src/admin/achievement/components/AchievementModal.vue new file mode 100644 index 0000000..bab15b1 --- /dev/null +++ b/src/admin/achievement/components/AchievementModal.vue @@ -0,0 +1,160 @@ + + + diff --git a/src/admin/achievement/list.vue b/src/admin/achievement/list.vue new file mode 100644 index 0000000..6c1f2f7 --- /dev/null +++ b/src/admin/achievement/list.vue @@ -0,0 +1,135 @@ + + + diff --git a/src/admin/api.ts b/src/admin/api.ts index 2d8f7c8..fe34e5b 100644 --- a/src/admin/api.ts +++ b/src/admin/api.ts @@ -531,3 +531,48 @@ export function pinAIReport(id: number) { export function getPinnedAIReports() { return http.get("admin/ai/reports", { params: { pinned_only: "true" } }) } + +// ==================== 成就 ==================== + +export interface AdminAchievement { + id: number + name: string + description: string + icon: string + rarity: string + hidden: boolean + metric: string + metric_name: string + operator: "gte" | "lte" + threshold: number + visible: boolean + unlock_count: number + order: number + create_time: string +} + +export interface MetricOption { + key: string + name: string + help_text: string +} + +export function getAdminAchievements() { + return http.get("admin/achievement") +} + +export function getMetricOptions() { + return http.get("admin/achievement/metrics") +} + +export function createAchievement(data: Partial) { + return http.post("admin/achievement", data) +} + +export function updateAchievement(data: Partial) { + return http.put("admin/achievement", data) +} + +export function deleteAchievement(id: number) { + return http.delete("admin/achievement", { params: { id } }) +} diff --git a/src/routes.ts b/src/routes.ts index 067f28e..8f8f383 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -301,6 +301,14 @@ export const admins: RouteRecordRaw = { component: () => import("admin/problemset/list.vue"), meta: { requiresTeacherAdmin: true }, }, + { + path: "achievement/list", + name: "admin achievement list", + // 后端 admin 接口是 super_admin_required,这里必须跟着用 + // requiresSuperAdmin,否则教师能进页面但每个请求都 403 + component: () => import("admin/achievement/list.vue"), + meta: { requiresSuperAdmin: true }, + }, { path: "problemset/create", name: "admin problemset create", diff --git a/src/shared/layout/admin.vue b/src/shared/layout/admin.vue index 1923e46..bf9d9e0 100644 --- a/src/shared/layout/admin.vue +++ b/src/shared/layout/admin.vue @@ -141,6 +141,15 @@ const options = computed(() => { ), key: "admin tutorial list", }, + { + label: () => + h( + RouterLink, + { to: "/admin/achievement/list" }, + { default: () => "成就" }, + ), + key: "admin achievement list", + }, { label: () => h(