84 lines
2.1 KiB
Python
84 lines
2.1 KiB
Python
"""掌握度引擎:状态分级、按全局知识点节点答题后更新。"""
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
from sqlalchemy.orm import Session
|
||
|
||
from models import Knowledge, UserKnowledge
|
||
from services.knowledge_service import ensure_knowledge, ensure_user_knowledge
|
||
|
||
|
||
MASTERY_DELTA = {
|
||
"chapter": (5, 4),
|
||
"legacy": (4, 3),
|
||
"imported": (0, 0),
|
||
}
|
||
|
||
|
||
@dataclass
|
||
class KnowledgeView:
|
||
id: int
|
||
knowledge_id: int
|
||
name: str
|
||
mastery: int
|
||
position: int
|
||
domain: str
|
||
category: str
|
||
|
||
|
||
def status_for(mastery: int) -> str:
|
||
if mastery >= 85:
|
||
return "已掌握"
|
||
if mastery >= 75:
|
||
return "基本掌握"
|
||
if mastery >= 60:
|
||
return "待加强"
|
||
return "重点"
|
||
|
||
|
||
def action_for(mastery: int) -> str:
|
||
if mastery < 60:
|
||
return "优先强化"
|
||
if mastery < 75:
|
||
return "继续练习"
|
||
return "保持复习"
|
||
|
||
|
||
def snapshot(db: Session, user_id: int) -> list[KnowledgeView]:
|
||
rows = (
|
||
db.query(UserKnowledge, Knowledge)
|
||
.join(Knowledge, Knowledge.id == UserKnowledge.knowledge_id)
|
||
.filter(UserKnowledge.user_id == user_id)
|
||
.order_by(UserKnowledge.position.asc(), UserKnowledge.id.asc())
|
||
.all()
|
||
)
|
||
return [
|
||
KnowledgeView(
|
||
id=user_knowledge.id,
|
||
knowledge_id=knowledge.id,
|
||
name=knowledge.name,
|
||
mastery=user_knowledge.mastery,
|
||
position=user_knowledge.position,
|
||
domain=knowledge.domain,
|
||
category=knowledge.category,
|
||
)
|
||
for user_knowledge, knowledge in rows
|
||
]
|
||
|
||
|
||
def apply_answers(
|
||
db: Session,
|
||
user_id: int,
|
||
mode: str,
|
||
answered: list[tuple[str, bool]],
|
||
) -> None:
|
||
"""按题目全量知识点逐点调整掌握度(答对加分、答错扣分,封顶 0-100)。"""
|
||
plus, minus = MASTERY_DELTA.get(mode, (4, 3))
|
||
for knowledge_name, is_correct in answered:
|
||
knowledge = ensure_knowledge(db, knowledge_name)
|
||
row = ensure_user_knowledge(db, user_id, knowledge)
|
||
row.mastery = max(
|
||
0, min(100, row.mastery + (plus if is_correct else -minus))
|
||
)
|