feat: 表拆分seek_info和deal_info,优化显示和分页
This commit is contained in:
parent
ea6528b7f3
commit
aec6ef7c79
|
|
@ -17,6 +17,8 @@ from app.routers import ocr as ocr_router
|
|||
from app.routers import users as users_router
|
||||
from app.routers import information as information_router
|
||||
from app.routers import yichens as yichens_router
|
||||
from app.routers import seek as seek_router
|
||||
from app.routers import deal as deal_router
|
||||
|
||||
# 版本信息 - 从 config/VERSION 文件读取
|
||||
def get_version():
|
||||
|
|
@ -84,6 +86,8 @@ app.include_router(users_router.router) # 当前用户接口
|
|||
app.include_router(users_router.admin_router) # 管理员用户管理
|
||||
app.include_router(information_router.router)
|
||||
app.include_router(yichens_router.router) # 一尘看板
|
||||
app.include_router(seek_router.router) # 寻配号
|
||||
app.include_router(deal_router.router) # 成交行情
|
||||
|
||||
|
||||
@app.get("/")
|
||||
|
|
@ -106,3 +110,6 @@ if __name__ == "__main__":
|
|||
import uvicorn
|
||||
port = int(os.getenv("PORT", "3000"))
|
||||
uvicorn.run(app, host="0.0.0.0", port=port)
|
||||
|
||||
from app.routers import seek as seek_router
|
||||
from app.routers import deal as deal_router
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
from sqlalchemy import Column, String, Text, Float, Date, Boolean, Integer, DateTime
|
||||
from sqlalchemy.sql import func
|
||||
from app.core.database import Base
|
||||
import uuid
|
||||
|
||||
def generate_uuid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
class DealInfo(Base):
|
||||
__tablename__ = "deal_info"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||
user_id = Column(String(36), nullable=True, index=True)
|
||||
|
||||
# 标题和内容
|
||||
title = Column(String(255), nullable=False)
|
||||
content = Column(Text, nullable=True)
|
||||
|
||||
# 成交信息
|
||||
deal_price = Column(Float, nullable=True) # 成交价格
|
||||
deal_date = Column(Date, nullable=True) # 成交日期
|
||||
deal_no = Column(String(20), nullable=True, index=True) # 行情编号(从A000001开始递增)
|
||||
|
||||
# 包装和分类
|
||||
packaging = Column(String(50), nullable=True) # 包装(标百/标十/单张)
|
||||
category = Column(String(100), nullable=True) # 分类
|
||||
|
||||
# 评级相关
|
||||
is_graded = Column(Boolean, default=False) # 是否评级
|
||||
grading_company = Column(String(100), nullable=True) # 评级机构
|
||||
grading_score = Column(String(50), nullable=True) # 评级分数
|
||||
|
||||
# 号码特征
|
||||
tail_number = Column(String(10), nullable=True) # 尾号
|
||||
size_type = Column(String(20), nullable=True) # 大小号
|
||||
|
||||
# 版别
|
||||
version = Column(String(50), nullable=True) # 版别
|
||||
|
||||
# 交易信息
|
||||
platform = Column(String(50), nullable=True) # 成交平台
|
||||
seller = Column(String(100), nullable=True) # 出售者
|
||||
buyer = Column(String(100), nullable=True) # 购买者
|
||||
|
||||
# 状态
|
||||
status = Column(String(20), default="active")
|
||||
|
||||
# 统计
|
||||
view_count = Column(Integer, default=0)
|
||||
contact_count = Column(Integer, default=0)
|
||||
|
||||
# 时间
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
from sqlalchemy import Column, String, Text, Float, Date, Boolean, Integer, DateTime
|
||||
from sqlalchemy.sql import func
|
||||
from app.core.database import Base
|
||||
import uuid
|
||||
|
||||
def generate_uuid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
class SeekInfo(Base):
|
||||
__tablename__ = "seek_info"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||
user_id = Column(String(36), nullable=False, index=True)
|
||||
|
||||
# 标题和内容
|
||||
title = Column(String(255), nullable=False)
|
||||
content = Column(Text, nullable=True)
|
||||
|
||||
# 期望条件(求购条件)
|
||||
expect_category = Column(String(100), nullable=True) # 期望类别
|
||||
expect_version = Column(String(100), nullable=True) # 期望版别
|
||||
expect_packaging = Column(String(100), nullable=True) # 期望包装
|
||||
expect_number = Column(String(50), nullable=True) # 期望号码
|
||||
expect_price_min = Column(Float, nullable=True) # 期望最低价
|
||||
expect_price_max = Column(Float, nullable=True) # 期望最高价
|
||||
|
||||
# 匹配状态
|
||||
status = Column(String(20), default="active") # active/closed/expired
|
||||
is_matched = Column(String(10), default="false") # 是否已匹配
|
||||
matched_user_id = Column(String(36), nullable=True) # 匹配的用户ID
|
||||
matched_contact = Column(String(100), nullable=True) # 匹配的联系方式
|
||||
|
||||
# 统计
|
||||
view_count = Column(Integer, default=0)
|
||||
contact_count = Column(Integer, default=0)
|
||||
|
||||
# 时间
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
from fastapi import APIRouter, Depends, Query, HTTPException
|
||||
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=500),
|
||||
current_user: Optional = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取成交行情列表"""
|
||||
query = db.query(DealInfo).filter(DealInfo.status == status)
|
||||
|
||||
# 成交日期过滤
|
||||
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": "删除成功"}
|
||||
|
|
@ -134,7 +134,7 @@ def get_information_list(
|
|||
query = query.filter(Information.deal_date == deal_date_obj)
|
||||
|
||||
# 按创建时间倒序
|
||||
query = query.order_by(Information.created_at.desc())
|
||||
query = query.order_by(Information.deal_date.desc().nullslast(), Information.deal_no.desc().nullslast())
|
||||
|
||||
# 分页
|
||||
offset = (page - 1) * page_size
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
from fastapi import APIRouter, Depends, Query, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
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
|
||||
|
||||
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
|
||||
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=100),
|
||||
current_user: Optional = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取寻配号列表"""
|
||||
query = db.query(SeekInfo).filter(SeekInfo.status == status)
|
||||
|
||||
# 排序
|
||||
query = query.order_by(SeekInfo.created_at.desc())
|
||||
|
||||
# 分页
|
||||
offset = (page - 1) * page_size
|
||||
items = query.offset(offset).limit(page_size).all()
|
||||
|
||||
return items
|
||||
|
||||
@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": "删除成功"}
|
||||
|
|
@ -79,7 +79,7 @@ export default function List() {
|
|||
}
|
||||
try {
|
||||
const user = JSON.parse(userStr)
|
||||
const res = await fetch(`${API_BASE}/api/information/list?info_type=deal&page_size=500`, {
|
||||
const res = await fetch(`${API_BASE}/api/deal/list?page_size=500`, {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
})
|
||||
const data = await res.json()
|
||||
|
|
@ -758,7 +758,7 @@ function DealListItem({ deal, onRefresh }) {
|
|||
const saveEdit = async () => {
|
||||
const token = localStorage.getItem('token')
|
||||
try {
|
||||
await fetch(`${API_BASE}/api/information/${deal.id}`, {
|
||||
await fetch(`${API_BASE}/api/deal/${deal.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(editForm)
|
||||
|
|
@ -772,7 +772,7 @@ function DealListItem({ deal, onRefresh }) {
|
|||
if (!confirm('确定删除这条行情?')) return
|
||||
const token = localStorage.getItem('token')
|
||||
try {
|
||||
await fetch(`${API_BASE}/api/information/${deal.id}`, {
|
||||
await fetch(`${API_BASE}/api/deal/${deal.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
})
|
||||
|
|
|
|||
|
|
@ -79,16 +79,21 @@ export default function News() {
|
|||
const headers = token ? { Authorization: `Bearer ${token}` } : {}
|
||||
|
||||
// 构建URL参数
|
||||
let url = `${API_BASE}/api/information/list?info_type=${type}`
|
||||
// 使用新的独立API(seek和deal已拆分)
|
||||
let url = activeTab === 'yichen'
|
||||
? `${API_BASE}/api/information/list?info_type=${activeTab}`
|
||||
: activeTab === 'seek'
|
||||
? `${API_BASE}/api/seek/list`
|
||||
: `${API_BASE}/api/deal/list`
|
||||
|
||||
// 成交行情tab,获取500条数据
|
||||
// 成交行情和寻配号每页500条
|
||||
if (activeTab === 'deal') {
|
||||
url += `&page_size=500`
|
||||
url += (url.includes('?') ? '&' : '?') + 'page_size=500'
|
||||
if (dealDate) {
|
||||
url += `&deal_date=${dealDate}`
|
||||
url += '&deal_date=' + dealDate
|
||||
}
|
||||
} else {
|
||||
url += `&page=${currentPage}&page_size=50`
|
||||
} else if (activeTab === 'seek') {
|
||||
url += (url.includes("?") ? "&" : "?") + "page=" + currentPage + "&page_size=500"
|
||||
}
|
||||
|
||||
const res = await fetch(url, { headers })
|
||||
|
|
@ -107,25 +112,17 @@ export default function News() {
|
|||
|
||||
// 成交行情按分类排序
|
||||
let sortedData = data || []
|
||||
if (activeTab === 'deal') {
|
||||
const categoryOrder = ['带4号', '带7号', '永恒号', '天马号', '天马王', '金山号', '金山王', '钻石号', '朦胧号', '朦胧王', '金马号', '金马王', '倒置号', '圆圆号']
|
||||
// 标准化分类名称(通货->带4号,无4->带7号)
|
||||
const normalizeCat = (c) => {
|
||||
if (c === '通货') return '带4号'
|
||||
if (c === '无4') return '带7号'
|
||||
return c
|
||||
}
|
||||
if (activeTab === 'deal' || activeTab === 'seek') {
|
||||
// 优先按日期倒序,同日按编号倒序
|
||||
sortedData = [...(data || [])].sort((a, b) => {
|
||||
const contentA = a.content || ''
|
||||
const contentB = b.content || ''
|
||||
const catA = normalizeCat(contentA.match(/分类:\s*(.+?)(?:\n|$)/)?.[1]?.trim() || a.category || '')
|
||||
const catB = normalizeCat(contentB.match(/分类:\s*(.+?)(?:\n|$)/)?.[1]?.trim() || b.category || '')
|
||||
const idxA = categoryOrder.indexOf(catA)
|
||||
const idxB = categoryOrder.indexOf(catB)
|
||||
return (idxA === -1 ? 999 : idxA) - (idxB === -1 ? 999 : idxB)
|
||||
const dateA = a.deal_date || a.created_at?.split('T')[0] || ""
|
||||
const dateB = b.deal_date || b.created_at?.split('T')[0] || ""
|
||||
if (dateA !== dateB) return dateB.localeCompare(dateA)
|
||||
const noA = a.deal_no || ""
|
||||
const noB = b.deal_no || ""
|
||||
return noB.localeCompare(noA)
|
||||
})
|
||||
}
|
||||
|
||||
setInfoList(sortedData)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
|
@ -293,12 +290,12 @@ export default function News() {
|
|||
const token = localStorage.getItem('token')
|
||||
if (!token) { alert('请先登录'); return }
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/information/my/list`, {
|
||||
const res = await fetch(`${API_BASE}/api/seek/list`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
const data = await res.json()
|
||||
// 过滤出寻号类型的并筛选当前用户
|
||||
const seeks = Array.isArray(data) ? data.filter(item => item.info_type === 'seek' && item.user_id === currentUserId) : []
|
||||
// 筛选当前用户
|
||||
const seeks = Array.isArray(data) ? data.filter(item => item.user_id === currentUserId) : []
|
||||
setMySeekList(seeks)
|
||||
setInfoList(seeks) // 在主列表显示
|
||||
} catch (e) { console.error(e) }
|
||||
|
|
@ -309,7 +306,7 @@ export default function News() {
|
|||
const token = localStorage.getItem('token')
|
||||
if (!token) { alert('请先登录'); return }
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/information/list?info_type=seek`, {
|
||||
const res = await fetch(`${API_BASE}/api/seek/list`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
const data = await res.json()
|
||||
|
|
@ -707,28 +704,26 @@ export default function News() {
|
|||
else if (serial.startsWith('J3')) version = '蛇钞'
|
||||
|
||||
return (
|
||||
<div key={item.id} style={{ background: '#1e293b', borderRadius: '8px', padding: '10px', marginBottom: '8px' }}>
|
||||
{/* 第一行:成交日期 | 版别 | 包装 | 分类 | 价格 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '6px', flexWrap: 'wrap' }}>
|
||||
<span style={{ background: '#64748b', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{dealDate}</span>
|
||||
<span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span>
|
||||
<span style={{ background: '#3b82f6', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{version}</span>
|
||||
<span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span>
|
||||
<span style={{ background: '#8b5cf6', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{packaging}</span>
|
||||
<span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span>
|
||||
<span style={{ background: '#f97316', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{category}</span>
|
||||
<div key={item.id} style={{ borderBottom: '1px solid #334155', padding: '12px 0' }}>
|
||||
{/* 标题行:冠字号 + 价格 */}
|
||||
<div style={{ fontSize: '15px', fontWeight: '500', marginBottom: '6px' }}>
|
||||
<span style={{ color: '#fbbf24' }}>{serial}</span>
|
||||
<span style={{ color: '#22c55e', marginLeft: '12px' }}>¥{item.deal_price?.toLocaleString()}</span>
|
||||
<span style={{ color: '#64748b', marginLeft: '12px', fontSize: '12px' }}>{item.deal_no}</span>
|
||||
</div>
|
||||
<div style={{ color: '#22c55e', fontSize: '14px', fontWeight: '700' }}>¥{item.deal_price?.toLocaleString()}</div>
|
||||
</div>
|
||||
{/* 第二行:冠字号 | 评级机构 | 分数 | 平台 */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
||||
<span style={{ color: '#fbbf24', fontSize: '13px', fontWeight: '600' }}>{serial}</span>
|
||||
<span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span>
|
||||
{gradingCompany && <><span style={{ background: '#ec4899', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{gradingCompany}</span><span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span></>}
|
||||
<span style={{ background: '#06b6d4', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{grade}</span>
|
||||
<span style={{ color: '#94a3b8', fontSize: '10px' }}>|</span>
|
||||
<span style={{ background: '#10b981', color: '#fff', padding: '2px 6px', borderRadius: '3px', fontSize: '10px' }}>{platform}</span>
|
||||
{/* 信息行:版别 | 包装 | 分类 | 评级 | 分数 | 平台 */}
|
||||
<div style={{ fontSize: '12px', color: '#94a3b8' }}>
|
||||
<span style={{ color: '#fff' }}>{version}</span>
|
||||
<span style={{ margin: '0 8px' }}>|</span>
|
||||
<span style={{ color: '#3b82f6' }}>{packaging}</span>
|
||||
<span style={{ margin: '0 8px' }}>|</span>
|
||||
<span style={{ color: '#fbbf24' }}>{category}</span>
|
||||
{gradingCompany && <><span style={{ margin: '0 8px' }}>|</span><span>{gradingCompany}</span></>}
|
||||
{grade && <><span style={{ margin: '0 8px' }}>|</span><span>{grade}</span></>}
|
||||
<span style={{ margin: '0 8px' }}>|</span>
|
||||
<span>{platform}</span>
|
||||
<span style={{ margin: '0 8px' }}>|</span>
|
||||
<span>{dealDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -1085,7 +1080,7 @@ export default function News() {
|
|||
)}
|
||||
|
||||
{/* 分页组件 */}
|
||||
{totalPages > 1 && (
|
||||
{infoList.length > 0 && (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '8px', padding: '16px', marginTop: '8px' }}>
|
||||
<button
|
||||
onClick={() => { if (currentPage > 1) { setCurrentPage(currentPage - 1); fetchInfoList() } }}
|
||||
|
|
|
|||
Loading…
Reference in New Issue