jiachenlong/frontend/src/pages/News.jsx

234 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react'
// 资讯页面 - 展示寻配号和行情信息(所有人可见)
export default function News() {
const [activeTab, setActiveTab] = useState('deal')
const [showSeekPublish, setShowSeekPublish] = useState(false)
const [seekForm, setSeekForm] = useState({
edition: '龙钞', type: '标百', category: '寻号', price: '', matchType: '模糊', features: 'J0', content: '', title: '', contact: ''
})
const [infoList, setInfoList] = useState([])
const [loading, setLoading] = useState(false)
const API_BASE = localStorage.getItem('API_BASE') || ''
// 获取资讯列表
useEffect(() => {
fetchInfoList()
}, [activeTab])
// 自动生成寻号标题
useEffect(() => {
const title = `「寻号 ${seekForm.edition || '龙钞,马钞,蛇钞'} ${seekForm.type} ${seekForm.features || 'J0'} ${seekForm.matchType}`
setSeekForm(prev => ({...prev, title}))
}, [seekForm.edition, seekForm.type, seekForm.features, seekForm.matchType])
const fetchInfoList = async () => {
setLoading(true)
try {
const token = localStorage.getItem('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 || [])
} catch (e) {
console.error(e)
}
setLoading(false)
}
const handleSeekPublish = async () => {
if (!seekForm.contact) { alert('请填写联系方式'); return }
try {
const token = localStorage.getItem('token')
const content = (seekForm.content ? seekForm.content + '\n' : '') + (seekForm.price ? `价格: ${seekForm.price}` : '') + (seekForm.features ? '\n号码特征: ' + seekForm.features : '') + '\n联系方式: ' + seekForm.contact
const res = await fetch(`${API_BASE}/api/information/`, {
method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ title: seekForm.title, content, info_type: 'seek' })
})
const data = await res.json()
if (data.id || data.code === 0) {
alert('发布成功!')
setShowSeekPublish(false)
setSeekForm({ edition: '龙钞', type: '标百', category: '寻号', price: '', matchType: '模糊', features: 'J0', content: '', title: '', contact: '' })
fetchInfoList()
} else { alert(data.message || '发布失败') }
} catch (e) { alert('发布失败: ' + e.message) }
}
// Tab切换
const tabs = [
{ key: 'seek', label: '🔍 寻配号' },
{ key: 'deal', label: '💰 成交行情' }
]
const formatDate = (dateStr) => {
if (!dateStr) return '-'
const date = new Date(dateStr)
return `${date.getMonth() + 1}/${date.getDate()}`
}
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>
{/* 资讯列表 */}
<div style={{ padding: '16px' }}>
{showSeekPublish && activeTab === 'seek' && (
<div style={{ background: '#1e293b', borderRadius: '12px', padding: '16px', marginBottom: '16px' }}>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>版别</label>
<div style={{ display: 'flex', gap: '8px', marginTop: '6px' }}>
{['龙钞','马钞','蛇钞'].map(item => {
const isSelected = seekForm.edition ? seekForm.edition.split(',').includes(item) : false
return (
<button key={item} onClick={() => {
const eds = seekForm.edition ? seekForm.edition.split(',').filter(x => x) : []
if (isSelected) {
const idx = eds.indexOf(item)
if (idx > -1) eds.splice(idx, 1)
} else {
eds.push(item)
}
setSeekForm({...seekForm, edition: eds.join(',')})
}}
style={{ flex: 1, padding: '8px', borderRadius: '6px', border: isSelected?'2px solid #10b981':'1px solid #334155', background: isSelected?'rgba(16,185,129,0.2)':'#0f172a', color: '#fff', fontSize: '12px' }}>{item}</button>
)
})}
</div>
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>类型</label>
<div style={{ display: 'flex', gap: '8px', marginTop: '6px' }}>
{['标百','标十','单张'].map(e => (
<button key={e} onClick={() => setSeekForm({...seekForm, type: e})}
style={{ flex: 1, padding: '8px', borderRadius: '6px', border: seekForm.type===e?'2px solid #10b981':'1px solid #334155', background: seekForm.type===e?'rgba(16,185,129,0.2)':'#0f172a', color: '#fff', fontSize: '12px' }}>{e}</button>
))}
</div>
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>分类</label>
<div style={{ display: 'flex', gap: '8px', marginTop: '6px' }}>
{['求购','出售','寻号'].map(e => (
<button key={e} onClick={() => setSeekForm({...seekForm, category: e})}
style={{ flex: 1, padding: '8px', borderRadius: '6px', border: seekForm.category===e?'2px solid #10b981':'1px solid #334155', background: seekForm.category===e?'rgba(16,185,129,0.2)':'#0f172a', color: '#fff', fontSize: '12px' }}>{e}</button>
))}
</div>
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>价格选填</label>
<input type="text" value={seekForm.price} onChange={(e) => setSeekForm({...seekForm, price: e.target.value})} placeholder="请输入价格"
style={{ width: '100%', padding: '8px', marginTop: '6px', background: '#0f172a', border: '1px solid #334155', borderRadius: '6px', color: '#fff', fontSize: '13px', boxSizing: 'border-box' }} />
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>匹配度</label>
<div style={{ display: 'flex', gap: '8px', marginTop: '6px' }}>
{['精准','模糊'].map(e => (
<button key={e} onClick={() => setSeekForm({...seekForm, matchType: e})}
style={{ flex: 1, padding: '8px', borderRadius: '6px', border: seekForm.matchType===e?'2px solid #10b981':'1px solid #334155', background: seekForm.matchType===e?'rgba(16,185,129,0.2)':'#0f172a', color: '#fff', fontSize: '12px' }}>{e}</button>
))}
</div>
</div>
<div style={{ marginBottom: '8px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>号码特征10</label>
<div style={{ display: 'flex', gap: '4px', marginTop: '6px', flexWrap: 'wrap' }}>
{[0,1,2,3,4,5,6,7,8,9].map(i => {
const isFixed = i < 2
const placeholder = isFixed ? (i === 0 ? 'J' : '0') : 'X'
return <input key={i} ref={el => { if (el) el.dataset.index = i }} type="text" maxLength={1}
value={isFixed ? placeholder : (seekForm.features?.[i] || '')}
readOnly={isFixed}
onChange={(e) => {
if (i < 2) return
const arr = (seekForm.features || 'J0XXXXXXXX').split('')
arr[i] = e.target.value.toUpperCase()
setSeekForm({...seekForm, features: arr.join('')})
// 输入后自动跳转下一个
if (e.target.value && i < 9) {
setTimeout(() => {
const nextInput = document.querySelector(`input[data-index="${i+1}"]`)
if (nextInput) nextInput.focus()
}, 0)
}
}}
placeholder={placeholder}
style={{ width: '32px', height: '36px', textAlign: 'center', padding: '6px', background: '#0f172a', border: '1px solid #334155', borderRadius: '4px', color: isFixed ? '#10b981' : '#fff', fontSize: '14px', boxSizing: 'border-box' }} />
})}
</div>
<div style={{ color: '#64748b', fontSize: '10px', marginTop: '6px' }}>X=任意数字 A=非4 B=非47 C=非347 D=非247 E=非2347 F=非12347 F=非23457 G=非123457</div>
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>正文</label>
<textarea value={seekForm.content || ''} onChange={(e) => setSeekForm({...seekForm, content: e.target.value})} placeholder="请输入详细信息..."
style={{ width: '100%', padding: '8px', marginTop: '6px', background: '#0f172a', border: '1px solid #334155', borderRadius: '6px', color: '#fff', fontSize: '13px', boxSizing: 'border-box', resize: 'vertical', minHeight: '60px' }} />
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#ef4444', fontSize: '12px' }}>联系方式 *</label>
<input type="text" value={seekForm.contact || ''} onChange={(e) => setSeekForm({...seekForm, contact: e.target.value})} placeholder="请输入手机号或微信"
style={{ width: '100%', padding: '8px', marginTop: '6px', background: '#0f172a', border: '1px solid #334155', borderRadius: '6px', color: '#fff', fontSize: '13px', boxSizing: 'border-box' }} />
</div>
<div style={{ marginBottom: '12px' }}><label style={{ color: '#94a3b8', fontSize: '12px' }}>标题自动生成</label>
<input type="text" value={seekForm.title} readOnly
style={{ width: '100%', padding: '8px', marginTop: '6px', background: '#0f172a', border: '1px solid #334155', borderRadius: '6px', color: '#fff', fontSize: '13px', boxSizing: 'border-box' }} onChange={(e) => setSeekForm({...seekForm, title: e.target.value})} />
</div>
<div style={{ display: 'flex', gap: '12px' }}>
<button onClick={handleSeekPublish} style={{ flex: 1, padding: '12px', background: '#10b981', border: 'none', borderRadius: '8px', color: '#fff', fontSize: '14px', fontWeight: 'bold', cursor: 'pointer' }}>发布寻号</button>
<button onClick={() => setShowSeekPublish(false)} style={{ flex: 1, padding: '12px', background: 'transparent', border: '1px solid #334155', borderRadius: '8px', color: '#94a3b8', fontSize: '14px', cursor: 'pointer' }}>取消</button>
</div>
</div>
)}
<h3 style={{ color: '#fff', marginBottom: '16px' }}>
{activeTab === 'seek' ? '🔍 寻配号信息' : '💰 成交行情信息'}
{activeTab === 'seek' && (
<div style={{ display: 'flex', gap: '8px', marginLeft: 'auto' }}>
<button onClick={() => setShowSeekPublish(!showSeekPublish)} style={{ padding: '6px 12px', background: showSeekPublish ? '#6b7280' : '#10b981', border: 'none', borderRadius: '6px', color: '#fff', fontSize: '12px', cursor: 'pointer' }}>
'+ 发布寻号'
</button>
</div>
)}
</h3>
{loading ? (
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '40px' }}>加载中...</div>
) : infoList.length === 0 ? (
<div style={{ color: '#94a3b8', textAlign: 'center', padding: '40px' }}>
暂无{activeTab === 'seek' ? '寻配号' : '成交行情'}信息
</div>
) : (
<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>
<div style={{ color: '#94a3b8', fontSize: '12px', marginBottom: '8px' }}>
{formatDate(item.created_at)} | {item.info_source || '系统'}
</div>
{item.content && (
<div style={{ color: '#e2e8f0', fontSize: '14px', lineHeight: '1.6' }}>
{item.content}
</div>
)}
</div>
))}
</div>
)}
</div>
</div>
)
}