feat: update medical training case and auth modules

This commit is contained in:
2026-06-03 17:34:47 +08:00
parent b4bb38b7be
commit fd0b3e1982
45 changed files with 1459 additions and 812 deletions
+146 -146
View File
@@ -1,146 +1,146 @@
# Generated by Django 6.0.5 on 2026-05-26 07:02
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CaseBase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('title', models.CharField(max_length=255, verbose_name='病例标题')),
('case_type', models.CharField(choices=[('traditional', '传统病例'), ('script', '剧本病例'), ('teaching', '教学互动病例'), ('osce', 'OSCE')], max_length=30, verbose_name='病例类型')),
('difficulty', models.CharField(blank=True, max_length=20, verbose_name='难度')),
('difficulty_score', models.IntegerField(blank=True, null=True, verbose_name='AI难度评分')),
('chief_complaint', models.TextField(blank=True, verbose_name='主诉')),
('description', models.TextField(blank=True, verbose_name='病例简介')),
('patient_age', models.IntegerField(blank=True, null=True, verbose_name='患者年龄')),
('patient_gender', models.CharField(blank=True, max_length=10, verbose_name='患者性别')),
('tags', models.CharField(blank=True, max_length=500, verbose_name='标签')),
('symptom_tags', models.JSONField(blank=True, default=list, verbose_name='症状标签')),
('disease_tags', models.JSONField(blank=True, default=list, verbose_name='疾病标签')),
('competency_tags', models.JSONField(blank=True, default=list, verbose_name='能力标签')),
('guideline_tags', models.JSONField(blank=True, default=list, verbose_name='指南标签')),
('knowledge_points', models.JSONField(blank=True, default=list, verbose_name='知识点')),
('icd_codes', models.CharField(blank=True, max_length=500, verbose_name='ICD编码')),
('estimated_minutes', models.IntegerField(blank=True, null=True, verbose_name='预计训练时长')),
('osce_enabled', models.BooleanField(default=False, verbose_name='是否OSCE')),
('rag_enabled', models.BooleanField(default=False, verbose_name='是否启用知识增强')),
('ai_prompt_template', models.TextField(blank=True, verbose_name='AI角色Prompt')),
('multimodal_assets', models.JSONField(blank=True, default=dict, verbose_name='图片/影像/附件')),
('vector_status', models.SmallIntegerField(default=0, verbose_name='是否向量化')),
('publish_status', models.SmallIntegerField(choices=[(0, '草稿'), (1, '已发布'), (2, '已下架')], default=0, verbose_name='发布状态')),
('status', models.SmallIntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='状态')),
],
options={
'verbose_name': '病例',
'verbose_name_plural': '病例',
'db_table': 'case_base',
},
),
migrations.CreateModel(
name='CaseStage',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('stage_type', models.CharField(blank=True, max_length=50, verbose_name='阶段类型')),
('stage_name', models.CharField(max_length=100, verbose_name='阶段名称')),
('stage_mode', models.CharField(choices=[('dialogue', '对话'), ('osce', 'OSCE'), ('choice', '选择')], default='dialogue', max_length=30, verbose_name='阶段模式')),
('stage_goal', models.TextField(blank=True, verbose_name='阶段目标')),
('ai_role_prompt', models.TextField(blank=True, verbose_name='AI阶段Prompt')),
('standard_action', models.TextField(blank=True, verbose_name='标准动作')),
('expected_questions', models.TextField(blank=True, verbose_name='期望问题')),
('scoring_points', models.TextField(blank=True, verbose_name='评分点')),
('timeout_seconds', models.IntegerField(blank=True, null=True, verbose_name='超时时间')),
('unlock_condition', models.CharField(blank=True, max_length=255, verbose_name='解锁条件')),
('sort_order', models.IntegerField(default=0, verbose_name='排序')),
],
options={
'verbose_name': '病例阶段',
'verbose_name_plural': '病例阶段',
'db_table': 'case_stage',
'ordering': ['sort_order', 'id'],
},
),
migrations.CreateModel(
name='ScoringRule',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('dimension', models.CharField(max_length=50, verbose_name='评分维度')),
('competency_dimension', models.CharField(blank=True, max_length=50, verbose_name='能力维度')),
('score_weight', models.DecimalField(decimal_places=2, default=1.0, max_digits=5, verbose_name='权重')),
('ai_auto_score', models.BooleanField(default=False, verbose_name='AI自动评分')),
('osce_dimension', models.BooleanField(default=False, verbose_name='是否OSCE')),
('scoring_standard', models.TextField(blank=True, verbose_name='评分标准')),
('rubric_json', models.JSONField(blank=True, default=dict, verbose_name='评分Rubric')),
],
options={
'verbose_name': '评分规则',
'verbose_name_plural': '评分规则',
'db_table': 'scoring_rule',
},
),
migrations.CreateModel(
name='ScriptCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('scenario_setting', models.TextField(blank=True, verbose_name='场景设定')),
('emotional_state', models.CharField(blank=True, max_length=50, verbose_name='情绪状态')),
('cultural_level', models.CharField(blank=True, max_length=50, verbose_name='文化水平')),
('branch_logic', models.TextField(blank=True, verbose_name='分支逻辑')),
('hidden_clues', models.TextField(blank=True, verbose_name='隐藏线索')),
],
options={
'verbose_name': '剧本病例',
'verbose_name_plural': '剧本病例',
'db_table': 'script_case',
},
),
migrations.CreateModel(
name='TeachingCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('teaching_goal', models.TextField(blank=True, verbose_name='教学目标')),
('discussion_questions', models.TextField(blank=True, verbose_name='讨论问题')),
('teacher_guide', models.TextField(blank=True, verbose_name='教师指南')),
('scoring_focus', models.TextField(blank=True, verbose_name='评分重点')),
],
options={
'verbose_name': '教学互动病例',
'verbose_name_plural': '教学互动病例',
'db_table': 'teaching_case',
},
),
migrations.CreateModel(
name='TraditionalCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('standard_diagnosis', models.TextField(blank=True, verbose_name='标准诊断')),
('standard_treatment', models.TextField(blank=True, verbose_name='标准治疗')),
('guideline_reference', models.TextField(blank=True, verbose_name='指南参考')),
],
options={
'verbose_name': '传统病例',
'verbose_name_plural': '传统病例',
'db_table': 'traditional_case',
},
),
]
# Generated by Django 6.0.5 on 2026-05-26 07:02
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CaseBase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('title', models.CharField(max_length=255, verbose_name='病例标题')),
('case_type', models.CharField(choices=[('traditional', '传统病例'), ('script', '剧本病例'), ('teaching', '教学互动病例'), ('osce', 'OSCE')], max_length=30, verbose_name='病例类型')),
('difficulty', models.CharField(blank=True, max_length=20, verbose_name='难度')),
('difficulty_score', models.IntegerField(blank=True, null=True, verbose_name='AI难度评分')),
('chief_complaint', models.TextField(blank=True, verbose_name='主诉')),
('description', models.TextField(blank=True, verbose_name='病例简介')),
('patient_age', models.IntegerField(blank=True, null=True, verbose_name='患者年龄')),
('patient_gender', models.CharField(blank=True, max_length=10, verbose_name='患者性别')),
('tags', models.CharField(blank=True, max_length=500, verbose_name='标签')),
('symptom_tags', models.JSONField(blank=True, default=list, verbose_name='症状标签')),
('disease_tags', models.JSONField(blank=True, default=list, verbose_name='疾病标签')),
('competency_tags', models.JSONField(blank=True, default=list, verbose_name='能力标签')),
('guideline_tags', models.JSONField(blank=True, default=list, verbose_name='指南标签')),
('knowledge_points', models.JSONField(blank=True, default=list, verbose_name='知识点')),
('icd_codes', models.CharField(blank=True, max_length=500, verbose_name='ICD编码')),
('estimated_minutes', models.IntegerField(blank=True, null=True, verbose_name='预计训练时长')),
('osce_enabled', models.BooleanField(default=False, verbose_name='是否OSCE')),
('rag_enabled', models.BooleanField(default=False, verbose_name='是否启用知识增强')),
('ai_prompt_template', models.TextField(blank=True, verbose_name='AI角色Prompt')),
('multimodal_assets', models.JSONField(blank=True, default=dict, verbose_name='图片/影像/附件')),
('vector_status', models.SmallIntegerField(default=0, verbose_name='是否向量化')),
('publish_status', models.SmallIntegerField(choices=[(0, '草稿'), (1, '已发布'), (2, '已下架')], default=0, verbose_name='发布状态')),
('status', models.SmallIntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='状态')),
],
options={
'verbose_name': '病例',
'verbose_name_plural': '病例',
'db_table': 'case_base',
},
),
migrations.CreateModel(
name='CaseStage',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('stage_type', models.CharField(blank=True, max_length=50, verbose_name='阶段类型')),
('stage_name', models.CharField(max_length=100, verbose_name='阶段名称')),
('stage_mode', models.CharField(choices=[('dialogue', '对话'), ('osce', 'OSCE'), ('choice', '选择')], default='dialogue', max_length=30, verbose_name='阶段模式')),
('stage_goal', models.TextField(blank=True, verbose_name='阶段目标')),
('ai_role_prompt', models.TextField(blank=True, verbose_name='AI阶段Prompt')),
('standard_action', models.TextField(blank=True, verbose_name='标准动作')),
('expected_questions', models.TextField(blank=True, verbose_name='期望问题')),
('scoring_points', models.TextField(blank=True, verbose_name='评分点')),
('timeout_seconds', models.IntegerField(blank=True, null=True, verbose_name='超时时间')),
('unlock_condition', models.CharField(blank=True, max_length=255, verbose_name='解锁条件')),
('sort_order', models.IntegerField(default=0, verbose_name='排序')),
],
options={
'verbose_name': '病例阶段',
'verbose_name_plural': '病例阶段',
'db_table': 'case_stage',
'ordering': ['sort_order', 'id'],
},
),
migrations.CreateModel(
name='ScoringRule',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('dimension', models.CharField(max_length=50, verbose_name='评分维度')),
('competency_dimension', models.CharField(blank=True, max_length=50, verbose_name='能力维度')),
('score_weight', models.DecimalField(decimal_places=2, default=1.0, max_digits=5, verbose_name='权重')),
('ai_auto_score', models.BooleanField(default=False, verbose_name='AI自动评分')),
('osce_dimension', models.BooleanField(default=False, verbose_name='是否OSCE')),
('scoring_standard', models.TextField(blank=True, verbose_name='评分标准')),
('rubric_json', models.JSONField(blank=True, default=dict, verbose_name='评分Rubric')),
],
options={
'verbose_name': '评分规则',
'verbose_name_plural': '评分规则',
'db_table': 'scoring_rule',
},
),
migrations.CreateModel(
name='ScriptCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('scenario_setting', models.TextField(blank=True, verbose_name='场景设定')),
('emotional_state', models.CharField(blank=True, max_length=50, verbose_name='情绪状态')),
('cultural_level', models.CharField(blank=True, max_length=50, verbose_name='文化水平')),
('branch_logic', models.TextField(blank=True, verbose_name='分支逻辑')),
('hidden_clues', models.TextField(blank=True, verbose_name='隐藏线索')),
],
options={
'verbose_name': '剧本病例',
'verbose_name_plural': '剧本病例',
'db_table': 'script_case',
},
),
migrations.CreateModel(
name='TeachingCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('teaching_goal', models.TextField(blank=True, verbose_name='教学目标')),
('discussion_questions', models.TextField(blank=True, verbose_name='讨论问题')),
('teacher_guide', models.TextField(blank=True, verbose_name='教师指南')),
('scoring_focus', models.TextField(blank=True, verbose_name='评分重点')),
],
options={
'verbose_name': '教学互动病例',
'verbose_name_plural': '教学互动病例',
'db_table': 'teaching_case',
},
),
migrations.CreateModel(
name='TraditionalCase',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('standard_diagnosis', models.TextField(blank=True, verbose_name='标准诊断')),
('standard_treatment', models.TextField(blank=True, verbose_name='标准治疗')),
('guideline_reference', models.TextField(blank=True, verbose_name='指南参考')),
],
options={
'verbose_name': '传统病例',
'verbose_name_plural': '传统病例',
'db_table': 'traditional_case',
},
),
]
+54 -54
View File
@@ -1,54 +1,54 @@
# Generated by Django 6.0.5 on 2026-05-26 07:02
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('case', '0001_initial'),
('user', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='casebase',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AddField(
model_name='casebase',
name='department',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='user.department', verbose_name='所属科室'),
),
migrations.AddField(
model_name='casestage',
name='case',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stages', to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='scoringrule',
name='case',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scoring_rules', to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='scriptcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='teachingcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='traditionalcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
]
# Generated by Django 6.0.5 on 2026-05-26 07:02
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('case', '0001_initial'),
('user', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='casebase',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AddField(
model_name='casebase',
name='department',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='user.department', verbose_name='所属科室'),
),
migrations.AddField(
model_name='casestage',
name='case',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stages', to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='scoringrule',
name='case',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scoring_rules', to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='scriptcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='teachingcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
migrations.AddField(
model_name='traditionalcase',
name='case',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='case.casebase', verbose_name='病例'),
),
]
@@ -0,0 +1,40 @@
# Generated by Django 5.2.14 on 2026-06-03 07:07
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('case', '0002_initial'),
]
operations = [
migrations.CreateModel(
name='CaseExamItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('item_code', models.CharField(max_length=64, verbose_name='检查项目编码')),
('item_name', models.CharField(max_length=128, verbose_name='检查项目名称')),
('item_type', models.CharField(max_length=32, verbose_name='项目类型')),
('category', models.CharField(blank=True, default='', max_length=64, verbose_name='项目分类')),
('result_text', models.TextField(verbose_name='结果文本')),
('result_structured', models.JSONField(blank=True, default=None, null=True, verbose_name='结构化结果')),
('is_key', models.BooleanField(default=False, verbose_name='是否关键检查')),
('is_abnormal', models.BooleanField(default=False, verbose_name='是否异常')),
('score_weight', models.DecimalField(decimal_places=2, default=1.0, max_digits=5, verbose_name='评分权重')),
('display_order', models.IntegerField(default=0, verbose_name='展示顺序')),
('case', models.ForeignKey(db_column='case_id', on_delete=django.db.models.deletion.CASCADE, related_name='exam_items', to='case.casebase', verbose_name='病例')),
],
options={
'verbose_name': '病例检查项',
'verbose_name_plural': '病例检查项',
'db_table': 'case_exam_item',
'ordering': ['display_order', 'id'],
'constraints': [models.UniqueConstraint(fields=('case', 'item_code'), name='uk_case_exam_item_code')],
},
),
]
+1 -1
View File
@@ -1,2 +1,2 @@