JhHardwareWRS_BackPoint/app/routers/notices.py
2026-06-24 15:19:14 +08:00

147 lines
5.6 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import select
from sqlalchemy.orm import Session, selectinload
from app.database import get_db
from app.deps import current_user, require_roles
from app.models import Notice, NoticePoint, Personnel, Role
from app.schemas import NoticeCreate, NoticeOut, NoticeUpdate, PageResponse
from app.services.common import paginate
from app.services.attendance_points import accessible_point_names
router = APIRouter(prefix="/api/notices", tags=["notices"])
def _notice_out(notice: Notice) -> NoticeOut:
point_names = sorted([item.attendance_point_name for item in notice.attendance_points])
return NoticeOut(
id=notice.id,
title=notice.title,
content=notice.content,
attendance_point_names=point_names,
sort_order=notice.sort_order,
is_active=notice.is_active,
created_by=notice.created_by,
creator_name=notice.creator.name if notice.creator else "",
created_at=notice.created_at,
updated_at=notice.updated_at,
)
def _clean_text(value: str, field_name: str) -> str:
text = value.strip()
if not text:
raise HTTPException(status_code=400, detail=f"{field_name}不能为空")
return text
@router.get("", response_model=PageResponse)
def list_notices(
include_inactive: bool = False,
page: int = Query(1, ge=1),
page_size: int = Query(10, ge=1, le=100),
user: Personnel = Depends(current_user),
db: Session = Depends(get_db),
) -> PageResponse:
if include_inactive and user.role not in (Role.admin, Role.manager):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="无权限")
query = (
select(Notice)
.options(selectinload(Notice.creator), selectinload(Notice.attendance_points))
.order_by(Notice.sort_order.asc(), Notice.updated_at.desc())
)
if not include_inactive:
query = query.where(Notice.is_active.is_(True))
point_names = accessible_point_names(db, user)
query = query.where(Notice.attendance_points.any(NoticePoint.attendance_point_name.in_(point_names)))
result = paginate(db, query, page, page_size)
return PageResponse(**{**result, "rows": [_notice_out(row) for row in result["rows"]]})
@router.post("", response_model=NoticeOut)
def create_notice(
payload: NoticeCreate,
user: Personnel = Depends(require_roles(Role.admin, Role.manager)),
db: Session = Depends(get_db),
) -> NoticeOut:
allowed = set(accessible_point_names(db, user))
point_names = payload.attendance_point_names or list(allowed)
denied = [name for name in point_names if name not in allowed]
if denied:
raise HTTPException(status_code=403, detail=f"无该考勤点通知配置权限:{''.join(denied)}")
notice = Notice(
title=_clean_text(payload.title, "标题"),
content=_clean_text(payload.content, "内容"),
sort_order=payload.sort_order,
is_active=payload.is_active,
created_by=user.phone,
)
for name in dict.fromkeys(point_names):
notice.attendance_points.append(NoticePoint(attendance_point_name=name))
db.add(notice)
db.commit()
db.refresh(notice)
return _notice_out(notice)
@router.put("/{notice_id}", response_model=NoticeOut)
def update_notice(
notice_id: int,
payload: NoticeUpdate,
user: Personnel = Depends(require_roles(Role.admin, Role.manager)),
db: Session = Depends(get_db),
) -> NoticeOut:
notice = db.scalar(
select(Notice)
.options(selectinload(Notice.attendance_points))
.where(Notice.id == notice_id)
)
if notice is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="通知不存在")
allowed = set(accessible_point_names(db, user))
if user.role == Role.admin and not any(item.attendance_point_name in allowed for item in notice.attendance_points):
raise HTTPException(status_code=403, detail="无该考勤点通知配置权限")
if payload.title is not None:
notice.title = _clean_text(payload.title, "标题")
if payload.content is not None:
notice.content = _clean_text(payload.content, "内容")
if payload.sort_order is not None:
notice.sort_order = payload.sort_order
if payload.is_active is not None:
notice.is_active = payload.is_active
if payload.attendance_point_names is not None:
denied = [name for name in payload.attendance_point_names if name not in allowed]
if denied:
raise HTTPException(status_code=403, detail=f"无该考勤点通知配置权限:{''.join(denied)}")
notice.attendance_points.clear()
db.flush()
for name in dict.fromkeys(payload.attendance_point_names or list(allowed)):
notice.attendance_points.append(NoticePoint(attendance_point_name=name))
db.commit()
db.refresh(notice)
return _notice_out(notice)
@router.delete("/{notice_id}", status_code=204)
def delete_notice(
notice_id: int,
user: Personnel = Depends(require_roles(Role.admin, Role.manager)),
db: Session = Depends(get_db),
) -> None:
notice = db.scalar(
select(Notice)
.options(selectinload(Notice.attendance_points))
.where(Notice.id == notice_id)
)
if notice is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="通知不存在")
allowed = set(accessible_point_names(db, user))
if user.role == Role.admin and not any(item.attendance_point_name in allowed for item in notice.attendance_points):
raise HTTPException(status_code=403, detail="无该考勤点通知配置权限")
db.delete(notice)
db.commit()