Files
zkxw/backend/app/api/pilot_checkup.py
T
2026-05-28 13:05:46 +08:00

420 lines
15 KiB
Python

"""中试服务体检管理 API(体检信息、预约项目、实际项目)"""
from typing import List, Optional
from fastapi import APIRouter, Depends, Query
from pydantic import AliasChoices, BaseModel, ConfigDict, Field
from starlette.requests import Request
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin
from app.core.response import error_response, success_response
from app.crud import pilot_checkup
from app.models.models import SysUser
router = APIRouter(prefix="/web/admin", tags=["中试服务体检管理"])
def _get_tenant_no(db: Session, user: dict) -> str:
user_id = user.get("user_id")
if not user_id:
raise PermissionError("用户身份信息缺失,无法确定租户")
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
if not sys_user or not sys_user.tenant_no:
raise PermissionError("用户租户信息缺失")
return sys_user.tenant_no
# ---------------------------------------------------------------------------
# Pydantic Schemas
# ---------------------------------------------------------------------------
class IdBody(BaseModel):
id: str
class CheckupSaveBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
application_id: Optional[str] = Field(
None, validation_alias=AliasChoices("applicationId", "application_id")
)
checkup_id: Optional[str] = Field(
None, validation_alias=AliasChoices("checkupId", "checkup_id")
)
patient_id: Optional[str] = Field(
None, validation_alias=AliasChoices("patientId", "patient_id")
)
checkup_institution_id: Optional[str] = Field(
None, validation_alias=AliasChoices("checkupInstitutionId", "checkup_institution_id")
)
reserve_time: Optional[str] = Field(
None, validation_alias=AliasChoices("reserveTime", "reserve_time")
)
reserve_fee: Optional[float] = Field(
None, validation_alias=AliasChoices("reserveFee", "reserve_fee")
)
actual_checkup_time: Optional[str] = Field(
None, validation_alias=AliasChoices("actualCheckupTime", "actual_checkup_time")
)
actual_checkup_fee: Optional[float] = Field(
None, validation_alias=AliasChoices("actualCheckupFee", "actual_checkup_fee")
)
checkup_remark: Optional[str] = Field(
None, validation_alias=AliasChoices("checkupRemark", "checkup_remark")
)
report_attachments: Optional[str] = Field(
None, validation_alias=AliasChoices("reportAttachments", "report_attachments")
)
class CheckupItemBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
project_name: str = Field(..., validation_alias=AliasChoices("projectName", "project_name"))
project_fee: Optional[float] = Field(
None, validation_alias=AliasChoices("projectFee", "project_fee")
)
class CheckupItemsSaveBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
pilot_checkup_id: str = Field(
..., validation_alias=AliasChoices("pilotCheckupId", "pilot_checkup_id")
)
items: List[CheckupItemBody]
class BatchCheckupSaveBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
patient_ids: List[str] = Field(..., validation_alias=AliasChoices("patientIds", "patient_ids"))
checkup_institution_id: Optional[str] = Field(
None, validation_alias=AliasChoices("checkupInstitutionId", "checkup_institution_id")
)
reserve_time: Optional[str] = Field(
None, validation_alias=AliasChoices("reserveTime", "reserve_time")
)
reserve_items: Optional[List[CheckupItemBody]] = Field(
None, validation_alias=AliasChoices("reserveItems", "reserve_items")
)
# ---------------------------------------------------------------------------
# 1. 体检信息 CRUD + 状态变更
# ---------------------------------------------------------------------------
@router.get("/pilot-checkup/detail")
async def api_get_checkup_detail(
application_id: Optional[str] = Query(None, alias="applicationId"),
checkup_id: Optional[str] = Query(None, alias="checkupId"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
if checkup_id:
result = pilot_checkup.get_checkup_by_id(
db, checkup_id=checkup_id, tenant_no=tenant_no
)
elif application_id:
result = pilot_checkup.get_checkup_by_application(
db, application_id=application_id, tenant_no=tenant_no
)
else:
return error_response(400, "请提供 application_id 或 checkupId")
if result is None:
return success_response(None)
return success_response(result)
@router.post("/pilot-checkup/save")
async def api_save_checkup(
request: Request,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
payload = await request.json()
if not isinstance(payload, dict):
return error_response(400, "请求体格式错误")
body = CheckupSaveBody.model_validate(payload)
tenant_no = _get_tenant_no(db, user)
data = {
"checkupInstitutionId": body.checkup_institution_id,
"pilotPatientId": body.patient_id,
"reserveTime": body.reserve_time,
"reserveFee": body.reserve_fee,
"actualCheckupTime": body.actual_checkup_time,
"actualCheckupFee": body.actual_checkup_fee,
"checkupRemark": body.checkup_remark,
"reportAttachments": body.report_attachments,
}
if body.checkup_id:
result = pilot_checkup.update_checkup(
db, checkup_id=body.checkup_id, data=data, tenant_no=tenant_no
)
return success_response(result, message="更新成功")
if not body.application_id:
return error_response(400, "请提供 application_id 或 checkup_id")
existing = pilot_checkup.get_checkup_by_application(
db, application_id=body.application_id, tenant_no=tenant_no
)
if existing:
result = pilot_checkup.update_checkup(
db, checkup_id=existing["id"], data=data, tenant_no=tenant_no
)
return success_response(result, message="更新成功")
else:
result = pilot_checkup.create_checkup(
db,
application_id=body.application_id,
data=data,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(result, message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/pilot-checkup/delete")
async def api_delete_checkup(
body: IdBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
pilot_checkup.soft_delete_checkup(db, checkup_id=body.id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
@router.post("/pilot-checkup/mark-checked")
async def api_mark_checked(
body: IdBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.mark_checkup_checked(
db, checkup_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
)
return success_response(result, message="操作成功")
except ValueError as e:
return error_response(400, str(e))
@router.post("/pilot-checkup/settle-fee")
async def api_settle_fee(
body: IdBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.settle_checkup_fee(
db, checkup_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
)
return success_response(result, message="结算成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 2. 预约项目
# ---------------------------------------------------------------------------
@router.get("/pilot-checkup/reserve-items")
async def api_list_reserve_items(
pilot_checkup_id: str = Query(..., alias="pilotCheckupId"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.list_reserve_items(
db, checkup_id=pilot_checkup_id, tenant_no=tenant_no
)
return success_response(result)
@router.post("/pilot-checkup/reserve-items/save")
async def api_save_reserve_items(
body: CheckupItemsSaveBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items_json = [item.model_dump(by_alias=False) for item in body.items]
result = pilot_checkup.save_reserve_items(
db,
checkup_id=body.pilot_checkup_id,
items_json=items_json,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(result, message="保存成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/pilot-checkup/reserve-item/delete")
async def api_delete_reserve_item(
body: IdBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
pilot_checkup.delete_reserve_item(db, item_id=body.id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 3. 实际项目
# ---------------------------------------------------------------------------
@router.get("/pilot-checkup/actual-items")
async def api_list_actual_items(
pilot_checkup_id: str = Query(..., alias="pilotCheckupId"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.list_actual_items(
db, checkup_id=pilot_checkup_id, tenant_no=tenant_no
)
return success_response(result)
@router.post("/pilot-checkup/actual-items/save")
async def api_save_actual_items(
body: CheckupItemsSaveBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items_json = [item.model_dump(by_alias=False) for item in body.items]
result = pilot_checkup.save_actual_items(
db,
checkup_id=body.pilot_checkup_id,
items_json=items_json,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(result, message="保存成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/pilot-checkup/actual-item/delete")
async def api_delete_actual_item(
body: IdBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
pilot_checkup.delete_actual_item(db, item_id=body.id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 4. 体检管理列表、待体检患者、批量创建
# ---------------------------------------------------------------------------
@router.get("/pilot-checkup/list")
async def api_list_checkups(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
checkupStatus: Optional[str] = Query(None, alias="checkupStatus"),
feeStatus: Optional[str] = Query(None, alias="feeStatus"),
checkupInstitutionId: Optional[str] = Query(None, alias="checkupInstitutionId"),
keyword: Optional[str] = Query(None, alias="keyword"),
applicationNo: Optional[str] = Query(None, alias="applicationNo"),
patientName: Optional[str] = Query(None, alias="patientName"),
channelId: Optional[str] = Query(None, alias="channelId"),
bizType: Optional[str] = Query(None, alias="bizType"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.list_checkups_paginated(
db,
tenant_no=tenant_no,
page=page,
page_size=pageSize,
checkup_status=checkupStatus,
fee_status=feeStatus,
checkup_institution_id=checkupInstitutionId,
keyword=keyword,
application_no=applicationNo,
patient_name=patientName,
channel_id=channelId,
biz_type=bizType,
)
return success_response(result)
@router.get("/pilot-checkup/pending-patients")
async def api_list_pending_patients(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
applicationNo: Optional[str] = Query(None, alias="applicationNo"),
patientName: Optional[str] = Query(None, alias="patientName"),
channelId: Optional[str] = Query(None, alias="channelId"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
result = pilot_checkup.list_pending_patients(
db,
tenant_no=tenant_no,
page=page,
page_size=pageSize,
application_no=applicationNo,
patient_name=patientName,
channel_id=channelId,
)
return success_response(result)
@router.post("/pilot-checkup/batch-save")
async def api_batch_save_checkup(
body: BatchCheckupSaveBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items_json = [item.model_dump(by_alias=False) for item in body.reserve_items] if body.reserve_items else []
result = pilot_checkup.batch_create_checkups(
db,
patient_ids=body.patient_ids,
checkup_institution_id=body.checkup_institution_id or "",
reserve_time=body.reserve_time or None,
reserve_items=items_json,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(result, message=f"成功为 {len(result)} 名患者创建体检记录")
except ValueError as e:
return error_response(400, str(e))