cleanroom_garment.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  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.database import get_db
  7. from app.core.menu_guard import require_admin_or_super_admin, require_menu_code
  8. from app.core.response import error_response, success_response
  9. from app.crud import cleanroom_garment as garment_svc
  10. from app.models.models import SysUser
  11. router = APIRouter(prefix="/web/admin", tags=["洁净服管理"])
  12. def _get_tenant_no(db: Session, user: dict) -> str:
  13. user_id = user.get("user_id")
  14. if not user_id:
  15. raise PermissionError("用户身份信息缺失,无法确定租户")
  16. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  17. if not sys_user or not sys_user.tenant_no:
  18. raise PermissionError("用户租户信息缺失")
  19. return sys_user.tenant_no
  20. class GarmentCreateBody(BaseModel):
  21. model_config = ConfigDict(populate_by_name=True)
  22. garment_code: str = Field(..., alias="garmentCode")
  23. garment_name: str = Field(..., alias="garmentName")
  24. wash_discard_limit: int = Field(..., alias="washDiscardLimit")
  25. sterilize_discard_limit: int = Field(..., alias="sterilizeDiscardLimit")
  26. inbound_date: str = Field(..., alias="inboundDate")
  27. order_num: Optional[int] = Field(None, alias="orderNum")
  28. remark: Optional[str] = None
  29. class GarmentUpdateBody(BaseModel):
  30. model_config = ConfigDict(populate_by_name=True)
  31. garment_code: Optional[str] = Field(None, alias="garmentCode")
  32. garment_name: Optional[str] = Field(None, alias="garmentName")
  33. wash_discard_limit: Optional[int] = Field(None, alias="washDiscardLimit")
  34. sterilize_discard_limit: Optional[int] = Field(None, alias="sterilizeDiscardLimit")
  35. inbound_date: Optional[str] = Field(None, alias="inboundDate")
  36. order_num: Optional[int] = Field(None, alias="orderNum")
  37. remark: Optional[str] = None
  38. class GarmentBatchDeleteBody(BaseModel):
  39. model_config = ConfigDict(populate_by_name=True)
  40. ids: List[str] = Field(..., alias="ids")
  41. class GarmentDiscardBody(BaseModel):
  42. model_config = ConfigDict(populate_by_name=True)
  43. discard_date: Optional[str] = Field(None, alias="discardDate")
  44. remark: Optional[str] = None
  45. class GarmentBatchDiscardBody(BaseModel):
  46. model_config = ConfigDict(populate_by_name=True)
  47. garment_ids: List[str] = Field(..., alias="garmentIds")
  48. discard_date: Optional[str] = Field(None, alias="discardDate")
  49. remark: Optional[str] = None
  50. class WashLogCreateBody(BaseModel):
  51. model_config = ConfigDict(populate_by_name=True)
  52. garment_id: str = Field(..., alias="garmentId")
  53. wash_time: str = Field(..., alias="washTime")
  54. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  55. operator_name: Optional[str] = Field(None, alias="operatorName")
  56. order_num: Optional[int] = Field(0, alias="orderNum")
  57. remark: Optional[str] = None
  58. class WashLogUpdateBody(BaseModel):
  59. model_config = ConfigDict(populate_by_name=True)
  60. wash_time: Optional[str] = Field(None, alias="washTime")
  61. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  62. operator_name: Optional[str] = Field(None, alias="operatorName")
  63. order_num: Optional[int] = Field(None, alias="orderNum")
  64. remark: Optional[str] = None
  65. class WashLogBatchBody(BaseModel):
  66. model_config = ConfigDict(populate_by_name=True)
  67. garment_ids: List[str] = Field(..., alias="garmentIds")
  68. wash_time: str = Field(..., alias="washTime")
  69. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  70. operator_name: Optional[str] = Field(None, alias="operatorName")
  71. remark: Optional[str] = None
  72. class SterilizeLogCreateBody(BaseModel):
  73. model_config = ConfigDict(populate_by_name=True)
  74. garment_id: str = Field(..., alias="garmentId")
  75. sterilize_time: str = Field(..., alias="sterilizeTime")
  76. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  77. operator_name: Optional[str] = Field(None, alias="operatorName")
  78. order_num: Optional[int] = Field(0, alias="orderNum")
  79. remark: Optional[str] = None
  80. class SterilizeLogUpdateBody(BaseModel):
  81. model_config = ConfigDict(populate_by_name=True)
  82. sterilize_time: Optional[str] = Field(None, alias="sterilizeTime")
  83. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  84. operator_name: Optional[str] = Field(None, alias="operatorName")
  85. order_num: Optional[int] = Field(None, alias="orderNum")
  86. remark: Optional[str] = None
  87. class SterilizeLogBatchBody(BaseModel):
  88. model_config = ConfigDict(populate_by_name=True)
  89. garment_ids: List[str] = Field(..., alias="garmentIds")
  90. sterilize_time: str = Field(..., alias="sterilizeTime")
  91. operator_user_id: Optional[str] = Field(None, alias="operatorUserId")
  92. operator_name: Optional[str] = Field(None, alias="operatorName")
  93. remark: Optional[str] = None
  94. @router.get("/cleanroom-garments")
  95. async def list_cleanroom_garments(
  96. page: int = Query(1, ge=1),
  97. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  98. keyword: Optional[str] = None,
  99. garmentStatus: Optional[str] = Query(None, alias="garmentStatus"),
  100. needAttention: Optional[str] = Query(None, alias="needAttention"),
  101. user: dict = Depends(require_menu_code("production:cleanroom-garment:list")),
  102. db: Session = Depends(get_db),
  103. ):
  104. tenant_no = _get_tenant_no(db, user)
  105. items, total = garment_svc.list_garments(
  106. db,
  107. page=page,
  108. page_size=pageSize,
  109. keyword=keyword,
  110. garment_status=garmentStatus,
  111. need_attention=needAttention in ("1", "true", "True"),
  112. tenant_no=tenant_no,
  113. user_info=user,
  114. )
  115. tp = garment_svc.total_pages(total, pageSize)
  116. return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
  117. @router.get("/cleanroom-garments/{garment_id}")
  118. async def get_cleanroom_garment(
  119. garment_id: str,
  120. user: dict = Depends(require_menu_code("production:cleanroom-garment:list")),
  121. db: Session = Depends(get_db),
  122. ):
  123. tenant_no = _get_tenant_no(db, user)
  124. detail = garment_svc.get_garment_detail(db, garment_id, tenant_no=tenant_no)
  125. if not detail:
  126. return error_response(404, "洁净服不存在")
  127. return success_response(detail)
  128. @router.post("/cleanroom-garments")
  129. async def create_cleanroom_garment(
  130. body: GarmentCreateBody,
  131. user: dict = Depends(require_admin_or_super_admin),
  132. db: Session = Depends(get_db),
  133. ):
  134. try:
  135. tenant_no = _get_tenant_no(db, user)
  136. obj = garment_svc.create_garment(
  137. db,
  138. garment_code=body.garment_code,
  139. garment_name=body.garment_name,
  140. wash_discard_limit=body.wash_discard_limit,
  141. sterilize_discard_limit=body.sterilize_discard_limit,
  142. inbound_date=body.inbound_date,
  143. tenant_no=tenant_no,
  144. order_num=body.order_num,
  145. remark=body.remark,
  146. user_id=user.get("user_id"),
  147. )
  148. return success_response(garment_svc.get_garment_detail(db, obj.id, tenant_no=tenant_no), message="创建成功")
  149. except ValueError as e:
  150. return error_response(400, str(e))
  151. @router.put("/cleanroom-garments/{garment_id}")
  152. async def update_cleanroom_garment(
  153. garment_id: str,
  154. body: GarmentUpdateBody,
  155. user: dict = Depends(require_admin_or_super_admin),
  156. db: Session = Depends(get_db),
  157. ):
  158. try:
  159. tenant_no = _get_tenant_no(db, user)
  160. payload = body.model_dump(exclude_unset=True, by_alias=False)
  161. obj = garment_svc.update_garment(
  162. db,
  163. garment_id,
  164. garment_code=payload.get("garment_code"),
  165. garment_name=payload.get("garment_name"),
  166. wash_discard_limit=payload.get("wash_discard_limit"),
  167. sterilize_discard_limit=payload.get("sterilize_discard_limit"),
  168. inbound_date=payload.get("inbound_date"),
  169. order_num=payload.get("order_num"),
  170. remark=payload.get("remark"),
  171. user_id=user.get("user_id"),
  172. tenant_no=tenant_no,
  173. )
  174. return success_response(garment_svc.get_garment_detail(db, obj.id, tenant_no=tenant_no), message="更新成功")
  175. except ValueError as e:
  176. return error_response(400, str(e))
  177. @router.post("/cleanroom-garments/batch-delete")
  178. async def batch_delete_cleanroom_garments(
  179. body: GarmentBatchDeleteBody,
  180. user: dict = Depends(require_admin_or_super_admin),
  181. db: Session = Depends(get_db),
  182. ):
  183. try:
  184. tenant_no = _get_tenant_no(db, user)
  185. count = garment_svc.batch_soft_delete_garments(db, body.ids, tenant_no=tenant_no)
  186. return success_response({"deletedCount": count}, message="删除成功")
  187. except ValueError as e:
  188. return error_response(400, str(e))
  189. @router.delete("/cleanroom-garments/{garment_id}")
  190. async def delete_cleanroom_garment(
  191. garment_id: str,
  192. user: dict = Depends(require_admin_or_super_admin),
  193. db: Session = Depends(get_db),
  194. ):
  195. try:
  196. tenant_no = _get_tenant_no(db, user)
  197. garment_svc.soft_delete_garment(db, garment_id, tenant_no=tenant_no)
  198. return success_response(None, message="删除成功")
  199. except ValueError as e:
  200. return error_response(400, str(e))
  201. @router.post("/cleanroom-garments/batch-discard")
  202. async def batch_discard_cleanroom_garments(
  203. body: GarmentBatchDiscardBody,
  204. user: dict = Depends(require_admin_or_super_admin),
  205. db: Session = Depends(get_db),
  206. ):
  207. try:
  208. tenant_no = _get_tenant_no(db, user)
  209. result = garment_svc.batch_discard_garments(
  210. db,
  211. body.garment_ids,
  212. discard_date=body.discard_date,
  213. remark=body.remark,
  214. user_id=user.get("user_id"),
  215. tenant_no=tenant_no,
  216. )
  217. return success_response(result, message="废弃成功")
  218. except ValueError as e:
  219. return error_response(400, str(e))
  220. @router.post("/cleanroom-garments/{garment_id}/discard")
  221. async def discard_cleanroom_garment(
  222. garment_id: str,
  223. body: GarmentDiscardBody,
  224. user: dict = Depends(require_admin_or_super_admin),
  225. db: Session = Depends(get_db),
  226. ):
  227. try:
  228. tenant_no = _get_tenant_no(db, user)
  229. obj = garment_svc.discard_garment(
  230. db,
  231. garment_id,
  232. discard_date=body.discard_date,
  233. remark=body.remark,
  234. user_id=user.get("user_id"),
  235. tenant_no=tenant_no,
  236. )
  237. return success_response(garment_svc.get_garment_detail(db, obj.id, tenant_no=tenant_no), message="废弃成功")
  238. except ValueError as e:
  239. return error_response(400, str(e))
  240. @router.get("/cleanroom-garment-wash-logs")
  241. async def list_wash_logs(
  242. page: int = Query(1, ge=1),
  243. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  244. garmentId: str = Query(..., alias="garmentId"),
  245. user: dict = Depends(require_menu_code("production:cleanroom-garment:list")),
  246. db: Session = Depends(get_db),
  247. ):
  248. tenant_no = _get_tenant_no(db, user)
  249. items, total = garment_svc.list_wash_logs(
  250. db, garment_id=garmentId, page=page, page_size=pageSize, tenant_no=tenant_no
  251. )
  252. tp = garment_svc.total_pages(total, pageSize)
  253. return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
  254. @router.post("/cleanroom-garment-wash-logs")
  255. async def create_wash_log(
  256. body: WashLogCreateBody,
  257. user: dict = Depends(require_admin_or_super_admin),
  258. db: Session = Depends(get_db),
  259. ):
  260. try:
  261. tenant_no = _get_tenant_no(db, user)
  262. obj = garment_svc.create_wash_log(
  263. db,
  264. garment_id=body.garment_id,
  265. wash_time=body.wash_time,
  266. operator_user_id=body.operator_user_id,
  267. operator_name=body.operator_name,
  268. tenant_no=tenant_no,
  269. order_num=body.order_num,
  270. remark=body.remark,
  271. user_id=user.get("user_id"),
  272. )
  273. return success_response(garment_svc._wash_log_to_dict(obj), message="创建成功")
  274. except ValueError as e:
  275. return error_response(400, str(e))
  276. @router.post("/cleanroom-garment-wash-logs/batch")
  277. async def batch_create_wash_logs(
  278. body: WashLogBatchBody,
  279. user: dict = Depends(require_admin_or_super_admin),
  280. db: Session = Depends(get_db),
  281. ):
  282. try:
  283. tenant_no = _get_tenant_no(db, user)
  284. result = garment_svc.batch_create_wash_logs(
  285. db,
  286. garment_ids=body.garment_ids,
  287. wash_time=body.wash_time,
  288. operator_user_id=body.operator_user_id,
  289. operator_name=body.operator_name,
  290. remark=body.remark,
  291. tenant_no=tenant_no,
  292. user_id=user.get("user_id"),
  293. )
  294. return success_response(result, message="批量清洗登记成功")
  295. except ValueError as e:
  296. return error_response(400, str(e))
  297. @router.put("/cleanroom-garment-wash-logs/{log_id}")
  298. async def update_wash_log(
  299. log_id: str,
  300. body: WashLogUpdateBody,
  301. user: dict = Depends(require_admin_or_super_admin),
  302. db: Session = Depends(get_db),
  303. ):
  304. try:
  305. tenant_no = _get_tenant_no(db, user)
  306. payload = body.model_dump(exclude_unset=True, by_alias=False)
  307. obj = garment_svc.update_wash_log(
  308. db,
  309. log_id,
  310. wash_time=payload.get("wash_time"),
  311. operator_user_id=payload.get("operator_user_id"),
  312. operator_name=payload.get("operator_name"),
  313. order_num=payload.get("order_num"),
  314. remark=payload.get("remark"),
  315. user_id=user.get("user_id"),
  316. tenant_no=tenant_no,
  317. )
  318. return success_response(garment_svc._wash_log_to_dict(obj), message="更新成功")
  319. except ValueError as e:
  320. return error_response(400, str(e))
  321. @router.delete("/cleanroom-garment-wash-logs/{log_id}")
  322. async def delete_wash_log(
  323. log_id: str,
  324. user: dict = Depends(require_admin_or_super_admin),
  325. db: Session = Depends(get_db),
  326. ):
  327. try:
  328. tenant_no = _get_tenant_no(db, user)
  329. garment_svc.soft_delete_wash_log(db, log_id, tenant_no=tenant_no)
  330. return success_response(None, message="删除成功")
  331. except ValueError as e:
  332. return error_response(400, str(e))
  333. @router.get("/cleanroom-garment-sterilize-logs")
  334. async def list_sterilize_logs(
  335. page: int = Query(1, ge=1),
  336. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  337. garmentId: str = Query(..., alias="garmentId"),
  338. user: dict = Depends(require_menu_code("production:cleanroom-garment:list")),
  339. db: Session = Depends(get_db),
  340. ):
  341. tenant_no = _get_tenant_no(db, user)
  342. items, total = garment_svc.list_sterilize_logs(
  343. db, garment_id=garmentId, page=page, page_size=pageSize, tenant_no=tenant_no
  344. )
  345. tp = garment_svc.total_pages(total, pageSize)
  346. return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
  347. @router.post("/cleanroom-garment-sterilize-logs")
  348. async def create_sterilize_log(
  349. body: SterilizeLogCreateBody,
  350. user: dict = Depends(require_admin_or_super_admin),
  351. db: Session = Depends(get_db),
  352. ):
  353. try:
  354. tenant_no = _get_tenant_no(db, user)
  355. obj = garment_svc.create_sterilize_log(
  356. db,
  357. garment_id=body.garment_id,
  358. sterilize_time=body.sterilize_time,
  359. operator_user_id=body.operator_user_id,
  360. operator_name=body.operator_name,
  361. tenant_no=tenant_no,
  362. order_num=body.order_num,
  363. remark=body.remark,
  364. user_id=user.get("user_id"),
  365. )
  366. return success_response(garment_svc._sterilize_log_to_dict(obj), message="创建成功")
  367. except ValueError as e:
  368. return error_response(400, str(e))
  369. @router.post("/cleanroom-garment-sterilize-logs/batch")
  370. async def batch_create_sterilize_logs(
  371. body: SterilizeLogBatchBody,
  372. user: dict = Depends(require_admin_or_super_admin),
  373. db: Session = Depends(get_db),
  374. ):
  375. try:
  376. tenant_no = _get_tenant_no(db, user)
  377. result = garment_svc.batch_create_sterilize_logs(
  378. db,
  379. garment_ids=body.garment_ids,
  380. sterilize_time=body.sterilize_time,
  381. operator_user_id=body.operator_user_id,
  382. operator_name=body.operator_name,
  383. remark=body.remark,
  384. tenant_no=tenant_no,
  385. user_id=user.get("user_id"),
  386. )
  387. return success_response(result, message="批量灭菌登记成功")
  388. except ValueError as e:
  389. return error_response(400, str(e))
  390. @router.put("/cleanroom-garment-sterilize-logs/{log_id}")
  391. async def update_sterilize_log(
  392. log_id: str,
  393. body: SterilizeLogUpdateBody,
  394. user: dict = Depends(require_admin_or_super_admin),
  395. db: Session = Depends(get_db),
  396. ):
  397. try:
  398. tenant_no = _get_tenant_no(db, user)
  399. payload = body.model_dump(exclude_unset=True, by_alias=False)
  400. obj = garment_svc.update_sterilize_log(
  401. db,
  402. log_id,
  403. sterilize_time=payload.get("sterilize_time"),
  404. operator_user_id=payload.get("operator_user_id"),
  405. operator_name=payload.get("operator_name"),
  406. order_num=payload.get("order_num"),
  407. remark=payload.get("remark"),
  408. user_id=user.get("user_id"),
  409. tenant_no=tenant_no,
  410. )
  411. return success_response(garment_svc._sterilize_log_to_dict(obj), message="更新成功")
  412. except ValueError as e:
  413. return error_response(400, str(e))
  414. @router.delete("/cleanroom-garment-sterilize-logs/{log_id}")
  415. async def delete_sterilize_log(
  416. log_id: str,
  417. user: dict = Depends(require_admin_or_super_admin),
  418. db: Session = Depends(get_db),
  419. ):
  420. try:
  421. tenant_no = _get_tenant_no(db, user)
  422. garment_svc.soft_delete_sterilize_log(db, log_id, tenant_no=tenant_no)
  423. return success_response(None, message="删除成功")
  424. except ValueError as e:
  425. return error_response(400, str(e))