Files
Yuzhiran Dev f6e5e90736 feat: Wave 3 - Dashboard redesign + RBAC + AI assistant updates
- Redesign index.html from system-monitor to user-centric workspace
  (welcome banner, summary cards, 今日待办, AI 智能建议, collapsible admin section)
- Add fetchTodos/fetchSuggestions/getPriorityClass/isOverdue methods
- Update uni-nav current-page from 'dashboard' to 'workspace'
- Add require_role to 10 admin router imports (RBAC foundation)
- Update ai-assistant.js: add factory/insights pages, org_id in chat requests
2026-06-17 18:24:57 +08:00

128 lines
4.3 KiB
Python

"""采集管理 API:类别与信息源的 CRUD"""
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List
from pydantic import BaseModel
from typing import Optional
from ..database import get_db
from ..models import CollectorCategory, CollectorSource
from .auth import get_current_admin, require_role
router = APIRouter(prefix="/api/admin/collector", tags=["collector_mgmt"], dependencies=[Depends(get_current_admin)])
# ---------- Schemas ----------
class CategoryCreate(BaseModel):
name: str
description: Optional[str] = None
search_query: Optional[str] = None
sort_order: int = 0
is_active: bool = True
class CategoryUpdate(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
search_query: Optional[str] = None
sort_order: Optional[int] = None
is_active: Optional[bool] = None
class SourceCreate(BaseModel):
category_id: Optional[int] = None
name: str
source_type: str
url: Optional[str] = None
query: Optional[str] = None
credibility: str = "medium"
focus: Optional[str] = None
is_active: bool = True
sort_order: int = 0
class SourceUpdate(BaseModel):
category_id: Optional[int] = None
name: Optional[str] = None
source_type: Optional[str] = None
url: Optional[str] = None
query: Optional[str] = None
credibility: Optional[str] = None
focus: Optional[str] = None
is_active: Optional[bool] = None
sort_order: Optional[int] = None
# ---------- Categories ----------
@router.get("/categories")
def list_categories(db: Session = Depends(get_db)):
cats = db.query(CollectorCategory).order_by(CollectorCategory.sort_order).all()
result = []
for c in cats:
d = c.to_dict()
d["source_count"] = db.query(CollectorSource).filter(CollectorSource.category_id == c.id).count()
result.append(d)
return result
@router.post("/categories", status_code=201)
def create_category(data: CategoryCreate, db: Session = Depends(get_db)):
existing = db.query(CollectorCategory).filter(CollectorCategory.name == data.name).first()
if existing:
raise HTTPException(400, "类别名已存在")
cat = CollectorCategory(**data.model_dump())
db.add(cat)
db.commit()
db.refresh(cat)
return cat.to_dict()
@router.put("/categories/{cat_id}")
def update_category(cat_id: int, data: CategoryUpdate, db: Session = Depends(get_db)):
cat = db.query(CollectorCategory).filter(CollectorCategory.id == cat_id).first()
if not cat:
raise HTTPException(404, "类别不存在")
for k, v in data.model_dump(exclude_unset=True).items():
setattr(cat, k, v)
db.commit()
db.refresh(cat)
return cat.to_dict()
@router.delete("/categories/{cat_id}")
def delete_category(cat_id: int, db: Session = Depends(get_db)):
cat = db.query(CollectorCategory).filter(CollectorCategory.id == cat_id).first()
if not cat:
raise HTTPException(404, "类别不存在")
db.delete(cat)
db.commit()
return {"ok": True}
# ---------- Sources ----------
@router.get("/sources")
def list_sources(category_id: Optional[int] = None, db: Session = Depends(get_db)):
q = db.query(CollectorSource).order_by(CollectorSource.sort_order)
if category_id is not None:
q = q.filter(CollectorSource.category_id == category_id)
return [s.to_dict() for s in q.all()]
@router.post("/sources", status_code=201)
def create_source(data: SourceCreate, db: Session = Depends(get_db)):
src = CollectorSource(**data.model_dump())
db.add(src)
db.commit()
db.refresh(src)
return src.to_dict()
@router.put("/sources/{src_id}")
def update_source(src_id: int, data: SourceUpdate, db: Session = Depends(get_db)):
src = db.query(CollectorSource).filter(CollectorSource.id == src_id).first()
if not src:
raise HTTPException(404, "信息源不存在")
for k, v in data.model_dump(exclude_unset=True).items():
setattr(src, k, v)
db.commit()
db.refresh(src)
return src.to_dict()
@router.delete("/sources/{src_id}")
def delete_source(src_id: int, db: Session = Depends(get_db)):
src = db.query(CollectorSource).filter(CollectorSource.id == src_id).first()
if not src:
raise HTTPException(404, "信息源不存在")
db.delete(src)
db.commit()
return {"ok": True}