env_detect.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. """环境检测 — 检测项维护 + 登记管理 API"""
  2. from typing import List, Optional
  3. from fastapi import APIRouter, Depends, Query
  4. from pydantic import BaseModel, ConfigDict, Field
  5. from sqlalchemy.orm import Session
  6. from app.core.data_scope import apply_data_scope
  7. from app.core.database import get_db
  8. from app.core.menu_guard import require_admin_or_super_admin, require_menu_code
  9. from app.core.response import error_response, success_response
  10. from app.core.utils import parse_datetime
  11. from app.crud import env_detect_item as item_svc
  12. from app.crud import env_detect_record as record_svc
  13. from app.crud.collection_protocol import total_pages
  14. from app.models.models import BizEnvDetectItem, BizEnvDetectRecord, SysUser
  15. router = APIRouter(prefix="/web/admin", tags=["环境检测"])
  16. def _get_tenant_no(db: Session, user: dict) -> str:
  17. user_id = user.get("user_id")
  18. if not user_id:
  19. raise PermissionError("用户身份信息缺失,无法确定租户")
  20. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  21. if not sys_user or not sys_user.tenant_no:
  22. raise PermissionError("用户租户信息缺失")
  23. return sys_user.tenant_no
  24. def _get_current_user_id(user: dict) -> str:
  25. user_id = user.get("user_id")
  26. if not user_id:
  27. raise PermissionError("用户身份信息缺失")
  28. return str(user_id)
  29. def _page_payload(items: list, total: int, page: int, page_size: int) -> dict:
  30. return {
  31. "list": items,
  32. "total": total,
  33. "page": page,
  34. "pageSize": page_size,
  35. "totalPages": total_pages(total, page_size),
  36. }
  37. # ---------- 环境检测项 ----------
  38. class EnvDetectItemBody(BaseModel):
  39. model_config = ConfigDict(populate_by_name=True)
  40. item_code: str = Field(..., alias="itemCode")
  41. item_name: str = Field(..., alias="itemName")
  42. status: str = Field("1", alias="status")
  43. order_num: Optional[int] = Field(None, alias="orderNum")
  44. remark: Optional[str] = None
  45. class EnvDetectItemUpdateBody(BaseModel):
  46. model_config = ConfigDict(populate_by_name=True)
  47. item_code: Optional[str] = Field(None, alias="itemCode")
  48. item_name: Optional[str] = Field(None, alias="itemName")
  49. status: Optional[str] = None
  50. order_num: Optional[int] = Field(None, alias="orderNum")
  51. remark: Optional[str] = None
  52. @router.get("/env-detect-items")
  53. async def list_env_detect_items(
  54. page: int = Query(1, ge=1),
  55. pageSize: int = Query(10, ge=1, le=100),
  56. keyword: Optional[str] = None,
  57. status: Optional[str] = None,
  58. db: Session = Depends(get_db),
  59. user: dict = Depends(require_menu_code("biz:envDetectItem:list")),
  60. ):
  61. try:
  62. tenant_no = _get_tenant_no(db, user)
  63. query = db.query(BizEnvDetectItem).filter(
  64. BizEnvDetectItem.del_flag == 0,
  65. BizEnvDetectItem.tenant_no == tenant_no,
  66. )
  67. kw = (keyword or "").strip()
  68. if kw:
  69. from sqlalchemy import or_
  70. like = f"%{kw}%"
  71. query = query.filter(
  72. or_(
  73. BizEnvDetectItem.item_code.like(like),
  74. BizEnvDetectItem.item_name.like(like),
  75. )
  76. )
  77. if status:
  78. query = query.filter(BizEnvDetectItem.status == status)
  79. query = apply_data_scope(query, BizEnvDetectItem, user, db, tenant_no)
  80. total = query.count()
  81. items = (
  82. query.order_by(BizEnvDetectItem.create_time.desc())
  83. .offset((page - 1) * pageSize)
  84. .limit(pageSize)
  85. .all()
  86. )
  87. result_list = [item_svc._row_to_dict(r) for r in items]
  88. return success_response(_page_payload(result_list, total, page, pageSize))
  89. except PermissionError as e:
  90. return error_response(403, str(e))
  91. except Exception as e:
  92. return error_response(400, str(e))
  93. @router.get("/env-detect-items/active")
  94. async def list_active_env_detect_items(
  95. db: Session = Depends(get_db),
  96. user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
  97. ):
  98. try:
  99. tenant_no = _get_tenant_no(db, user)
  100. items = item_svc.list_active_env_detect_items(db, tenant_no)
  101. return success_response(items)
  102. except PermissionError as e:
  103. return error_response(403, str(e))
  104. except Exception as e:
  105. return error_response(400, str(e))
  106. @router.get("/env-detect-items/{row_id}")
  107. async def get_env_detect_item(
  108. row_id: str,
  109. db: Session = Depends(get_db),
  110. user: dict = Depends(require_menu_code("biz:envDetectItem:list")),
  111. ):
  112. try:
  113. tenant_no = _get_tenant_no(db, user)
  114. obj = item_svc.get_env_detect_item(db, row_id, tenant_no=tenant_no)
  115. if not obj:
  116. return error_response(404, "检测项不存在")
  117. return success_response(item_svc._row_to_dict(obj))
  118. except PermissionError as e:
  119. return error_response(403, str(e))
  120. except Exception as e:
  121. return error_response(400, str(e))
  122. @router.post("/env-detect-items")
  123. async def create_env_detect_item(
  124. body: EnvDetectItemBody,
  125. db: Session = Depends(get_db),
  126. user: dict = Depends(require_admin_or_super_admin),
  127. ):
  128. try:
  129. tenant_no = _get_tenant_no(db, user)
  130. user_id = _get_current_user_id(user)
  131. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  132. dept_id = (sys_user.dept_id or "") if sys_user else ""
  133. obj = item_svc.create_env_detect_item(
  134. db,
  135. item_code=body.item_code,
  136. item_name=body.item_name,
  137. status=body.status,
  138. tenant_no=tenant_no,
  139. order_num=body.order_num,
  140. remark=body.remark,
  141. user_id=user_id,
  142. create_dept_id=dept_id,
  143. )
  144. return success_response(item_svc._row_to_dict(obj))
  145. except PermissionError as e:
  146. return error_response(403, str(e))
  147. except ValueError as e:
  148. return error_response(400, str(e))
  149. except Exception as e:
  150. return error_response(400, str(e))
  151. @router.put("/env-detect-items/{row_id}")
  152. async def update_env_detect_item(
  153. row_id: str,
  154. body: EnvDetectItemUpdateBody,
  155. db: Session = Depends(get_db),
  156. user: dict = Depends(require_admin_or_super_admin),
  157. ):
  158. try:
  159. tenant_no = _get_tenant_no(db, user)
  160. user_id = _get_current_user_id(user)
  161. obj = item_svc.update_env_detect_item(
  162. db,
  163. row_id,
  164. item_code=body.item_code,
  165. item_name=body.item_name,
  166. status=body.status,
  167. order_num=body.order_num,
  168. remark=body.remark,
  169. user_id=user_id,
  170. tenant_no=tenant_no,
  171. )
  172. return success_response(item_svc._row_to_dict(obj))
  173. except PermissionError as e:
  174. return error_response(403, str(e))
  175. except ValueError as e:
  176. return error_response(400, str(e))
  177. except Exception as e:
  178. return error_response(400, str(e))
  179. @router.delete("/env-detect-items/{row_id}")
  180. async def delete_env_detect_item(
  181. row_id: str,
  182. db: Session = Depends(get_db),
  183. user: dict = Depends(require_admin_or_super_admin),
  184. ):
  185. try:
  186. tenant_no = _get_tenant_no(db, user)
  187. item_svc.soft_delete_env_detect_item(db, row_id, tenant_no=tenant_no)
  188. return success_response(None)
  189. except PermissionError as e:
  190. return error_response(403, str(e))
  191. except ValueError as e:
  192. return error_response(400, str(e))
  193. except Exception as e:
  194. return error_response(400, str(e))
  195. # ---------- 环境检测登记 ----------
  196. class EnvDetectRecordBody(BaseModel):
  197. model_config = ConfigDict(populate_by_name=True)
  198. detect_time: str = Field(..., alias="detectTime")
  199. inspector_ids: List[str] = Field(..., alias="inspectorIds")
  200. env_detect_item_id: str = Field(..., alias="envDetectItemId")
  201. result_desc: str = Field(..., alias="resultDesc")
  202. attachment_urls: Optional[str] = Field(None, alias="attachmentUrls")
  203. remark: Optional[str] = None
  204. class EnvDetectRecordUpdateBody(BaseModel):
  205. model_config = ConfigDict(populate_by_name=True)
  206. detect_time: Optional[str] = Field(None, alias="detectTime")
  207. inspector_ids: Optional[List[str]] = Field(None, alias="inspectorIds")
  208. env_detect_item_id: Optional[str] = Field(None, alias="envDetectItemId")
  209. result_desc: Optional[str] = Field(None, alias="resultDesc")
  210. attachment_urls: Optional[str] = Field(None, alias="attachmentUrls")
  211. remark: Optional[str] = None
  212. @router.get("/env-detect-records")
  213. async def list_env_detect_records(
  214. page: int = Query(1, ge=1),
  215. pageSize: int = Query(10, ge=1, le=100),
  216. keyword: Optional[str] = None,
  217. envDetectItemId: Optional[str] = None,
  218. inspectorId: Optional[str] = None,
  219. detectTimeStart: Optional[str] = None,
  220. detectTimeEnd: Optional[str] = None,
  221. db: Session = Depends(get_db),
  222. user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
  223. ):
  224. try:
  225. tenant_no = _get_tenant_no(db, user)
  226. query = db.query(BizEnvDetectRecord).filter(
  227. BizEnvDetectRecord.del_flag == 0,
  228. BizEnvDetectRecord.tenant_no == tenant_no,
  229. )
  230. kw = (keyword or "").strip()
  231. if kw:
  232. from sqlalchemy import or_
  233. like = f"%{kw}%"
  234. query = query.filter(
  235. or_(
  236. BizEnvDetectRecord.record_no.like(like),
  237. BizEnvDetectRecord.inspector_names.like(like),
  238. BizEnvDetectRecord.result_desc.like(like),
  239. )
  240. )
  241. item_id = (envDetectItemId or "").strip()
  242. if item_id:
  243. query = query.filter(BizEnvDetectRecord.env_detect_item_id == item_id)
  244. insp_id = (inspectorId or "").strip()
  245. if insp_id:
  246. from sqlalchemy import func
  247. query = query.filter(func.find_in_set(insp_id, BizEnvDetectRecord.inspector_ids) > 0)
  248. dt_start = parse_datetime(detectTimeStart) if detectTimeStart else None
  249. dt_end = parse_datetime(detectTimeEnd) if detectTimeEnd else None
  250. if dt_start:
  251. query = query.filter(BizEnvDetectRecord.detect_time >= dt_start)
  252. if dt_end:
  253. query = query.filter(BizEnvDetectRecord.detect_time <= dt_end)
  254. query = apply_data_scope(query, BizEnvDetectRecord, user, db, tenant_no)
  255. total = query.count()
  256. items = (
  257. query.order_by(BizEnvDetectRecord.create_time.desc())
  258. .offset((page - 1) * pageSize)
  259. .limit(pageSize)
  260. .all()
  261. )
  262. result_list = [record_svc._row_to_dict(r) for r in items]
  263. return success_response(_page_payload(result_list, total, page, pageSize))
  264. except PermissionError as e:
  265. return error_response(403, str(e))
  266. except Exception as e:
  267. return error_response(400, str(e))
  268. @router.get("/env-detect-records/{row_id}")
  269. async def get_env_detect_record(
  270. row_id: str,
  271. db: Session = Depends(get_db),
  272. user: dict = Depends(require_menu_code("biz:envDetectRecord:list")),
  273. ):
  274. try:
  275. tenant_no = _get_tenant_no(db, user)
  276. obj = record_svc.get_env_detect_record(db, row_id, tenant_no=tenant_no)
  277. if not obj:
  278. return error_response(404, "登记记录不存在")
  279. return success_response(record_svc._row_to_dict(obj))
  280. except PermissionError as e:
  281. return error_response(403, str(e))
  282. except Exception as e:
  283. return error_response(400, str(e))
  284. @router.post("/env-detect-records")
  285. async def create_env_detect_record(
  286. body: EnvDetectRecordBody,
  287. db: Session = Depends(get_db),
  288. user: dict = Depends(require_admin_or_super_admin),
  289. ):
  290. try:
  291. tenant_no = _get_tenant_no(db, user)
  292. user_id = _get_current_user_id(user)
  293. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  294. dept_id = (sys_user.dept_id or "") if sys_user else ""
  295. detect_time = parse_datetime(body.detect_time)
  296. if not detect_time:
  297. return error_response(400, "检测时间格式无效")
  298. obj = record_svc.create_env_detect_record(
  299. db,
  300. detect_time=detect_time,
  301. inspector_ids=body.inspector_ids,
  302. env_detect_item_id=body.env_detect_item_id,
  303. result_desc=body.result_desc,
  304. attachment_urls=body.attachment_urls,
  305. tenant_no=tenant_no,
  306. remark=body.remark,
  307. user_id=user_id,
  308. create_dept_id=dept_id,
  309. )
  310. return success_response(record_svc._row_to_dict(obj))
  311. except PermissionError as e:
  312. return error_response(403, str(e))
  313. except ValueError as e:
  314. return error_response(400, str(e))
  315. except Exception as e:
  316. return error_response(400, str(e))
  317. @router.put("/env-detect-records/{row_id}")
  318. async def update_env_detect_record(
  319. row_id: str,
  320. body: EnvDetectRecordUpdateBody,
  321. db: Session = Depends(get_db),
  322. user: dict = Depends(require_admin_or_super_admin),
  323. ):
  324. try:
  325. tenant_no = _get_tenant_no(db, user)
  326. user_id = _get_current_user_id(user)
  327. detect_time = parse_datetime(body.detect_time) if body.detect_time else None
  328. if body.detect_time and not detect_time:
  329. return error_response(400, "检测时间格式无效")
  330. obj = record_svc.update_env_detect_record(
  331. db,
  332. row_id,
  333. detect_time=detect_time,
  334. inspector_ids=body.inspector_ids,
  335. env_detect_item_id=body.env_detect_item_id,
  336. result_desc=body.result_desc,
  337. attachment_urls=body.attachment_urls,
  338. remark=body.remark,
  339. user_id=user_id,
  340. tenant_no=tenant_no,
  341. )
  342. return success_response(record_svc._row_to_dict(obj))
  343. except PermissionError as e:
  344. return error_response(403, str(e))
  345. except ValueError as e:
  346. return error_response(400, str(e))
  347. except Exception as e:
  348. return error_response(400, str(e))
  349. @router.delete("/env-detect-records/{row_id}")
  350. async def delete_env_detect_record(
  351. row_id: str,
  352. db: Session = Depends(get_db),
  353. user: dict = Depends(require_admin_or_super_admin),
  354. ):
  355. try:
  356. tenant_no = _get_tenant_no(db, user)
  357. record_svc.soft_delete_env_detect_record(db, row_id, tenant_no=tenant_no)
  358. return success_response(None)
  359. except PermissionError as e:
  360. return error_response(403, str(e))
  361. except ValueError as e:
  362. return error_response(400, str(e))
  363. except Exception as e:
  364. return error_response(400, str(e))