Files
medical_training/apps/case/models.py
T

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}"