from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession from app.core.security import get_current_user from app.models.drug import get_db router = APIRouter(prefix="/drug", tags=["药品"]) @router.get("/search") async def search_drug( keyword: Optional[str] = Query(None), category: Optional[str] = Query(None), page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), user: dict = Depends(get_current_user), ): db = get_db() offset = (page - 1) * page_size conditions = ["is_active = TRUE"] params = {} if keyword: conditions.append("(name ILIKE :kw OR pinyin ILIKE :kw OR name_en ILIKE :kw)") params["kw"] = f"%{keyword}%" if category: conditions.append("category = :cat") params["cat"] = category where = "WHERE " + " AND ".join(conditions) count_query = f"SELECT COUNT(*) FROM drugs {where}" data_query = f""" SELECT drug_id, name, name_en, pinyin, category, subcategory, source_version, source_volume, source_page, is_active FROM drugs {where} ORDER BY name LIMIT :limit OFFSET :offset """ params["limit"] = page_size params["offset"] = offset async with db() as session: total = (await session.execute(text(count_query), params)).scalar() rows = (await session.execute(text(data_query), params)).fetchall() items = [] for row in rows: items.append({ "drug_id": row.drug_id, "name": row.name, "name_en": row.name_en or "", "pinyin": row.pinyin or "", "category": row.category or "", "subcategory": row.subcategory or "", "source_version": row.source_version or "", "source_volume": row.source_volume or "", "source_page": row.source_page or "", "is_active": row.is_active, }) total_pages = max(1, (total + page_size - 1) // page_size) return { "items": items, "total": total, "page": page, "page_size": page_size, "total_pages": total_pages, } @router.get("/{drug_id}") async def get_drug_detail( drug_id: str, user: dict = Depends(get_current_user), ): db = get_db() async with db() as session: row = (await session.execute( text("SELECT * FROM drugs WHERE drug_id = :drug_id"), {"drug_id": drug_id} )).fetchone() if not row: raise HTTPException(status_code=404, detail="Drug not found") return { "data": { "drug_id": row.drug_id, "name": row.name, "name_en": row.name_en or "", "pinyin": row.pinyin or "", "category": row.category or "", "subcategory": row.subcategory or "", "sections": row.sections or {}, "source_version": row.source_version or "", "source_volume": row.source_volume or "", "source_page": row.source_page or "", "is_active": row.is_active, } } @router.get("/category/tree") async def get_category_tree(user: dict = Depends(get_current_user)): db = get_db() async with db() as session: rows = (await session.execute( text("SELECT DISTINCT category, subcategory FROM drugs WHERE category IS NOT NULL ORDER BY category, subcategory") )).fetchall() tree = {} for row in rows: cat = row.category sub = row.subcategory or "" if cat not in tree: tree[cat] = [] if sub and sub not in tree[cat]: tree[cat].append(sub) return {"tree": [{"name": k, "children": v} for k, v in tree.items()]}