fix(exams): fix toolbar tracking and prevent list-to-options for non-choice questions
Two fixes: 1. Selection toolbar tracking: add pointerup listener so the toolbar updates its position immediately after the user finishes dragging the selection, not just on selectionUpdate events which can lag. 2. List-to-options conversion: parseOptions now only converts orderedList/bulletList to A/B/C options for choice question types (single_choice, multiple_choice, judgment). For text/composite questions, list content is preserved as part of the question stem text, preventing unwanted 'A.' prefixes.
This commit is contained in:
@@ -51,9 +51,15 @@ const collectImages = (
|
||||
return imgs
|
||||
}
|
||||
|
||||
/** 选择题类型:只有这些类型才会把列表解析为选项 */
|
||||
const CHOICE_TYPES = new Set(["single_choice", "multiple_choice", "judgment"])
|
||||
|
||||
const parseOptions = (
|
||||
nodes: JSONContent[]
|
||||
nodes: JSONContent[],
|
||||
questionType: RichQuestionType
|
||||
): Array<{ id: string; text: string; isCorrect?: boolean }> => {
|
||||
// 只有选择题才解析选项,填空/简答/复合题的列表保持为普通文本
|
||||
if (!CHOICE_TYPES.has(questionType)) return []
|
||||
const options: Array<{ id: string; text: string; isCorrect?: boolean }> = []
|
||||
const seenIds = new Set<string>()
|
||||
for (const n of nodes) {
|
||||
@@ -106,16 +112,19 @@ const buildQuestion = (qb: JSONContent): EditorQuestion => {
|
||||
return true
|
||||
})
|
||||
|
||||
const text = extractText({
|
||||
type: "doc",
|
||||
content: nonQuestionBlocks.filter(
|
||||
// 选择题:过滤掉列表(列表作为选项单独处理)
|
||||
// 非选择题:保留列表内容在文本中(列表是题干的一部分)
|
||||
const isChoice = CHOICE_TYPES.has(type)
|
||||
const textNodes = isChoice
|
||||
? nonQuestionBlocks.filter(
|
||||
(n) =>
|
||||
n.type !== "orderedList" &&
|
||||
n.type !== "bulletList" &&
|
||||
n.type !== "image"
|
||||
),
|
||||
})
|
||||
const options = parseOptions(nonQuestionBlocks)
|
||||
)
|
||||
: nonQuestionBlocks.filter((n) => n.type !== "image")
|
||||
const text = extractText({ type: "doc", content: textNodes })
|
||||
const options = parseOptions(nonQuestionBlocks, type)
|
||||
const blanks = collectBlanks(nonQuestionBlocks)
|
||||
const images = collectImages(nonQuestionBlocks)
|
||||
const content: RichQuestionContent = { text: text.trim() }
|
||||
|
||||
@@ -128,6 +128,14 @@ export function SelectionToolbar({
|
||||
}
|
||||
|
||||
editor.on("selectionUpdate", updatePosition)
|
||||
|
||||
// 鼠标释放后立即更新位置(选区拖动结束时)
|
||||
const handlePointerUp = () => {
|
||||
// 微延迟确保选区已更新
|
||||
requestAnimationFrame(updatePosition)
|
||||
}
|
||||
document.addEventListener("pointerup", handlePointerUp)
|
||||
|
||||
editor.on("blur", () => {
|
||||
// 延迟以允许点击工具栏按钮
|
||||
setTimeout(() => {
|
||||
@@ -140,6 +148,7 @@ export function SelectionToolbar({
|
||||
|
||||
return () => {
|
||||
editor.off("selectionUpdate", updatePosition)
|
||||
document.removeEventListener("pointerup", handlePointerUp)
|
||||
}
|
||||
}, [editor])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user