更新组件现代化

This commit is contained in:
2025-11-09 12:18:34 +08:00
parent 35ed4e63be
commit 8a39ddab09
2 changed files with 125 additions and 25 deletions

View File

@@ -12,14 +12,16 @@ from textual.message import Message
class ClozePuzzle(BasePuzzleWidget): class ClozePuzzle(BasePuzzleWidget):
def __init__(self, *children: Widget, atom: pt.Atom, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None: def __init__(self, *children: Widget, atom: pt.Atom, alia: str = "", name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup) super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
self.inputlist = list() self.inputlist = list()
self.hashtable = {} self.hashtable = {}
self.alia = alia
self._work() self._work()
def _work(self): def _work(self):
self.puzzle = pz.ClozePuzzle(text=self.atom.registry["nucleon"]["content"], min_denominator=2) cfg = self.atom.registry["orbital"]["puzzles"][self.alia]
self.puzzle = pz.ClozePuzzle(text=cfg["content"], delimiter=cfg["delimiter"], min_denominator=cfg["min_denominator"])
self.puzzle.refresh() self.puzzle.refresh()
self.ans = copy.copy(self.puzzle.answer) self.ans = copy.copy(self.puzzle.answer)
random.shuffle(self.ans) random.shuffle(self.ans)

View File

@@ -20,44 +20,142 @@ import heurams.kernel.puzzles as pz
from .base_puzzle_widget import BasePuzzleWidget from .base_puzzle_widget import BasePuzzleWidget
import copy import copy
import random import random
from .. import shim from textual.message import Message
class MCQPuzzle(BasePuzzleWidget): class MCQPuzzle(BasePuzzleWidget):
def __init__(self, *children: Widget, atom: pt.Atom, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None: def __init__(self, *children: Widget, atom: pt.Atom, alia: str = "", name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup) super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
self.inputlist = [] self.inputlist = []
self.alia = alia
self.hashtable = {} self.hashtable = {}
self._work() self._work()
def _work(self): def _work(self):
self.puzzle = pz.SelectionPuzzle(self.atom[1]["keyword_note"], [], 2, "选择正确词义: ") # type: ignore cfg = self.atom.registry["orbital"]["puzzles"][self.alia]
self.puzzle = pz.MCQPuzzle(cfg["mapping"], cfg["jammer"], cfg["max_riddles_num"], cfg['prefix'])
self.puzzle.refresh() self.puzzle.refresh()
class PuzzleCompleted(Message):
"""选择题完成消息"""
def __init__(self, atom: pt.Atom, rating: int, is_correct: bool, user_answers: list, correct_answers: list) -> None:
self.atom = atom
self.rating = rating # 评分
self.is_correct = is_correct # 是否正确
self.user_answers = user_answers # 用户答案
self.correct_answers = correct_answers # 正确答案
super().__init__()
class InputChanged(Message):
"""输入变化消息"""
def __init__(self, current_input: list, current_question: int, total_questions: int, current_question_text: str) -> None:
self.current_input = current_input # 当前输入
self.current_question = current_question # 当前题号
self.total_questions = total_questions # 总题数
self.current_question_text = current_question_text # 当前问题文本
self.progress = current_question / total_questions # 进度
super().__init__()
class QuestionAdvanced(Message):
"""题目切换消息"""
def __init__(self, question_index: int, question_text: str, options: list) -> None:
self.question_index = question_index # 题目索引
self.question_text = question_text
self.options = options # 选项列表
super().__init__()
def compose(self): def compose(self):
yield Label(self.atom[1].content.replace("/",""), id="sentence") yield Label(self.atom[1].content.replace("/",""), id="sentence")
yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle") yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle")
yield Label(f"当前输入: {self.inputlist}", id="inputpreview") yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
for i in self.puzzle.options[len(self.inputlist)]:
# 渲染当前问题的选项
current_options = self.puzzle.options[len(self.inputlist)]
for i in current_options:
self.hashtable[str(hash(i))] = i self.hashtable[str(hash(i))] = i
yield Button(i, id=f"select{hash(i)}") yield Button(i, id=f"select{hash(i)}")
yield Button("退格", id=f"delete")
yield Button("退格", id="delete")
def handler(self, event, type_): def update_display(self):
if type_ == "button": # 更新预览标签
if event.button.id == "delete": preview = self.query_one("#inputpreview")
if len(self.inputlist) > 0: preview.update(f"当前输入: {self.inputlist}") # type: ignore
self.inputlist.pop()
else: # 更新问题标签
return 1 puzzle_label = self.query_one("#puzzle")
else: current_question_index = len(self.inputlist)
self.inputlist.append(self.hashtable[event.button.id[6:]]) if current_question_index < len(self.puzzle.wording):
if len(self.inputlist) < len(self.puzzle.answer): puzzle_label.update(self.puzzle.wording[current_question_index]) # type: ignore
return 1
else: # 发送输入变化消息
if self.inputlist == self.puzzle.answer: self.post_message(self.InputChanged(
shim.report_to_staging(self.atom, 4) current_input=self.inputlist.copy(),
return 0 current_question=current_question_index,
else: total_questions=len(self.puzzle.answer),
current_question_text=self.puzzle.wording[current_question_index] if current_question_index < len(self.puzzle.wording) else ""
))
# 如果还有下一题,发送题目切换消息
if current_question_index < len(self.puzzle.options):
self.post_message(self.QuestionAdvanced(
question_index=current_question_index,
question_text=self.puzzle.wording[current_question_index],
options=self.puzzle.options[current_question_index]
))
def on_button_pressed(self, event: Button.Pressed) -> None:
"""处理按钮点击事件"""
button_id = event.button.id
if button_id == "delete":
# 退格处理
if len(self.inputlist) > 0:
self.inputlist.pop()
self.refresh_buttons()
self.update_display()
elif button_id.startswith("select"): # type: ignore
# 选项选择处理
answer_text = self.hashtable[button_id[6:]] # type: ignore
self.inputlist.append(answer_text)
# 检查是否完成所有题目
if len(self.inputlist) >= len(self.puzzle.answer):
is_correct = self.inputlist == self.puzzle.answer
rating = 4 if is_correct else 2
# 发送完成消息
self.post_message(self.PuzzleCompleted(
atom=self.atom,
rating=rating,
is_correct=is_correct,
user_answers=self.inputlist.copy(),
correct_answers=self.puzzle.answer.copy()
))
# 重置输入(如果回答错误)
if not is_correct:
self.inputlist = [] self.inputlist = []
shim.report_to_staging(self.atom, 2) self.refresh_buttons()
return 2 self.update_display()
else:
# 进入下一题
self.refresh_buttons()
self.update_display()
def refresh_buttons(self):
"""刷新按钮显示(用于题目切换)"""
# 移除所有选项按钮
buttons_to_remove = [child for child in self.children if hasattr(child, 'id') and child.id and child.id.startswith('select')]
for button in buttons_to_remove:
self.remove_child(button) # type: ignore
# 添加当前题目的选项按钮
current_question_index = len(self.inputlist)
if current_question_index < len(self.puzzle.options):
current_options = self.puzzle.options[current_question_index]
for option in current_options:
button_id = f"select{hash(option)}"
if button_id not in self.hashtable:
self.hashtable[button_id] = option
new_button = Button(option, id=button_id)
self.mount(new_button)