You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
8.5 KiB

import React, { useState, useEffect } from 'react';
import { Card, Row, Col, Button, Input, Select, Table, Badge, Statistic, Typography, Spin } from 'antd';
import { ReloadOutlined, FilterOutlined, EyeOutlined, EyeInvisibleOutlined, ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
import { allFuturesData, aiAnalysis, marketHotspots, riskAlerts } from '../../utils/mockData';
import useTheme from '../../hooks/useTheme';
const { Title, Text } = Typography;
const { Search } = Input;
const { Option } = Select;
const { Column } = Table;
const Dashboard = () => {
const [futuresData, setFuturesData] = useState(allFuturesData);
const [filteredData, setFilteredData] = useState(allFuturesData);
const [loading, setLoading] = useState(false);
const [viewMode, setViewMode] = useState('card'); // card or list
const [filterType, setFilterType] = useState('');
const [filterKeyword, setFilterKeyword] = useState('');
// 模拟数据刷新
const handleRefresh = () => {
setLoading(true);
setTimeout(() => {
const refreshedData = allFuturesData.map(item => ({
...item,
currentPrice: (parseFloat(item.currentPrice) * (1 + (Math.random() * 0.02 - 0.01))).toFixed(2),
changePercent: (parseFloat(item.changePercent) + (Math.random() * 2 - 1)).toFixed(2)
}));
setFuturesData(refreshedData);
setFilteredData(refreshedData);
setLoading(false);
}, 1000);
};
// 过滤数据
useEffect(() => {
let result = futuresData;
if (filterKeyword) {
const keyword = filterKeyword.toLowerCase();
result = result.filter(item =>
item.code.toLowerCase().includes(keyword) ||
item.name.toLowerCase().includes(keyword)
);
}
if (filterType) {
result = result.filter(item => item.type === filterType);
}
setFilteredData(result);
}, [futuresData, filterKeyword, filterType]);
// 品种类型选项
const typeOptions = Array.from(new Set(allFuturesData.map(item => item.type))).map(type => (
<Option key={type} value={type}>{type}</Option>
));
// 渲染品种卡片
const renderCard = (item) => (
<Card
key={item.code}
style={{ marginBottom: 16, transition: 'all 0.3s', cursor: 'pointer' }}
hoverable
onClick={() => console.log('查看详情:', item.code)}
>
<Row gutter={[16, 16]}>
<Col span={24}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
<div style={{ fontWeight: 'bold', fontSize: '16px' }}>{item.name} ({item.code})</div>
<Badge
status={item.changePercent > 0 ? 'success' : 'error'}
text={`${item.changePercent > 0 ? '+' : ''}${item.changePercent}%`}
/>
</div>
</Col>
<Col span={24}>
<Statistic
title="当前价格"
value={item.currentPrice}
valueStyle={{ color: item.changePercent > 0 ? '#52c41a' : '#ff4d4f' }}
suffix="元"
size="small"
/>
</Col>
<Col span={12}>
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>胜率: {item.winRate}%</div>
</Col>
<Col span={12}>
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>ATR: {item.atr}</div>
</Col>
<Col span={12}>
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>ADX: {item.adx}</div>
</Col>
<Col span={12}>
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>趋势: {item.adxStatus}</div>
</Col>
</Row>
</Card>
);
return (
<div>
{/* 页面头部 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col flex="auto">
<Title level={3}>欢迎使用AI期货分析系统</Title>
<Text>当前市场整体处于{aiAnalysis.overallView.split('')[0]}</Text>
</Col>
<Col flex="none">
<div style={{ display: 'flex', gap: 12 }}>
<Button onClick={handleRefresh} icon={<ReloadOutlined />} loading={loading}>
刷新数据
</Button>
<Button
onClick={() => setViewMode(viewMode === 'card' ? 'list' : 'card')}
icon={viewMode === 'card' ? <EyeInvisibleOutlined /> : <EyeOutlined />}
>
{viewMode === 'card' ? '列表视图' : '卡片视图'}
</Button>
</div>
</Col>
</Row>
{/* 筛选栏 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col span={8}>
<Search
placeholder="搜索品种代码或名称"
value={filterKeyword}
onChange={(e) => setFilterKeyword(e.target.value)}
style={{ width: '100%' }}
/>
</Col>
<Col span={8}>
<Select
placeholder="按品种类型筛选"
style={{ width: '100%' }}
value={filterType}
onChange={setFilterType}
allowClear
>
{typeOptions}
</Select>
</Col>
</Row>
{/* 品种概览区 */}
<Card title="品种概览" style={{ marginBottom: 24 }}>
<Spin spinning={loading}>
{viewMode === 'card' ? (
<Row gutter={[16, 16]}>
{filteredData.map(item => (
<Col key={item.code} xs={24} sm={12} md={8} lg={6}>
{renderCard(item)}
</Col>
))}
</Row>
) : (
<Table dataSource={filteredData} rowKey="code" pagination={{ pageSize: 10 }}>
<Column title="品种" dataIndex="name" key="name" render={(text, record) => `${text} (${record.code})`} />
<Column title="当前价格" dataIndex="currentPrice" key="currentPrice" />
<Column
title="涨跌幅"
dataIndex="changePercent"
key="changePercent"
render={(text) => (
<span style={{ color: text > 0 ? '#52c41a' : '#ff4d4f' }}>
{text > 0 ? '+' : ''}{text}%
</span>
)}
/>
<Column title="胜率" dataIndex="winRate" key="winRate" render={(text) => `${text}%`} />
<Column title="ATR" dataIndex="atr" key="atr" />
<Column title="ADX" dataIndex="adx" key="adx" />
<Column title="趋势状态" dataIndex="adxStatus" key="adxStatus" />
</Table>
)}
</Spin>
</Card>
{/* 市场热点和AI研判区 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col xs={24} lg={12}>
<Card title="AI研判">
<div style={{ marginBottom: 16 }}>
<Text strong>市场整体观点</Text>
<Text>{aiAnalysis.overallView}</Text>
</div>
<div style={{ marginBottom: 16 }}>
<Text strong>投资建议</Text>
<ul style={{ marginLeft: 20, marginTop: 8 }}>
{aiAnalysis.recommendations.map((item, index) => (
<li key={index} style={{ marginBottom: 4 }}>{item}</li>
))}
</ul>
</div>
<div>
<Text strong>置信度</Text>
<Badge status="success" text={`${aiAnalysis.confidence}%`} />
</div>
</Card>
</Col>
<Col xs={24} lg={12}>
<Card title="风险预警">
<Row gutter={[16, 16]}>
{riskAlerts.map(alert => (
<Col key={alert.id} span={24}>
<Card
size="small"
style={{
borderLeft: `4px solid ${alert.level === '高' ? '#ff4d4f' : alert.level === '中等' ? '#faad14' : '#52c41a'}`
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
<Text strong>{alert.title}</Text>
<Badge
status={alert.level === '高' ? 'error' : alert.level === '中等' ? 'warning' : 'success'}
text={alert.level}
/>
</div>
<Text type="secondary">{alert.message}</Text>
</Card>
</Col>
))}
</Row>
</Card>
</Col>
</Row>
</div>
);
};
export default Dashboard;