v1.2.101 - 寻配号网络数据匹配修复
- 修复寻配号列表API: /api/seek/list -> /api/information/seek/list - 修复page_size限制: 500 -> 100 - 修复录入成功后serialDigits未重置导致崩溃问题 - 优化包装类型和成交平台同一行显示
This commit is contained in:
parent
4c92f4e070
commit
7939abc60a
|
|
@ -76,6 +76,8 @@ class InformationResponse(BaseModel):
|
|||
collection_number: Optional[str] = None
|
||||
# 匹配数量(我的藏品中满足条件的数量)
|
||||
matched_count: Optional[int] = 0
|
||||
# 网络匹配数量(coolbot_data数据库中满足条件的数量)
|
||||
network_matched_count: Optional[int] = 0
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
|
@ -115,6 +117,11 @@ def get_information_list(
|
|||
if item.info_type == 'seek' and item.expect_number and current_user:
|
||||
matched_count = match_collections_count(db, current_user.f99_90_id, item.expect_number)
|
||||
|
||||
# 计算网络匹配数量(coolbot_data数据库)
|
||||
network_matched_count = 0
|
||||
if item.info_type == 'seek' and item.expect_number:
|
||||
network_matched_count = match_collections_count_from_coolbot(item.expect_number)
|
||||
|
||||
result.append(InformationResponse(
|
||||
id=item.id,
|
||||
user_id=item.user_id,
|
||||
|
|
@ -144,6 +151,7 @@ def get_information_list(
|
|||
collection_version=item.collection.f02_11_version if item.collection else None,
|
||||
collection_number=item.collection.f02_10_prefix_serial if item.collection else None,
|
||||
matched_count=matched_count,
|
||||
network_matched_count=network_matched_count,
|
||||
))
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
VERSION=1.2.100
|
||||
export const APP_VERSION = '1.2.101'
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ export default function Add() {
|
|||
// 行情录入表单
|
||||
const [dealForm, setDealForm] = useState({
|
||||
serial: '',
|
||||
serialDigits: ['','','','','','','','','',''], // 冠字号10位分别存储
|
||||
category: '',
|
||||
packaging: '标十',
|
||||
price: '',
|
||||
|
|
@ -730,9 +731,100 @@ export default function Add() {
|
|||
<div>
|
||||
<div style={{ marginBottom: '12px' }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>冠字号 *</div>
|
||||
<input value={dealForm.serial} onChange={(e) => setDealForm({...dealForm, serial: e.target.value.toUpperCase(), category: autoCategory(e.target.value)})}
|
||||
placeholder="J0xxxxxxxx"
|
||||
style={{ width: '100%', padding: '12px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', fontSize: '15px' }} />
|
||||
|
||||
{/* 冠字号每位单独输入框 - 共10位,J0可编辑,后面8位数字 */}
|
||||
<div style={{ display: 'flex', gap: '4px', justifyContent: 'center' }}>
|
||||
{/* 第1位: J - 可编辑 */}
|
||||
<input value={dealForm.serialDigits[0] || 'J'}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value.replace(/[^Jj]/g, '').slice(-1).toUpperCase()
|
||||
const newDigits = [...dealForm.serialDigits]
|
||||
newDigits[0] = val || 'J'
|
||||
const fullSerial = (newDigits[0] || 'J') + (newDigits[1] || '0') + newDigits.slice(2).join('')
|
||||
setDealForm({...dealForm, serialDigits: newDigits, serial: fullSerial, category: autoCategory(fullSerial)})
|
||||
}}
|
||||
maxLength={1}
|
||||
style={{
|
||||
width: '32px', height: '44px', textAlign: 'center',
|
||||
background: 'rgba(251,191,36,0.2)', border: '1px solid rgba(251,191,36,0.3)',
|
||||
borderRadius: '6px', color: '#fbbf24', fontSize: '16px', fontWeight: 'bold'
|
||||
}}
|
||||
/>
|
||||
{/* 第2位: 0 - 可编辑 */}
|
||||
<input value={dealForm.serialDigits[1] || '0'}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value.replace(/[^0]/g, '').slice(-1)
|
||||
const newDigits = [...dealForm.serialDigits]
|
||||
newDigits[1] = val || '0'
|
||||
const fullSerial = (newDigits[0] || 'J') + (newDigits[1] || '0') + newDigits.slice(2).join('')
|
||||
setDealForm({...dealForm, serialDigits: newDigits, serial: fullSerial, category: autoCategory(fullSerial)})
|
||||
}}
|
||||
maxLength={1}
|
||||
style={{
|
||||
width: '32px', height: '44px', textAlign: 'center',
|
||||
background: 'rgba(251,191,36,0.2)', border: '1px solid rgba(251,191,36,0.3)',
|
||||
borderRadius: '6px', color: '#fbbf24', fontSize: '16px', fontWeight: 'bold'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 后面8位数字输入 - 带自动跳转 */}
|
||||
{dealForm.serialDigits.slice(2).map((digit, idx) => {
|
||||
const realIdx = idx + 2 // 实际索引 (2-9)
|
||||
return (
|
||||
<input key={realIdx} value={digit}
|
||||
data-real-idx={realIdx}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value.replace(/\D/g, '').slice(-1)
|
||||
const newDigits = [...dealForm.serialDigits]
|
||||
newDigits[realIdx] = val
|
||||
const fullSerial = newDigits[0] + newDigits[1] + newDigits.slice(2).join('')
|
||||
setDealForm({
|
||||
...dealForm,
|
||||
serialDigits: newDigits,
|
||||
serial: fullSerial,
|
||||
category: autoCategory(fullSerial)
|
||||
})
|
||||
// 输入后自动跳到下一个框(索引+1)
|
||||
if (val && realIdx < 9) {
|
||||
setTimeout(() => {
|
||||
const inputs = document.querySelectorAll('[data-real-idx]')
|
||||
const nextInput = inputs[idx + 1] // 用遍历的idx而不是realIdx
|
||||
if (nextInput) nextInput.focus()
|
||||
}, 10)
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
// 按退格键时自动跳回上一个框
|
||||
if (e.key === 'Backspace' && !e.target.value && realIdx > 2) {
|
||||
setTimeout(() => {
|
||||
const inputs = document.querySelectorAll('[data-real-idx]')
|
||||
const prevInput = inputs[idx - 1]
|
||||
if (prevInput) prevInput.focus()
|
||||
}, 10)
|
||||
}
|
||||
}}
|
||||
maxLength={1}
|
||||
placeholder="×"
|
||||
style={{
|
||||
width: '32px', height: '44px', textAlign: 'center',
|
||||
background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: '6px', color: '#fff', fontSize: '16px', fontWeight: 'bold'
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 快捷清除按钮 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '8px' }}>
|
||||
<button type="button" onClick={() => setDealForm({...dealForm, serial: '', serialDigits: ['','','','','','','','','',''], category: ''})}
|
||||
style={{ padding: '4px 12px', background: 'rgba(255,255,255,0.1)', border: 'none', borderRadius: '4px', color: '#94a3b8', fontSize: '12px', cursor: 'pointer' }}>
|
||||
清空
|
||||
</button>
|
||||
<div style={{ color: '#64748b', fontSize: '12px' }}>
|
||||
已输入: {dealForm.serialDigits.filter(d => d).length}/8 位
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{dealForm.category && (
|
||||
|
|
@ -741,19 +833,8 @@ export default function Add() {
|
|||
<div style={{ fontSize: '14px', color: '#fbbf24', fontWeight: 'bold' }}>{dealForm.category}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginBottom: '12px' }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>包装类型</div>
|
||||
<div style={{ display: 'flex', gap: '8px' }}>
|
||||
{['单张', '标十', '标百'].map(p => (
|
||||
<button key={p} onClick={() => setDealForm({...dealForm, packaging: p})}
|
||||
style={{ flex: 1, padding: '10px', background: dealForm.packaging === p ? '#fbbf24' : 'rgba(255,255,255,0.05)', color: dealForm.packaging === p ? '#1e293b' : '#fff', border: 'none', borderRadius: '8px', fontSize: '13px', fontWeight: '600', cursor: 'pointer' }}>
|
||||
{p}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 成交价格 - 调整到冠字号下面 */}
|
||||
<div style={{ marginBottom: '12px' }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>成交价格 *</div>
|
||||
<input type="number" value={dealForm.price} onChange={(e) => setDealForm({...dealForm, price: e.target.value})}
|
||||
|
|
@ -761,20 +842,34 @@ export default function Add() {
|
|||
style={{ width: '100%', padding: '12px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', fontSize: '15px' }} />
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '12px' }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>成交平台 *</div>
|
||||
<select value={dealForm.platform} onChange={(e) => setDealForm({...dealForm, platform: e.target.value})}
|
||||
style={{ width: '100%', padding: '12px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', fontSize: '15px' }}>
|
||||
<option value="淘宝">淘宝</option>
|
||||
<option value="咸鱼">咸鱼</option>
|
||||
<option value="抖音">抖音</option>
|
||||
<option value="快手">快手</option>
|
||||
<option value="微拍堂">微拍堂</option>
|
||||
<option value="拼多多">拼多多</option>
|
||||
<option value="一尘">一尘</option>
|
||||
<option value="爱藏">爱藏</option>
|
||||
<option value="其他">其他</option>
|
||||
</select>
|
||||
{/* 成交价格和成交平台同一行 */}
|
||||
<div style={{ display: 'flex', gap: '12px', marginBottom: '12px' }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>包装类型</div>
|
||||
<div style={{ display: 'flex', gap: '4px' }}>
|
||||
{['单张', '标十', '标百'].map(p => (
|
||||
<button key={p} onClick={() => setDealForm({...dealForm, packaging: p})}
|
||||
style={{ flex: 1, padding: '10px 4px', background: dealForm.packaging === p ? '#fbbf24' : 'rgba(255,255,255,0.05)', color: dealForm.packaging === p ? '#1e293b' : '#fff', border: 'none', borderRadius: '6px', fontSize: '12px', fontWeight: '600', cursor: 'pointer' }}>
|
||||
{p}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ color: '#94a3b8', fontSize: '13px', marginBottom: '6px' }}>成交平台 *</div>
|
||||
<select value={dealForm.platform} onChange={(e) => setDealForm({...dealForm, platform: e.target.value})}
|
||||
style={{ width: '100%', padding: '10px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', fontSize: '14px' }}>
|
||||
<option value="淘宝">淘宝</option>
|
||||
<option value="咸鱼">咸鱼</option>
|
||||
<option value="抖音">抖音</option>
|
||||
<option value="快手">快手</option>
|
||||
<option value="微拍堂">微拍堂</option>
|
||||
<option value="拼多多">拼多多</option>
|
||||
<option value="一尘">一尘</option>
|
||||
<option value="爱藏">爱藏</option>
|
||||
<option value="其他">其他</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '12px', marginBottom: '12px' }}>
|
||||
|
|
@ -863,7 +958,7 @@ export default function Add() {
|
|||
})
|
||||
if (response.ok) {
|
||||
alert('行情录入成功!')
|
||||
setDealForm({ serial: '', category: '', packaging: '标十', price: '', platform: '抖音', seller: '', buyer: '', date: new Date().toISOString().split('T')[0] })
|
||||
setDealForm({ serial: '', serialDigits: ['','','','','','','','','',''], category: '', packaging: '标十', price: '', platform: '抖音', seller: '', buyer: '', date: new Date().toISOString().split('T')[0] })
|
||||
} else {
|
||||
const data = await response.json()
|
||||
alert('录入失败: ' + (data.detail || '未知错误'))
|
||||
|
|
|
|||
|
|
@ -79,21 +79,21 @@ export default function News() {
|
|||
const headers = token ? { Authorization: `Bearer ${token}` } : {}
|
||||
|
||||
// 构建URL参数
|
||||
// 使用新的独立API(seek和deal已拆分)
|
||||
// 寻配号和成交行情都使用 information/list 接口
|
||||
let url = activeTab === 'yichen'
|
||||
? `${API_BASE}/api/information/list?info_type=${activeTab}`
|
||||
: activeTab === 'seek'
|
||||
? `${API_BASE}/api/seek/list`
|
||||
? `${API_BASE}/api/information/list?info_type=seek`
|
||||
: `${API_BASE}/api/deal/list`
|
||||
|
||||
// 成交行情和寻配号每页500条
|
||||
// 成交行情和寻配号每页100条(后端限制最大100)
|
||||
if (activeTab === 'deal') {
|
||||
url += (url.includes('?') ? '&' : '?') + 'page_size=500'
|
||||
url += (url.includes('?') ? '&' : '?') + 'page_size=100'
|
||||
if (dealDate) {
|
||||
url += '&deal_date=' + dealDate
|
||||
}
|
||||
} else if (activeTab === 'seek') {
|
||||
url += (url.includes("?") ? "&" : "?") + "page=" + currentPage + "&page_size=500"
|
||||
url += (url.includes("?") ? "&" : "?") + "page=" + currentPage + "&page_size=100"
|
||||
}
|
||||
|
||||
const res = await fetch(url, { headers })
|
||||
|
|
@ -290,7 +290,7 @@ export default function News() {
|
|||
const token = localStorage.getItem('token')
|
||||
if (!token) { alert('请先登录'); return }
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/seek/list`, {
|
||||
const res = await fetch(`${API_BASE}/api/information/seek/list`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
const data = await res.json()
|
||||
|
|
@ -306,7 +306,7 @@ export default function News() {
|
|||
const token = localStorage.getItem('token')
|
||||
if (!token) { alert('请先登录'); return }
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/seek/list`, {
|
||||
const res = await fetch(`${API_BASE}/api/information/seek/list`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
const data = await res.json()
|
||||
|
|
|
|||
Loading…
Reference in New Issue