www: 项目分类功能 - 左侧导航分类筛选(全部/未归类/分类)、编辑弹窗放大+分类下拉、右上角新建分类

This commit is contained in:
Ubuntu
2026-08-07 21:25:48 +08:00
parent e20c1656b7
commit b538239fe4
2 changed files with 145 additions and 27 deletions
+55 -4
View File
@@ -29,6 +29,16 @@ def init_db():
url TEXT NOT NULL,
desc TEXT DEFAULT '',
icon TEXT DEFAULT '',
category TEXT DEFAULT '',
sort_order INTEGER DEFAULT 0
)""")
# 兼容迁移:旧库补充 category 列
cols = [r[1] for r in conn.execute("PRAGMA table_info(links)").fetchall()]
if "category" not in cols:
conn.execute("ALTER TABLE links ADD COLUMN category TEXT DEFAULT ''")
conn.execute("""CREATE TABLE IF NOT EXISTS categories (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
sort_order INTEGER DEFAULT 0
)""")
# 首次启动:如果表为空则写入默认数据
@@ -91,23 +101,50 @@ class LinkCreate(BaseModel):
url: str
desc: str = ""
icon: str = ""
category: str = ""
class CategoryCreate(BaseModel):
name: str
@app.get("/api/links")
def list_links():
with get_db() as conn:
rows = conn.execute("SELECT id,name,url,desc,icon FROM links ORDER BY sort_order, id").fetchall()
rows = conn.execute("SELECT id,name,url,desc,icon,category FROM links ORDER BY sort_order, id").fetchall()
return [dict(r) for r in rows]
@app.get("/api/categories")
def list_categories():
with get_db() as conn:
rows = conn.execute("SELECT id,name FROM categories ORDER BY sort_order, id").fetchall()
return [dict(r) for r in rows]
@app.post("/api/categories")
def add_category(cat: CategoryCreate, username: str = Depends(require_sso)):
import time, random
name = cat.name.strip()
if not name:
raise HTTPException(400, "分类名称不能为空")
cid = f"c{int(time.time()):x}{random.randint(0,0xffffff):06x}"
with get_db() as conn:
try:
max_sort = conn.execute("SELECT COALESCE(MAX(sort_order),0) FROM categories").fetchone()[0]
conn.execute("INSERT INTO categories (id,name,sort_order) VALUES (?,?,?)",
(cid, name, max_sort + 1))
conn.commit()
except sqlite3.IntegrityError:
raise HTTPException(400, "分类已存在")
return {"id": cid, "name": name}
@app.post("/api/links")
def add_link(link: LinkCreate, username: str = Depends(require_sso)):
import time, random
lid = f"{int(time.time()):x}{random.randint(0,0xffffff):06x}"
with get_db() as conn:
max_sort = conn.execute("SELECT COALESCE(MAX(sort_order),0) FROM links").fetchone()[0]
conn.execute("INSERT INTO links (id,name,url,desc,icon,sort_order) VALUES (?,?,?,?,?,?)",
(lid, link.name, link.url, link.desc, link.icon, max_sort + 1))
conn.execute("INSERT INTO links (id,name,url,desc,icon,category,sort_order) VALUES (?,?,?,?,?,?,?)",
(lid, link.name, link.url, link.desc, link.icon, link.category, max_sort + 1))
conn.commit()
return {"id": lid, "name": link.name, "url": link.url, "desc": link.desc, "icon": link.icon}
return {"id": lid, "name": link.name, "url": link.url, "desc": link.desc, "icon": link.icon, "category": link.category}
@app.delete("/api/links/{link_id}")
def delete_link(link_id: str, username: str = Depends(require_sso)):
@@ -118,6 +155,20 @@ def delete_link(link_id: str, username: str = Depends(require_sso)):
raise HTTPException(404, "链接不存在")
return {"success": True}
@app.put("/api/links/{link_id}")
def update_link(link_id: str, link: LinkCreate, username: str = Depends(require_sso)):
with get_db() as conn:
row = conn.execute("SELECT * FROM links WHERE id=?", (link_id,)).fetchone()
if not row:
raise HTTPException(404, "链接不存在")
# 图标不传则保留原值,避免改名称时图标被重新生成
icon = link.icon if link.icon else row["icon"]
# 分类始终按提交值更新(空字符串 = 未归类)
conn.execute("UPDATE links SET name=?, url=?, desc=?, icon=?, category=? WHERE id=?",
(link.name, link.url, link.desc, icon, link.category, link_id))
conn.commit()
return {"id": link_id, "name": link.name, "url": link.url, "desc": link.desc, "icon": icon, "category": link.category}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8887)