feat: update medical training case and auth modules
This commit is contained in:
+49
-4
@@ -13,7 +13,7 @@ from apps.user.permissions import IsCaseOperationPermitted
|
||||
from apps.user.throttling import PdfParseUserThrottle, ScoringRuleGenerateUserThrottle
|
||||
from .models import (
|
||||
CaseBase, TraditionalCase, ScriptCase,
|
||||
TeachingCase, CaseStage, ScoringRule
|
||||
TeachingCase, CaseStage, ScoringRule, CaseExamItem,
|
||||
)
|
||||
from .serializers import (
|
||||
CaseBaseListSerializer, CaseBaseDetailSerializer,
|
||||
@@ -23,6 +23,9 @@ from .serializers import (
|
||||
)
|
||||
from .services import case_importer, scoring_rule_generator
|
||||
from .services.department_resolver import resolve_department
|
||||
from .services.exam_items import (
|
||||
normalize_exam_items, assert_no_duplicate_exam_items, EXAM_ITEM_FIELDS,
|
||||
)
|
||||
|
||||
audit = logging.getLogger('audit')
|
||||
|
||||
@@ -135,6 +138,10 @@ class CaseBaseViewSet(viewsets.ModelViewSet):
|
||||
'traditional': drf_serializers.DictField(required=False),
|
||||
'teaching': drf_serializers.DictField(required=False),
|
||||
'scoring_rules': drf_serializers.ListField(child=drf_serializers.DictField(), help_text='评分规则(≥1 条,必填)'),
|
||||
'exam_items': drf_serializers.ListField(
|
||||
child=drf_serializers.DictField(), required=False,
|
||||
help_text='检查项(可选;同一病例 item_code 不可重复)',
|
||||
),
|
||||
'parse_id': drf_serializers.CharField(required=False, help_text='来自 parse-pdf 的 parse_id(审计用)'),
|
||||
'auto_publish': drf_serializers.BooleanField(required=False, default=False),
|
||||
}),
|
||||
@@ -168,6 +175,9 @@ class CaseBaseViewSet(viewsets.ModelViewSet):
|
||||
raise AppError('CASE_VALIDATION_ERROR', 'scoring_rules 必填且至少 1 条', status_code=400)
|
||||
_validate_scoring_rules(scoring_rules_data)
|
||||
|
||||
exam_items_data = normalize_exam_items(data.get('exam_items') or [])
|
||||
assert_no_duplicate_exam_items(exam_items_data)
|
||||
|
||||
department = resolve_department(data.get('department_name', ''))
|
||||
|
||||
with transaction.atomic():
|
||||
@@ -189,9 +199,20 @@ class CaseBaseViewSet(viewsets.ModelViewSet):
|
||||
]
|
||||
ScoringRule.objects.bulk_create(rule_objs)
|
||||
|
||||
if exam_items_data:
|
||||
exam_objs = [
|
||||
CaseExamItem(
|
||||
case=case,
|
||||
**{k: v for k, v in item.items() if k in EXAM_ITEM_FIELDS},
|
||||
)
|
||||
for item in exam_items_data
|
||||
]
|
||||
CaseExamItem.objects.bulk_create(exam_objs)
|
||||
|
||||
audit.info(
|
||||
'CASE_CREATE case_id=%s from=%s by=%s scoring_rules=%d',
|
||||
case.id, data.get('parse_id', 'form'), request.user.id, len(rule_objs),
|
||||
'CASE_CREATE case_id=%s from=%s by=%s scoring_rules=%d exam_items=%d',
|
||||
case.id, data.get('parse_id', 'form'), request.user.id,
|
||||
len(rule_objs), len(exam_items_data),
|
||||
)
|
||||
|
||||
return Response(_build_full_response(case), status=status.HTTP_201_CREATED)
|
||||
@@ -214,7 +235,7 @@ class CaseBaseViewSet(viewsets.ModelViewSet):
|
||||
def _full_detail(self, request, pk):
|
||||
case = CaseBase.objects.select_related(
|
||||
'department', 'created_by'
|
||||
).prefetch_related('scoring_rules').filter(pk=pk).first()
|
||||
).prefetch_related('scoring_rules', 'exam_items').filter(pk=pk).first()
|
||||
|
||||
if not case:
|
||||
raise AppError('NOT_FOUND', '病例不存在', status_code=404)
|
||||
@@ -384,6 +405,13 @@ def _validate_scoring_rules(rules):
|
||||
|
||||
|
||||
def _build_full_response(case):
|
||||
if hasattr(case, '_prefetched_objects_cache') and 'exam_items' in getattr(
|
||||
case, '_prefetched_objects_cache', {}
|
||||
):
|
||||
exam_qs = case.exam_items.all()
|
||||
else:
|
||||
exam_qs = CaseExamItem.objects.filter(case_id=case.id).order_by('display_order', 'id')
|
||||
|
||||
result = {
|
||||
'case': {
|
||||
'id': case.id,
|
||||
@@ -456,4 +484,21 @@ def _build_full_response(case):
|
||||
for r in rules
|
||||
]
|
||||
|
||||
result['exam_items'] = [
|
||||
{
|
||||
'id': e.id,
|
||||
'item_code': e.item_code,
|
||||
'item_name': e.item_name,
|
||||
'item_type': e.item_type,
|
||||
'category': e.category,
|
||||
'result_text': e.result_text,
|
||||
'result_structured': e.result_structured,
|
||||
'is_key': e.is_key,
|
||||
'is_abnormal': e.is_abnormal,
|
||||
'score_weight': float(e.score_weight),
|
||||
'display_order': e.display_order,
|
||||
}
|
||||
for e in exam_qs
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user