From eff635fb49368e0ee14ace52160d475f371a80a2 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sat, 2 May 2026 07:57:28 -0600 Subject: [PATCH] feat: add gradebook frontend API types --- src/api.ts | 46 +++++++++++++++++++++++++++++++++++++++++ src/utils/type.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/api.ts b/src/api.ts index 17a9adb..ce06356 100644 --- a/src/api.ts +++ b/src/api.ts @@ -14,6 +14,8 @@ import type { AwardItemIn, AwardItemUpdateIn, AwardItemManageOut, + GradebookOut, + GradebookQuery, ShowcaseSubmissionLookupOut, ShowcaseDetail, PromptRound, @@ -252,6 +254,50 @@ export const Submission = { }, } +function gradebookParams(query: GradebookQuery) { + const params: Record = { + classname: query.classname, + } + if (query.task_type) params.task_type = query.task_type + if (query.username) params.username = query.username + if (query.include_all_tasks) params.include_all_tasks = true + return params +} + +function filenameFromDisposition( + disposition: string | undefined, + fallback: string, +) { + const match = disposition?.match(/filename\*=UTF-8''([^;]+)/) + return match ? decodeURIComponent(match[1]) : fallback +} + +export const Gradebook = { + async get(query: GradebookQuery): Promise { + const res = await http.get("/submission/gradebook/", { + params: gradebookParams(query), + }) + return res.data + }, + + async downloadCsv(query: GradebookQuery) { + const res = await http.get("/submission/gradebook/export/", { + params: gradebookParams(query), + responseType: "blob", + }) + const blob = new Blob([res.data], { type: "text/csv;charset=utf-8" }) + const url = URL.createObjectURL(blob) + const a = document.createElement("a") + a.href = url + a.download = filenameFromDisposition( + res.headers["content-disposition"], + `gradebook-${query.classname}.csv`, + ) + a.click() + URL.revokeObjectURL(url) + }, +} + export const Prompt = { async listConversations(taskId?: number, userId?: number) { const params: Record = {} diff --git a/src/utils/type.ts b/src/utils/type.ts index 09145e4..36669fa 100644 --- a/src/utils/type.ts +++ b/src/utils/type.ts @@ -161,6 +161,58 @@ export interface TaskStatsOut { top_viewed: TopViewedItem[] } +export type GradebookTaskType = "tutorial" | "challenge" +export type GradebookGrade = "A" | "B" | "C" | "D" | "E" + +export interface GradebookQuery { + classname: string + task_type?: GradebookTaskType | "" + username?: string + include_all_tasks?: boolean +} + +export interface GradebookTask { + id: number + display: number + title: string + task_type: GradebookTaskType + submitted_count: number + coverage: number + included: boolean +} + +export interface GradebookCell { + score: number + submitted: boolean + submission_id: string | null +} + +export interface GradebookRow { + user_id: number + username: string + classname: string + rank: number + grade: GradebookGrade + scores: Record + tutorial_total: number + challenge_total: number + total_score: number + average_score: number | null + submitted_task_count: number + missing_task_count: number +} + +export interface GradebookOut { + classname: string + classes: string[] + task_count: number + included_task_count: number + student_count: number + coverage_threshold_count: number + tasks: GradebookTask[] + rows: GradebookRow[] +} + export interface ShowcaseItem { submission_id: string username: string