diff --git a/.gitignore b/.gitignore index 18b1f9d..1013e8e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,9 +20,14 @@ build/ docs/spikes/node_modules/ docs/spikes/endpoints-*.json -# 本地判题验收数据来自生产测试点,只读挂载,不进入版本库 -data/test_case/ -data/judge_server/ +# data/ 整个目录都是运行时数据,一律不进版本库。 +# +# 必须写成整目录:原来只忽略了 test_case/ 和 judge_server/,而 +# docker/compose.*.yml 会在这里生成 data/postgres/(**整个数据库**,含 +# raw_password 明文列)、data/redis/、data/backend/(学生上传的文件)。 +# 阶段 5 演练时 `git add -A` 差一点就把生产库快照提交上去,只因为 postgres +# 容器用的是别的 uid、目录读不了才失败。别再收窄这条。 +data/ # 生产题目样本只用于本地验收,不进入 git *.csv diff --git a/apps/web/src/oj/class/pk.vue b/apps/web/src/oj/class/pk.vue index 76dbaec..eaf3cd2 100644 --- a/apps/web/src/oj/class/pk.vue +++ b/apps/web/src/oj/class/pk.vue @@ -57,9 +57,9 @@ interface ClassComparison { q3_ac: number iqr: number std_dev: number - top_10_avg: number - middle_80_avg: number - bottom_10_avg: number + top10_avg: number + middle80_avg: number + bottom10_avg: number excellent_rate: number pass_rate: number active_rate: number @@ -68,7 +68,7 @@ interface ClassComparison { recent_total_ac?: number recent_avg_ac?: number recent_median_ac?: number - recent_top_10_avg?: number + recent_top10_avg?: number recent_active_count?: number } @@ -176,7 +176,7 @@ async function analyzeWithAI() { if (csrfToken) headers["X-CSRFToken"] = csrfToken try { - const response = await fetch("/api2/ai/class-pk-analysis", { + const response = await fetch("/api/ai/class-pk-analysis", { method: "POST", headers, body: JSON.stringify({ @@ -382,7 +382,7 @@ const top10AvgChartData = computed(() => { const datasets = [ { label: "前10%平均", - data: comparisons.value.map((c) => c.top_10_avg), + data: comparisons.value.map((c) => c.top10_avg), backgroundColor: comparisons.value.map((_, i) => getClassColor(i).bg), borderColor: comparisons.value.map((_, i) => getClassColor(i).border), borderWidth: 2, @@ -400,7 +400,7 @@ const bottom10AvgChartData = computed(() => { const datasets = [ { label: "后10%平均", - data: comparisons.value.map((c) => c.bottom_10_avg), + data: comparisons.value.map((c) => c.bottom10_avg), backgroundColor: comparisons.value.map((_, i) => getClassColor(i).bg), borderColor: comparisons.value.map((_, i) => getClassColor(i).border), borderWidth: 2, @@ -418,7 +418,7 @@ const middle80AvgChartData = computed(() => { const datasets = [ { label: "中间80%均值", - data: comparisons.value.map((c) => c.middle_80_avg), + data: comparisons.value.map((c) => c.middle80_avg), backgroundColor: comparisons.value.map((_, i) => getClassColor(i).bg), borderColor: comparisons.value.map((_, i) => getClassColor(i).border), borderWidth: 2, @@ -640,35 +640,35 @@ const tableColumns: DataTableColumn[] = [ }, { title: "前10%均值", - key: "top_10_avg", + key: "top10_avg", width: 100, render: (row) => h( "span", { style: { color: "#cf1322", fontWeight: "600" } }, - row.top_10_avg.toFixed(2), + row.top10_avg.toFixed(2), ), }, { title: "中间80%均值", - key: "middle_80_avg", + key: "middle80_avg", width: 110, render: (row) => h( "span", { style: { color: "#389e0d", fontWeight: "600" } }, - row.middle_80_avg.toFixed(2), + row.middle80_avg.toFixed(2), ), }, { title: "后10%均值", - key: "bottom_10_avg", + key: "bottom10_avg", width: 100, render: (row) => h( "span", { style: { color: "#096dd9", fontWeight: "500" } }, - row.bottom_10_avg.toFixed(2), + row.bottom10_avg.toFixed(2), ), }, { @@ -956,17 +956,17 @@ const radarChartOptions = { {{ - classData.top_10_avg.toFixed(2) + classData.top10_avg.toFixed(2) }} {{ - classData.middle_80_avg.toFixed(2) + classData.middle80_avg.toFixed(2) }} {{ - classData.bottom_10_avg.toFixed(2) + classData.bottom10_avg.toFixed(2) }} @@ -1049,7 +1049,7 @@ const radarChartOptions = { {{ - classData.recent_top_10_avg?.toFixed(2) + classData.recent_top10_avg?.toFixed(2) }} diff --git a/apps/web/src/oj/problem/components/SubmissionResult.vue b/apps/web/src/oj/problem/components/SubmissionResult.vue index 25c6d4c..dc8bf66 100644 --- a/apps/web/src/oj/problem/components/SubmissionResult.vue +++ b/apps/web/src/oj/problem/components/SubmissionResult.vue @@ -83,7 +83,7 @@ async function fetchHint(submissionId: string) { headers["X-CSRFToken"] = csrfToken } - const response = await fetch("/api2/ai/hint", { + const response = await fetch("/api/ai/hint", { method: "POST", headers, body: JSON.stringify({ submissionId }), diff --git a/apps/web/src/oj/rank/list.vue b/apps/web/src/oj/rank/list.vue index 505bc30..14e94c3 100644 --- a/apps/web/src/oj/rank/list.vue +++ b/apps/web/src/oj/rank/list.vue @@ -95,7 +95,7 @@ async function analyzeSingleClassWithAI() { if (csrfToken) headers["X-CSRFToken"] = csrfToken try { - const response = await fetch("/api2/ai/class-analysis", { + const response = await fetch("/api/ai/class-analysis", { method: "POST", headers, body: JSON.stringify({ comparison: classDetailData.value }), @@ -158,9 +158,9 @@ interface ClassComparison { q3_ac: number iqr: number std_dev: number - top_10_avg: number - middle_80_avg: number - bottom_10_avg: number + top10_avg: number + middle80_avg: number + bottom10_avg: number excellent_rate: number pass_rate: number active_rate: number @@ -719,17 +719,17 @@ watch( {{ - classDetailData.top_10_avg.toFixed(2) + classDetailData.top10_avg.toFixed(2) }} {{ - classDetailData.middle_80_avg.toFixed(2) + classDetailData.middle80_avg.toFixed(2) }} {{ - classDetailData.bottom_10_avg.toFixed(2) + classDetailData.bottom10_avg.toFixed(2) }} diff --git a/apps/web/src/oj/store/ai.ts b/apps/web/src/oj/store/ai.ts index 95ef9c5..2e66c95 100644 --- a/apps/web/src/oj/store/ai.ts +++ b/apps/web/src/oj/store/ai.ts @@ -104,7 +104,7 @@ export const useAIStore = defineStore("ai", () => { } try { - const response = await fetch("/api2/ai/analysis", { + const response = await fetch("/api/ai/analysis", { method: "POST", headers, body: JSON.stringify({ diff --git a/apps/web/src/utils/download.ts b/apps/web/src/utils/download.ts index d2f4e5c..62ebf40 100644 --- a/apps/web/src/utils/download.ts +++ b/apps/web/src/utils/download.ts @@ -1,9 +1,9 @@ import axios from "axios" -// 指向新后端的 /api2/admin。响应是 zip 二进制,不走 { error, data } 信封, +// 指向新后端的 /api/admin。响应是 zip 二进制,不走 { error, data } 信封, // 所以不能复用 utils/api2 的拦截器(它会把 response.data.data 取出来)。 const http = axios.create({ - baseURL: "/api2/admin", + baseURL: "/api/admin", responseType: "blob", withCredentials: true, })