""" 快捷门户入口:持久化在 data/portal_links.json,支持增删改查。 """ import json import uuid from pathlib import Path from typing import Any, Dict, List from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel, Field router = APIRouter(prefix="/settings/portal-links", tags=["portal-links"]) CONFIG_PATH = Path("data/portal_links.json") class PortalLinkCreate(BaseModel): name: str = Field(..., min_length=1, max_length=64, description="显示名称") url: str = Field(..., min_length=1, max_length=512, description="门户 URL") class PortalLinkRead(BaseModel): id: str name: str url: str class PortalLinkUpdate(BaseModel): name: str | None = Field(None, min_length=1, max_length=64) url: str | None = Field(None, min_length=1, max_length=512) def _load_links() -> List[Dict[str, Any]]: if not CONFIG_PATH.exists(): return [] try: data = json.loads(CONFIG_PATH.read_text(encoding="utf-8")) return data if isinstance(data, list) else [] except Exception: return [] def _save_links(links: List[Dict[str, Any]]) -> None: CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) CONFIG_PATH.write_text( json.dumps(links, ensure_ascii=False, indent=2), encoding="utf-8", ) @router.get("", response_model=List[PortalLinkRead]) async def list_portal_links(): """获取所有快捷门户入口。""" links = _load_links() return [PortalLinkRead(**x) for x in links] @router.post("", response_model=PortalLinkRead, status_code=status.HTTP_201_CREATED) async def create_portal_link(payload: PortalLinkCreate): """新增一条快捷门户入口。""" links = _load_links() new_id = str(uuid.uuid4())[:8] new_item = {"id": new_id, "name": payload.name.strip(), "url": payload.url.strip()} links.append(new_item) _save_links(links) return PortalLinkRead(**new_item) @router.put("/{link_id}", response_model=PortalLinkRead) async def update_portal_link(link_id: str, payload: PortalLinkUpdate): """更新名称或 URL。""" links = _load_links() for item in links: if item.get("id") == link_id: if payload.name is not None: item["name"] = payload.name.strip() if payload.url is not None: item["url"] = payload.url.strip() _save_links(links) return PortalLinkRead(**item) raise HTTPException(status_code=404, detail="快捷门户入口不存在") @router.delete("/{link_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_portal_link(link_id: str): """删除一条快捷门户入口。""" links = _load_links() new_list = [x for x in links if x.get("id") != link_id] if len(new_list) == len(links): raise HTTPException(status_code=404, detail="快捷门户入口不存在") _save_links(new_list)