post.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. """职位 CRUD(sys_post)"""
  2. from __future__ import annotations
  3. import math
  4. from datetime import datetime
  5. from typing import Any, Dict, List, Optional, Tuple
  6. from sqlalchemy import and_, func, or_
  7. from sqlalchemy.orm import Session
  8. from app.core.delete_guard import assert_row_deletable_by_creator
  9. from app.core.utils import generate_uuid
  10. from app.models.models import SysPost
  11. def _row_to_dict(p: SysPost) -> Dict[str, Any]:
  12. return {
  13. "id": p.id,
  14. "postName": p.post_name,
  15. "postCode": p.post_code,
  16. "status": p.status,
  17. "tenantNo": p.tenant_no,
  18. "orderNum": p.order_num if p.order_num is not None else 0,
  19. "remark": p.remark or "",
  20. "createBy": p.create_by or "",
  21. "createTime": p.create_time.strftime("%Y-%m-%d %H:%M:%S") if p.create_time else "",
  22. "updateTime": p.update_time.strftime("%Y-%m-%d %H:%M:%S") if p.update_time else "",
  23. }
  24. def list_posts(
  25. db: Session,
  26. *,
  27. page: int = 1,
  28. page_size: int = 10,
  29. keyword: Optional[str] = None,
  30. tenant_no: Optional[str] = None,
  31. ids: Optional[List[str]] = None,
  32. max_page_size: Optional[int] = None,
  33. user_info=None,
  34. ) -> Tuple[List[Dict[str, Any]], int]:
  35. def _filtered():
  36. q0 = db.query(SysPost).filter(SysPost.del_flag == 0)
  37. if tenant_no:
  38. q0 = q0.filter(SysPost.tenant_no == tenant_no)
  39. kw = (keyword or "").strip()
  40. if kw:
  41. like = f"%{kw}%"
  42. q0 = q0.filter(or_(SysPost.post_name.like(like), SysPost.post_code.like(like)))
  43. if ids:
  44. q0 = q0.filter(SysPost.id.in_(ids))
  45. # 职位为租户主数据,不做 create_by 数据范围过滤
  46. return q0
  47. total = _filtered().order_by(None).with_entities(func.count(SysPost.id)).scalar() or 0
  48. page = max(1, page)
  49. cap = int(max_page_size) if max_page_size else 500
  50. page_size = min(max(1, page_size), cap)
  51. rows = (
  52. _filtered()
  53. .order_by(SysPost.create_time.desc())
  54. .offset((page - 1) * page_size)
  55. .limit(page_size)
  56. .all()
  57. )
  58. return [_row_to_dict(x) for x in rows], int(total)
  59. def get_post(db: Session, post_id: str) -> Optional[SysPost]:
  60. return (
  61. db.query(SysPost)
  62. .filter(and_(SysPost.id == post_id, SysPost.del_flag == 0))
  63. .first()
  64. )
  65. def post_code_exists(db: Session, code: str, tenant_no: str, exclude_id: Optional[str] = None) -> bool:
  66. q = db.query(SysPost).filter(and_(SysPost.post_code == code.strip(), SysPost.tenant_no == tenant_no, SysPost.del_flag == 0))
  67. if exclude_id:
  68. q = q.filter(SysPost.id != exclude_id)
  69. return q.first() is not None
  70. def create_post(
  71. db: Session,
  72. *,
  73. post_name: str,
  74. post_code: str,
  75. status: str = "1",
  76. tenant_no: str = "shanxia2.0",
  77. order_num: Optional[int] = None,
  78. remark: Optional[str] = None,
  79. user_id: Optional[str] = None,
  80. ) -> SysPost:
  81. pc = (post_code or "").strip()
  82. if not pc:
  83. raise ValueError("职位编码不能为空")
  84. if post_code_exists(db, pc, tenant_no):
  85. raise ValueError("职位编码已存在")
  86. obj = SysPost(
  87. id=generate_uuid(),
  88. post_name=(post_name or "").strip() or pc,
  89. post_code=pc,
  90. status=status or "1",
  91. tenant_no=tenant_no,
  92. order_num=order_num if order_num is not None else 0,
  93. remark=(remark or "").strip() or None,
  94. create_by=user_id,
  95. create_dept_id="",
  96. create_time=datetime.now(),
  97. update_by=user_id,
  98. update_time=datetime.now(),
  99. del_flag=0,
  100. )
  101. db.add(obj)
  102. db.commit()
  103. db.refresh(obj)
  104. return obj
  105. def update_post(
  106. db: Session,
  107. post_id: str,
  108. *,
  109. post_name: Optional[str] = None,
  110. post_code: Optional[str] = None,
  111. status: Optional[str] = None,
  112. order_num: Optional[int] = None,
  113. remark: Optional[str] = None,
  114. user_id: Optional[str] = None,
  115. ) -> SysPost:
  116. obj = get_post(db, post_id)
  117. if not obj:
  118. raise ValueError("职位不存在")
  119. if post_code is not None:
  120. new_code = post_code.strip()
  121. if not new_code:
  122. raise ValueError("职位编码不能为空")
  123. if new_code != obj.post_code and post_code_exists(db, new_code, obj.tenant_no, exclude_id=post_id):
  124. raise ValueError("职位编码已存在")
  125. obj.post_code = new_code
  126. if post_name is not None:
  127. obj.post_name = (post_name or "").strip() or obj.post_name
  128. if status is not None:
  129. obj.status = status
  130. if order_num is not None:
  131. obj.order_num = order_num
  132. if remark is not None:
  133. obj.remark = (remark or "").strip() or None
  134. obj.update_by = user_id
  135. obj.update_time = datetime.now()
  136. db.add(obj)
  137. db.commit()
  138. db.refresh(obj)
  139. return obj
  140. def soft_delete_post(db: Session, post_id: str, *, user_info: dict = None) -> None:
  141. obj = get_post(db, post_id)
  142. if not obj:
  143. raise ValueError("职位不存在")
  144. assert_row_deletable_by_creator(obj, user_info)
  145. obj.del_flag = 1
  146. obj.update_time = datetime.now()
  147. db.add(obj)
  148. db.commit()
  149. def total_pages(total: int, page_size: int) -> int:
  150. if total <= 0:
  151. return 0
  152. return int(math.ceil(total / float(page_size)))