feat: 资讯页面和发布页面分离,添加信息发布管理功能

This commit is contained in:
甲辰生产 2026-03-26 15:32:27 +08:00
parent 80effaaa29
commit 66c086e35d
4 changed files with 433 additions and 648 deletions

View File

@ -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]
}

View File

@ -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 <Home />
if (basePath === '/news') return <News />
if (basePath === '/info') return <Info />
if (basePath === '/stats') return <Stats />
if (basePath === '/list') return <List />
if (basePath === '/add') return <Add />
@ -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 => (
<div

352
frontend/src/pages/Info.jsx Normal file
View File

@ -0,0 +1,352 @@
import React, { useState, useEffect } from 'react'
// - /
export default function Info() {
const [activeTab, setActiveTab] = useState('publish')
const [showPublish, setShowPublish] = useState(false)
const [myList, setMyList] = useState([])
const [loading, setLoading] = useState(false)
//
const [formData, setFormData] = useState({
edition: '龙钞',
type: '标百',
isGraded: true,
category: '成交',
source: '直播',
prices: {},
title: '',
content: ''
})
//
useEffect(() => {
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 }) => (
<div style={{ marginBottom: '14px' }}>
{label && <label style={{ color: '#94a3b8', fontSize: '12px', display: 'block', marginBottom: '6px' }}>{label}</label>}
<div style={{ display: 'flex', gap: '8px' }}>
{options.map(opt => (
<button
key={opt.value}
onClick={() => onChange(opt.value)}
style={{
flex: 1,
padding: '10px',
borderRadius: '6px',
border: value === opt.value ? '2px solid #fbbf24' : '1px solid #334155',
background: value === opt.value ? 'rgba(251,191,36,0.2)' : '#0f172a',
color: '#fff',
cursor: 'pointer',
fontSize: '14px'
}}
>
{opt.label}
</button>
))}
</div>
</div>
)
//
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 (
<div style={{ marginBottom: '14px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px', display: 'block', marginBottom: '6px' }}>价格可选</label>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '8px' }}>
{priceItems.map(item => (
<div key={item.key}>
<label style={{ color: '#64748b', fontSize: '11px' }}>{item.label}</label>
<input
type="number"
value={formData.prices?.[item.key] || ''}
onChange={(e) => 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'
}}
/>
</div>
))}
</div>
</div>
)
}
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 (
<div style={{ minHeight: '100vh', background: '#0f172a', paddingBottom: '60px' }}>
{/* Tab导航 */}
<div style={{ display: 'flex', padding: '12px 16px', background: '#1e293b', gap: '8px', overflowX: 'auto' }}>
{tabs.map(tab => (
<div
key={tab.key}
onClick={() => 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}
</div>
))}
</div>
{/* 发布行情 */}
{activeTab === 'publish' && (
<div style={{ padding: '16px' }}>
<div style={{ marginBottom: '16px', textAlign: 'right' }}>
<button
onClick={() => setShowPublish(!showPublish)}
style={{
background: '#3b82f6',
color: '#fff',
border: 'none',
padding: '10px 20px',
borderRadius: '8px',
cursor: 'pointer',
fontSize: '14px'
}}
>
{showPublish ? '❌ 取消' : ' 新增发布'}
</button>
</div>
{showPublish && (
<div style={{ background: '#1e293b', borderRadius: '12px', padding: '16px', marginBottom: '16px' }}>
<h3 style={{ color: '#fbbf24', marginTop: 0, marginBottom: '16px' }}>📝 发布行情信息</h3>
<ButtonGroup label="版别 *" options={[
{ value: '龙钞', label: '🐉 龙钞' },
{ value: '马钞', label: '🐎 马钞' },
{ value: '蛇钞', label: '🐍 蛇钞' },
{ value: '其他', label: '📄 其他' }
]} value={formData.edition} onChange={(v) => setFormData({...formData, edition: v})} />
<div style={{ marginBottom: '14px' }}>
<div style={{ display: 'flex', gap: '12px' }}>
<div style={{ flex: 2 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>类型 *</label>
<div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>
{['标百', '标十', '单张'].map(t => (
<button key={t} onClick={() => setFormData({...formData, type: t})}
style={{ flex: 1, padding: '10px', borderRadius: '6px',
border: formData.type === t ? '2px solid #fbbf24' : '1px solid #334155',
background: formData.type === t ? 'rgba(251,191,36,0.2)' : '#0f172a',
color: '#fff', cursor: 'pointer', fontSize: '13px' }}>
{t}
</button>
))}
</div>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>是否评级</label>
<button onClick={() => setFormData({...formData, isGraded: !formData.isGraded})}
style={{ width: '100%', padding: '10px', marginTop: '6px', borderRadius: '6px',
border: formData.isGraded ? '2px solid #fbbf24' : '1px solid #334155',
background: formData.isGraded ? 'rgba(251,191,36,0.2)' : '#0f172a',
color: formData.isGraded ? '#fbbf24' : '#94a3b8', cursor: 'pointer', fontSize: '13px' }}>
{formData.isGraded ? '✅ 评级' : '○ 未评级'}
</button>
</div>
</div>
</div>
<ButtonGroup label="分类 *" options={[
{ value: '成交', label: '💰 成交' },
{ value: '求购', label: '🔍 求购' },
{ value: '出售', label: '💵 出售' }
]} value={formData.category} onChange={(v) => setFormData({...formData, category: v})} />
<ButtonGroup label="信息源 *" options={[
{ value: '直播', label: '📺 直播' },
{ value: '一尘', label: '💼 一尘' },
{ value: '爱藏', label: '📦 爱藏' },
{ value: '其他', label: '📋 其他' }
]} value={formData.source} onChange={(v) => setFormData({...formData, source: v})} />
<PriceGrid />
<div style={{ marginBottom: '14px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>标题自动生成</label>
<input type="text" value={formData.title} readOnly
style={{ width: '100%', padding: '10px', marginTop: '6px', background: '#0f172a',
border: '1px solid #334155', borderRadius: '6px', color: '#fbbf24', fontSize: '14px', boxSizing: 'border-box' }} />
</div>
<div style={{ marginBottom: '16px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>正文</label>
<textarea value={formData.content} onChange={(e) => setFormData({...formData, content: e.target.value})}
placeholder="请输入详细信息..." rows={4}
style={{ width: '100%', padding: '10px', marginTop: '6px', background: '#0f172a',
border: '1px solid #334155', borderRadius: '6px', color: '#fff', resize: 'vertical', boxSizing: 'border-box' }} />
</div>
<button onClick={handlePublish}
style={{ width: '100%', padding: '14px', background: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)',
border: 'none', borderRadius: '8px', color: '#fff', fontSize: '16px', fontWeight: 'bold', cursor: 'pointer' }}>
📤 提交发布
</button>
</div>
)}
</div>
)}
{/* 发布管理 */}
{activeTab === 'manage' && (
<div style={{ padding: '16px' }}>
<h3 style={{ color: '#fff', marginBottom: '16px' }}>📋 我的发布</h3>
{loading ? (
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '20px' }}>加载中...</div>
) : myList.length === 0 ? (
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '20px' }}>暂无发布记录</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
{myList.map(item => (
<div key={item.id} style={{ background: '#1e293b', borderRadius: '8px', padding: '12px' }}>
<div style={{ color: '#fbbf24', fontSize: '14px', marginBottom: '4px' }}>{item.title}</div>
<div style={{ color: '#94a3b8', fontSize: '12px' }}>{formatDate(item.created_at)} | {item.info_type === 'deal' ? '💰 成交' : '🔍 求购'}</div>
</div>
))}
</div>
)}
</div>
)}
</div>
)
}

View File

@ -1,47 +1,26 @@
import React, { useState, useEffect } from 'react'
// -
// -
export default function News() {
const [activeTab, setActiveTab] = useState('seek') // seek-, deal-, publish-
const [activeTab, setActiveTab] = useState('seek')
const [infoList, setInfoList] = useState([])
const [loading, setLoading] = useState(false)
const [showPublish, setShowPublish] = useState(false)
const [myList, setMyList] = useState([])
//
const [formData, setFormData] = useState({
info_type: 'seek',
title: '',
content: '',
collection_id: '',
expect_category: '',
expect_version: '',
expect_packaging: '',
expect_number: '',
expect_price_min: '',
expect_price_max: '',
deal_price: '',
deal_date: ''
})
//
const [myCollections, setMyCollections] = useState([])
const API_BASE = localStorage.getItem('API_BASE') || ''
//
useEffect(() => {
fetchInfoList()
fetchMyCollections()
fetchMyList()
}, [activeTab])
//
const fetchInfoList = async () => {
setLoading(true)
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/list?info_type=${activeTab}`, {
headers: { 'Authorization': `Bearer ${token}` }
// tab
const type = activeTab === 'seek' ? 'seek' : 'deal'
const res = await fetch(`${API_BASE}/api/information/list?info_type=${type}`, {
headers: { Authorization: `Bearer ${token}` }
})
const data = await res.json()
setInfoList(data || [])
@ -51,141 +30,34 @@ export default function News() {
setLoading(false)
}
//
const fetchMyCollections = async () => {
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/collections?page=1&page_size=100`, {
headers: { 'Authorization': `Bearer ${token}` }
})
const data = await res.json()
setMyCollections(data.items || [])
} catch (e) {
console.error(e)
}
}
// Tab
const tabs = [
{ key: 'seek', label: '🔍 寻配号' },
{ key: 'deal', label: '💰 成交行情' }
]
//
const fetchMyList = async () => {
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/my/list`, {
headers: { 'Authorization': `Bearer ${token}` }
})
const data = await res.json()
setMyList(data || [])
} catch (e) {
console.error(e)
}
}
//
const handlePublish = async () => {
if (!formData.title) {
alert('请输入标题')
return
}
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
...formData,
expect_price_min: formData.expect_price_min ? parseFloat(formData.expect_price_min) : null,
expect_price_max: formData.expect_price_max ? parseFloat(formData.expect_price_max) : null,
deal_price: formData.deal_price ? parseFloat(formData.deal_price) : null,
})
})
if (res.ok) {
alert('发布成功!')
setShowPublish(false)
setFormData({
info_type: 'seek',
title: '',
content: '',
collection_id: '',
expect_category: '',
expect_version: '',
expect_packaging: '',
expect_number: '',
expect_price_min: '',
expect_price_max: '',
deal_price: '',
deal_date: ''
})
fetchInfoList()
fetchMyList()
}
} catch (e) {
alert('发布失败')
}
}
//
const handleDelete = async (id) => {
if (!confirm('确定删除?')) return
try {
const token = localStorage.getItem('token')
await fetch(`${API_BASE}/api/information/${id}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
})
fetchMyList()
} catch (e) {
console.error(e)
}
}
//
const formatDate = (dateStr) => {
if (!dateStr) return ''
return new Date(dateStr).toLocaleDateString('zh-CN')
}
//
const typeMap = {
seek: '寻配号',
deal: '成交数据',
publish: '发布'
if (!dateStr) return '-'
const date = new Date(dateStr)
return `${date.getMonth() + 1}/${date.getDate()}`
}
return (
<div style={{ padding: '16px', paddingBottom: '80px', minHeight: '100vh', background: '#0f172a' }}>
{/* 顶部标题 */}
<div style={{ textAlign: 'center', marginBottom: '16px' }}>
<h1 style={{ fontSize: '20px', color: '#fbbf24', margin: 0 }}>📰 资讯中心</h1>
</div>
{/* 二级标签切换 */}
<div style={{
display: 'flex',
background: '#1e293b',
borderRadius: '8px',
padding: '4px',
marginBottom: '16px'
}}>
{[
{ key: 'seek', label: '🔍 寻配号' },
{ key: 'deal', label: '📈 成交数据' },
{ key: 'publish', label: ' 发布' }
].map(tab => (
<div style={{ minHeight: '100vh', background: '#0f172a', paddingBottom: '60px' }}>
{/* Tab导航 */}
<div style={{ display: 'flex', padding: '12px 16px', background: '#1e293b', gap: '8px', overflowX: 'auto' }}>
{tabs.map(tab => (
<div
key={tab.key}
onClick={() => setActiveTab(tab.key)}
style={{
flex: 1,
textAlign: 'center',
padding: '10px',
borderRadius: '6px',
cursor: 'pointer',
padding: '10px 20px',
borderRadius: '8px',
background: activeTab === tab.key ? '#3b82f6' : 'transparent',
color: activeTab === tab.key ? '#fff' : '#94a3b8',
fontSize: '14px',
fontWeight: activeTab === tab.key ? 'bold' : 'normal'
color: '#fff',
cursor: 'pointer',
whiteSpace: 'nowrap',
fontSize: '14px'
}}
>
{tab.label}
@ -193,508 +65,38 @@ export default function News() {
))}
</div>
{/* 发布按钮 */}
{activeTab !== 'publish' && (
<div style={{ marginBottom: '16px', textAlign: 'right' }}>
<button
onClick={() => setShowPublish(!showPublish)}
style={{
background: '#3b82f6',
color: '#fff',
border: 'none',
padding: '8px 16px',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '14px'
}}
>
{showPublish ? '取消发布' : ' 发布'}
</button>
</div>
)}
{/* 发布表单 */}
{showPublish && (
<div style={{
background: '#1e293b',
borderRadius: '12px',
padding: '16px',
marginBottom: '16px'
}}>
<h3 style={{ color: '#fbbf24', marginTop: 0 }}>发布信息</h3>
{/* 选择类型 */}
<div style={{ marginBottom: '12px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>类型</label>
<select
value={formData.info_type}
onChange={(e) => setFormData({...formData, info_type: e.target.value})}
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px'
}}
>
<option value="seek">🔍 寻配号</option>
<option value="deal">📈 成交数据</option>
<option value="publish">📝 普通发布</option>
</select>
</div>
{/* 标题 */}
<div style={{ marginBottom: '12px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>标题 *</label>
<input
type="text"
value={formData.title}
onChange={(e) => setFormData({...formData, title: e.target.value})}
placeholder="请输入标题"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
{/* 内容 */}
<div style={{ marginBottom: '12px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>详细描述</label>
<textarea
value={formData.content}
onChange={(e) => setFormData({...formData, content: e.target.value})}
placeholder="请输入详细描述..."
rows={3}
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box',
resize: 'vertical'
}}
/>
</div>
{/* 关联藏品 */}
{formData.info_type === 'seek' && (
<div style={{ marginBottom: '12px' }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>关联我的藏品可选</label>
<select
value={formData.collection_id}
onChange={(e) => setFormData({...formData, collection_id: e.target.value})}
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px'
}}
>
<option value="">不关联</option>
{myCollections.map(c => (
<option key={c.f99_90_id} value={c.f99_90_id}>
{c.f01_01_name} - {c.f01_03_category}
</option>
))}
</select>
</div>
)}
{/* 寻配号条件 */}
{formData.info_type === 'seek' && (
<>
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>期望类别</label>
<input
type="text"
value={formData.expect_category}
onChange={(e) => setFormData({...formData, expect_category: e.target.value})}
placeholder="如:纪念钞"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>期望版别</label>
<input
type="text"
value={formData.expect_version}
onChange={(e) => setFormData({...formData, expect_version: e.target.value})}
placeholder="如2024版"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
</div>
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>期望包装</label>
<input
type="text"
value={formData.expect_packaging}
onChange={(e) => setFormData({...formData, expect_packaging: e.target.value})}
placeholder="如:散钞"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>期望号码</label>
<input
type="text"
value={formData.expect_number}
onChange={(e) => setFormData({...formData, expect_number: e.target.value})}
placeholder="如888"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
</div>
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>最低价格</label>
<input
type="number"
value={formData.expect_price_min}
onChange={(e) => setFormData({...formData, expect_price_min: e.target.value})}
placeholder="0"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>最高价格</label>
<input
type="number"
value={formData.expect_price_max}
onChange={(e) => setFormData({...formData, expect_price_max: e.target.value})}
placeholder="0"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
</div>
</>
)}
{/* 成交数据 */}
{formData.info_type === 'deal' && (
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>成交价格</label>
<input
type="number"
value={formData.deal_price}
onChange={(e) => setFormData({...formData, deal_price: e.target.value})}
placeholder="成交金额"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>版别</label>
<input
type="text"
value={formData.expect_version}
onChange={(e) => setFormData({...formData, expect_version: e.target.value})}
placeholder="如2024版"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
<div style={{ flex: 1 }}>
<label style={{ color: '#94a3b8', fontSize: '12px' }}>包装</label>
<input
type="text"
value={formData.expect_packaging}
onChange={(e) => setFormData({...formData, expect_packaging: e.target.value})}
placeholder="如:标十"
style={{
width: '100%',
padding: '10px',
background: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#fff',
marginTop: '4px',
boxSizing: 'border-box'
}}
/>
</div>
</div>
)}
<button
onClick={handlePublish}
style={{
width: '100%',
padding: '12px',
background: '#3b82f6',
color: '#fff',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '16px',
fontWeight: 'bold'
}}
>
发布
</button>
</div>
)}
{/* 资讯列表 */}
{activeTab === 'publish' ? (
//
<div>
<h3 style={{ color: '#fbbf24', marginBottom: '12px' }}>我的发布</h3>
<div style={{ padding: '16px' }}>
<h3 style={{ color: '#fff', marginBottom: '16px' }}>
{activeTab === 'seek' ? '🔍 寻配号信息' : '💰 成交行情信息'}
</h3>
{loading ? (
<div style={{ textAlign: 'center', color: '#94a3b8', padding: '20px' }}>加载中...</div>
) : myList.length === 0 ? (
<div style={{ textAlign: 'center', color: '#94a3b8', padding: '20px' }}>暂无发布</div>
) : (
myList.map(item => (
<div key={item.id} style={{
background: '#1e293b',
borderRadius: '12px',
padding: '16px',
marginBottom: '12px'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{
background: item.info_type === 'seek' ? '#3b82f6' : item.info_type === 'deal' ? '#10b981' : '#f59e0b',
color: '#fff',
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px'
}}>
{typeMap[item.info_type]}
</span>
<button
onClick={() => handleDelete(item.id)}
style={{
background: '#ef4444',
color: '#fff',
border: 'none',
padding: '4px 8px',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px'
}}
>
删除
</button>
</div>
<h4 style={{ color: '#fff', margin: '8px 0' }}>{item.title}</h4>
<p style={{ color: '#94a3b8', fontSize: '13px', margin: 0 }}>{item.content}</p>
<div style={{ color: '#64748b', fontSize: '12px', marginTop: '8px' }}>
{formatDate(item.created_at)} · 浏览 {item.view_count} · 联系 {item.contact_count}
</div>
</div>
))
)}
</div>
) : (
// /
<div>
{loading ? (
<div style={{ textAlign: 'center', color: '#94a3b8', padding: '20px' }}>加载中...</div>
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '40px' }}>加载中...</div>
) : infoList.length === 0 ? (
<div style={{ textAlign: 'center', color: '#94a3b8', padding: '20px' }}>
暂无{activeTab === 'seek' ? '寻配号' : '成交数据'}信息
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '40px' }}>
暂无{activeTab === 'seek' ? '寻配号' : '成交行情'}信息
</div>
) : (
infoList.map(item => (
<div key={item.id} style={{
background: '#1e293b',
borderRadius: '12px',
padding: '16px',
marginBottom: '12px'
}}>
{/* 用户信息 */}
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '8px' }}>
<div style={{
width: '32px',
height: '32px',
borderRadius: '50%',
background: '#3b82f6',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: '14px',
marginRight: '8px'
}}>
{item.user_name ? item.user_name[0] : '?'}
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
{infoList.map(item => (
<div key={item.id} style={{ background: '#1e293b', borderRadius: '12px', padding: '16px' }}>
<div style={{ color: '#fbbf24', fontSize: '15px', fontWeight: '500', marginBottom: '8px' }}>
{item.title}
</div>
<span style={{ color: '#94a3b8', fontSize: '13px' }}>{item.user_name}</span>
<span style={{ color: '#64748b', fontSize: '12px', marginLeft: 'auto' }}>
{formatDate(item.created_at)}
</span>
<div style={{ color: '#94a3b8', fontSize: '12px', marginBottom: '8px' }}>
{formatDate(item.created_at)} | {item.info_source || '系统'}
</div>
{/* 标题 */}
<h4 style={{ color: '#fff', margin: '0 0 8px 0', fontSize: '16px' }}>{item.title}</h4>
{/* 内容 */}
{item.content && (
<p style={{ color: '#94a3b8', fontSize: '14px', margin: '0 0 8px 0' }}>{item.content}</p>
)}
{/* 寻配号条件 */}
{item.info_type === 'seek' && (item.expect_category || item.expect_version || item.expect_number) && (
<div style={{
background: '#0f172a',
borderRadius: '8px',
padding: '12px',
marginBottom: '8px'
}}>
<div style={{ color: '#fbbf24', fontSize: '12px', marginBottom: '4px' }}>期望条件</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{item.expect_category && (
<span style={{ color: '#94a3b8', fontSize: '12px' }}>类别: {item.expect_category}</span>
)}
{item.expect_version && (
<span style={{ color: '#94a3b8', fontSize: '12px' }}>版别: {item.expect_version}</span>
)}
{item.expect_packaging && (
<span style={{ color: '#94a3b8', fontSize: '12px' }}>包装: {item.expect_packaging}</span>
)}
{item.expect_number && (
<span style={{ color: '#94a3b8', fontSize: '12px' }}>号码: {item.expect_number}</span>
)}
{(item.expect_price_min || item.expect_price_max) && (
<span style={{ color: '#94a3b8', fontSize: '12px' }}>
价格: {item.expect_price_min || '?'} - {item.expect_price_max || '?'}
</span>
)}
</div>
<div style={{ color: '#e2e8f0', fontSize: '14px', lineHeight: '1.6' }}>
{item.content}
</div>
)}
{/* 成交数据 */}
{item.info_type === 'deal' && (
<div style={{
background: '#0f172a',
borderRadius: '8px',
padding: '12px',
marginBottom: '8px'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ color: '#10b981', fontSize: '18px', fontWeight: 'bold' }}>
¥{item.deal_price || '-'}
</span>
<span style={{ color: '#64748b', fontSize: '12px' }}>
{item.expect_version} / {item.expect_packaging}
</span>
</div>
))}
</div>
)}
{/* 关联藏品 */}
{item.collection_name && (
<div style={{
background: '#3b82f620',
borderRadius: '8px',
padding: '8px 12px',
marginBottom: '8px',
borderLeft: '3px solid #3b82f6'
}}>
<span style={{ color: '#3b82f6', fontSize: '12px' }}>关联藏品: </span>
<span style={{ color: '#fff', fontSize: '13px' }}>{item.collection_name}</span>
</div>
)}
{/* 统计 */}
<div style={{ display: 'flex', gap: '16px', color: '#64748b', fontSize: '12px' }}>
<span>👁 {item.view_count}</span>
<span>📞 {item.contact_count}</span>
</div>
</div>
))
)}
</div>
)}
</div>
)
}