jiachenlong/frontend/src/pages/Info.jsx

249 lines
16 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 Info() {
const [activeTab, setActiveTab] = useState('publish')
const [showPublish, setShowPublish] = useState(false)
const [myList, setMyList] = useState([])
const [loading, setLoading] = useState(false)
const [editingItem, setEditingItem] = useState(null)
const [formData, setFormData] = useState({
edition: '龙钞', type: '标百', isGraded: true, category: '成交', source: '直播', title: '', content: ''
})
useEffect(() => {
if (activeTab === 'manage') fetchMyList()
}, [activeTab])
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') || ''
const fetchMyList = async () => {
setLoading(true)
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/my/list`, { headers: { Authorization: `Bearer ${token}` } })
setMyList(res.ok ? await res.json() : [])
} catch (e) { console.error(e) }
setLoading(false)
}
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({ title: formData.title, content: formData.content, 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: '直播', title: '', content: '' })
fetchMyList()
} else { alert(data.message || '发布失败') }
} catch (e) { alert('发布失败: ' + e.message) }
}
const handleDelete = async (id) => {
if (!confirm('确定删除这条信息吗?')) return
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } })
if (res.ok) { alert('删除成功'); fetchMyList() } else { alert('删除失败') }
} catch (e) { alert('删除失败: ' + e.message) }
}
const handleEdit = (item) => setEditingItem({ id: item.id, title: item.title, content: item.content })
const handleSaveEdit = async () => {
if (!editingItem) return
try {
const token = localStorage.getItem('token')
const res = await fetch(`${API_BASE}/api/information/${editingItem.id}`, {
method: 'PUT', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ title: editingItem.title, content: editingItem.content })
})
if (res.ok) { alert('保存成功'); setEditingItem(null); fetchMyList() } else { alert('保存失败') }
} catch (e) { alert('保存失败: ' + e.message) }
}
const BtnGroup = ({ options, value, onChange, label }) => (
<div style={{ marginBottom: '16px' }}>
<div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '8px', fontWeight: '500' }}>{label}</div>
<div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
{options.map(opt => (
<button key={opt.value} onClick={() => onChange(opt.value)}
style={{ padding: '10px 16px', borderRadius: '8px', border: value === opt.value ? '2px solid #10b981' : '1px solid #374151',
background: value === opt.value ? 'rgba(16,185,129,0.15)' : '#1f2937', color: value === opt.value ? '#10b981' : '#d1d5db',
cursor: 'pointer', fontSize: '13px', fontWeight: '500', transition: 'all 0.2s' }}>
{opt.label}
</button>
))}
</div>
</div>
)
const Card = ({ children, title, action }) => (
<div style={{ background: 'linear-gradient(145deg, #1f2937 0%, #111827 100%)', borderRadius: '16px', padding: '20px', marginBottom: '16px', border: '1px solid #374151', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }}>
{title && <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
<h3 style={{ color: '#f9fafb', margin: 0, fontSize: '16px', fontWeight: '600' }}>{title}</h3>
{action}
</div>}
{children}
</div>
)
const formatDate = (d) => d ? new Date(d).toLocaleString('zh-CN').slice(0, 16) : '-'
return (
<div style={{ minHeight: '100vh', background: 'linear-gradient(180deg, #0f172a 0%, #1e293b 100%)', paddingBottom: '80px' }}>
{/* 顶部标签 */}
<div style={{ position: 'sticky', top: 0, background: 'rgba(15,23,42,0.95)', backdropFilter: 'blur(10px)', padding: '16px 20px', borderBottom: '1px solid #1e293b', zIndex: 100 }}>
<div style={{ display: 'flex', gap: '8px', background: '#1e293b', borderRadius: '12px', padding: '4px' }}>
{[{ key: 'publish', label: '📝 发布行情', icon: '📝' }, { key: 'manage', label: '📋 发布管理', icon: '📋' }].map(t => (
<div key={t.key} onClick={() => setActiveTab(t.key)}
style={{ flex: 1, padding: '12px 16px', borderRadius: '10px', background: activeTab === t.key ? 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)' : 'transparent',
color: activeTab === t.key ? '#fff' : '#9ca3af', cursor: 'pointer', textAlign: 'center', fontSize: '14px', fontWeight: '600', transition: 'all 0.3s', boxShadow: activeTab === t.key ? '0 2px 10px rgba(59,130,246,0.4)' : 'none' }}>
{t.label}
</div>
))}
</div>
</div>
<div style={{ padding: '20px' }}>
{activeTab === 'publish' && (
<div>
{/* 新增按钮 */}
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '20px' }}>
<button onClick={() => setShowPublish(!showPublish)}
style={{ background: showPublish ? 'linear-gradient(135deg, #6b7280 0%, #4b5563 100%)' : 'linear-gradient(135deg, #10b981 0%, #059669 100%)',
color: '#fff', border: 'none', padding: '12px 24px', borderRadius: '10px', cursor: 'pointer', fontSize: '14px', fontWeight: '600', boxShadow: '0 4px 15px rgba(16,185,129,0.3)', transition: 'all 0.3s' }}>
{showPublish ? '✕ 收起表单' : '+ 新增发布'}
</button>
</div>
{showPublish && (
<Card title="📝 发布行情信息">
<BtnGroup label="版别" options={[
{ value: '龙钞', label: '🐉 龙钞' }, { value: '马钞', label: '🐎 马钞' }, { value: '蛇钞', label: '🐍 蛇钞' }, { value: '其他', label: '📄 其他' }
]} value={formData.edition} onChange={v => setFormData({...formData, edition: v})} />
<div style={{ display: 'flex', gap: '12px', marginBottom: '16px' }}>
<div style={{ flex: 2 }}>
<div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '8px', fontWeight: '500' }}>类型</div>
<div style={{ display: 'flex', gap: '6px' }}>
{['标百', '标十', '单张'].map(t => (
<button key={t} onClick={() => setFormData({...formData, type: t})}
style={{ flex: 1, padding: '10px', borderRadius: '8px', border: formData.type === t ? '2px solid #10b981' : '1px solid #374151',
background: formData.type === t ? 'rgba(16,185,129,0.15)' : '#1f2937', color: formData.type === t ? '#10b981' : '#d1d5db', cursor: 'pointer', fontSize: '13px' }}>{t}</button>
))}
</div>
</div>
<div style={{ flex: 1 }}>
<div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '8px', fontWeight: '500' }}>是否评级</div>
<button onClick={() => setFormData({...formData, isGraded: !formData.isGraded})}
style={{ width: '100%', padding: '10px', borderRadius: '8px', border: formData.isGraded ? '2px solid #10b981' : '1px solid #374151',
background: formData.isGraded ? 'rgba(16,185,129,0.15)' : '#1f2937', color: formData.isGraded ? '#10b981' : '#d1d5db', cursor: 'pointer', fontSize: '13px' }}>
{formData.isGraded ? '✓ 评级币' : '○ 裸钞'}
</button>
</div>
</div>
<BtnGroup label="分类" options={[
{ value: '成交', label: '💰 成交' }, { value: '求购', label: '🔍 求购' }, { value: '出售', label: '💵 出售' }
]} value={formData.category} onChange={v => setFormData({...formData, category: v})} />
<BtnGroup label="信息来源" options={[
{ value: '直播', label: '📺 直播' }, { value: '一尘', label: '💼 一尘' }, { value: '爱藏', label: '📦 爱藏' }, { value: '其他', label: '📋 其他' }
]} value={formData.source} onChange={v => setFormData({...formData, source: v})} />
<div style={{ marginBottom: '16px' }}>
<div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '8px', fontWeight: '500' }}>标题自动生成</div>
<input type="text" value={formData.title} readOnly
style={{ width: '100%', padding: '14px', background: '#0f172a', border: '1px solid #374151', borderRadius: '10px', color: '#10b981', fontSize: '14px', boxSizing: 'border-box' }} />
</div>
<div style={{ marginBottom: '20px' }}>
<div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '8px', fontWeight: '500' }}>正文内容</div>
<textarea value={formData.content} onChange={(e) => setFormData({...formData, content: e.target.value})} placeholder="请输入详细信息..." rows={4}
style={{ width: '100%', padding: '14px', background: '#0f172a', border: '1px solid #374151', borderRadius: '10px', color: '#fff', resize: 'vertical', boxSizing: 'border-box', fontSize: '14px' }} />
</div>
<button onClick={handlePublish}
style={{ width: '100%', padding: '16px', background: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', border: 'none', borderRadius: '12px', color: '#fff', fontSize: '16px', fontWeight: 'bold', cursor: 'pointer', boxShadow: '0 4px 15px rgba(245,158,11,0.3)', transition: 'transform 0.2s' }}>
🚀 提交发布
</button>
</Card>
)}
</div>
)}
{activeTab === 'manage' && (
<div>
<Card title="📋 我的发布">
{loading ? (
<div style={{ color: '#9ca3af', textAlign: 'center', padding: '30px' }}> 加载中...</div>
) : myList.length === 0 ? (
<div style={{ color: '#9ca3af', textAlign: 'center', padding: '30px', fontSize: '14px' }}>暂无发布记录</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
{myList.map(item => (
<div key={item.id} style={{ background: '#0f172a', borderRadius: '12px', padding: '16px', border: '1px solid #374151' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '8px' }}>
<div style={{ color: '#10b981', fontSize: '15px', fontWeight: '600', flex: 1 }}>{item.title}</div>
<span style={{ background: item.info_type === 'deal' ? 'rgba(16,185,129,0.2)' : 'rgba(59,130,246,0.2)', color: item.info_type === 'deal' ? '#10b981' : '#3b82f6', padding: '4px 10px', borderRadius: '20px', fontSize: '12px' }}>
{item.info_type === 'deal' ? '💰 成交' : '🔍 求购'}
</span>
</div>
{item.content && <div style={{ color: '#9ca3af', fontSize: '13px', marginBottom: '12px', lineHeight: '1.5' }}>{item.content}</div>}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div style={{ color: '#6b7280', fontSize: '12px' }}>{formatDate(item.created_at)}</div>
<div style={{ display: 'flex', gap: '8px' }}>
<button onClick={() => handleEdit(item)} style={{ padding: '8px 16px', borderRadius: '8px', border: '1px solid #3b82f6', background: 'transparent', color: '#3b82f6', cursor: 'pointer', fontSize: '13px' }}> 编辑</button>
<button onClick={() => handleDelete(item.id)} style={{ padding: '8px 16px', borderRadius: '8px', border: '1px solid #ef4444', background: 'transparent', color: '#ef4444', cursor: 'pointer', fontSize: '13px' }}>🗑 删除</button>
</div>
</div>
</div>
))}
</div>
)}
</Card>
</div>
)}
</div>
{/* 编辑弹窗 */}
{editingItem && (
<div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.8)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, padding: '20px', backdropFilter: 'blur(5px)' }}>
<div style={{ background: '#1f2937', borderRadius: '16px', padding: '24px', width: '100%', maxWidth: '420px', border: '1px solid #374151', boxShadow: '0 20px 40px rgba(0,0,0,0.5)' }}>
<h3 style={{ color: '#f9fafb', marginBottom: '20px', fontSize: '18px', fontWeight: '600' }}> 编辑信息</h3>
<div style={{ marginBottom: '16px' }}>
<label style={{ color: '#9ca3af', fontSize: '13px', display: 'block', marginBottom: '8px' }}>标题</label>
<input value={editingItem.title} onChange={(e) => setEditingItem({...editingItem, title: e.target.value})}
style={{ width: '100%', padding: '14px', background: '#0f172a', border: '1px solid #374151', borderRadius: '10px', color: '#fff', boxSizing: 'border-box', fontSize: '14px' }} />
</div>
<div style={{ marginBottom: '20px' }}>
<label style={{ color: '#9ca3af', fontSize: '13px', display: 'block', marginBottom: '8px' }}>内容</label>
<textarea value={editingItem.content} onChange={(e) => setEditingItem({...editingItem, content: e.target.value})}
rows={5} style={{ width: '100%', padding: '14px', background: '#0f172a', border: '1px solid #374151', borderRadius: '10px', color: '#fff', boxSizing: 'border-box', fontSize: '14px', resize: 'vertical' }} />
</div>
<div style={{ display: 'flex', gap: '12px' }}>
<button onClick={handleSaveEdit} style={{ flex: 1, padding: '14px', background: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)', border: 'none', borderRadius: '10px', color: '#fff', cursor: 'pointer', fontSize: '14px', fontWeight: '600' }}>💾 保存</button>
<button onClick={() => setEditingItem(null)} style={{ flex: 1, padding: '14px', border: '1px solid #374151', borderRadius: '10px', background: 'transparent', color: '#9ca3af', cursor: 'pointer', fontSize: '14px' }}>取消</button>
</div>
</div>
</div>
)}
</div>
)
}