353 lines
13 KiB
React
353 lines
13 KiB
React
|
|
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>
|
|||
|
|
)
|
|||
|
|
}
|