announcements.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. """
  2. 公告管理接口
  3. """
  4. from datetime import datetime
  5. from typing import Optional
  6. from fastapi import APIRouter, Depends, Query
  7. from pydantic import BaseModel
  8. from sqlalchemy import or_
  9. from sqlalchemy.orm import Session
  10. from app.api.deps import get_current_admin
  11. from app.database import get_db
  12. from app.models.announcement import Announcement
  13. router = APIRouter()
  14. class AnnouncementCreate(BaseModel):
  15. """创建公告请求"""
  16. title: str
  17. content: str
  18. priority: int = 0
  19. is_active: bool = True
  20. publish_time: Optional[str] = None # ISO格式时间字符串
  21. @router.get("")
  22. async def get_announcements(
  23. page: int = Query(1, ge=1),
  24. page_size: int = Query(10, ge=1, le=100),
  25. keyword: Optional[str] = Query(None, description="搜索关键词(标题、内容)"),
  26. db: Session = Depends(get_db),
  27. current_admin=Depends(get_current_admin),
  28. ):
  29. """获取公告列表(支持检索与分页),按发布时间倒序"""
  30. offset = (page - 1) * page_size
  31. query = db.query(Announcement)
  32. # 关键字搜索:标题或内容模糊匹配
  33. if keyword:
  34. like_pattern = f"%{keyword}%"
  35. query = query.filter(
  36. or_(
  37. Announcement.title.like(like_pattern),
  38. Announcement.content.like(like_pattern),
  39. )
  40. )
  41. # 按发布时间倒序,其次按ID倒序,确保最新的数据在前
  42. # 这里不使用 nullslast,以避免部分数据库方言不支持导致的错误
  43. query = query.order_by(Announcement.publish_time.desc(), Announcement.id.desc())
  44. total = query.count()
  45. announcements = query.offset(offset).limit(page_size).all()
  46. return {
  47. "code": 200,
  48. "msg": "成功",
  49. "data": [
  50. {
  51. "id": a.id,
  52. "title": a.title,
  53. "content": a.content,
  54. "priority": a.priority,
  55. "is_active": bool(a.is_active),
  56. "publish_time": a.publish_time.isoformat() if a.publish_time else None,
  57. "created_at": a.created_at.isoformat() if a.created_at else None,
  58. "updated_at": a.updated_at.isoformat() if a.updated_at else None,
  59. }
  60. for a in announcements
  61. ],
  62. "total": total,
  63. "page": page,
  64. "page_size": page_size,
  65. }
  66. @router.get("/{announcement_id}")
  67. async def get_announcement_detail(
  68. announcement_id: int,
  69. db: Session = Depends(get_db),
  70. current_admin = Depends(get_current_admin)
  71. ):
  72. """获取公告详情"""
  73. announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
  74. if not announcement:
  75. return {"code": 404, "msg": "公告不存在"}
  76. return {
  77. "code": 200,
  78. "msg": "成功",
  79. "data": {
  80. "id": announcement.id,
  81. "title": announcement.title,
  82. "content": announcement.content,
  83. "priority": announcement.priority,
  84. "is_active": bool(announcement.is_active),
  85. "publish_time": announcement.publish_time.isoformat() if announcement.publish_time else None,
  86. "created_at": announcement.created_at.isoformat() if announcement.created_at else None,
  87. "updated_at": announcement.updated_at.isoformat() if announcement.updated_at else None
  88. }
  89. }
  90. @router.post("")
  91. async def create_announcement(
  92. req: AnnouncementCreate,
  93. db: Session = Depends(get_db),
  94. current_admin = Depends(get_current_admin)
  95. ):
  96. """创建公告"""
  97. publish_time = datetime.now()
  98. if req.publish_time:
  99. try:
  100. publish_time = datetime.fromisoformat(req.publish_time.replace('Z', '+00:00'))
  101. except:
  102. pass
  103. announcement = Announcement(
  104. title=req.title,
  105. content=req.content,
  106. priority=req.priority,
  107. is_active=1 if req.is_active else 0,
  108. publish_time=publish_time,
  109. created_at=datetime.now(),
  110. updated_at=datetime.now()
  111. )
  112. db.add(announcement)
  113. db.commit()
  114. return {"code": 200, "msg": "创建成功", "data": {"id": announcement.id}}
  115. @router.put("/{announcement_id}")
  116. async def update_announcement(
  117. announcement_id: int,
  118. req: AnnouncementCreate,
  119. db: Session = Depends(get_db),
  120. current_admin = Depends(get_current_admin)
  121. ):
  122. """更新公告"""
  123. announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
  124. if not announcement:
  125. return {"code": 404, "msg": "公告不存在"}
  126. announcement.title = req.title
  127. announcement.content = req.content
  128. announcement.priority = req.priority
  129. announcement.is_active = 1 if req.is_active else 0
  130. if req.publish_time:
  131. try:
  132. announcement.publish_time = datetime.fromisoformat(req.publish_time.replace('Z', '+00:00'))
  133. except:
  134. pass
  135. announcement.updated_at = datetime.now()
  136. db.commit()
  137. return {"code": 200, "msg": "更新成功"}
  138. @router.put("/{announcement_id}/status")
  139. async def toggle_announcement_status(
  140. announcement_id: int,
  141. db: Session = Depends(get_db),
  142. current_admin = Depends(get_current_admin)
  143. ):
  144. """切换公告状态"""
  145. announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
  146. if not announcement:
  147. return {"code": 404, "msg": "公告不存在"}
  148. announcement.is_active = 0 if announcement.is_active else 1
  149. announcement.updated_at = datetime.now()
  150. db.commit()
  151. return {"code": 200, "msg": "状态更新成功", "data": {"is_active": bool(announcement.is_active)}}
  152. @router.delete("/{announcement_id}")
  153. async def delete_announcement(
  154. announcement_id: int,
  155. db: Session = Depends(get_db),
  156. current_admin = Depends(get_current_admin)
  157. ):
  158. """删除公告"""
  159. announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
  160. if not announcement:
  161. return {"code": 404, "msg": "公告不存在"}
  162. db.delete(announcement)
  163. db.commit()
  164. return {"code": 200, "msg": "删除成功"}