"""股票集合 CRUD 路由""" from fastapi import APIRouter, HTTPException from pydantic import BaseModel from typing import Optional from database import get_connection, dict_from_row router = APIRouter() class CollectionCreate(BaseModel): name: str description: Optional[str] = None user_id: str class CollectionUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None user_id: Optional[str] = None last_accessed_at: Optional[str] = None class StockAdd(BaseModel): stock_code: str stock_name: str added_price: Optional[float] = None @router.get("", summary="列表集合") async def list_collections(user_id: str = ""): conn = get_connection() try: rows = conn.execute( "SELECT * FROM stock_collections WHERE user_id = ? OR user_id = '' ORDER BY created_at DESC", (user_id,), ).fetchall() collections = [dict_from_row(r) for r in rows] # 更新空 user_id 的记录 for c in collections: if not c["user_id"]: conn.execute("UPDATE stock_collections SET user_id = ? WHERE id = ?", (user_id, c["id"])) conn.commit() return collections finally: conn.close() @router.post("", summary="创建集合", status_code=201) async def create_collection(body: CollectionCreate): from datetime import datetime now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") conn = get_connection() try: cur = conn.execute( "INSERT INTO stock_collections (name, description, user_id, last_accessed_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)", (body.name, body.description, body.user_id, now, now, now), ) conn.commit() row = conn.execute("SELECT * FROM stock_collections WHERE id = ?", (cur.lastrowid,)).fetchone() return dict_from_row(row) finally: conn.close() @router.get("/{collection_id}", summary="获取集合详情") async def get_collection(collection_id: int): conn = get_connection() try: row = conn.execute("SELECT * FROM stock_collections WHERE id = ?", (collection_id,)).fetchone() if not row: raise HTTPException(status_code=404, detail="集合不存在") return dict_from_row(row) finally: conn.close() @router.patch("/{collection_id}", summary="更新集合") async def update_collection(collection_id: int, body: CollectionUpdate): conn = get_connection() try: existing = conn.execute("SELECT * FROM stock_collections WHERE id = ?", (collection_id,)).fetchone() if not existing: raise HTTPException(status_code=404, detail="集合不存在") updates = {} if body.name is not None: updates["name"] = body.name if body.description is not None: updates["description"] = body.description if body.user_id is not None: updates["user_id"] = body.user_id if body.last_accessed_at is not None: updates["last_accessed_at"] = body.last_accessed_at if updates: from datetime import datetime updates["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") set_clause = ", ".join(f"{k} = ?" for k in updates) values = list(updates.values()) values.append(collection_id) conn.execute(f"UPDATE stock_collections SET {set_clause} WHERE id = ?", values) conn.commit() row = conn.execute("SELECT * FROM stock_collections WHERE id = ?", (collection_id,)).fetchone() return dict_from_row(row) finally: conn.close() @router.delete("/{collection_id}", summary="删除集合") async def delete_collection(collection_id: int): conn = get_connection() try: existing = conn.execute("SELECT * FROM stock_collections WHERE id = ?", (collection_id,)).fetchone() if not existing: raise HTTPException(status_code=404, detail="集合不存在") conn.execute("DELETE FROM stock_collections WHERE id = ?", (collection_id,)) conn.commit() return {"success": True} finally: conn.close() @router.get("/{collection_id}/stocks", summary="列表集合中的股票") async def list_stocks(collection_id: int): conn = get_connection() try: rows = conn.execute( "SELECT * FROM collection_stocks WHERE collection_id = ? ORDER BY added_at DESC", (collection_id,), ).fetchall() return [dict_from_row(r) for r in rows] finally: conn.close() @router.post("/{collection_id}/stocks", summary="添加股票到集合", status_code=201) async def add_stock(collection_id: int, body: StockAdd): conn = get_connection() try: # 检查集合存在 coll = conn.execute("SELECT id FROM stock_collections WHERE id = ?", (collection_id,)).fetchone() if not coll: raise HTTPException(status_code=404, detail="集合不存在") try: cur = conn.execute( "INSERT INTO collection_stocks (collection_id, stock_code, stock_name, added_price) VALUES (?, ?, ?, ?)", (collection_id, body.stock_code, body.stock_name, body.added_price), ) conn.commit() row = conn.execute("SELECT * FROM collection_stocks WHERE id = ?", (cur.lastrowid,)).fetchone() return dict_from_row(row) except Exception as e: if "UNIQUE constraint failed" in str(e): raise HTTPException(status_code=409, detail="该股票已在集合中") raise finally: conn.close() @router.get("/stock/{stock_code}", summary="在所有集合中查找股票记录") async def find_stock(stock_code: str): conn = get_connection() try: row = conn.execute( "SELECT * FROM collection_stocks WHERE stock_code = ? ORDER BY added_at DESC LIMIT 1", (stock_code,), ).fetchone() if not row: return None return dict_from_row(row) finally: conn.close() @router.delete("/{collection_id}/stocks/{stock_code}", summary="从集合移除股票") async def remove_stock(collection_id: int, stock_code: str): conn = get_connection() try: conn.execute( "DELETE FROM collection_stocks WHERE collection_id = ? AND stock_code = ?", (collection_id, stock_code), ) conn.commit() return {"success": True} finally: conn.close()