# seek - 寻号匹配路由 # Version: 0.0.1 from fastapi import APIRouter, Depends, Query, HTTPException # Version: 1.2.x from sqlalchemy.orm import Session from pydantic import BaseModel from typing import Optional, List from datetime import datetime from app.core.database import get_db from app.core.auth import get_current_user from app.models.seek_info import SeekInfo from app.models.models import User from app.routers.information import match_collections_count_from_coolbot router = APIRouter(prefix="/api/seek", tags=["寻配号"]) # ============ Schema ============ class SeekInfoCreate(BaseModel): title: str content: Optional[str] = None expect_category: Optional[str] = None expect_version: Optional[str] = None expect_packaging: Optional[str] = None expect_number: Optional[str] = None expect_price_min: Optional[float] = None expect_price_max: Optional[float] = None class SeekInfoUpdate(BaseModel): title: Optional[str] = None content: Optional[str] = None expect_category: Optional[str] = None expect_version: Optional[str] = None expect_packaging: Optional[str] = None expect_number: Optional[str] = None expect_price_min: Optional[float] = None expect_price_max: Optional[float] = None status: Optional[str] = None class SeekInfoResponse(BaseModel): id: str user_id: str user_name: Optional[str] = None network_matched_count: Optional[int] = 0 title: str content: Optional[str] expect_category: Optional[str] expect_version: Optional[str] expect_packaging: Optional[str] expect_number: Optional[str] expect_price_min: Optional[float] expect_price_max: Optional[float] status: str is_matched: Optional[str] matched_user_id: Optional[str] matched_contact: Optional[str] view_count: int contact_count: int created_at: Optional[datetime] updated_at: Optional[datetime] class Config: from_attributes = True # ============ API ============ @router.get("/list", response_model=list[SeekInfoResponse]) def get_seek_list( status: str = Query("active"), page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=1000), user_only: bool = Query(False), current_user: Optional = Depends(get_current_user), db: Session = Depends(get_db) ): """获取寻配号列表""" query = db.query(SeekInfo).filter(SeekInfo.status == status) # 我的寻配号:只查看自己的 if user_only and current_user: query = query.filter(SeekInfo.user_id == current_user.f99_90_id) # 排序 query = query.order_by(SeekInfo.created_at.desc()) # 分页 offset = (page - 1) * page_size items = query.offset(offset).limit(page_size).all() # 关联查询用户名 result = [] for item in items: user = db.query(User).filter(User.f99_90_id == item.user_id).first() user_name = user.f01_01_name if user else None # 计算网络数据匹配数 network_matched_count = 0 if item.expect_number: network_matched_count = match_collections_count_from_coolbot(item.expect_number) result.append({ "id": item.id, "user_id": item.user_id, "user_name": user_name, "title": item.title, "content": item.content, "expect_category": item.expect_category, "expect_version": item.expect_version, "expect_packaging": item.expect_packaging, "expect_number": item.expect_number, "expect_price_min": item.expect_price_min, "expect_price_max": item.expect_price_max, "status": item.status, "is_matched": item.is_matched, "matched_user_id": item.matched_user_id, "matched_contact": item.matched_contact, "view_count": item.view_count, "contact_count": item.contact_count, "network_matched_count": network_matched_count, "created_at": item.created_at.isoformat() if item.created_at else None, "updated_at": item.updated_at.isoformat() if item.updated_at else None, }) return result @router.get("/stats") def get_seek_stats( current_user = Depends(get_current_user), db: Session = Depends(get_db) ): """获取寻配号统计""" total = db.query(SeekInfo).filter(SeekInfo.status == "active").count() matched = db.query(SeekInfo).filter(SeekInfo.is_matched == "true").count() return { "total": total, "matched": matched, "unmatched": total - matched } @router.post("", response_model=SeekInfoResponse) def create_seek( data: SeekInfoCreate, current_user = Depends(get_current_user), db: Session = Depends(get_db) ): """创建寻配号""" if not current_user: raise HTTPException(status_code=401, detail="请先登录") seek = SeekInfo( user_id=current_user.f99_90_id, title=data.title, content=data.content, expect_category=data.expect_category, expect_version=data.expect_version, expect_packaging=data.expect_packaging, expect_number=data.expect_number, expect_price_min=data.expect_price_min, expect_price_max=data.expect_price_max, status="active" ) db.add(seek) db.commit() db.refresh(seek) return seek @router.get("/{seek_id}", response_model=SeekInfoResponse) def get_seek( seek_id: str, current_user = Depends(get_current_user), db: Session = Depends(get_db) ): """获取寻配号详情""" seek = db.query(SeekInfo).filter(SeekInfo.id == seek_id).first() if not seek: raise HTTPException(status_code=404, detail="寻配号不存在") # 增加浏览数 seek.view_count += 1 db.commit() return seek @router.put("/{seek_id}", response_model=SeekInfoResponse) def update_seek( seek_id: str, data: SeekInfoUpdate, current_user = Depends(get_current_user), db: Session = Depends(get_db) ): """更新寻配号""" if not current_user: raise HTTPException(status_code=401, detail="请先登录") seek = db.query(SeekInfo).filter( SeekInfo.id == seek_id, SeekInfo.user_id == current_user.f99_90_id ).first() if not seek: raise HTTPException(status_code=404, detail="寻配号不存在") for key, value in data.model_dump(exclude_unset=True).items(): setattr(seek, key, value) db.commit() db.refresh(seek) return seek @router.delete("/{seek_id}") def delete_seek( seek_id: str, current_user = Depends(get_current_user), db: Session = Depends(get_db) ): """删除寻配号""" if not current_user: raise HTTPException(status_code=401, detail="请先登录") seek = db.query(SeekInfo).filter( SeekInfo.id == seek_id, SeekInfo.user_id == current_user.f99_90_id ).first() if not seek: raise HTTPException(status_code=404, detail="寻配号不存在") seek.status = "deleted" db.commit() return {"message": "删除成功"}