init medical training project

This commit is contained in:
2026-05-29 15:58:00 +08:00
commit b4bb38b7be
91 changed files with 6765 additions and 0 deletions
+185
View File
@@ -0,0 +1,185 @@
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}"