feat: 修改部分导入文本的逻辑,添加部署脚本和样式文件,更新数据库迁移逻辑

- 新增部署脚本 `build-deploy-bundle.mjs`,用于构建和部署 web 和 server 目录。
- 新增样式文件 `index-acd65452.css`,包含基础样式和响应式设计。
- 新增脚本 `repro-import-text.mjs`,用于测试文本导入 API。
- 新增测试文件 `db-migration-score-zero.test.ts`,验证历史数据库中 questions.score 约束的迁移逻辑。
- 更新数据库初始化逻辑,允许插入 score=0 的问题。
This commit is contained in:
2026-01-04 09:20:04 +08:00
parent fbfd48e0ca
commit dbf9fdc01c
26 changed files with 1420 additions and 849 deletions

View File

@@ -236,7 +236,7 @@ test('前端文本解析支持 | 分隔格式', async () => {
'题型|题目类别|分值|题目内容|选项|答案|解析',
'单选|通用|5|我国首都是哪里?|北京|上海|广州|深圳|A|我国首都为北京',
'多选|通用|5|以下哪些是水果?|苹果|白菜|香蕉|西红柿|A,C,D|水果包括苹果/香蕉/西红柿',
'判断|通用|2|地球是圆的||正确|地球接近球体',
'判断|通用|0|地球是圆的||正确|地球接近球体',
].join('\n');
const res = parseTextQuestions(input);
@@ -259,6 +259,69 @@ test('前端文本解析支持 | 分隔格式', async () => {
assert.ok(judgment);
assert.equal(judgment.answer, '正确');
assert.equal(judgment.analysis, '地球接近球体');
assert.equal(judgment.score, 0);
});
test('前端文本解析:| 分隔时选项允许包含逗号/顿号', async () => {
const { parseTextQuestions } = await import('../src/utils/questionTextImport');
const input = [
'题型|题目类别|分值|题目内容|选项|答案|解析',
'单选|通用|5|带标点的选项是否应完整保留?|选项A包含中文逗号|选项B、包含顿号|选项C(括号)|选项D。句号|A|应能正常解析',
].join('\n');
const res = parseTextQuestions(input);
assert.deepEqual(res.errors, []);
assert.equal(res.questions.length, 1);
const q = res.questions[0];
assert.equal(q.type, 'single');
assert.deepEqual(q.options, ['选项A包含中文逗号', '选项B、包含顿号', '选项C(括号)', '选项D。句号']);
assert.equal(q.answer, '选项A包含中文逗号');
assert.equal(q.analysis, '应能正常解析');
});
test('题库文本导入应允许0分题目', async () => {
const { initDatabase, get } = await import('../api/database');
await initDatabase();
const { app } = await import('../api/server');
const server = app.listen(0);
try {
const addr = server.address();
assert.ok(addr && typeof addr === 'object');
const baseUrl = `http://127.0.0.1:${addr.port}`;
const res = await jsonFetch(baseUrl, '/api/questions/import-text', {
method: 'POST',
body: {
mode: 'incremental',
questions: [
{
content: '0分判断题示例',
type: 'judgment',
category: '通用',
options: undefined,
answer: '正确',
analysis: '该题用于验证0分允许导入',
score: 0,
},
],
},
});
assert.equal(res.status, 200);
assert.equal(res.json?.success, true);
assert.equal(res.json?.data?.inserted, 1);
const row = await get(`SELECT * FROM questions WHERE content = ?`, ['0分判断题示例']);
assert.ok(row);
assert.equal(row.score, 0);
assert.equal(row.type, 'judgment');
} finally {
await new Promise<void>((resolve) => server.close(() => resolve()));
}
});
test('题目类别列表应返回题库数量统计', async () => {