fix: capture practice choice option content

This commit is contained in:
suanyuit-cyber
2026-10-29 21:56:15 +08:00
parent 762408a347
commit 15fa009f9e
8 changed files with 76 additions and 8 deletions
+3 -1
View File
@@ -1,6 +1,8 @@
# 华谊题库助手 # 华谊题库助手
支持在普通 HTTP / HTTPS 网页中通过快捷键打开的本地题库油猴脚本:文字搜索、划词检索、自动选择已确认答案,并保留华谊练习平台的按库采集、CSV 导出与多题库导入。当前版本 **1.2.1**。 支持在普通 HTTP / HTTPS 网页中通过快捷键打开的本地题库油猴脚本:文字搜索、划词检索、自动选择已确认答案,并保留华谊练习平台的按库采集、CSV 导出与多题库导入。当前版本 **1.2.2**。
1.2.2 修复了练习接口选择题选项正文使用 `itemContent` 时,单选和多选整题未被采集的问题;同时兼容原有 `content` 字段,标准答案继续按选项 ID 对应。更新脚本并刷新、重新进入练习后生效。
安装文件:[`dist/huayi-question-bank.user.js`](dist/huayi-question-bank.user.js)。这是构建后的完整脚本,无须安装 Node.js 或运行服务器。 安装文件:[`dist/huayi-question-bank.user.js`](dist/huayi-question-bank.user.js)。这是构建后的完整脚本,无须安装 Node.js 或运行服务器。
+1 -1
View File
@@ -4,7 +4,7 @@ const root = __dirname;
const header = `// ==UserScript== const header = `// ==UserScript==
// @name 华谊题库助手 · CSV导出与划词检索 // @name 华谊题库助手 · CSV导出与划词检索
// @namespace local.huayi.question-bank // @namespace local.huayi.question-bank
// @version 1.2.1 // @version 1.2.2
// @description 全网页快捷键唤出、本地题库文字检索与自动选择答案,按库导入导出;每页默认完全隐藏。 // @description 全网页快捷键唤出、本地题库文字检索与自动选择答案,按库导入导出;每页默认完全隐藏。
// @match *://*/* // @match *://*/*
// @run-at document-start // @run-at document-start
+2 -2
View File
@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name 华谊题库助手 · CSV导出与划词检索 // @name 华谊题库助手 · CSV导出与划词检索
// @namespace local.huayi.question-bank // @namespace local.huayi.question-bank
// @version 1.2.1 // @version 1.2.2
// @description 全网页快捷键唤出、本地题库文字检索与自动选择答案,按库导入导出;每页默认完全隐藏。 // @description 全网页快捷键唤出、本地题库文字检索与自动选择答案,按库导入导出;每页默认完全隐藏。
// @match *://*/* // @match *://*/*
// @run-at document-start // @run-at document-start
@@ -654,7 +654,7 @@ const QBAdapter = (() => {
} else if (Array.isArray(node.choiceItems)) { } else if (Array.isArray(node.choiceItems)) {
if (node.choiceItems.some(option => !option || typeof option !== 'object')) return null; if (node.choiceItems.some(option => !option || typeof option !== 'object')) return null;
options = node.choiceItems.slice(0, 100).map((option, index) => ({ options = node.choiceItems.slice(0, 100).map((option, index) => ({
id: idString(option.id), text: text(option.content), label: labelFor(index) id: idString(option.id), text: text(option.itemContent) || text(option.content), label: labelFor(index)
})); }));
if (options.length < 2 || options.some(o => !o.text)) return null; if (options.length < 2 || options.some(o => !o.text)) return null;
} else if (previous) options = previous.options.map(o => ({ ...o })); } else if (previous) options = previous.options.map(o => ({ ...o }));
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "huayi-question-bank", "name": "huayi-question-bank",
"version": "1.2.1", "version": "1.2.2",
"private": true, "private": true,
"description": "华谊练习题库本地采集、CSV 导出与划词检索油猴脚本", "description": "华谊练习题库本地采集、CSV 导出与划词检索油猴脚本",
"scripts": { "scripts": {
+1 -1
View File
@@ -76,7 +76,7 @@ const QBAdapter = (() => {
} else if (Array.isArray(node.choiceItems)) { } else if (Array.isArray(node.choiceItems)) {
if (node.choiceItems.some(option => !option || typeof option !== 'object')) return null; if (node.choiceItems.some(option => !option || typeof option !== 'object')) return null;
options = node.choiceItems.slice(0, 100).map((option, index) => ({ options = node.choiceItems.slice(0, 100).map((option, index) => ({
id: idString(option.id), text: text(option.content), label: labelFor(index) id: idString(option.id), text: text(option.itemContent) || text(option.content), label: labelFor(index)
})); }));
if (options.length < 2 || options.some(o => !o.text)) return null; if (options.length < 2 || options.some(o => !o.text)) return null;
} else if (previous) options = previous.options.map(o => ({ ...o })); } else if (previous) options = previous.options.map(o => ({ ...o }));
+37
View File
@@ -16,6 +16,43 @@ test('extracts confirmed choices atomically and ignores student selection', () =
assert.deepEqual(q.answerTexts, ['提高温度']); assert.deepEqual(q.answerTexts, ['提高温度']);
}); });
test('practice single-choice itemContent preserves standard answers by option id', () => {
const raw = {
id: 'practice-single', quesType: 0, content: '<p>升温时应选择?</p>',
choiceItems: [
{ id: 'a2', itemContent: '<p>提高温度</p>', content: '旧选项正文', selected: 0 },
{ id: 'a1', itemContent: '<p>降低温度</p>', selected: 1 }
],
correctAnswers: ['a2']
};
const [q] = extractQuestions({ data: { praId: 'p1', listQues: [raw] } });
assert.ok(q);
assert.equal(q.answerStatus, 'confirmed');
assert.deepEqual(q.options.map(option => option.text), ['提高温度', '降低温度']);
assert.deepEqual(q.correctOptionIds, ['a2']);
assert.deepEqual(q.answerTexts, ['提高温度']);
assert.equal(q.options[0].label, 'A');
});
test('practice multiple-choice itemContent keeps shuffled answers and content fallback', () => {
const raw = {
id: 'practice-multiple', quesType: 1, content: '<p>可采用哪些措施?</p>',
choiceItems: [
{ id: 'a3', itemContent: '<p>保持压力</p>' },
{ id: 'a1', itemContent: '<p>降低温度</p>', selected: 1 },
{ id: 'a2', itemContent: ' ', content: '<p>提高温度</p>' }
],
correctAnswers: ['a2', 'a3']
};
const [q] = extractQuestions({ data: { praId: 'p2', listQues: [raw] } });
assert.ok(q);
assert.equal(q.answerStatus, 'confirmed');
assert.deepEqual(q.options.map(option => option.text), ['保持压力', '降低温度', '提高温度']);
assert.deepEqual(q.correctOptionIds, ['a2', 'a3']);
assert.deepEqual(q.answerTexts, ['提高温度', '保持压力']);
assert.equal(q.options.find(option => option.id === 'a2').label, 'C');
});
test('selected, submitContent, userAnswer and top-level answer/answers are not standard answers', () => { test('selected, submitContent, userAnswer and top-level answer/answers are not standard answers', () => {
const raw = single(); const raw = single();
raw.choiceItems.forEach(o => delete o.answer); raw.choiceItems.forEach(o => delete o.answer);
+4 -2
View File
@@ -7,9 +7,11 @@
| 判断题库1 | 500 | 已整理,原1502条重复记录还原为500题 | | 判断题库1 | 500 | 已整理,原1502条重复记录还原为500题 |
| 判断题库2 | 232 | 已整理,原696条重复记录还原为232题 | | 判断题库2 | 232 | 已整理,原696条重复记录还原为232题 |
| 单选题库1 | — | 页面显示500题,等待完整导出 | | 单选题库1 | — | 页面显示500题,等待完整导出 |
| 单选题库2 | — | 等待完整导出 | | 单选题库2 | — | 页面显示401题,等待完整导出 |
| 多选题库 | — | 等待完整导出 | | 多选题库 | — | 页面显示251题,等待完整导出 |
已有两库共732题,均有已确认答案,没有答案冲突。它们保留在 `分题库/`。原始下载 CSV 未修改。 已有两库共732题,均有已确认答案,没有答案冲突。它们保留在 `分题库/`。原始下载 CSV 未修改。
五库页面题数合计1884题,核对清单保存在 `页面题数核对.json`。
其余题库导出后,使用仓库 `scripts/merge-question-banks.cjs` 按页面题数检查并生成完整合并题库;未收齐前不以现有732题冒充五库全集。 其余题库导出后,使用仓库 `scripts/merge-question-banks.cjs` 按页面题数检查并生成完整合并题库;未收齐前不以现有732题冒充五库全集。
+27
View File
@@ -0,0 +1,27 @@
{
"schemaVersion": 1,
"checkedDate": "2026-10-29",
"source": "Chrome 学习页面的试题总数与答题卡总数",
"banks": [
{
"bankName": "华谊集团化工总控工(高级)-判断题库1",
"questionCount": 500
},
{
"bankName": "华谊集团化工总控工(高级)-判断题库2",
"questionCount": 232
},
{
"bankName": "华谊集团化工总控工(高级)-单选题库1",
"questionCount": 500
},
{
"bankName": "华谊集团化工总控工(高级)-单选题库2",
"questionCount": 401
},
{
"bankName": "华谊集团化工总控工(高级)-多选题库",
"questionCount": 251
}
]
}