feat: update medical training case and auth modules
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
"""病例检查项:C1 解析归一化、C3 落库校验。"""
|
||||
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
from config.exceptions import AppError
|
||||
|
||||
EXAM_ITEM_FIELDS = {
|
||||
'item_code', 'item_name', 'item_type', 'category',
|
||||
'result_text', 'result_structured',
|
||||
'is_key', 'is_abnormal', 'score_weight', 'display_order',
|
||||
}
|
||||
|
||||
|
||||
def normalize_exam_items(raw_items) -> list:
|
||||
"""归一化检查项列表;按 item_code 去重(保留首次出现)。"""
|
||||
if not raw_items:
|
||||
return []
|
||||
if not isinstance(raw_items, list):
|
||||
raise AppError('CASE_VALIDATION_ERROR', 'exam_items 必须为数组', status_code=400)
|
||||
|
||||
seen = set()
|
||||
normalized = []
|
||||
for i, item in enumerate(raw_items):
|
||||
if not isinstance(item, dict):
|
||||
raise AppError('CASE_VALIDATION_ERROR', f'exam_items[{i}] 必须为对象', status_code=400)
|
||||
code = (item.get('item_code') or '').strip()
|
||||
name = (item.get('item_name') or '').strip()
|
||||
item_type = (item.get('item_type') or '').strip()
|
||||
result_text = (item.get('result_text') or '').strip()
|
||||
if not code:
|
||||
raise AppError('CASE_VALIDATION_ERROR', f'exam_items[{i}].item_code 必填', status_code=400)
|
||||
if not name:
|
||||
raise AppError('CASE_VALIDATION_ERROR', f'exam_items[{i}].item_name 必填', status_code=400)
|
||||
if not item_type:
|
||||
raise AppError('CASE_VALIDATION_ERROR', f'exam_items[{i}].item_type 必填', status_code=400)
|
||||
if not result_text:
|
||||
raise AppError('CASE_VALIDATION_ERROR', f'exam_items[{i}].result_text 必填', status_code=400)
|
||||
if code in seen:
|
||||
continue
|
||||
seen.add(code)
|
||||
|
||||
try:
|
||||
weight = item.get('score_weight', 1)
|
||||
weight = Decimal(str(weight))
|
||||
except (InvalidOperation, TypeError, ValueError):
|
||||
raise AppError(
|
||||
'CASE_VALIDATION_ERROR',
|
||||
f'exam_items[{i}].score_weight 须为数字',
|
||||
status_code=400,
|
||||
)
|
||||
if weight <= 0:
|
||||
raise AppError(
|
||||
'CASE_VALIDATION_ERROR',
|
||||
f'exam_items[{i}].score_weight 须大于 0',
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
normalized.append({
|
||||
'item_code': code[:64],
|
||||
'item_name': name[:128],
|
||||
'item_type': item_type[:32],
|
||||
'category': (item.get('category') or '')[:64],
|
||||
'result_text': result_text,
|
||||
'result_structured': item.get('result_structured') if isinstance(
|
||||
item.get('result_structured'), dict
|
||||
) else None,
|
||||
'is_key': bool(item.get('is_key', False)),
|
||||
'is_abnormal': bool(item.get('is_abnormal', False)),
|
||||
'score_weight': float(weight),
|
||||
'display_order': int(item.get('display_order', len(normalized) + 1)),
|
||||
})
|
||||
return normalized
|
||||
|
||||
|
||||
def assert_no_duplicate_exam_items(items: list):
|
||||
"""创建前再次校验同一病例内 item_code 不重复。"""
|
||||
codes = [it['item_code'] for it in items]
|
||||
if len(codes) != len(set(codes)):
|
||||
raise AppError(
|
||||
'CASE_EXAM_ITEM_DUPLICATE',
|
||||
'同一病例内检查项 item_code 不能重复',
|
||||
status_code=400,
|
||||
)
|
||||
Reference in New Issue
Block a user