jiachenlong/backend/app/routers/deal.py

503 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# deal - 成交行情路由
# 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
# 更新:
from datetime import datetime, date
# 更新:
from app.core.database import get_db
# 更新:
from app.core.auth import get_current_user
# 更新:
from app.models.deal_info import DealInfo
# 更新:
# 更新:
router = APIRouter(prefix="/api/deal", tags=["成交行情"])
# 更新:
# 更新:
# ============ Schema ============
# 更新:
class DealInfoCreate(BaseModel):
# 更新:
title: str
# 更新:
content: Optional[str] = None
# 更新:
deal_price: Optional[float] = None
# 更新:
deal_date: Optional[str] = None # YYYY-MM-DD
# 更新:
packaging: Optional[str] = None
# 更新:
category: Optional[str] = None
# 更新:
is_graded: Optional[bool] = False
# 更新:
grading_company: Optional[str] = None
# 更新:
grading_score: Optional[str] = None
# 更新:
tail_number: Optional[str] = None
# 更新:
size_type: Optional[str] = None
# 更新:
version: Optional[str] = None
# 更新:
platform: Optional[str] = None
# 更新:
seller: Optional[str] = None
# 更新:
buyer: Optional[str] = None
# 更新:
# 更新:
class DealInfoUpdate(BaseModel):
# 更新:
title: Optional[str] = None
# 更新:
content: Optional[str] = None
# 更新:
deal_price: Optional[float] = None
# 更新:
deal_date: Optional[str] = None
# 更新:
packaging: Optional[str] = None
# 更新:
category: Optional[str] = None
# 更新:
is_graded: Optional[bool] = None
# 更新:
grading_company: Optional[str] = None
# 更新:
grading_score: Optional[str] = None
# 更新:
tail_number: Optional[str] = None
# 更新:
size_type: Optional[str] = None
# 更新:
version: Optional[str] = None
# 更新:
platform: Optional[str] = None
# 更新:
seller: Optional[str] = None
# 更新:
buyer: Optional[str] = None
# 更新:
status: Optional[str] = None
# 更新:
# 更新:
class DealInfoResponse(BaseModel):
# 更新:
id: str
# 更新:
user_id: Optional[str]
# 更新:
title: str
# 更新:
content: Optional[str]
# 更新:
deal_price: Optional[float]
# 更新:
deal_date: Optional[date]
# 更新:
deal_no: Optional[str]
# 更新:
packaging: Optional[str]
# 更新:
category: Optional[str]
# 更新:
is_graded: Optional[bool]
# 更新:
grading_company: Optional[str]
# 更新:
grading_score: Optional[str]
# 更新:
tail_number: Optional[str]
# 更新:
size_type: Optional[str]
# 更新:
version: Optional[str]
# 更新:
platform: Optional[str]
# 更新:
seller: Optional[str]
# 更新:
buyer: Optional[str]
# 更新:
status: str
# 更新:
view_count: int
# 更新:
contact_count: int
# 更新:
created_at: Optional[datetime]
# 更新:
updated_at: Optional[datetime]
# 更新:
# 更新:
class Config:
# 更新:
from_attributes = True
# 更新:
# 更新:
# 生成行情编号
# 更新:
def generate_deal_no(db: Session):
# 更新:
"""生成行情编号从A000001开始递增"""
# 更新:
last = db.query(DealInfo).order_by(DealInfo.deal_no.desc()).first()
# 更新:
if last and last.deal_no:
# 更新:
# 例如 A000001 -> 2 -> A000002
# 更新:
num = int(last.deal_no[1:]) + 1
# 更新:
return f"A{num:06d}"
# 更新:
return "A000001"
# 更新:
# 更新:
# ============ API ============
# 更新:
@router.get("/list", response_model=list[DealInfoResponse])
# 更新:
def get_deal_list(
# 更新:
status: str = Query("active"),
# 更新:
deal_date: Optional[str] = Query(None),
# 更新:
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(DealInfo).filter(DealInfo.status == status)
# 更新:
# 更新:
# 我的行情:只查看自己的(管理员也只看自己的)
# 更新:
if user_only and current_user:
# 更新:
query = query.filter(DealInfo.user_id == current_user.f99_90_id)
# 更新:
# 更新:
# 成交日期过滤
# 更新:
if deal_date:
# 更新:
query = query.filter(DealInfo.deal_date == deal_date)
# 更新:
# 更新:
# 排序:优先成交日期倒序,同日按编号倒序
# 更新:
query = query.order_by(DealInfo.deal_date.desc().nullslast(), DealInfo.deal_no.desc().nullslast())
# 更新:
# 更新:
# 分页
# 更新:
offset = (page - 1) * page_size
# 更新:
items = query.offset(offset).limit(page_size).all()
# 更新:
# 更新:
return items
# 更新:
# 更新:
@router.get("/stats")
# 更新:
def get_deal_stats(
# 更新:
db: Session = Depends(get_db)
# 更新:
):
# 更新:
"""获取成交行情统计"""
# 更新:
total = db.query(DealInfo).filter(DealInfo.status == "active").count()
# 更新:
# 更新:
# 按日期统计
# 更新:
from sqlalchemy import func
# 更新:
date_stats = db.query(
# 更新:
DealInfo.deal_date,
# 更新:
func.count(DealInfo.id).label('count')
# 更新:
).filter(
# 更新:
DealInfo.status == "active",
# 更新:
DealInfo.deal_date.isnot(None)
# 更新:
).group_by(DealInfo.deal_date).order_by(DealInfo.deal_date.desc()).limit(10).all()
# 更新:
# 更新:
return {
# 更新:
"total": total,
# 更新:
"by_date": [{"date": str(d.deal_date), "count": d.count} for d in date_stats]
# 更新:
}
# 更新:
# 更新:
@router.post("", response_model=DealInfoResponse)
# 更新:
def create_deal(
# 更新:
data: DealInfoCreate,
# 更新:
current_user = Depends(get_current_user),
# 更新:
db: Session = Depends(get_db)
# 更新:
):
# 更新:
"""创建成交行情"""
# 更新:
if not current_user:
# 更新:
raise HTTPException(status_code=401, detail="请先登录")
# 更新:
# 更新:
# 生成行情编号
# 更新:
deal_no = generate_deal_no(db)
# 更新:
# 更新:
# 解析日期
# 更新:
deal_date = None
# 更新:
if data.deal_date:
# 更新:
try:
# 更新:
deal_date = datetime.strptime(data.deal_date, "%Y-%m-%d").date()
# 更新:
except:
# 更新:
pass
# 更新:
# 更新:
deal = DealInfo(
# 更新:
user_id=current_user.f99_90_id if current_user else None,
# 更新:
title=data.title,
# 更新:
content=data.content,
# 更新:
deal_price=data.deal_price,
# 更新:
deal_date=deal_date,
# 更新:
deal_no=deal_no,
# 更新:
packaging=data.packaging,
# 更新:
category=data.category,
# 更新:
is_graded=data.is_graded or False,
# 更新:
grading_company=data.grading_company,
# 更新:
grading_score=data.grading_score,
# 更新:
tail_number=data.tail_number,
# 更新:
size_type=data.size_type,
# 更新:
version=data.version,
# 更新:
platform=data.platform,
# 更新:
seller=data.seller,
# 更新:
buyer=data.buyer,
# 更新:
status="active"
# 更新:
)
# 更新:
db.add(deal)
# 更新:
db.commit()
# 更新:
db.refresh(deal)
# 更新:
return deal
# 更新:
# 更新:
@router.get("/{deal_id}", response_model=DealInfoResponse)
# 更新:
def get_deal(
# 更新:
deal_id: str,
# 更新:
current_user = Depends(get_current_user),
# 更新:
db: Session = Depends(get_db)
# 更新:
):
# 更新:
"""获取成交行情详情"""
# 更新:
deal = db.query(DealInfo).filter(DealInfo.id == deal_id).first()
# 更新:
if not deal:
# 更新:
raise HTTPException(status_code=404, detail="成交行情不存在")
# 更新:
# 更新:
# 增加浏览数
# 更新:
deal.view_count += 1
# 更新:
db.commit()
# 更新:
# 更新:
return deal
# 更新:
# 更新:
@router.put("/{deal_id}", response_model=DealInfoResponse)
# 更新:
def update_deal(
# 更新:
deal_id: str,
# 更新:
data: DealInfoUpdate,
# 更新:
current_user = Depends(get_current_user),
# 更新:
db: Session = Depends(get_db)
# 更新:
):
# 更新:
"""更新成交行情"""
# 更新:
if not current_user:
# 更新:
raise HTTPException(status_code=401, detail="请先登录")
# 更新:
# 更新:
deal = db.query(DealInfo).filter(DealInfo.id == deal_id).first()
# 更新:
if not deal:
# 更新:
raise HTTPException(status_code=404, detail="成交行情不存在")
# 更新:
# 更新:
# 处理日期
# 更新:
if data.deal_date:
# 更新:
try:
# 更新:
data.deal_date = datetime.strptime(data.deal_date, "%Y-%m-%d").date()
# 更新:
except:
# 更新:
data.deal_date = None
# 更新:
# 更新:
for key, value in data.model_dump(exclude_unset=True).items():
# 更新:
setattr(deal, key, value)
# 更新:
# 更新:
db.commit()
# 更新:
db.refresh(deal)
# 更新:
return deal
# 更新:
# 更新:
@router.delete("/{deal_id}")
# 更新:
def delete_deal(
# 更新:
deal_id: str,
# 更新:
current_user = Depends(get_current_user),
# 更新:
db: Session = Depends(get_db)
# 更新:
):
# 更新:
"""删除成交行情"""
# 更新:
if not current_user:
# 更新:
raise HTTPException(status_code=401, detail="请先登录")
# 更新:
# 更新:
deal = db.query(DealInfo).filter(DealInfo.id == deal_id).first()
# 更新:
if not deal:
# 更新:
raise HTTPException(status_code=404, detail="成交行情不存在")
# 更新:
# 更新:
deal.status = "deleted"
# 更新:
db.commit()
# 更新:
# 更新:
return {"message": "删除成功"}
# 更新: