「这行算不算数」原来判的是 `f.in.trim()`,把「这题没有输入」和「这行我还没 填」撞成了同一种状态。打印类题目(输出星号矩形、只靠 print 的格式化输出题) 输入留空 → 点「先运行」整行被删 → 一行不剩 → 「上传」永远是灰的,老师只能 往输入框里塞个「无」才存得下去,那两个字节就真的进了 stdin。8019 / 8020 / 8021 三道题的 1.in 就是这么变成 3 字节「无」的。 拆成两个判据: - hasOutput —— 有输出且没报错,这一行才打进 zip,输入空不空无所谓; - isFilled —— 输入或输出任一非空,只用来在「先运行」里筛掉面板上的空占位行, 全没填时留一行当无输入题跑。 canUpload 保留原来那条守卫:填了输入却没跑出输出的行仍然挡住上传。「先运行」 不再要求先填输入。 后端本来就收空的 .in(processTestCaseZip 无非空校验),已上线的 8007、P003 的 1.in 就是 0 字节,卡住的一直只有这个面板。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdMvixPo27sWFrUmk6ZStZ
This commit is contained in:
@@ -83,13 +83,32 @@ watch(
|
|||||||
const isRunning = ref(false)
|
const isRunning = ref(false)
|
||||||
const isUploading = ref(false)
|
const isUploading = ref(false)
|
||||||
|
|
||||||
const hasAnyInput = computed(() => files.value.some((f) => f.in.trim()))
|
/**
|
||||||
|
* 一个测试点必须有输出,但不一定有输入 —— 打印类题目(输出星号矩形、只靠
|
||||||
|
* print 的格式化输出题…)的 `N.in` 本来就该是空文件。
|
||||||
|
*
|
||||||
|
* 原来「这行算不算数」判的是 `f.in.trim()`,把「这题没有输入」和「这行我还没填」
|
||||||
|
* 撞成了同一种状态:输入留空 → 点「先运行」整行被删 → 一行不剩 → 「上传」
|
||||||
|
* 永远是灰的。老师只能往输入框里塞个「无」才存得下去,那两个字节就真的进了 stdin。
|
||||||
|
*/
|
||||||
|
function hasOutput(file: FileEntry) {
|
||||||
|
return !!file.out.trim() && !file.error
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 老师碰过这一行没有。面板一开就铺 5 个空行,`+1` / `+5` 还能再加,空行是占位不是测试点 */
|
||||||
|
function isFilled(file: FileEntry) {
|
||||||
|
return !!(file.in.trim() || file.out.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 真正会被打进 zip 的行:有输出就算数,输入空不空无所谓 */
|
||||||
|
const uploadable = computed(() => files.value.filter(hasOutput))
|
||||||
|
|
||||||
const canUpload = computed(
|
const canUpload = computed(
|
||||||
() =>
|
() =>
|
||||||
!isRunning.value &&
|
!isRunning.value &&
|
||||||
hasAnyInput.value &&
|
uploadable.value.length > 0 &&
|
||||||
files.value.filter((f) => f.in.trim()).every((f) => f.out && !f.error),
|
// 填了输入却没跑出输出:要么还没运行,要么运行炸了,这种状态不许传
|
||||||
|
files.value.every((f) => !f.in.trim() || hasOutput(f)),
|
||||||
)
|
)
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
@@ -122,14 +141,16 @@ async function run() {
|
|||||||
)
|
)
|
||||||
if (!answer?.code.trim()) return
|
if (!answer?.code.trim()) return
|
||||||
|
|
||||||
// 过滤空行,去重(按输入内容)
|
// 过滤没填过的行,去重(按输入内容)。全没填就留一行,当成无输入题跑一次 ——
|
||||||
|
// 无输入题只可能有一个测试点,去重那条规则本来也会把多行空输入并成一行。
|
||||||
const seen = new Set<string>()
|
const seen = new Set<string>()
|
||||||
files.value = files.value.filter((f) => {
|
const kept = files.value.filter((f) => {
|
||||||
if (!f.in.trim()) return false
|
if (!isFilled(f)) return false
|
||||||
if (seen.has(f.in)) return false
|
if (seen.has(f.in)) return false
|
||||||
seen.add(f.in)
|
seen.add(f.in)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
files.value = kept.length > 0 ? kept : files.value.slice(0, 1)
|
||||||
|
|
||||||
// 清空旧输出
|
// 清空旧输出
|
||||||
files.value = files.value.map((f) => ({ ...f, out: "", error: false }))
|
files.value = files.value.map((f) => ({ ...f, out: "", error: false }))
|
||||||
@@ -158,8 +179,7 @@ async function run() {
|
|||||||
async function upload() {
|
async function upload() {
|
||||||
isUploading.value = true
|
isUploading.value = true
|
||||||
try {
|
try {
|
||||||
const data = files.value
|
const data = uploadable.value
|
||||||
.filter((f) => f.in.trim() && f.out && !f.error)
|
|
||||||
.flatMap((f, i) => [
|
.flatMap((f, i) => [
|
||||||
{ name: `${i + 1}.in`, content: f.in },
|
{ name: `${i + 1}.in`, content: f.in },
|
||||||
{ name: `${i + 1}.out`, content: f.out },
|
{ name: `${i + 1}.out`, content: f.out },
|
||||||
@@ -208,20 +228,20 @@ async function upload() {
|
|||||||
<n-button :disabled="isRunning" @click="reset">清空</n-button>
|
<n-button :disabled="isRunning" @click="reset">清空</n-button>
|
||||||
<n-button :disabled="isRunning" @click="add(1)">+1</n-button>
|
<n-button :disabled="isRunning" @click="add(1)">+1</n-button>
|
||||||
<n-button :disabled="isRunning" @click="add(5)">+5</n-button>
|
<n-button :disabled="isRunning" @click="add(5)">+5</n-button>
|
||||||
<n-tooltip :disabled="hasAnswerCode && hasAnyInput">
|
<n-tooltip :disabled="hasAnswerCode">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span>
|
<span>
|
||||||
<n-button
|
<n-button
|
||||||
type="success"
|
type="success"
|
||||||
:loading="isRunning"
|
:loading="isRunning"
|
||||||
:disabled="!hasAnswerCode || !hasAnyInput"
|
:disabled="!hasAnswerCode"
|
||||||
@click="run"
|
@click="run"
|
||||||
>
|
>
|
||||||
先运行
|
先运行
|
||||||
</n-button>
|
</n-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
{{ !hasAnswerCode ? "请先在题目中填写答案代码" : "请先填写输入" }}
|
请先在题目中填写答案代码
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
<n-button
|
<n-button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
Reference in New Issue
Block a user