157 lines
5.8 KiB
Python
157 lines
5.8 KiB
Python
|
|
"""藏品路由"""
|
||
|
|
from fastapi import APIRouter, HTTPException, Query
|
||
|
|
from typing import Optional, List
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
from api.models.request import CollectionCreate, CollectionUpdate
|
||
|
|
from api.models.response import CollectionResponse
|
||
|
|
from api.middleware.response import ApiResponse, PaginatedData
|
||
|
|
from database import db
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/api/v1/collections", tags=["collections"])
|
||
|
|
|
||
|
|
@router.get("", response_model=ApiResponse)
|
||
|
|
async def list_collections(
|
||
|
|
category: Optional[str] = Query(None, description="品类筛选"),
|
||
|
|
rarity: Optional[str] = Query(None, description="珍惜度筛选"),
|
||
|
|
status: Optional[str] = Query(None, description="状态筛选"),
|
||
|
|
page: int = Query(1, ge=1, description="页码"),
|
||
|
|
page_size: int = Query(20, ge=1, le=100, description="每页数量")
|
||
|
|
):
|
||
|
|
"""获取藏品列表(分页)"""
|
||
|
|
offset = (page - 1) * page_size
|
||
|
|
|
||
|
|
where_clauses = []
|
||
|
|
params = []
|
||
|
|
if category:
|
||
|
|
where_clauses.append("category = %s")
|
||
|
|
params.append(category)
|
||
|
|
if rarity:
|
||
|
|
where_clauses.append("rarity = %s")
|
||
|
|
params.append(rarity)
|
||
|
|
if status:
|
||
|
|
where_clauses.append("status = %s")
|
||
|
|
params.append(status)
|
||
|
|
|
||
|
|
where_sql = " WHERE " + " AND ".join(where_clauses) if where_clauses else ""
|
||
|
|
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
cursor.execute(f"SELECT COUNT(*) as total FROM collections{where_sql}", params)
|
||
|
|
total = cursor.fetchone()["total"]
|
||
|
|
|
||
|
|
query_sql = f"""
|
||
|
|
SELECT * FROM collections{where_sql}
|
||
|
|
ORDER BY updated_at DESC LIMIT %s OFFSET %s
|
||
|
|
"""
|
||
|
|
cursor.execute(query_sql, params + [page_size, offset])
|
||
|
|
items = cursor.fetchall()
|
||
|
|
|
||
|
|
return ApiResponse.success(
|
||
|
|
PaginatedData.create(items, page, page_size, total)
|
||
|
|
)
|
||
|
|
|
||
|
|
@router.get("/{collection_id}", response_model=ApiResponse)
|
||
|
|
async def get_collection(collection_id: int):
|
||
|
|
"""获取单个藏品详情"""
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
cursor.execute("SELECT * FROM collections WHERE id = %s", (collection_id,))
|
||
|
|
item = cursor.fetchone()
|
||
|
|
|
||
|
|
if not item:
|
||
|
|
raise HTTPException(status_code=404, detail="Collection not found")
|
||
|
|
|
||
|
|
return ApiResponse.success(item)
|
||
|
|
|
||
|
|
@router.post("", response_model=ApiResponse, status_code=201)
|
||
|
|
async def create_collection(collection: CollectionCreate):
|
||
|
|
"""创建新藏品"""
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
cursor.execute("""
|
||
|
|
INSERT INTO collections (
|
||
|
|
name, category, serial_number, rarity, ownership_type,
|
||
|
|
is_graded, grading_company, grading_score,
|
||
|
|
cost_price, current_price, status, remark
|
||
|
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||
|
|
""", (
|
||
|
|
collection.name, collection.category, collection.serial_number,
|
||
|
|
collection.rarity, collection.ownership_type, collection.is_graded,
|
||
|
|
collection.grading_company, collection.grading_score,
|
||
|
|
collection.cost_price, collection.current_price, collection.status, collection.remark
|
||
|
|
))
|
||
|
|
|
||
|
|
new_id = cursor.lastrowid
|
||
|
|
cursor.execute("SELECT * FROM collections WHERE id = %s", (new_id,))
|
||
|
|
item = cursor.fetchone()
|
||
|
|
|
||
|
|
return ApiResponse.success(item, "Collection created successfully")
|
||
|
|
|
||
|
|
@router.put("/{collection_id}", response_model=ApiResponse)
|
||
|
|
async def update_collection(collection_id: int, collection: CollectionUpdate):
|
||
|
|
"""更新藏品"""
|
||
|
|
update_fields = []
|
||
|
|
params = []
|
||
|
|
|
||
|
|
for field, value in collection.model_dump(exclude_unset=True).items():
|
||
|
|
if value is not None:
|
||
|
|
update_fields.append(f"{field} = %s")
|
||
|
|
params.append(value)
|
||
|
|
|
||
|
|
if not update_fields:
|
||
|
|
raise HTTPException(status_code=400, detail="No fields to update")
|
||
|
|
|
||
|
|
params.append(collection_id)
|
||
|
|
set_clause = ", ".join(update_fields)
|
||
|
|
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
sql = f"UPDATE collections SET {set_clause}, updated_at = NOW() WHERE id = %s"
|
||
|
|
cursor.execute(sql, params)
|
||
|
|
|
||
|
|
if cursor.rowcount == 0:
|
||
|
|
raise HTTPException(status_code=404, detail="Collection not found")
|
||
|
|
|
||
|
|
cursor.execute("SELECT * FROM collections WHERE id = %s", (collection_id,))
|
||
|
|
item = cursor.fetchone()
|
||
|
|
|
||
|
|
return ApiResponse.success(item, "Collection updated successfully")
|
||
|
|
|
||
|
|
@router.delete("/{collection_id}", response_model=ApiResponse)
|
||
|
|
async def delete_collection(collection_id: int):
|
||
|
|
"""删除藏品"""
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
cursor.execute("DELETE FROM collections WHERE id = %s", (collection_id,))
|
||
|
|
if cursor.rowcount == 0:
|
||
|
|
raise HTTPException(status_code=404, detail="Collection not found")
|
||
|
|
|
||
|
|
return ApiResponse.success(message="Collection deleted successfully")
|
||
|
|
|
||
|
|
@router.get("/{collection_id}/prices", response_model=ApiResponse)
|
||
|
|
async def get_collection_prices(
|
||
|
|
collection_id: int,
|
||
|
|
page: int = Query(1, ge=1),
|
||
|
|
page_size: int = Query(20, ge=1, le=100)
|
||
|
|
):
|
||
|
|
"""获取藏品的价柗历史"""
|
||
|
|
offset = (page - 1) * page_size
|
||
|
|
|
||
|
|
with db.get_cursor() as cursor:
|
||
|
|
cursor.execute("SELECT id FROM collections WHERE id = %s", (collection_id,))
|
||
|
|
if not cursor.fetchone():
|
||
|
|
raise HTTPException(status_code=404, detail="Collection not found")
|
||
|
|
|
||
|
|
cursor.execute(
|
||
|
|
"SELECT COUNT(*) as total FROM price_history WHERE collection_id = %s",
|
||
|
|
(collection_id,)
|
||
|
|
)
|
||
|
|
total = cursor.fetchone()["total"]
|
||
|
|
|
||
|
|
cursor.execute("""
|
||
|
|
SELECT * FROM price_history
|
||
|
|
WHERE collection_id = %s
|
||
|
|
ORDER BY crawled_at DESC LIMIT %s OFFSET %s
|
||
|
|
""", (collection_id, page_size, offset))
|
||
|
|
items = cursor.fetchall()
|
||
|
|
|
||
|
|
return ApiResponse.success(
|
||
|
|
PaginatedData.create(items, page, page_size, total)
|
||
|
|
)
|