diff --git a/src/modules/exams/editor/editor-to-structure.ts b/src/modules/exams/editor/editor-to-structure.ts index 64610ab..11d3aa7 100644 --- a/src/modules/exams/editor/editor-to-structure.ts +++ b/src/modules/exams/editor/editor-to-structure.ts @@ -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() for (const n of nodes) { @@ -106,16 +112,19 @@ const buildQuestion = (qb: JSONContent): EditorQuestion => { return true }) - const text = extractText({ - type: "doc", - content: nonQuestionBlocks.filter( - (n) => - n.type !== "orderedList" && - n.type !== "bulletList" && - n.type !== "image" - ), - }) - const options = parseOptions(nonQuestionBlocks) + // 选择题:过滤掉列表(列表作为选项单独处理) + // 非选择题:保留列表内容在文本中(列表是题干的一部分) + const isChoice = CHOICE_TYPES.has(type) + const textNodes = isChoice + ? nonQuestionBlocks.filter( + (n) => + n.type !== "orderedList" && + n.type !== "bulletList" && + n.type !== "image" + ) + : 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() } diff --git a/src/modules/exams/editor/selection-toolbar.tsx b/src/modules/exams/editor/selection-toolbar.tsx index 746eb66..5d5d145 100644 --- a/src/modules/exams/editor/selection-toolbar.tsx +++ b/src/modules/exams/editor/selection-toolbar.tsx @@ -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])