v0.2.2 - 寻配号支持评级字段

This commit is contained in:
甲辰生产 2026-05-11 13:46:03 +08:00
parent 73075a1474
commit 33ca624e70
6 changed files with 78 additions and 22 deletions

View File

@ -24,6 +24,12 @@ class SeekInfo(Base):
expect_price_min = Column(Float, nullable=True) # 期望最低价
expect_price_max = Column(Float, nullable=True) # 期望最高价
# 评级字段
number = Column(String(50), nullable=True) # 号码
is_graded = Column(Boolean, default=False) # 是否评级
grading_company = Column(String(100), nullable=True) # 评级公司
grading_score = Column(String(20), nullable=True) # 评级分数
# 匹配状态
status = Column(String(20), default="active") # active/closed/expired
is_matched = Column(String(10), default="false") # 是否已匹配

View File

@ -1,6 +1,6 @@
# seek - 寻配号路由
# Version: 0.0.9 (2026-04-24)
# 稳定版:自有匹配+网络匹配缓存
# Version: 0.2.0 (2026-05-11)
# 稳定版:支持评级字段number, is_graded, grading_company, grading_score
from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy.orm import Session
@ -30,6 +30,11 @@ class SeekInfoCreate(BaseModel):
expect_number: Optional[str] = None
expect_price_min: Optional[float] = None
expect_price_max: Optional[float] = None
# 评级字段
number: Optional[str] = None
is_graded: Optional[bool] = False
grading_company: Optional[str] = None
grading_score: Optional[str] = None
class SeekInfoUpdate(BaseModel):
title: Optional[str] = None
@ -41,6 +46,11 @@ class SeekInfoUpdate(BaseModel):
expect_price_min: Optional[float] = None
expect_price_max: Optional[float] = None
status: Optional[str] = None
# 评级字段
number: Optional[str] = None
is_graded: Optional[bool] = False
grading_company: Optional[str] = None
grading_score: Optional[str] = None
class SeekInfoResponse(BaseModel):
id: str
@ -64,6 +74,11 @@ class SeekInfoResponse(BaseModel):
user_name: Optional[str] = None # 发布者用户名
matched_count: Optional[int] = 0 # 自有匹配数量
network_matched_count: Optional[int] = 0 # 网络匹配数量
# 评级字段
number: Optional[str] = None
is_graded: Optional[bool] = False
grading_company: Optional[str] = None
grading_score: Optional[str] = None
class Config:
from_attributes = True
@ -182,7 +197,12 @@ def create_seek(
status="active",
view_count=0,
contact_count=0,
network_matched_count=network_matched_count # 保存初始化值
network_matched_count=network_matched_count, # 保存初始化值
# 评级字段
number=data.number,
is_graded=data.is_graded,
grading_company=data.grading_company,
grading_score=data.grading_score
)
db.add(seek)
db.commit()

View File

@ -1,6 +1,26 @@
# 版本更新记录
## v0.2.0 (2026-05-02)
## v0.2.2 (2026-05-11)
### 后端更新
- **seek.py**
- 新增寻配号支持评级字段number, is_graded, grading_company, grading_score
- 更新SeekInfoCreate/Update/Response Schema 新增评级字段支持
- **seek_info模型**
- 新增number, is_graded, grading_company, grading_score 字段
## v0.2.1 (2026-05-07)
### 前端更新
- **Add.jsx**
- 修复:行情录入时评级信息(is_graded, grading_company, grading_score)未保存到数据库的问题
- 修复:表单重置后未清空评级字段的问题
- 同步修复:批量录入时的评级字段问题
- **News.jsx**
- 修复:成交行情列表按成交日期(deal_date)倒序排序
- 修复:统计表格详情弹窗列表按成交日期倒序排序
### 后端更新
- **purchase.py**

View File

@ -1,22 +1,22 @@
{
"version": "0.2.0",
"updated": "2026-05-02",
"version": "0.2.2",
"updated": "2026-05-11",
"modules": {
"frontend": {
"version": "0.1.8",
"version": "0.1.9",
"pages": {
"Home": "0.1.0",
"Purchase": "0.2.0",
"List": "0.1.6",
"News": "0.0.9"
"Add": "0.0.2",
"News": "0.1.0"
}
},
"backend": {
"version": "0.2.0",
"version": "0.2.1",
"routers": {
"seek": "0.2.0",
"purchase": "0.3.0"
},
"models": {
"seek_info": "0.2.0",
"purchase": "0.0.3"
}
}

View File

@ -1,7 +1,7 @@
/**
* Add - 添加藏品页面
* Version: 0.0.1
* 更新
* Version: 0.0.2
* 更新修复行情录入时评级信息(is_graded, grading_company, grading_score)未保存的问题
*/
import React, { useState, useRef } from 'react'
@ -863,12 +863,15 @@ export default function Add() {
size_type: sizeType,
platform: dealForm.platform,
seller: dealForm.seller || '',
buyer: dealForm.buyer || ''
buyer: dealForm.buyer || '',
is_graded: !!dealForm.gradingCompany,
grading_company: dealForm.gradingCompany || '',
grading_score: dealForm.gradingScore || ''
})
})
if (response.ok) {
alert('行情录入成功!')
setDealForm({ serial: '', category: '', packaging: '标十', price: '', platform: '抖音', seller: '', buyer: '', date: new Date().toISOString().split('T')[0] })
setDealForm({ serial: '', category: '', packaging: '标十', price: '', platform: '抖音', seller: '', buyer: '', date: new Date().toISOString().split('T')[0], gradingCompany: '', gradingScore: '' })
} else {
const data = await response.json()
alert('录入失败: ' + (data.detail || '未知错误'))
@ -1055,7 +1058,7 @@ export default function Add() {
method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
title: `${item.serial}${item.price}`,
content: `分类: ${item.category || '-'}\n尾号: ${tail_number || '-'}\n大小号: ${size_type || '-'}\n包装: ${item.packaging || '单张'}\n平台: ${item.platform || '-'}\n价格: ¥${item.price}\n出售者: ${item.seller || '-'}\n购买者: ${item.buyer || '-'}\n日期: ${item.deal_date || new Date().toISOString().split('T')[0]}`,
content: `分类: ${item.category || '-'}\n尾号: ${tail_number || '-'}\n大小号: ${size_type || '-'}\n包装: ${item.packaging || '单张'}\n平台: ${item.platform || '-'}\n价格: ¥${item.price}\n出售者: ${item.seller || '-'}\n购买者: ${item.buyer || '-'}\n日期: ${item.deal_date || new Date().toISOString().split('T')[0]}\n评级: ${item.grading_company ? item.grading_company + ' ' + item.grading_score : '未评级'}`,
deal_price: parseFloat(item.price),
deal_date: item.deal_date || new Date().toISOString().split('T')[0],
packaging: item.packaging || '单张',
@ -1064,7 +1067,10 @@ export default function Add() {
size_type: size_type,
platform: item.platform || '-',
seller: item.seller || '',
buyer: item.buyer || ''
buyer: item.buyer || '',
is_graded: !!item.grading_company,
grading_company: item.grading_company || '',
grading_score: item.grading_score || ''
})
})
count++

View File

@ -1,8 +1,7 @@
/**
* News - 资讯列表页面
* Version: 0.0.9 (2026-05-01)
* 稳定版自有匹配+网络匹配缓存
* 更新成交行情页面新增筛选功能版别包装类型号码分类
* Version: 0.1.0 (2026-05-07)
* 更新成交行情列表和详情弹窗列表都按成交日期(deal_date)倒序排序
*/
import React, { useState, useEffect } from 'react'
@ -730,7 +729,12 @@ export default function News() {
style={{ background: 'none', border: 'none', color: '#94a3b8', fontSize: '20px', cursor: 'pointer' }}></button>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
{([...dealDetailItems].sort((a, b) => (a.deal_price || 0) - (b.deal_price || 0))).map((item, idx) => {
{/* 按成交日期倒序排序 */}
{([...dealDetailItems].sort((a, b) => {
const dateA = a.deal_date || a.created_at?.split('T')[0] || ''
const dateB = b.deal_date || b.created_at?.split('T')[0] || ''
return dateB.localeCompare(dateA)
})).map((item, idx) => {
const content = item.content || ''
const grade = content.includes('评级:') ? content.split('评级:')[1].split('\n')[0].trim() : (item.grading_score || '')
const sizeMatch = content.match(/大小号:\s*(.+?)(?:\n|$)/)