Files
2026-08-18 14:40:15 +08:00

452 lines
16 KiB
Python

"""环境检测 — 检测项维护 + 登记管理 API"""
from datetime import datetime, time
from typing import List, Optional
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from app.core.data_scope import apply_data_scope
from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin, require_menu_code
from app.core.response import error_response, success_response
from app.core.utils import parse_datetime
from app.crud import env_detect_item as item_svc
from app.crud import env_detect_record as record_svc
from app.crud.collection_protocol import total_pages
from app.models.models import BizEnvDetectItem, BizEnvDetectRecord, 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
def _get_current_user_id(user: dict) -> str:
user_id = user.get("user_id")
if not user_id:
raise PermissionError("用户身份信息缺失")
return str(user_id)
def _page_payload(items: list, total: int, page: int, page_size: int) -> dict:
return {
"list": items,
"total": total,
"page": page,
"pageSize": page_size,
"totalPages": total_pages(total, page_size),
}
# ---------- 环境检测项 ----------
class EnvDetectItemBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
item_code: str = Field(..., alias="itemCode")
item_name: str = Field(..., alias="itemName")
status: str = Field("1", alias="status")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
class EnvDetectItemUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
item_code: Optional[str] = Field(None, alias="itemCode")
item_name: Optional[str] = Field(None, alias="itemName")
status: Optional[str] = None
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/env-detect-items")
async def list_env_detect_items(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100),
keyword: Optional[str] = None,
status: Optional[str] = None,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("biz:envDetectItem:list")),
):
try:
tenant_no = _get_tenant_no(db, user)
query = db.query(BizEnvDetectItem).filter(
BizEnvDetectItem.del_flag == 0,
BizEnvDetectItem.tenant_no == tenant_no,
)
kw = (keyword or "").strip()
if kw:
from sqlalchemy import or_
like = f"%{kw}%"
query = query.filter(
or_(
BizEnvDetectItem.item_code.like(like),
BizEnvDetectItem.item_name.like(like),
)
)
if status:
query = query.filter(BizEnvDetectItem.status == status)
query = apply_data_scope(query, BizEnvDetectItem, user, db, tenant_no)
total = query.count()
items = (
query.order_by(BizEnvDetectItem.create_time.desc())
.offset((page - 1) * pageSize)
.limit(pageSize)
.all()
)
result_list = [item_svc._row_to_dict(r) for r in items]
return success_response(_page_payload(result_list, total, page, pageSize))
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.get("/env-detect-items/active")
async def list_active_env_detect_items(
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
):
try:
tenant_no = _get_tenant_no(db, user)
items = item_svc.list_active_env_detect_items(db, tenant_no)
return success_response(items)
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.get("/env-detect-items/{row_id}")
async def get_env_detect_item(
row_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("biz:envDetectItem:list")),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = item_svc.get_env_detect_item(db, row_id, tenant_no=tenant_no)
if not obj:
return error_response(404, "检测项不存在")
return success_response(item_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.post("/env-detect-items")
async def create_env_detect_item(
body: EnvDetectItemBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
dept_id = (sys_user.dept_id or "") if sys_user else ""
obj = item_svc.create_env_detect_item(
db,
item_code=body.item_code,
item_name=body.item_name,
status=body.status,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user_id,
create_dept_id=dept_id,
)
return success_response(item_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))
@router.put("/env-detect-items/{row_id}")
async def update_env_detect_item(
row_id: str,
body: EnvDetectItemUpdateBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
obj = item_svc.update_env_detect_item(
db,
row_id,
item_code=body.item_code,
item_name=body.item_name,
status=body.status,
order_num=body.order_num,
remark=body.remark,
user_id=user_id,
tenant_no=tenant_no,
)
return success_response(item_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))
@router.delete("/env-detect-items/{row_id}")
async def delete_env_detect_item(
row_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
item_svc.soft_delete_env_detect_item(db, row_id, tenant_no=tenant_no)
return success_response(None)
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))
# ---------- 环境检测登记 ----------
def _parse_detect_date(value: Optional[str]) -> Optional[datetime]:
s = (value or "").strip()
if not s:
return None
dt = parse_datetime(s)
if not dt and len(s) >= 10:
dt = parse_datetime(f"{s[:10]} 00:00:00")
return dt
def _parse_detect_date_bound(value: Optional[str], *, end_of_day: bool = False) -> Optional[datetime]:
dt = _parse_detect_date(value)
if not dt:
return None
s = (value or "").strip()
if end_of_day and " " not in s:
return datetime.combine(dt.date(), time(23, 59, 59))
return dt
class EnvDetectRecordBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
detect_time: str = Field(..., alias="detectTime")
result_time: Optional[str] = Field(None, alias="resultTime")
inspector_ids: List[str] = Field(..., alias="inspectorIds")
env_detect_item_id: str = Field(..., alias="envDetectItemId")
result_desc: str = Field(..., alias="resultDesc")
attachment_urls: Optional[str] = Field(None, alias="attachmentUrls")
remark: Optional[str] = None
class EnvDetectRecordUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
detect_time: Optional[str] = Field(None, alias="detectTime")
result_time: Optional[str] = Field(None, alias="resultTime")
inspector_ids: Optional[List[str]] = Field(None, alias="inspectorIds")
env_detect_item_id: Optional[str] = Field(None, alias="envDetectItemId")
result_desc: Optional[str] = Field(None, alias="resultDesc")
attachment_urls: Optional[str] = Field(None, alias="attachmentUrls")
remark: Optional[str] = None
@router.get("/env-detect-records")
async def list_env_detect_records(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100),
keyword: Optional[str] = None,
envDetectItemId: Optional[str] = None,
inspectorId: Optional[str] = None,
detectTimeStart: Optional[str] = None,
detectTimeEnd: Optional[str] = None,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
):
try:
tenant_no = _get_tenant_no(db, user)
query = db.query(BizEnvDetectRecord).filter(
BizEnvDetectRecord.del_flag == 0,
BizEnvDetectRecord.tenant_no == tenant_no,
)
kw = (keyword or "").strip()
if kw:
from sqlalchemy import or_
like = f"%{kw}%"
query = query.filter(
or_(
BizEnvDetectRecord.record_no.like(like),
BizEnvDetectRecord.inspector_names.like(like),
BizEnvDetectRecord.result_desc.like(like),
)
)
item_id = (envDetectItemId or "").strip()
if item_id:
query = query.filter(BizEnvDetectRecord.env_detect_item_id == item_id)
insp_id = (inspectorId or "").strip()
if insp_id:
from sqlalchemy import func
query = query.filter(func.find_in_set(insp_id, BizEnvDetectRecord.inspector_ids) > 0)
dt_start = _parse_detect_date_bound(detectTimeStart, end_of_day=False)
dt_end = _parse_detect_date_bound(detectTimeEnd, end_of_day=True)
if dt_start:
query = query.filter(BizEnvDetectRecord.detect_time >= dt_start)
if dt_end:
query = query.filter(BizEnvDetectRecord.detect_time <= dt_end)
query = apply_data_scope(query, BizEnvDetectRecord, user, db, tenant_no)
total = query.count()
items = (
query.order_by(BizEnvDetectRecord.detect_time.desc())
.offset((page - 1) * pageSize)
.limit(pageSize)
.all()
)
result_list = [record_svc._row_to_dict(r) for r in items]
return success_response(_page_payload(result_list, total, page, pageSize))
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.get("/env-detect-records/{row_id}")
async def get_env_detect_record(
row_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = record_svc.get_env_detect_record(db, row_id, tenant_no=tenant_no)
if not obj:
return error_response(404, "登记记录不存在")
return success_response(record_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.post("/env-detect-records")
async def create_env_detect_record(
body: EnvDetectRecordBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
dept_id = (sys_user.dept_id or "") if sys_user else ""
detect_time = _parse_detect_date(body.detect_time)
if not detect_time:
return error_response(400, "检测日期格式无效")
result_time = None
if body.result_time:
result_time = _parse_detect_date(body.result_time)
if not result_time:
return error_response(400, "结果日期格式无效")
obj = record_svc.create_env_detect_record(
db,
detect_time=detect_time,
result_time=result_time,
inspector_ids=body.inspector_ids,
env_detect_item_id=body.env_detect_item_id,
result_desc=body.result_desc,
attachment_urls=body.attachment_urls,
tenant_no=tenant_no,
remark=body.remark,
user_id=user_id,
create_dept_id=dept_id,
)
return success_response(record_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))
@router.put("/env-detect-records/{row_id}")
async def update_env_detect_record(
row_id: str,
body: EnvDetectRecordUpdateBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
detect_time = _parse_detect_date(body.detect_time) if body.detect_time else None
if body.detect_time and not detect_time:
return error_response(400, "检测日期格式无效")
update_result_time = "result_time" in body.model_fields_set
result_time = None
if update_result_time and body.result_time:
result_time = _parse_detect_date(body.result_time)
if not result_time:
return error_response(400, "结果日期格式无效")
obj = record_svc.update_env_detect_record(
db,
row_id,
detect_time=detect_time,
result_time=result_time,
update_result_time=update_result_time,
inspector_ids=body.inspector_ids,
env_detect_item_id=body.env_detect_item_id,
result_desc=body.result_desc,
attachment_urls=body.attachment_urls,
remark=body.remark,
user_id=user_id,
tenant_no=tenant_no,
)
return success_response(record_svc._row_to_dict(obj))
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))
@router.delete("/env-detect-records/{row_id}")
async def delete_env_detect_record(
row_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
try:
tenant_no = _get_tenant_no(db, user)
record_svc.soft_delete_env_detect_record(db, row_id, tenant_no=tenant_no)
return success_response(None)
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(400, str(e))