From 6bc2140052f53688f03730ee44161140f31ad150 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Wed, 22 Oct 2025 18:47:41 +0800 Subject: [PATCH] add problemset --- src/admin/api.ts | 106 +++++ src/admin/problemset/components/Actions.vue | 105 +++++ src/admin/problemset/detail.vue | 427 ++++++++++++++++++++ src/admin/problemset/edit.vue | 167 ++++++++ src/admin/problemset/list.vue | 211 ++++++++++ src/oj/problemset/list.vue | 0 src/routes.ts | 27 ++ src/shared/layout/admin.vue | 9 + src/utils/types.ts | 84 ++++ 9 files changed, 1136 insertions(+) create mode 100644 src/admin/problemset/components/Actions.vue create mode 100644 src/admin/problemset/detail.vue create mode 100644 src/admin/problemset/edit.vue create mode 100644 src/admin/problemset/list.vue create mode 100644 src/oj/problemset/list.vue diff --git a/src/admin/api.ts b/src/admin/api.ts index abed433..f78e270 100644 --- a/src/admin/api.ts +++ b/src/admin/api.ts @@ -285,3 +285,109 @@ export function updateACMHelperChecked( checked, }) } + +// 题单管理 API +export function getProblemSetList( + offset = 0, + limit = 10, + keyword = "", + difficulty = "", + status = "", +) { + return http.get("admin/problemset/", { + params: { + paging: true, + offset, + limit, + keyword, + difficulty, + status, + }, + }) +} + +export function getProblemSetDetail(id: number) { + return http.get(`admin/problemset/${id}/`) +} + +export function createProblemSet(data: { + title: string + description: string + difficulty: string + is_public: boolean + status: string +}) { + return http.post("admin/problemset/", data) +} + +export function editProblemSet(data: { + id: number + title?: string + description?: string + difficulty?: string + is_public?: boolean + status?: string + visible?: boolean +}) { + return http.put("admin/problemset/", data) +} + +export function deleteProblemSet(id: number) { + return http.delete("admin/problemset/", { params: { id } }) +} + +export function toggleProblemSetVisible(id: number) { + return http.put("admin/problemset/visible/", { id }) +} + +export function updateProblemSetStatus(id: number, status: string) { + return http.put("admin/problemset/status/", { id, status }) +} + +// 题单题目管理 API +export function getProblemSetProblems(problemSetId: number) { + return http.get(`admin/problemset/${problemSetId}/problems/`) +} + +export function addProblemToSet(problemSetId: number, data: { + problem_id: number + order?: number + is_required?: boolean + score?: number + hint?: string +}) { + return http.post(`admin/problemset/${problemSetId}/problems/`, data) +} + +export function removeProblemFromSet(problemSetId: number, problemId: number) { + return http.delete(`admin/problemset/${problemSetId}/problems/${problemId}/`) +} + +// 题单奖章管理 API +export function getProblemSetBadges(problemSetId: number) { + return http.get(`admin/problemset/${problemSetId}/badges/`) +} + +export function createProblemSetBadge(problemSetId: number, data: { + name: string + description: string + icon: string + condition_type: string + condition_value: number + level?: number +}) { + return http.post(`admin/problemset/${problemSetId}/badges/`, data) +} + +export function deleteProblemSetBadge(problemSetId: number, badgeId: number) { + return http.delete(`admin/problemset/${problemSetId}/badges/${badgeId}/`) +} + +// 题单进度管理 API +export function getProblemSetProgress(problemSetId: number) { + return http.get(`admin/problemset/${problemSetId}/progress/`) +} + +export function removeUserFromProblemSet(problemSetId: number, userId: number) { + return http.delete(`admin/problemset/${problemSetId}/progress/${userId}/`) +} diff --git a/src/admin/problemset/components/Actions.vue b/src/admin/problemset/components/Actions.vue new file mode 100644 index 0000000..97d1b7b --- /dev/null +++ b/src/admin/problemset/components/Actions.vue @@ -0,0 +1,105 @@ + + + diff --git a/src/admin/problemset/detail.vue b/src/admin/problemset/detail.vue new file mode 100644 index 0000000..0950e20 --- /dev/null +++ b/src/admin/problemset/detail.vue @@ -0,0 +1,427 @@ + + + + + diff --git a/src/admin/problemset/edit.vue b/src/admin/problemset/edit.vue new file mode 100644 index 0000000..579cb5e --- /dev/null +++ b/src/admin/problemset/edit.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/src/admin/problemset/list.vue b/src/admin/problemset/list.vue new file mode 100644 index 0000000..436f062 --- /dev/null +++ b/src/admin/problemset/list.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/src/oj/problemset/list.vue b/src/oj/problemset/list.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/routes.ts b/src/routes.ts index d235961..8918954 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -249,5 +249,32 @@ export const admins: RouteRecordRaw = { props: true, meta: { requiresSuperAdmin: true }, }, + // 题单管理路由 + { + path: "problemset/list", + name: "admin problemset list", + component: () => import("admin/problemset/list.vue"), + meta: { requiresSuperAdmin: true }, + }, + { + path: "problemset/create", + name: "admin problemset create", + component: () => import("admin/problemset/edit.vue"), + meta: { requiresSuperAdmin: true }, + }, + { + path: "problemset/edit/:problemSetId", + name: "admin problemset edit", + component: () => import("admin/problemset/edit.vue"), + props: true, + meta: { requiresSuperAdmin: true }, + }, + { + path: "problemset/:problemSetId", + name: "admin problemset detail", + component: () => import("admin/problemset/detail.vue"), + props: true, + meta: { requiresSuperAdmin: true }, + }, ], } diff --git a/src/shared/layout/admin.vue b/src/shared/layout/admin.vue index a2a8989..734a7d6 100644 --- a/src/shared/layout/admin.vue +++ b/src/shared/layout/admin.vue @@ -58,6 +58,15 @@ const options = computed(() => { ), key: "admin contest list", }, + { + label: () => + h( + RouterLink, + { to: "/admin/problemset/list" }, + { default: () => "题单" }, + ), + key: "admin problemset list", + }, { label: () => h(RouterLink, { to: "/admin/user/list" }, { default: () => "用户" }), diff --git a/src/utils/types.ts b/src/utils/types.ts index 714205f..69119e3 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -182,6 +182,90 @@ export interface AdminProblemFiltered { create_time: string } +// 题单相关类型 +export interface ProblemSet { + id: number + title: string + description: string + created_by: SampleUser + create_time: Date + difficulty: "Easy" | "Medium" | "Hard" + status: "active" | "archived" | "draft" + is_public: boolean + visible: boolean + problems_count: number + completed_count: number +} + +export interface ProblemSetList { + id: number + title: string + description: string + created_by: SampleUser + create_time: Date + difficulty: "Easy" | "Medium" | "Hard" + status: "active" | "archived" | "draft" + problems_count: number + visible: boolean + user_progress: { + is_joined: boolean + progress_percentage: number + completed_count: number + total_count: number + is_completed: boolean + } +} + +export interface ProblemSetProblem { + id: number + problemset: number + problem: Problem + order: number + is_required: boolean + score: number + hint: string +} + +export interface ProblemSetBadge { + id: number + problemset: number + name: string + description: string + icon: string + condition_type: "all_problems" | "problem_count" | "score" + condition_value: number + level: number +} + +export interface ProblemSetProgress { + id: number + problemset: ProblemSetList + user: SampleUser + join_time: Date + completed_problems_count: number + total_problems_count: number + progress_percentage: number + is_completed: boolean +} + +export interface CreateProblemSetData { + title: string + description: string + difficulty: "Easy" | "Medium" | "Hard" + is_public: boolean + status: "active" | "archived" | "draft" +} + +export interface EditProblemSetData { + id: number + title?: string + description?: string + difficulty?: "Easy" | "Medium" | "Hard" + is_public?: boolean + status?: "active" | "archived" | "draft" + visible?: boolean +} + export interface Code { language: LANGUAGE value: string