admin_ledger_service.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. """管理端反馈 / 建言办理"""
  2. from typing import Any, Dict, List, Optional, Set
  3. from sqlalchemy.orm import Session
  4. from app.core.response import AppHTTPError
  5. from app.crud import feedback as feedback_crud
  6. from app.crud import oper_log as oper_log_crud
  7. from app.crud import suggestion as suggestion_crud
  8. from app.models.business import Feedback, Suggestion
  9. from app.models.system import SysUser
  10. FEEDBACK_TRANSITIONS: Dict[str, Set[str]] = {
  11. "待处理": {"处理中", "已办结"},
  12. "处理中": {"已办结"},
  13. "已办结": set(),
  14. }
  15. SUGGESTION_TRANSITIONS: Dict[str, Set[str]] = {
  16. "待查阅": {"已采纳", "已回复"},
  17. "已采纳": {"已回复"},
  18. "已回复": {"已采纳"},
  19. }
  20. def _iso(dt) -> Optional[str]:
  21. if not dt:
  22. return None
  23. return dt.isoformat(sep=" ", timespec="seconds")
  24. def feedback_to_dict(row: Feedback) -> Dict[str, Any]:
  25. return {
  26. "id": row.id,
  27. "bizNo": row.biz_no,
  28. "fbType": row.fb_type,
  29. "targetName": row.target_name,
  30. "targetDept": row.target_dept,
  31. "targetPost": row.target_post,
  32. "content": row.content,
  33. "reporterName": row.reporter_name,
  34. "reporterUnit": row.reporter_unit,
  35. "reporterPost": row.reporter_post,
  36. "reporterPhone": row.reporter_phone,
  37. "attachmentUrls": list(row.attachments or []),
  38. "status": row.status,
  39. "handleRemark": row.handle_remark,
  40. "createTime": _iso(row.create_time),
  41. "updateTime": _iso(row.update_time),
  42. }
  43. def suggestion_to_dict(row: Suggestion) -> Dict[str, Any]:
  44. return {
  45. "id": row.id,
  46. "bizNo": row.biz_no,
  47. "content": row.content,
  48. "contactName": row.contact_name,
  49. "contactUnit": row.contact_unit,
  50. "contactPost": row.contact_post,
  51. "contactPhone": row.contact_phone,
  52. "attachmentUrls": list(row.attachments or []),
  53. "status": row.status,
  54. "handleRemark": row.handle_remark,
  55. "createTime": _iso(row.create_time),
  56. "updateTime": _iso(row.update_time),
  57. }
  58. def _assert_transition(
  59. current: str, new_status: str, table: Dict[str, Set[str]]
  60. ) -> None:
  61. if current == new_status:
  62. return
  63. allowed = table.get(current, set())
  64. if new_status not in allowed:
  65. raise AppHTTPError(400, f"不允许从「{current}」变更为「{new_status}」")
  66. def list_feedbacks_page(
  67. db: Session,
  68. *,
  69. status: Optional[str],
  70. fb_type: Optional[str],
  71. keyword: Optional[str],
  72. page: int,
  73. page_size: int,
  74. ) -> Dict[str, Any]:
  75. items, total = feedback_crud.list_feedbacks(
  76. db,
  77. status=status,
  78. fb_type=fb_type,
  79. keyword=keyword,
  80. page=page,
  81. page_size=page_size,
  82. )
  83. return {
  84. "list": [feedback_to_dict(r) for r in items],
  85. "total": total,
  86. "page": page,
  87. "pageSize": page_size,
  88. }
  89. def get_feedback_detail(db: Session, feedback_id: str) -> Dict[str, Any]:
  90. row = feedback_crud.get_feedback(db, feedback_id)
  91. if not row:
  92. raise AppHTTPError(404, "反馈不存在")
  93. return feedback_to_dict(row)
  94. def update_feedback_status(
  95. db: Session,
  96. user: SysUser,
  97. feedback_id: str,
  98. *,
  99. status: str,
  100. handle_remark: Optional[str] = None,
  101. ) -> Dict[str, Any]:
  102. row = feedback_crud.get_feedback(db, feedback_id)
  103. if not row:
  104. raise AppHTTPError(404, "反馈不存在")
  105. old = row.status
  106. _assert_transition(old, status, FEEDBACK_TRANSITIONS)
  107. feedback_crud.update_feedback_status(
  108. db,
  109. row,
  110. status=status,
  111. handle_remark=handle_remark,
  112. update_by=user.username,
  113. )
  114. oper_log_crud.create_oper_log(
  115. db,
  116. module="feedback",
  117. action="status",
  118. user_id=user.id,
  119. username=user.username,
  120. detail=f"{row.biz_no}: {old}→{status}; {(handle_remark or '')[:120]}",
  121. )
  122. return feedback_to_dict(row)
  123. def list_suggestions_page(
  124. db: Session,
  125. *,
  126. status: Optional[str],
  127. keyword: Optional[str],
  128. page: int,
  129. page_size: int,
  130. ) -> Dict[str, Any]:
  131. items, total = suggestion_crud.list_suggestions(
  132. db, status=status, keyword=keyword, page=page, page_size=page_size
  133. )
  134. return {
  135. "list": [suggestion_to_dict(r) for r in items],
  136. "total": total,
  137. "page": page,
  138. "pageSize": page_size,
  139. }
  140. def get_suggestion_detail(db: Session, suggestion_id: str) -> Dict[str, Any]:
  141. row = suggestion_crud.get_suggestion(db, suggestion_id)
  142. if not row:
  143. raise AppHTTPError(404, "建言不存在")
  144. return suggestion_to_dict(row)
  145. def update_suggestion_status(
  146. db: Session,
  147. user: SysUser,
  148. suggestion_id: str,
  149. *,
  150. status: str,
  151. handle_remark: Optional[str] = None,
  152. ) -> Dict[str, Any]:
  153. row = suggestion_crud.get_suggestion(db, suggestion_id)
  154. if not row:
  155. raise AppHTTPError(404, "建言不存在")
  156. old = row.status
  157. _assert_transition(old, status, SUGGESTION_TRANSITIONS)
  158. suggestion_crud.update_suggestion_status(
  159. db,
  160. row,
  161. status=status,
  162. handle_remark=handle_remark,
  163. update_by=user.username,
  164. )
  165. oper_log_crud.create_oper_log(
  166. db,
  167. module="suggestion",
  168. action="status",
  169. user_id=user.id,
  170. username=user.username,
  171. detail=f"{row.biz_no}: {old}→{status}; {(handle_remark or '')[:120]}",
  172. )
  173. return suggestion_to_dict(row)