277b13eaae
优化内容: 1. 表格布局: - 使用 calc(100vw - 160px) 确保表格不超出视口 - 操作列 fixed='right' 固定在右侧,宽度 300px - 按钮 3 个后自动换行 (max-width: 200px) - 恢复合理列宽,不再过度压缩 2. 批量操作区域: - 容器改为 inline-block,宽度自适应按钮内容 - 背景宽度与按钮总宽度匹配 3. 分类标签: - 显示数量 (如 '待处理 (20)') - 点击切换筛选,去掉误导的 'X' 图标 4. 删除功能: - 操作列增加删除按钮 - 删除前弹出确认对话框 5. 系统日志: - 修复后端日志路径 (parents[4]) - 404 时显示友好提示 6. 其他: - 左侧菜单宽度 160px - 所有功能保留 (登录、用户管理、批量操作等)
188 lines
5.7 KiB
Python
188 lines
5.7 KiB
Python
# 宇之然内容创作平台 - 选题管理API
|
|
|
|
from datetime import datetime
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
import json
|
|
|
|
from ..core.security import get_current_admin_user, create_audit_log
|
|
from ..database import get_db
|
|
from ..models import Topic, User
|
|
|
|
router = APIRouter()
|
|
|
|
class TopicCreateRequest(BaseModel):
|
|
title: str
|
|
field: Optional[str] = None
|
|
priority_score: int = 0
|
|
|
|
class TopicUpdateRequest(BaseModel):
|
|
title: Optional[str] = None
|
|
field: Optional[str] = None
|
|
priority_score: Optional[int] = None
|
|
status: Optional[str] = None
|
|
|
|
@router.get("/", response_model=List[dict])
|
|
async def get_topics(
|
|
status: Optional[str] = Query(None),
|
|
page: int = Query(1, ge=1),
|
|
size: int = Query(20, ge=1, le=100),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取选题列表"""
|
|
query = db.query(Topic)
|
|
|
|
# 状态筛选
|
|
if status:
|
|
query = query.filter(Topic.status == status)
|
|
|
|
# 分页
|
|
offset = (page - 1) * size
|
|
topics = query.offset(offset).limit(size).all()
|
|
|
|
# 转换为字典格式
|
|
result = []
|
|
for topic in topics:
|
|
result.append({
|
|
"id": topic.id,
|
|
"title": topic.title,
|
|
"field": topic.field,
|
|
"priority_score": topic.priority_score,
|
|
"status": topic.status,
|
|
"compliance_score": topic.compliance_score,
|
|
"created_at": topic.created_at.isoformat() if topic.created_at else None,
|
|
"updated_at": topic.updated_at.isoformat() if topic.updated_at else None,
|
|
"generated_at": topic.generated_at.isoformat() if topic.generated_at else None,
|
|
"published_at": topic.published_at.isoformat() if topic.published_at else None,
|
|
"published_urls": topic.published_urls
|
|
})
|
|
|
|
return result
|
|
|
|
@router.post("/", response_model=dict)
|
|
async def create_topic(
|
|
topic_data: TopicCreateRequest,
|
|
current_user: User = Depends(get_current_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""创建新选题(管理员功能)"""
|
|
new_topic = Topic(
|
|
title=topic_data.title,
|
|
field=topic_data.field,
|
|
priority_score=topic_data.priority_score,
|
|
status="待处理"
|
|
)
|
|
db.add(new_topic)
|
|
db.commit()
|
|
db.refresh(new_topic)
|
|
|
|
# 记录审计日志
|
|
create_audit_log(
|
|
db=db,
|
|
user_id=current_user.id,
|
|
action="create_topic",
|
|
resource_type="topic",
|
|
resource_id=new_topic.id,
|
|
details=f"标题: {topic_data.title}"
|
|
)
|
|
|
|
return {
|
|
"id": new_topic.id,
|
|
"title": new_topic.title,
|
|
"status": new_topic.status,
|
|
"created_at": new_topic.created_at.isoformat() if new_topic.created_at else None
|
|
}
|
|
|
|
@router.put("/{topic_id}", response_model=dict)
|
|
async def update_topic(
|
|
topic_id: int,
|
|
topic_data: TopicUpdateRequest,
|
|
current_user: User = Depends(get_current_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""更新选题信息(管理员功能)"""
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="选题不存在")
|
|
|
|
# 更新字段
|
|
if topic_data.title is not None:
|
|
topic.title = topic_data.title
|
|
if topic_data.field is not None:
|
|
topic.field = topic_data.field
|
|
if topic_data.priority_score is not None:
|
|
topic.priority_score = topic_data.priority_score
|
|
if topic_data.status is not None:
|
|
topic.status = topic_data.status
|
|
|
|
topic.updated_at = datetime.utcnow()
|
|
db.commit()
|
|
db.refresh(topic)
|
|
|
|
# 记录审计日志
|
|
create_audit_log(
|
|
db=db,
|
|
user_id=current_user.id,
|
|
action="update_topic",
|
|
resource_type="topic",
|
|
resource_id=topic_id,
|
|
details=f"状态更新为: {topic_data.status}"
|
|
)
|
|
|
|
return {
|
|
"id": topic.id,
|
|
"title": topic.title,
|
|
"status": topic.status,
|
|
"updated_at": topic.updated_at.isoformat() if topic.updated_at else None
|
|
}
|
|
|
|
@router.delete("/{topic_id}")
|
|
async def delete_topic(
|
|
topic_id: int,
|
|
current_user: User = Depends(get_current_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""删除选题(管理员功能)"""
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="选题不存在")
|
|
|
|
db.delete(topic)
|
|
db.commit()
|
|
|
|
# 记录审计日志
|
|
create_audit_log(
|
|
db=db,
|
|
user_id=current_user.id,
|
|
action="delete_topic",
|
|
resource_type="topic",
|
|
resource_id=topic_id,
|
|
details="选题已删除"
|
|
)
|
|
|
|
return {"message": "选题已成功删除"}
|
|
|
|
@router.get("/{topic_id}", response_model=dict)
|
|
async def get_topic(
|
|
topic_id: int,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取单个选题详情"""
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="选题不存在")
|
|
|
|
return {
|
|
"id": topic.id,
|
|
"title": topic.title,
|
|
"field": topic.field,
|
|
"priority_score": topic.priority_score,
|
|
"status": topic.status,
|
|
"compliance_score": topic.compliance_score,
|
|
"created_at": topic.created_at.isoformat() if topic.created_at else None,
|
|
"updated_at": topic.updated_at.isoformat() if topic.updated_at else None,
|
|
"generated_at": topic.generated_at.isoformat() if topic.generated_at else None,
|
|
"published_at": topic.published_at.isoformat() if topic.published_at else None,
|
|
"published_urls": topic.published_urls
|
|
} |