| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- """
- 公告管理接口
- """
- from datetime import datetime
- from app.utils.timezone import beijing_now
- from typing import Optional
- from fastapi import APIRouter, Depends, Query, Request
- from pydantic import BaseModel
- from sqlalchemy import or_
- from sqlalchemy.orm import Session
- from app.api.deps import get_current_admin
- from app.database import get_db
- from app.models.announcement import Announcement
- router = APIRouter()
- class AnnouncementCreate(BaseModel):
- """创建公告请求"""
- title: str
- content: str
- priority: int = 0
- is_active: bool = True
- publish_time: Optional[str] = None # ISO格式时间字符串
- @router.get("")
- async def get_announcements(
- page: int = Query(1, ge=1),
- page_size: int = Query(10, ge=1, le=100),
- keyword: Optional[str] = Query(None, description="搜索关键词(标题、内容)"),
- db: Session = Depends(get_db),
- current_admin=Depends(get_current_admin),
- ):
- """获取公告列表(支持检索与分页),按发布时间倒序"""
- offset = (page - 1) * page_size
- query = db.query(Announcement).filter(Announcement.is_deleted == 0)
- # 关键字搜索:标题或内容模糊匹配
- if keyword:
- like_pattern = f"%{keyword}%"
- query = query.filter(
- or_(
- Announcement.title.like(like_pattern),
- Announcement.content.like(like_pattern),
- )
- )
- # 按发布时间倒序,其次按ID倒序,确保最新的数据在前
- # 这里不使用 nullslast,以避免部分数据库方言不支持导致的错误
- query = query.order_by(Announcement.publish_time.desc(), Announcement.id.desc())
- total = query.count()
- announcements = query.offset(offset).limit(page_size).all()
- return {
- "code": 200,
- "msg": "成功",
- "data": [
- {
- "id": a.id,
- "title": a.title,
- "content": a.content,
- "priority": a.priority,
- "is_active": bool(a.is_active),
- "publish_time": a.publish_time.isoformat() if a.publish_time else None,
- "created_at": a.created_at.isoformat() if a.created_at else None,
- "updated_at": a.updated_at.isoformat() if a.updated_at else None,
- }
- for a in announcements
- ],
- "total": total,
- "page": page,
- "page_size": page_size,
- }
- @router.get("/{announcement_id}")
- async def get_announcement_detail(
- announcement_id: int,
- db: Session = Depends(get_db),
- current_admin = Depends(get_current_admin)
- ):
- """获取公告详情"""
- announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
- if not announcement:
- return {"code": 404, "msg": "公告不存在"}
-
- return {
- "code": 200,
- "msg": "成功",
- "data": {
- "id": announcement.id,
- "title": announcement.title,
- "content": announcement.content,
- "priority": announcement.priority,
- "is_active": bool(announcement.is_active),
- "publish_time": announcement.publish_time.isoformat() if announcement.publish_time else None,
- "created_at": announcement.created_at.isoformat() if announcement.created_at else None,
- "updated_at": announcement.updated_at.isoformat() if announcement.updated_at else None
- }
- }
- @router.post("")
- async def create_announcement(
- req: AnnouncementCreate,
- request: Request,
- db: Session = Depends(get_db),
- current_admin = Depends(get_current_admin)
- ):
- """创建公告"""
- publish_time = beijing_now()
- if req.publish_time:
- try:
- publish_time = datetime.fromisoformat(req.publish_time.replace('Z', '+00:00'))
- except:
- pass
- announcement = Announcement(
- title=req.title,
- content=req.content,
- priority=req.priority,
- is_active=1 if req.is_active else 0,
- publish_time=publish_time,
- created_at=beijing_now(),
- updated_at=beijing_now()
- )
- db.add(announcement)
- # 先提交主记录,获取ID
- db.flush()
- # 创建历史记录
- from app.utils.history import create_announcement_history, create_operation_log
- create_announcement_history(db, announcement, "INSERT")
- # 记录操作日志
- client_ip = request.client.host if request.client else None
- create_operation_log(
- db=db,
- admin_id=current_admin.id,
- module="公告管理",
- action="创建公告",
- description=f"创建公告:{req.title}",
- new_data={
- "title": req.title,
- "content": req.content[:100] + "..." if len(req.content) > 100 else req.content,
- "priority": req.priority,
- "is_active": req.is_active
- },
- ip_address=client_ip
- )
- # 一次性提交所有更改
- db.commit()
- return {"code": 200, "msg": "创建成功", "data": {"id": announcement.id}}
- @router.put("/{announcement_id}")
- async def update_announcement(
- announcement_id: int,
- req: AnnouncementCreate,
- request: Request,
- db: Session = Depends(get_db),
- current_admin = Depends(get_current_admin)
- ):
- """更新公告"""
- announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
- if not announcement:
- return {"code": 404, "msg": "公告不存在"}
- # 记录更新前的状态
- old_data = {
- "title": announcement.title,
- "content": announcement.content[:100] + "..." if len(announcement.content) > 100 else announcement.content,
- "priority": announcement.priority,
- "is_active": bool(announcement.is_active)
- }
- announcement.title = req.title
- announcement.content = req.content
- announcement.priority = req.priority
- announcement.is_active = 1 if req.is_active else 0
- if req.publish_time:
- try:
- announcement.publish_time = datetime.fromisoformat(req.publish_time.replace('Z', '+00:00'))
- except:
- pass
- announcement.updated_at = beijing_now()
- # 创建历史记录
- from app.utils.history import create_announcement_history, create_operation_log
- create_announcement_history(db, announcement, "UPDATE")
- # 记录操作日志
- client_ip = request.client.host if request.client else None
- create_operation_log(
- db=db,
- admin_id=current_admin.id,
- module="公告管理",
- action="更新公告",
- description=f"更新公告:{announcement.title}",
- old_data=old_data,
- new_data={
- "title": req.title,
- "content": req.content[:100] + "..." if len(req.content) > 100 else req.content,
- "priority": req.priority,
- "is_active": req.is_active
- },
- ip_address=client_ip
- )
- # 一次性提交所有更改
- db.commit()
- return {"code": 200, "msg": "更新成功"}
- @router.put("/{announcement_id}/status")
- async def toggle_announcement_status(
- announcement_id: int,
- request: Request,
- db: Session = Depends(get_db),
- current_admin = Depends(get_current_admin)
- ):
- """切换公告状态"""
- announcement = db.query(Announcement).filter(Announcement.id == announcement_id).first()
- if not announcement:
- return {"code": 404, "msg": "公告不存在"}
- old_active = announcement.is_active
- announcement.is_active = 0 if announcement.is_active else 1
- announcement.updated_at = beijing_now()
- # 创建历史记录
- from app.utils.history import create_announcement_history, create_operation_log
- create_announcement_history(db, announcement, "UPDATE")
- # 记录操作日志
- client_ip = request.client.host if request.client else None
- status_text = "启用" if announcement.is_active == 1 else "禁用"
- create_operation_log(
- db=db,
- admin_id=current_admin.id,
- module="公告管理",
- action="切换公告状态",
- description=f"{status_text}公告:{announcement.title}",
- old_data={"is_active": bool(old_active)},
- new_data={"is_active": bool(announcement.is_active)},
- ip_address=client_ip
- )
- # 一次性提交所有更改
- db.commit()
- return {"code": 200, "msg": "状态更新成功", "data": {"is_active": bool(announcement.is_active)}}
- @router.delete("/{announcement_id}")
- async def delete_announcement(
- announcement_id: int,
- request: Request,
- db: Session = Depends(get_db),
- current_admin = Depends(get_current_admin)
- ):
- """删除公告(软删除)"""
- announcement = db.query(Announcement).filter(Announcement.id == announcement_id, Announcement.is_deleted == 0).first()
- if not announcement:
- return {"code": 404, "msg": "公告不存在"}
- announcement.is_deleted = 1
- announcement.updated_at = beijing_now()
- # 记录操作日志(删除公告没有历史记录,因为它本身就是历史记录)
- from app.utils.history import create_operation_log
- client_ip = request.client.host if request.client else None
- create_operation_log(
- db=db,
- admin_id=current_admin.id,
- module="公告管理",
- action="删除公告",
- description=f"删除公告:{announcement.title}",
- old_data={
- "title": announcement.title,
- "content": announcement.content[:100] + "..." if len(announcement.content) > 100 else announcement.content,
- "priority": announcement.priority,
- "is_active": bool(announcement.is_active)
- },
- ip_address=client_ip
- )
- # 一次性提交所有更改
- db.commit()
- return {"code": 200, "msg": "删除成功"}
|