Files
shanxia2.0/backend/app/api/basic_info.py
T
2026-05-17 08:36:37 +08:00

861 lines
30 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""基础信息管理 API(客户、样本类型、采集地区/医院、协议号池、样本编码池)"""
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
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 cell_sample_type as cell_type_svc
from app.crud import collection_region as region_svc
from app.crud import collection_protocol_no as protocol_no_svc
from app.crud import customer as customer_svc
from app.crud import sample_code as sample_code_svc
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
# ---------------------------------------------------------------------------
# 客户
# ---------------------------------------------------------------------------
class CustomerCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
customer_name: str = Field(..., alias="customerName")
sex: Optional[str] = Field("2", alias="sex")
id_card_no: Optional[str] = Field(None, alias="idCardNo")
age: Optional[int] = None
phone_no: Optional[str] = Field(None, alias="phoneNo")
customer_tags: Optional[str] = Field(None, alias="customerTags")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class CustomerUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
customer_name: Optional[str] = Field(None, alias="customerName")
sex: Optional[str] = None
id_card_no: Optional[str] = Field(None, alias="idCardNo")
age: Optional[int] = None
phone_no: Optional[str] = Field(None, alias="phoneNo")
customer_tags: Optional[str] = Field(None, alias="customerTags")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/customers")
async def list_customers(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = customer_svc.list_customers(db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no)
tp = customer_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
@router.post("/customers")
async def create_customer(
body: CustomerCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = customer_svc.create_customer(
db,
customer_name=body.customer_name,
sex=body.sex or "2",
id_card_no=body.id_card_no,
age=body.age,
phone_no=body.phone_no,
customer_tags=body.customer_tags,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(customer_svc._row_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/customers/{customer_id}")
async def update_customer(
customer_id: str,
body: CustomerUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = customer_svc.update_customer(
db,
customer_id,
customer_name=payload.get("customer_name"),
sex=payload.get("sex"),
id_card_no=payload.get("id_card_no"),
age=payload.get("age"),
phone_no=payload.get("phone_no"),
customer_tags=payload.get("customer_tags"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(customer_svc._row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/customers/{customer_id}")
async def delete_customer(
customer_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
customer_svc.soft_delete_customer(db, customer_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 细胞样本类型
# ---------------------------------------------------------------------------
class CellSampleTypeCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
type_code: str = Field(..., alias="typeCode")
type_name: str = Field(..., alias="typeName")
storage_years: Optional[int] = Field(None, alias="storageYears")
storage_price: Optional[float] = Field(None, alias="storagePrice")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class CellSampleTypeUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
type_code: Optional[str] = Field(None, alias="typeCode")
type_name: Optional[str] = Field(None, alias="typeName")
storage_years: Optional[int] = Field(None, alias="storageYears")
storage_price: Optional[float] = Field(None, alias="storagePrice")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/cell-sample-types")
async def list_cell_sample_types(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = cell_type_svc.list_cell_sample_types(
db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = cell_type_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
@router.post("/cell-sample-types")
async def create_cell_sample_type(
body: CellSampleTypeCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = cell_type_svc.create_cell_sample_type(
db,
type_code=body.type_code,
type_name=body.type_name,
storage_years=body.storage_years,
storage_price=body.storage_price,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(cell_type_svc._row_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/cell-sample-types/{row_id}")
async def update_cell_sample_type(
row_id: str,
body: CellSampleTypeUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = cell_type_svc.update_cell_sample_type(
db,
row_id,
type_code=payload.get("type_code"),
type_name=payload.get("type_name"),
storage_years=payload.get("storage_years"),
storage_price=payload.get("storage_price"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(cell_type_svc._row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/cell-sample-types/{row_id}")
async def delete_cell_sample_type(
row_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
cell_type_svc.soft_delete_cell_sample_type(db, row_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 采集地区
# ---------------------------------------------------------------------------
class CollectionRegionCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
region_name: str = Field(..., alias="regionName")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class CollectionRegionUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
region_name: Optional[str] = Field(None, alias="regionName")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/collection-regions")
async def list_collection_regions(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = region_svc.list_collection_regions(
db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = region_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
@router.post("/collection-regions")
async def create_collection_region(
body: CollectionRegionCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = region_svc.create_collection_region(
db,
region_name=body.region_name,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(region_svc._region_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/collection-regions/{region_id}")
async def update_collection_region(
region_id: str,
body: CollectionRegionUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = region_svc.update_collection_region(
db,
region_id,
region_name=payload.get("region_name"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(region_svc._region_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/collection-regions/{region_id}")
async def delete_collection_region(
region_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
region_svc.soft_delete_collection_region(db, region_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 采集地区 — 下属医院
# ---------------------------------------------------------------------------
class HospitalCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
hospital_name: str = Field(..., alias="hospitalName")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class HospitalUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
hospital_name: Optional[str] = Field(None, alias="hospitalName")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/collection-regions/{region_id}/hospitals")
async def list_hospitals(
region_id: str,
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items, total = region_svc.list_hospitals(
db, region_id=region_id, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = region_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
except ValueError as e:
return error_response(400, str(e))
@router.post("/collection-regions/{region_id}/hospitals")
async def create_hospital(
region_id: str,
body: HospitalCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = region_svc.create_hospital(
db,
region_id=region_id,
hospital_name=body.hospital_name,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(region_svc._hospital_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/collection-regions/{region_id}/hospitals/{hospital_id}")
async def update_hospital(
region_id: str,
hospital_id: str,
body: HospitalUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
h = region_svc.get_hospital(db, hospital_id, tenant_no=tenant_no)
if not h or h.region_id != region_id:
return error_response(400, "医院不存在")
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = region_svc.update_hospital(
db,
hospital_id,
hospital_name=payload.get("hospital_name"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(region_svc._hospital_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/collection-regions/{region_id}/hospitals/{hospital_id}")
async def delete_hospital(
region_id: str,
hospital_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
h = region_svc.get_hospital(db, hospital_id, tenant_no=tenant_no)
if not h or h.region_id != region_id:
return error_response(400, "医院不存在")
region_svc.soft_delete_hospital(db, hospital_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 采集协议号池
# ---------------------------------------------------------------------------
class ProtocolNoCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
protocol_no: str = Field(..., alias="protocolNo")
issued: int = 0
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class ProtocolNoUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
protocol_no: Optional[str] = Field(None, alias="protocolNo")
issued: Optional[int] = None
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
issued_user_id: Optional[str] = Field(None, alias="issuedUserId")
issued_user_name: Optional[str] = Field(None, alias="issuedUserName")
issued_time: Optional[str] = Field(None, alias="issuedTime")
@router.get("/collection-protocol-nos")
async def list_protocol_nos(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = protocol_no_svc.list_protocol_nos(
db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = protocol_no_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
class ProtocolNoBatchGenerateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
prefix: str = Field("ZKZX", alias="prefix")
middle: str = Field("34", alias="middle")
seq_start: int = Field(..., alias="seqStart")
seq_end: int = Field(..., alias="seqEnd")
digit_count: int = Field(6, alias="digitCount")
class ProtocolNoBatchIssueBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
ids: List[str] = Field(..., alias="ids")
issued_user_id: str = Field(..., alias="issuedUserId")
issued_user_name: Optional[str] = Field(None, alias="issuedUserName")
@router.post("/collection-protocol-nos/batch-generate")
async def batch_generate_protocol_nos(
body: ProtocolNoBatchGenerateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = protocol_no_svc.batch_generate_protocol_nos(
db,
prefix=body.prefix,
middle=body.middle,
seq_start=body.seq_start,
seq_end=body.seq_end,
digit_count=body.digit_count,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功生成 {result['created']} 条"
if result['skipped'] > 0:
msg += f",跳过已存在 {result['skipped']} 条"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
@router.post("/collection-protocol-nos/batch-issue")
async def batch_issue_protocol_nos(
body: ProtocolNoBatchIssueBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = protocol_no_svc.batch_issue_protocol_nos(
db,
ids=body.ids,
issued_user_id=body.issued_user_id,
issued_user_name=body.issued_user_name,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功下发 {result['issuedCount']} 条"
if result['alreadyIssued']:
msg += f",{len(result['alreadyIssued'])} 条已下发被跳过"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
class ProtocolNoBatchRevokeBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
ids: List[str] = Field(..., alias="ids")
@router.post("/collection-protocol-nos/batch-revoke")
async def batch_revoke_protocol_nos(
body: ProtocolNoBatchRevokeBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = protocol_no_svc.batch_revoke_protocol_nos(
db,
ids=body.ids,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功收回 {result['revokedCount']} 条"
if result["notIssued"]:
msg += f",{len(result['notIssued'])} 条未下发已跳过"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
@router.post("/collection-protocol-nos")
async def create_protocol_no(
body: ProtocolNoCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = protocol_no_svc.create_protocol_no(
db,
protocol_no=body.protocol_no,
issued=body.issued,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(protocol_no_svc._row_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/collection-protocol-nos/{row_id}")
async def update_protocol_no(
row_id: str,
body: ProtocolNoUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = protocol_no_svc.update_protocol_no(
db,
row_id,
protocol_no=payload.get("protocol_no"),
issued=payload.get("issued"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
issued_user_id=payload.get("issued_user_id"),
issued_user_name=payload.get("issued_user_name"),
issued_time=payload.get("issued_time"),
)
return success_response(protocol_no_svc._row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/collection-protocol-nos/{row_id}")
async def delete_protocol_no(
row_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
protocol_no_svc.soft_delete_protocol_no(db, row_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 样本编码池
# ---------------------------------------------------------------------------
class SampleCodeCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
sample_code: str = Field(..., alias="sampleCode")
issued: int = 0
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class SampleCodeUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
sample_code: Optional[str] = Field(None, alias="sampleCode")
issued: Optional[int] = None
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
issued_user_id: Optional[str] = Field(None, alias="issuedUserId")
issued_user_name: Optional[str] = Field(None, alias="issuedUserName")
issued_time: Optional[str] = Field(None, alias="issuedTime")
class SampleCodeBatchGenerateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
sample_code_type: str = Field(..., alias="sampleCodeType")
middle: str = Field("34", alias="middle")
seq_start: int = Field(..., alias="seqStart")
seq_end: int = Field(..., alias="seqEnd")
digit_count: int = Field(6, alias="digitCount")
class SampleCodeBatchIssueBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
ids: List[str] = Field(..., alias="ids")
issued_user_id: str = Field(..., alias="issuedUserId")
issued_user_name: Optional[str] = Field(None, alias="issuedUserName")
@router.post("/sample-codes/batch-generate")
async def batch_generate_sample_codes(
body: SampleCodeBatchGenerateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = sample_code_svc.batch_generate_sample_codes(
db,
sample_code_type=body.sample_code_type,
middle=body.middle,
seq_start=body.seq_start,
seq_end=body.seq_end,
digit_count=body.digit_count,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功生成 {result['created']} 条"
if result["skipped"] > 0:
msg += f",跳过已存在 {result['skipped']} 条"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
@router.post("/sample-codes/batch-issue")
async def batch_issue_sample_codes(
body: SampleCodeBatchIssueBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = sample_code_svc.batch_issue_sample_codes(
db,
ids=body.ids,
issued_user_id=body.issued_user_id,
issued_user_name=body.issued_user_name,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功下发 {result['issuedCount']} 条"
if result["alreadyIssued"]:
msg += f",{len(result['alreadyIssued'])} 条已下发被跳过"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
class SampleCodeBatchRevokeBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
ids: List[str] = Field(..., alias="ids")
@router.post("/sample-codes/batch-revoke")
async def batch_revoke_sample_codes(
body: SampleCodeBatchRevokeBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
result = sample_code_svc.batch_revoke_sample_codes(
db,
ids=body.ids,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
msg = f"成功收回 {result['revokedCount']} 条"
if result["notIssued"]:
msg += f",{len(result['notIssued'])} 条未下发已跳过"
return success_response(result, message=msg)
except ValueError as e:
return error_response(400, str(e))
@router.get("/sample-codes")
async def list_sample_codes(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = sample_code_svc.list_sample_codes(
db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = sample_code_svc.total_pages(total, pageSize)
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
@router.post("/sample-codes")
async def create_sample_code(
body: SampleCodeCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = sample_code_svc.create_sample_code(
db,
sample_code=body.sample_code,
issued=body.issued,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(sample_code_svc._row_to_dict(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/sample-codes/{row_id}")
async def update_sample_code(
row_id: str,
body: SampleCodeUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = sample_code_svc.update_sample_code(
db,
row_id,
sample_code=payload.get("sample_code"),
issued=payload.get("issued"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
issued_user_id=payload.get("issued_user_id"),
issued_user_name=payload.get("issued_user_name"),
issued_time=payload.get("issued_time"),
)
return success_response(sample_code_svc._row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/sample-codes/{row_id}")
async def delete_sample_code(
row_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
sample_code_svc.soft_delete_sample_code(db, row_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))