From 66c086e35d922b777f90af4b5fd61bef85a3a618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B2=E8=BE=B0=E7=94=9F=E4=BA=A7?= Date: Thu, 26 Mar 2026 15:32:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B5=84=E8=AE=AF=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=92=8C=E5=8F=91=E5=B8=83=E9=A1=B5=E9=9D=A2=E5=88=86=E7=A6=BB?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BF=A1=E6=81=AF=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/routers/information.py | 26 ++ frontend/src/App.jsx | 5 + frontend/src/pages/Info.jsx | 352 +++++++++++++++ frontend/src/pages/News.jsx | 698 +++-------------------------- 4 files changed, 433 insertions(+), 648 deletions(-) create mode 100644 frontend/src/pages/Info.jsx diff --git a/backend/app/routers/information.py b/backend/app/routers/information.py index ea7771b..1b56533 100644 --- a/backend/app/routers/information.py +++ b/backend/app/routers/information.py @@ -494,3 +494,29 @@ def get_my_information_list( )) return result + +# ============ 获取当前用户发布的列表 ============ +@router.get("/my") +def get_my_information( + page: int = Query(1, ge=1), + limit: int = Query(20, ge=1, le=100), + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取当前用户发布的信息列表""" + total = db.query(Information).filter(Information.author == current_user.f01_01_name).count() + infos = db.query(Information).filter( + Information.author == current_user.f01_01_name + ).order_by(Information.created_at.desc()).offset((page-1)*limit).limit(limit).all() + + return { + "total": total, + "list": [{ + "id": i.id, + "title": i.title, + "content": i.content, + "info_type": i.info_type, + "author": i.author, + "created_at": i.created_at.isoformat() if i.created_at else None + } for i in infos] + } diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4c37794..ae35683 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -5,6 +5,7 @@ import List from './pages/List' import Add from './pages/Add' import Stats from './pages/Stats' import News from './pages/News' +import Info from './pages/Info' import Login from './pages/Login' import Detail from './pages/Detail' import Edit from './pages/Edit' @@ -30,6 +31,7 @@ export default function App() { const basePath = path.split('?')[0] if (basePath === '/') return if (basePath === '/news') return + if (basePath === '/info') return if (basePath === '/stats') return if (basePath === '/list') return if (basePath === '/add') return @@ -50,6 +52,8 @@ export default function App() { console.error('Parse user error:', e) } const isAdmin = user && user.role === 'admin' + const isEditor = user && user.role === 'editor' + const canAccessInfo = isAdmin || isEditor // 登录页面独立渲染,不显示底部导航 if (!token) { @@ -88,6 +92,7 @@ export default function App() { { path: '/stats', icon: '📊', label: '统计' }, { path: '/list', icon: '📚', label: '藏品' }, { path: '/add', icon: '🎯', label: '添加' }, + ...(canAccessInfo ? [{ path: '/info', icon: '📝', label: '信息' }] : []), ...(isAdmin ? [{ path: '/admin', icon: '⚙️', label: '管理' }] : []) ].map(tab => (
{ + const now = new Date() + const date = `${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()}` + const gradeNote = formData.isGraded ? '(评级币)' : '(裸钞)' + const title = `「${date} ${formData.edition} ${formData.type} ${formData.category} 行情信息${gradeNote}」` + setFormData(prev => ({...prev, title})) + }, [formData.edition, formData.type, formData.isGraded, formData.category]) + + const API_BASE = localStorage.getItem('API_BASE') || '' + + // 获取我的发布列表 + useEffect(() => { + if (activeTab === 'manage') { + fetchMyList() + } + }, [activeTab]) + + const fetchMyList = async () => { + setLoading(true) + try { + const token = localStorage.getItem('token') + const res = await fetch(`${API_BASE}/api/information/my`, { + headers: { Authorization: `Bearer ${token}` } + }) + const data = await res.json() + setMyList(data || []) + } catch (e) { + console.error(e) + } + setLoading(false) + } + + // 发布信息 + const handlePublish = async () => { + if (!formData.title) { + alert('请填写标题') + return + } + + try { + const token = localStorage.getItem('token') + const gradeNote = formData.isGraded ? '(评级币)' : '(裸钞)' + + let priceContent = '' + if (formData.prices && Object.keys(formData.prices).length > 0) { + priceContent = '\n价格:' + const priceLabels = { + price_4: '带4', + price_no4: '无4', + price_no47: '无47', + price_no347: '无347', + price_no1347: '无1347', + price_no247: '无247', + price_no1247: '无1247', + price_no12347: '无12347' + } + Object.entries(formData.prices).forEach(([key, value]) => { + if (value) { + priceContent += `${priceLabels[key] || key}:¥${value} ` + } + }) + } + + const res = await fetch(`${API_BASE}/api/information/publish`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + title: formData.title, + content: formData.content + priceContent, + info_type: formData.category === '成交' ? 'deal' : 'seek' + }) + }) + + const data = await res.json() + if (data.id || data.code === 0) { + alert('发布成功!') + setShowPublish(false) + setFormData({ + edition: '龙钞', + type: '标百', + isGraded: true, + category: '成交', + source: '直播', + prices: {}, + title: '', + content: '' + }) + fetchMyList() + } else { + alert(data.message || '发布失败') + } + } catch (e) { + alert('发布失败: ' + e.message) + } + } + + // Tab切换 + const tabs = [ + { key: 'publish', label: '📝 发布行情' }, + { key: 'manage', label: '📋 发布管理' } + ] + + // 按钮选择组件 + const ButtonGroup = ({ options, value, onChange, label }) => ( +
+ {label && } +
+ {options.map(opt => ( + + ))} +
+
+ ) + + // 价格网格 + const PriceGrid = () => { + const priceItems = [ + { key: 'price_4', label: '带4' }, + { key: 'price_no4', label: '无4' }, + { key: 'price_no47', label: '无47' }, + { key: 'price_no347', label: '无347' }, + { key: 'price_no1347', label: '无1347' }, + { key: 'price_no247', label: '无247' }, + { key: 'price_no1247', label: '无1247' }, + { key: 'price_no12347', label: '无12347' } + ] + + return ( +
+ +
+ {priceItems.map(item => ( +
+ + setFormData({ + ...formData, + prices: {...formData.prices, [item.key]: e.target.value} + })} + placeholder="¥" + style={{ + width: '100%', + padding: '8px', + background: '#0f172a', + border: '1px solid #334155', + borderRadius: '4px', + color: '#fff', + boxSizing: 'border-box', + fontSize: '13px' + }} + /> +
+ ))} +
+
+ ) + } + + const formatDate = (dateStr) => { + if (!dateStr) return '-' + const date = new Date(dateStr) + return `${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}` + } + + return ( +
+ {/* Tab导航 */} +
+ {tabs.map(tab => ( +
setActiveTab(tab.key)} + style={{ + padding: '10px 20px', + borderRadius: '8px', + background: activeTab === tab.key ? '#3b82f6' : 'transparent', + color: '#fff', + cursor: 'pointer', + whiteSpace: 'nowrap', + fontSize: '14px' + }} + > + {tab.label} +
+ ))} +
+ + {/* 发布行情 */} + {activeTab === 'publish' && ( +
+
+ +
+ + {showPublish && ( +
+

📝 发布行情信息

+ + setFormData({...formData, edition: v})} /> + +
+
+
+ +
+ {['标百', '标十', '单张'].map(t => ( + + ))} +
+
+
+ + +
+
+
+ + setFormData({...formData, category: v})} /> + + setFormData({...formData, source: v})} /> + + + +
+ + +
+ +
+ +