220 lines
8.6 KiB
Python
220 lines
8.6 KiB
Python
from django.db import models
|
|
from apps.common.models import BaseModel
|
|
from apps.user.models import User
|
|
|
|
|
|
class CaseBase(BaseModel):
|
|
"""病例主表"""
|
|
CASE_TYPE_CHOICES = [
|
|
('traditional', '传统病例'),
|
|
('script', '剧本病例'),
|
|
('teaching', '教学互动病例'),
|
|
('osce', 'OSCE'),
|
|
]
|
|
STATUS_CHOICES = [
|
|
(0, '禁用'),
|
|
(1, '正常'),
|
|
]
|
|
PUBLISH_STATUS_CHOICES = [
|
|
(0, '草稿'),
|
|
(1, '已发布'),
|
|
(2, '已下架'),
|
|
]
|
|
|
|
id = models.BigAutoField(primary_key=True)
|
|
title = models.CharField('病例标题', max_length=255)
|
|
case_type = models.CharField('病例类型', max_length=30, choices=CASE_TYPE_CHOICES)
|
|
difficulty = models.CharField('难度', max_length=20, blank=True)
|
|
difficulty_score = models.IntegerField('AI难度评分', null=True, blank=True)
|
|
department = models.ForeignKey(
|
|
'user.Department', on_delete=models.SET_NULL,
|
|
null=True, blank=True, verbose_name='所属科室'
|
|
)
|
|
chief_complaint = models.TextField('主诉', blank=True)
|
|
description = models.TextField('病例简介', blank=True)
|
|
patient_age = models.IntegerField('患者年龄', null=True, blank=True)
|
|
patient_gender = models.CharField('患者性别', max_length=10, blank=True)
|
|
tags = models.CharField('标签', max_length=500, blank=True)
|
|
symptom_tags = models.JSONField('症状标签', default=list, blank=True)
|
|
disease_tags = models.JSONField('疾病标签', default=list, blank=True)
|
|
competency_tags = models.JSONField('能力标签', default=list, blank=True)
|
|
guideline_tags = models.JSONField('指南标签', default=list, blank=True)
|
|
knowledge_points = models.JSONField('知识点', default=list, blank=True)
|
|
icd_codes = models.CharField('ICD编码', max_length=500, blank=True)
|
|
estimated_minutes = models.IntegerField('预计训练时长', null=True, blank=True)
|
|
osce_enabled = models.BooleanField('是否OSCE', default=False)
|
|
rag_enabled = models.BooleanField('是否启用知识增强', default=False)
|
|
ai_prompt_template = models.TextField('AI角色Prompt', blank=True)
|
|
multimodal_assets = models.JSONField('图片/影像/附件', default=dict, blank=True)
|
|
vector_status = models.SmallIntegerField('是否向量化', default=0)
|
|
created_by = models.ForeignKey(
|
|
User, on_delete=models.SET_NULL,
|
|
null=True, blank=True, verbose_name='创建人'
|
|
)
|
|
publish_status = models.SmallIntegerField('发布状态', choices=PUBLISH_STATUS_CHOICES, default=0)
|
|
status = models.SmallIntegerField('状态', choices=STATUS_CHOICES, default=1)
|
|
|
|
class Meta:
|
|
db_table = 'case_base'
|
|
verbose_name = '病例'
|
|
verbose_name_plural = '病例'
|
|
|
|
def __str__(self):
|
|
return self.title
|
|
|
|
|
|
class TraditionalCase(BaseModel):
|
|
"""传统病例表"""
|
|
id = models.BigAutoField(primary_key=True)
|
|
case = models.OneToOneField(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
verbose_name='病例'
|
|
)
|
|
standard_diagnosis = models.TextField('标准诊断', blank=True)
|
|
standard_treatment = models.TextField('标准治疗', blank=True)
|
|
guideline_reference = models.TextField('指南参考', blank=True)
|
|
|
|
class Meta:
|
|
db_table = 'traditional_case'
|
|
verbose_name = '传统病例'
|
|
verbose_name_plural = '传统病例'
|
|
|
|
def __str__(self):
|
|
return f"传统病例: {self.case.title}"
|
|
|
|
|
|
class ScriptCase(BaseModel):
|
|
"""剧本病例表"""
|
|
id = models.BigAutoField(primary_key=True)
|
|
case = models.OneToOneField(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
verbose_name='病例'
|
|
)
|
|
scenario_setting = models.TextField('场景设定', blank=True)
|
|
emotional_state = models.CharField('情绪状态', max_length=50, blank=True)
|
|
cultural_level = models.CharField('文化水平', max_length=50, blank=True)
|
|
branch_logic = models.TextField('分支逻辑', blank=True)
|
|
hidden_clues = models.TextField('隐藏线索', blank=True)
|
|
|
|
class Meta:
|
|
db_table = 'script_case'
|
|
verbose_name = '剧本病例'
|
|
verbose_name_plural = '剧本病例'
|
|
|
|
def __str__(self):
|
|
return f"剧本病例: {self.case.title}"
|
|
|
|
|
|
class TeachingCase(BaseModel):
|
|
"""教学互动病例表"""
|
|
id = models.BigAutoField(primary_key=True)
|
|
case = models.OneToOneField(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
verbose_name='病例'
|
|
)
|
|
teaching_goal = models.TextField('教学目标', blank=True)
|
|
discussion_questions = models.TextField('讨论问题', blank=True)
|
|
teacher_guide = models.TextField('教师指南', blank=True)
|
|
scoring_focus = models.TextField('评分重点', blank=True)
|
|
|
|
class Meta:
|
|
db_table = 'teaching_case'
|
|
verbose_name = '教学互动病例'
|
|
verbose_name_plural = '教学互动病例'
|
|
|
|
def __str__(self):
|
|
return f"教学病例: {self.case.title}"
|
|
|
|
|
|
class CaseStage(BaseModel):
|
|
"""病例阶段表"""
|
|
STAGE_MODE_CHOICES = [
|
|
('dialogue', '对话'),
|
|
('osce', 'OSCE'),
|
|
('choice', '选择'),
|
|
]
|
|
|
|
id = models.BigAutoField(primary_key=True)
|
|
case = models.ForeignKey(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
related_name='stages', verbose_name='病例'
|
|
)
|
|
stage_type = models.CharField('阶段类型', max_length=50, blank=True)
|
|
stage_name = models.CharField('阶段名称', max_length=100)
|
|
stage_mode = models.CharField('阶段模式', max_length=30, choices=STAGE_MODE_CHOICES, default='dialogue')
|
|
stage_goal = models.TextField('阶段目标', blank=True)
|
|
ai_role_prompt = models.TextField('AI阶段Prompt', blank=True)
|
|
standard_action = models.TextField('标准动作', blank=True)
|
|
expected_questions = models.TextField('期望问题', blank=True)
|
|
scoring_points = models.TextField('评分点', blank=True)
|
|
timeout_seconds = models.IntegerField('超时时间', null=True, blank=True)
|
|
unlock_condition = models.CharField('解锁条件', max_length=255, blank=True)
|
|
sort_order = models.IntegerField('排序', default=0)
|
|
|
|
class Meta:
|
|
db_table = 'case_stage'
|
|
verbose_name = '病例阶段'
|
|
verbose_name_plural = '病例阶段'
|
|
ordering = ['sort_order', 'id']
|
|
|
|
def __str__(self):
|
|
return f"{self.case.title} - {self.stage_name}"
|
|
|
|
|
|
class ScoringRule(BaseModel):
|
|
"""评分规则表"""
|
|
id = models.BigAutoField(primary_key=True)
|
|
case = models.ForeignKey(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
related_name='scoring_rules', verbose_name='病例'
|
|
)
|
|
dimension = models.CharField('评分维度', max_length=50)
|
|
competency_dimension = models.CharField('能力维度', max_length=50, blank=True)
|
|
score_weight = models.DecimalField('权重', max_digits=5, decimal_places=2, default=1.00)
|
|
ai_auto_score = models.BooleanField('AI自动评分', default=False)
|
|
osce_dimension = models.BooleanField('是否OSCE', default=False)
|
|
scoring_standard = models.TextField('评分标准', blank=True)
|
|
rubric_json = models.JSONField('评分Rubric', default=dict, blank=True)
|
|
|
|
class Meta:
|
|
db_table = 'scoring_rule'
|
|
verbose_name = '评分规则'
|
|
verbose_name_plural = '评分规则'
|
|
|
|
def __str__(self):
|
|
return f"{self.case.title} - {self.dimension}"
|
|
|
|
|
|
class CaseExamItem(BaseModel):
|
|
"""病例检查/检验项目表(与 consultation 库 case_exam_item 同构)"""
|
|
case = models.ForeignKey(
|
|
CaseBase, on_delete=models.CASCADE,
|
|
related_name='exam_items', db_column='case_id',
|
|
verbose_name='病例',
|
|
)
|
|
item_code = models.CharField('检查项目编码', max_length=64)
|
|
item_name = models.CharField('检查项目名称', max_length=128)
|
|
item_type = models.CharField('项目类型', max_length=32)
|
|
category = models.CharField('项目分类', max_length=64, blank=True, default='')
|
|
result_text = models.TextField('结果文本')
|
|
result_structured = models.JSONField('结构化结果', null=True, blank=True, default=None)
|
|
is_key = models.BooleanField('是否关键检查', default=False)
|
|
is_abnormal = models.BooleanField('是否异常', default=False)
|
|
score_weight = models.DecimalField('评分权重', max_digits=5, decimal_places=2, default=1.00)
|
|
display_order = models.IntegerField('展示顺序', default=0)
|
|
|
|
class Meta:
|
|
db_table = 'case_exam_item'
|
|
verbose_name = '病例检查项'
|
|
verbose_name_plural = '病例检查项'
|
|
ordering = ['display_order', 'id']
|
|
constraints = [
|
|
models.UniqueConstraint(
|
|
fields=['case', 'item_code'],
|
|
name='uk_case_exam_item_code',
|
|
),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.case_id}:{self.item_code}"
|