Skip to content

Commit 275e44d

Browse files
ZnPdCoclaude
andcommitted
refactor(exportutil): replace file field with pre-assembled info string
- Use C++-side info string for status text instead of template-side file/no_source check - Add compile_message field for compile error details - AnswersOnly without info no longer shows spurious text Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent c8e1316 commit 275e44d

3 files changed

Lines changed: 67 additions & 24 deletions

File tree

src/component/exportutil/README.md

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,13 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
2727
| `total` | `"总分"` |
2828
| `contestant` | `"选手"` |
2929
| `task` | `"试题"` |
30-
| `source_file` | `"源程序:"` |
31-
| `no_source` | `"未找到选手程序"` |
3230
| `testcase` | `"测试点"` |
3331
| `input` | `"输入文件"` |
3432
| `result` | `"测试结果"` |
3533
| `time` | `"运行用时"` |
3634
| `memory` | `"内存消耗"` |
37-
| `score` | `"得分"` |
38-
| `return_to_top` | `"返回顶部"` |
35+
| `score` | `"得分"` |
36+
| `return_to_top` | `"返回顶部"` |
3937

4038
---
4139

@@ -54,12 +52,13 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
5452

5553
### tasks 数组内对象
5654

57-
| 字段名 | 类型 | 说明 | 举例 |
58-
| --------- | ---------- | ------------------ | ----------------- |
59-
| `score` | `number` | 该题单项得分 | `100` |
60-
| `bg` | `string` | 该题得分背景 (HSL) | `"120, 30%, 60%"` |
61-
| `file` | `string` | 选手程序文件名(可选,若无该字段则表示找不到选手程序) | `"plus.cpp"` |
62-
| `details` | `object[]` | 测试点详情数组 | 见下节 |
55+
| 字段名 | 类型 | 说明 | 举例 |
56+
| ------------------- | ---------- | -------------------------- | ----------------- |
57+
| `score` | `number` | 该题单项得分 | `100` |
58+
| `bg` | `string` | 该题得分背景 (HSL) | `"120, 30%, 60%"` |
59+
| `info` | `string` | 评测状态/源文件信息 | `"源程序:plus.cpp"` |
60+
| `compile_message` | `string` | 编译错误详情(可选) | `"error: expected ';'"` |
61+
| `details` | `object[]` | 测试点详情数组 | 见下节 |
6362

6463
---
6564

@@ -96,8 +95,6 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
9695
"total": "总分",
9796
"contestant": "选手",
9897
"task": "试题",
99-
"source_file": "源程序:",
100-
"no_source": "未找到选手程序",
10198
"testcase": "测试点",
10299
"input": "输入文件",
103100
"result": "测试结果",
@@ -117,7 +114,7 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
117114
{
118115
"score": 100,
119116
"bg": "120, 30%, 70%",
120-
"file": "plus.cpp",
117+
"info": "源程序:plus.cpp",
121118
"details": [
122119
{ "label": "#1", "row_span": 1, "input": "plus1.in", "result": "评测通过", "time": "0.001 s", "memory": "1.2 MiB", "score": 50, "full_score": 50, "bg": "rgb(192, 255, 192)" },
123120
{ "label": "#2", "row_span": 1, "input": "plus2.in", "result": "评测通过", "time": "0.002 s", "memory": "1.2 MiB", "score": 50, "full_score": 50, "bg": "rgb(192, 255, 192)" }
@@ -126,7 +123,7 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
126123
{
127124
"score": 50,
128125
"bg": "120,28.9006%,82.3499%",
129-
"file": "minus.cpp",
126+
"info": "源程序:minus.cpp",
130127
"details": [
131128
{ "label": "#1", "row_span": 1, "input": "minus1.in", "result": "评测通过", "time": "0.001 s", "memory": "1.2 MiB", "score": 50, "full_score": 50, "bg": "rgb(192, 255, 192)" },
132129
{ "label": "#2<br>子任务依赖情况:Pure", "row_span": 2, "input": "minus2.in", "result": "答案错误", "time": "0.001 s", "memory": "2.0 MiB", "score": 0, "full_score": 50, "bg": "rgb(255, 192, 192)", "info": "在第四行,读取到 123456,但期望 789123" },
@@ -142,10 +139,10 @@ HTML 导出采用 JSON + 模板 方案:C++ 端通过 `buildExportJson()` 构
142139
"total_bg": "0, 0%, 90%",
143140
"total_border": "0, 0%, 70%",
144141
"tasks": [
145-
{ "score": 0, "bg": "0, 0%, 90%" },
146-
{ "score": 0, "bg": "0, 0%, 90%" }
142+
{ "score": 0, "bg": "0, 0%, 90%", "info": "未测试" },
143+
{ "score": 0, "bg": "0, 0%, 90%", "info": "未测试" }
147144
]
148145
}
149146
]
150147
}
151-
```
148+
```

src/component/exportutil/export_template.html

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,18 @@
209209
taskH3.innerText = `${data.i18n.task} ${data.task_names[j]}`;
210210
taskContainer.append(taskH3);
211211

212-
const fileP = document.createElement('p');
213-
fileP.innerText = t.file ? `${data.i18n.source_file}${t.file}` : data.i18n.no_source;
214-
taskContainer.append(fileP);
212+
if (t.info) {
213+
const fileP = document.createElement('p');
214+
fileP.innerText = t.info;
215+
taskContainer.append(fileP);
216+
}
217+
218+
if (t.compile_message) {
219+
const msgPre = document.createElement('pre');
220+
msgPre.textContent = t.compile_message;
221+
msgPre.style.textAlign = 'left';
222+
taskContainer.append(msgPre);
223+
}
215224

216225
if (t.details && t.details.length > 0) {
217226
const detailTable = document.createElement('table');

src/component/exportutil/exportutil.cpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ QJsonObject ExportUtil::buildExportJson(Contest *contest) {
7676
i18n["total"] = tr("Total Score");
7777
i18n["contestant"] = tr("Contestant");
7878
i18n["task"] = tr("Task");
79-
i18n["source_file"] = tr("Source file: ");
80-
i18n["no_source"] = tr("Cannot find valid source file");
8179
i18n["testcase"] = tr("Test Case");
8280
i18n["input"] = tr("Input File");
8381
i18n["result"] = tr("Result");
@@ -158,9 +156,48 @@ QJsonObject ExportUtil::buildExportJson(Contest *contest) {
158156
taskList[j]->getTaskType() == Task::Interaction ||
159157
taskList[j]->getTaskType() == Task::Communication ||
160158
taskList[j]->getTaskType() == Task::CommunicationExec) {
161-
if (contestant->getCheckJudged(j) && contestant->getCompileState(j) == CompileSuccessfully) {
162-
tObj["file"] = contestant->getSourceFile(j);
159+
QString info;
160+
161+
if (! contestant->getCheckJudged(j)) {
162+
info = tr("Not judged");
163+
} else {
164+
switch (contestant->getCompileState(j)) {
165+
case CompileSuccessfully:
166+
info = tr("Source file: ") + contestant->getSourceFile(j);
167+
break;
168+
case NoValidGraderFile:
169+
info = tr("Main grader (grader.*) cannot be found");
170+
break;
171+
case NoValidSourceFile:
172+
info = tr("Cannot find valid source file");
173+
break;
174+
case CompileTimeLimitExceeded:
175+
info = tr("Source file: ") + contestant->getSourceFile(j) +
176+
QString(", ") + tr("Compile time limit exceeded");
177+
break;
178+
case InvalidCompiler:
179+
info = tr("Cannot run given compiler");
180+
break;
181+
case CompileError:
182+
info = tr("Source file: ") + contestant->getSourceFile(j) +
183+
QString(", ") + tr("Compile error");
184+
break;
185+
default:
186+
break;
187+
}
188+
}
189+
190+
if (! info.isEmpty()) {
191+
tObj["info"] = info;
192+
}
193+
194+
if (contestant->getCheckJudged(j) &&
195+
contestant->getCompileState(j) == CompileError &&
196+
! contestant->getCompileMessage(j).isEmpty()) {
197+
tObj["compile_message"] = contestant->getCompileMessage(j);
163198
}
199+
} else if (! contestant->getCheckJudged(j)) {
200+
tObj["info"] = tr("Not judged");
164201
}
165202

166203
bool isAnswersOnly = taskList[j]->getTaskType() == Task::AnswersOnly;

0 commit comments

Comments
 (0)