From eaab224ba89d9f905263fc9838ece625aed79445 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sat, 10 Oct 2026 14:07:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=87=BA=E9=A2=98):=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9C=80=E5=A4=9A=2020=20=E7=BB=84=EF=BC=8C?= =?UTF-8?q?=E5=87=A0=E7=99=BE=E7=BB=84=E7=9A=84=E9=A2=98=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E6=88=AA=E5=9B=BE=E6=88=AA=E4=B8=8D=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上传 zip 超过 20 组直接报错(编程题、SQL 题都算);出题页加满 20 组后「加一组」 「AI 想几组输入」变灰,导入超过 20 组的 zip 在浏览器里就拦下,改老题超了不让保存。 上限在契约 TEST_CASE_MAX_CASES。线上超过 20 组的题已经手工缩到 20 组。 Co-Authored-By: Claude Opus 5.5 --- apps/api/src/services/test-case.ts | 10 ++++- apps/web/src/admin/problem/SqlDetail.vue | 29 +++++++++--- .../src/admin/problem/components/caseRows.ts | 11 ++++- apps/web/src/admin/problem/detail.vue | 45 ++++++++++++++++--- packages/contract/src/admin.ts | 7 +++ 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/apps/api/src/services/test-case.ts b/apps/api/src/services/test-case.ts index 780f45d..c18cb0a 100644 --- a/apps/api/src/services/test-case.ts +++ b/apps/api/src/services/test-case.ts @@ -4,6 +4,8 @@ import { resolve } from "node:path" import { unzipSync, zipSync } from "fflate" +import { TEST_CASE_MAX_CASES } from "@oj2/contract" + import { config } from "../config" /** @@ -18,7 +20,7 @@ import { config } from "../config" const MAX_ENTRY_BYTES = 32 * 1024 * 1024 /** 解压后总大小上限,防 zip bomb */ const MAX_TOTAL_BYTES = 128 * 1024 * 1024 -/** 测试点数量上限 */ +/** 往后找连续编号最多找到几号。真正的上限是契约的 TEST_CASE_MAX_CASES,多出来的要报错而不是静默截掉 */ const MAX_CASES = 500 export class TestCaseError extends Error {} @@ -132,6 +134,12 @@ export async function processTestCaseZip( const selected = options.sql ? collectSqlScripts(names) : collectPairs(names).flat() if (selected.length === 0) throw new TestCaseError("压缩包里没有找到从 1 开始连续编号的测试点") + const count = options.sql ? selected.length : selected.length / 2 + if (count > TEST_CASE_MAX_CASES) { + throw new TestCaseError( + `测试数据最多 ${TEST_CASE_MAX_CASES} 组,这个压缩包里有 ${count} 组,挑有代表性的留下`, + ) + } if (options.sql && selected.length < 2) { // 题目页会展示测试点 1 的期望结果,只有一个测试点时学生可以对照着硬编码 AC throw new TestCaseError("SQL 题至少需要 2 个数据不同的测试点,防止硬编码期望结果") diff --git a/apps/web/src/admin/problem/SqlDetail.vue b/apps/web/src/admin/problem/SqlDetail.vue index e113574..e518580 100644 --- a/apps/web/src/admin/problem/SqlDetail.vue +++ b/apps/web/src/admin/problem/SqlDetail.vue @@ -1,6 +1,6 @@