diff --git a/VERSION b/VERSION index 85de19b..b54183a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.100 +1.2.101 \ No newline at end of file diff --git a/backend/app/routers/information.py b/backend/app/routers/information.py index fc65d26..5a8c00f 100644 --- a/backend/app/routers/information.py +++ b/backend/app/routers/information.py @@ -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 diff --git a/frontend/src/config/version.js b/frontend/src/config/version.js index 4810618..49e32ca 100644 --- a/frontend/src/config/version.js +++ b/frontend/src/config/version.js @@ -1 +1 @@ -VERSION=1.2.100 +export const APP_VERSION = '1.2.101' diff --git a/frontend/src/pages/Add.jsx b/frontend/src/pages/Add.jsx index 09a9208..22406f2 100644 --- a/frontend/src/pages/Add.jsx +++ b/frontend/src/pages/Add.jsx @@ -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() {
冠字号 *
- 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位数字 */} +
+ {/* 第1位: J - 可编辑 */} + { + 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 - 可编辑 */} + { + 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 ( + { + 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' + }} + /> + ) + })} +
+ + {/* 快捷清除按钮 */} +
+ +
+ 已输入: {dealForm.serialDigits.filter(d => d).length}/8 位 +
+
{dealForm.category && ( @@ -741,19 +833,8 @@ export default function Add() {
{dealForm.category}
)} - -
-
包装类型
-
- {['单张', '标十', '标百'].map(p => ( - - ))} -
-
- + + {/* 成交价格 - 调整到冠字号下面 */}
成交价格 *
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' }} />
-
-
成交平台 *
- + {/* 成交价格和成交平台同一行 */} +
+
+
包装类型
+
+ {['单张', '标十', '标百'].map(p => ( + + ))} +
+
+
+
成交平台 *
+ +
@@ -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 || '未知错误')) diff --git a/frontend/src/pages/News.jsx b/frontend/src/pages/News.jsx index c77c20f..69686df 100644 --- a/frontend/src/pages/News.jsx +++ b/frontend/src/pages/News.jsx @@ -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()