fix: 修复卡片样式

master
Lxy 3 months ago
parent 578e88dbf0
commit f19d765d5f

@ -167,21 +167,28 @@
} }
/* 当前价格和支撑压力位 */ /* 当前价格和支撑压力位 */
.future-price-container-new {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.future-price-new { .future-price-new {
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
margin-bottom: 12px;
} }
.future-levels-new { .future-levels-new {
display: flex; display: flex;
justify-content: space-between; flex-direction: column;
margin-bottom: 16px; align-items: flex-end;
font-size: 14px; font-size: 12px;
color: #262626; color: #8c8c8c;
} }
.level-label-new { .level-label-new {
margin-bottom: 4px;
} }
/* 多周期趋势 */ /* 多周期趋势 */

@ -242,12 +242,14 @@ const Dashboard = () => {
</div> </div>
{/* 当前价格和支撑压力位 */} {/* 当前价格和支撑压力位 */}
<div className="future-price-new" style={{ color: getChangeColor(item.changePercent) }}> <div className="future-price-container-new">
{item.currentPrice.toFixed(2)} <div className="future-price-new" style={{ color: getChangeColor(item.changePercent) }}>
</div> {item.currentPrice.toFixed(2)}
<div className="future-levels-new"> </div>
<span className="level-label-new">支撑: {item.tradingAdvice?.support?.toFixed(2) || '-'}</span> <div className="future-levels-new">
<span className="level-label-new">压力: {item.tradingAdvice?.resistance?.toFixed(2) || '-'}</span> <span className="level-label-new">支撑: {item.tradingAdvice?.support?.toFixed(2) || '-'}</span>
<span className="level-label-new">压力: {item.tradingAdvice?.resistance?.toFixed(2) || '-'}</span>
</div>
</div> </div>
{/* 多周期趋势 */} {/* 多周期趋势 */}

@ -4,7 +4,7 @@ import { Card, Row, Col, Button, Select, Tag, Statistic, Alert, Spin } from 'ant
import { ArrowUpOutlined, ArrowDownOutlined, LineChartOutlined, BarChartOutlined, AlertOutlined, CalculatorOutlined } from '@ant-design/icons'; import { ArrowUpOutlined, ArrowDownOutlined, LineChartOutlined, BarChartOutlined, AlertOutlined, CalculatorOutlined } from '@ant-design/icons';
import { fetchFutureDetail } from '../../store/futuresSlice'; import { fetchFutureDetail } from '../../store/futuresSlice';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { generateKlineData } from '../../utils/mockData'; import { generateKlineData, generateFutureData } from '../../utils/mockData';
import './Detail.css'; import './Detail.css';
// TradingView Lightweight Charts // TradingView Lightweight Charts
@ -18,8 +18,9 @@ const Detail = () => {
const location = useLocation(); const location = useLocation();
const chartRef = useRef(null); const chartRef = useRef(null);
const chartInstance = useRef(null); const chartInstance = useRef(null);
const { selectedFuture, loading } = useSelector(state => state.futures); const { selectedFuture, loading, error } = useSelector(state => state.futures);
const [timeframe, setTimeframe] = useState('1D'); const [timeframe, setTimeframe] = useState('1D');
const [localData, setLocalData] = useState(null);
// URL // URL
const getQueryParams = () => { const getQueryParams = () => {
@ -32,14 +33,25 @@ const Detail = () => {
const { code, name } = getQueryParams(); const { code, name } = getQueryParams();
//
console.log('Detail page loaded with:', { code, name });
useEffect(() => { useEffect(() => {
// // 使
const fallbackData = generateFutureData(code, name);
setLocalData(fallbackData);
console.log('Generated fallback data:', fallbackData);
// Redux
console.log('Dispatching fetchFutureDetail with:', { code, name });
dispatch(fetchFutureDetail({ code, name })); dispatch(fetchFutureDetail({ code, name }));
}, [dispatch, code, name]); }, [dispatch, code, name]);
useEffect(() => { useEffect(() => {
// K线 // K线
if (chartRef.current && selectedFuture) { const dataToUse = selectedFuture || localData;
if (chartRef.current && dataToUse) {
console.log('Initializing chart with data:', dataToUse);
if (chartInstance.current) { if (chartInstance.current) {
chartInstance.current.destroy(); chartInstance.current.destroy();
} }
@ -122,7 +134,7 @@ const Detail = () => {
} }
}; };
} }
}, [selectedFuture]); }, [selectedFuture, localData]);
const handleBack = () => { const handleBack = () => {
navigate('/'); navigate('/');
@ -142,24 +154,11 @@ const Detail = () => {
return '#faad14'; return '#faad14';
}; };
if (loading) { // 使Redux
return ( const dataToDisplay = selectedFuture || localData;
<div className="loading-container">
<Spin size="large" tip="加载数据中..." /> // 使
</div> console.log('Rendering Detail component with state:', { loading, selectedFuture, localData, error });
);
}
if (!selectedFuture) {
return (
<div className="error-container">
<Alert message="未找到品种数据" type="error" />
<Button type="primary" onClick={handleBack} style={{ marginTop: 16 }}>
返回主页
</Button>
</div>
);
}
return ( return (
<div className="detail"> <div className="detail">
@ -168,208 +167,235 @@ const Detail = () => {
<Button type="default" onClick={handleBack} style={{ marginBottom: 16 }}> <Button type="default" onClick={handleBack} style={{ marginBottom: 16 }}>
返回主页 返回主页
</Button> </Button>
<h2>{selectedFuture.fullName}</h2> <h2>{dataToDisplay ? dataToDisplay.fullName : `${name}-${code}`}</h2>
</div> </div>
{/* 基本信息 */} {/* 错误信息 */}
<Card className="detail-card" style={{ marginBottom: 24 }}> {error && (
<Row gutter={[16, 16]}> <Alert message="加载失败" description={error} type="error" showIcon style={{ marginBottom: 24 }} />
<Col span={8}> )}
<Statistic
title="当前价格" {/* 加载状态 */}
value={selectedFuture.currentPrice} {loading && !dataToDisplay && (
valueStyle={{ color: '#262626' }} <div className="loading-container">
/> <Spin size="large" tip="加载数据中..." />
</Col> </div>
<Col span={8}> )}
<Statistic
title="涨跌幅" {/* 数据内容 */}
value={Math.abs(selectedFuture.changePercent)} {dataToDisplay && (
suffix="%" <>
valueStyle={{ color: getChangeColor(selectedFuture.changePercent) }} {/* 基本信息 */}
prefix={getChangeIcon(selectedFuture.changePercent)} <Card className="detail-card" style={{ marginBottom: 24 }}>
/> <Row gutter={[16, 16]}>
</Col> <Col span={8}>
<Col span={8}> <Statistic
<Statistic title="当前价格"
title="胜率" value={dataToDisplay.currentPrice}
value={selectedFuture.winRate} valueStyle={{ color: '#262626' }}
suffix="%" />
valueStyle={{ color: selectedFuture.winRate > 60 ? '#52c41a' : selectedFuture.winRate > 40 ? '#faad14' : '#ff4d4f' }} </Col>
/> <Col span={8}>
</Col> <Statistic
<Col span={8}> title="涨跌幅"
<Statistic value={Math.abs(dataToDisplay.changePercent)}
title="ATR" suffix="%"
value={selectedFuture.atr} valueStyle={{ color: getChangeColor(dataToDisplay.changePercent) }}
valueStyle={{ color: '#1890ff' }} prefix={getChangeIcon(dataToDisplay.changePercent)}
/> />
</Col> </Col>
<Col span={8}> <Col span={8}>
<Statistic <Statistic
title="ADX" title="胜率"
value={selectedFuture.adx} value={dataToDisplay.winRate}
valueStyle={{ color: '#1890ff' }} suffix="%"
/> valueStyle={{ color: dataToDisplay.winRate > 60 ? '#52c41a' : dataToDisplay.winRate > 40 ? '#faad14' : '#ff4d4f' }}
</Col> />
<Col span={8}> </Col>
<Statistic <Col span={8}>
title="趋势状态" <Statistic
value={selectedFuture.adxStatus} title="ATR"
valueStyle={{ color: '#1890ff' }} value={dataToDisplay.atr}
/> valueStyle={{ color: '#1890ff' }}
</Col> />
</Row> </Col>
</Card> <Col span={8}>
<Statistic
{/* K线图表 */} title="ADX"
<Card value={dataToDisplay.adx}
title={ valueStyle={{ color: '#1890ff' }}
<div className="chart-title"> />
<LineChartOutlined /> K线图表 </Col>
<Select <Col span={8}>
defaultValue="1D" <Statistic
style={{ width: 120, marginLeft: 16 }} title="趋势状态"
onChange={setTimeframe} value={dataToDisplay.adxStatus}
> valueStyle={{ color: '#1890ff' }}
<Option value="5MIN">5分钟</Option> />
<Option value="30MIN">30分钟</Option> </Col>
<Option value="1H">1小时</Option> </Row>
<Option value="1D">1</Option> </Card>
<Option value="1W">1</Option>
</Select> {/* K线图表 */}
</div> <Card
} title={
className="detail-card" <div className="chart-title">
style={{ marginBottom: 24 }} <LineChartOutlined /> K线图表
> <Select
<div ref={chartRef} className="kline-chart"></div> defaultValue="1D"
</Card> style={{ width: 120, marginLeft: 16 }}
onChange={setTimeframe}
{/* 多周期趋势分析 */} >
<Card <Option value="5MIN">5分钟</Option>
title={<span><BarChartOutlined /> 多周期趋势分析</span>} <Option value="30MIN">30分钟</Option>
className="detail-card" <Option value="1H">1小时</Option>
style={{ marginBottom: 24 }} <Option value="1D">1</Option>
> <Option value="1W">1</Option>
<Row gutter={[16, 16]}> </Select>
{Object.entries(selectedFuture.trends).map(([period, trend]) => ( </div>
<Col span={6} key={period}> }
<Card className="trend-card"> className="detail-card"
<div className="trend-header"> style={{ marginBottom: 24 }}
<h4>{period}</h4> >
<Tag color={getTrendColor(trend.direction)}> <div ref={chartRef} className="kline-chart"></div>
{trend.direction} </Card>
</Tag>
{/* 多周期趋势分析 */}
<Card
title={<span><BarChartOutlined /> 多周期趋势分析</span>}
className="detail-card"
style={{ marginBottom: 24 }}
>
<Row gutter={[16, 16]}>
{Object.entries(dataToDisplay.trends).map(([period, trend]) => (
<Col span={6} key={period}>
<Card className="trend-card">
<div className="trend-header">
<h4>{period}</h4>
<Tag color={getTrendColor(trend.direction)}>
{trend.direction}
</Tag>
</div>
<div className="trend-status">
{trend.status}
</div>
<div className="trend-rsi">
RSI: {trend.rsi}
</div>
</Card>
</Col>
))}
</Row>
</Card>
{/* 技术指标 */}
<Card
title="技术指标"
className="detail-card"
style={{ marginBottom: 24 }}
>
<Row gutter={[16, 16]}>
<Col span={6}>
<div className="indicator-item">
<div className="indicator-label">MACD</div>
<div className="indicator-value">{dataToDisplay.indicators.macd}</div>
</div> </div>
<div className="trend-status"> </Col>
{trend.status} <Col span={6}>
<div className="indicator-item">
<div className="indicator-label">RSI</div>
<div className="indicator-value">{dataToDisplay.indicators.rsi}</div>
</div> </div>
<div className="trend-rsi"> </Col>
RSI: {trend.rsi} <Col span={6}>
<div className="indicator-item">
<div className="indicator-label">布林带</div>
<div className="indicator-value">{dataToDisplay.indicators.bollinger}</div>
</div> </div>
</Card> </Col>
</Col> <Col span={6}>
))} <div className="indicator-item">
</Row> <div className="indicator-label">KDJ</div>
</Card> <div className="indicator-value">{dataToDisplay.indicators.kdj}</div>
</div>
{/* 技术指标 */} </Col>
<Card </Row>
title="技术指标" </Card>
className="detail-card"
style={{ marginBottom: 24 }} {/* 交易建议 */}
> <Card
<Row gutter={[16, 16]}> title={<span><CalculatorOutlined /> 交易建议</span>}
<Col span={6}> className="detail-card"
<div className="indicator-item"> style={{ marginBottom: 24 }}
<div className="indicator-label">MACD</div> >
<div className="indicator-value">{selectedFuture.indicators.macd}</div> <Row gutter={[16, 16]}>
</div> <Col span={8}>
</Col> <Statistic
<Col span={6}> title="入场价"
<div className="indicator-item"> value={dataToDisplay.tradingAdvice.entry}
<div className="indicator-label">RSI</div> valueStyle={{ color: '#1890ff' }}
<div className="indicator-value">{selectedFuture.indicators.rsi}</div> />
</div> </Col>
</Col> <Col span={8}>
<Col span={6}> <Statistic
<div className="indicator-item"> title="止损价"
<div className="indicator-label">布林带</div> value={dataToDisplay.tradingAdvice.stopLoss}
<div className="indicator-value">{selectedFuture.indicators.bollinger}</div> valueStyle={{ color: '#ff4d4f' }}
</div> />
</Col> </Col>
<Col span={6}> <Col span={8}>
<div className="indicator-item"> <Statistic
<div className="indicator-label">KDJ</div> title="目标价"
<div className="indicator-value">{selectedFuture.indicators.kdj}</div> value={dataToDisplay.tradingAdvice.target}
</div> valueStyle={{ color: '#52c41a' }}
</Col> />
</Row> </Col>
</Card> </Row>
</Card>
{/* 交易建议 */}
<Card {/* 风险评估 */}
title={<span><CalculatorOutlined /> 交易建议</span>} <Card
className="detail-card" title={<span><AlertOutlined /> 风险评估</span>}
style={{ marginBottom: 24 }} className="detail-card"
> >
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col span={8}> <Col span={12}>
<Statistic <div className="risk-item">
title="入场价" <div className="risk-label">风险等级</div>
value={selectedFuture.tradingAdvice.entry} <Tag color={dataToDisplay.riskLevel === '高' ? 'red' : dataToDisplay.riskLevel === '中等' ? 'orange' : 'green'}>
valueStyle={{ color: '#1890ff' }} {dataToDisplay.riskLevel}
/> </Tag>
</Col> </div>
<Col span={8}> </Col>
<Statistic <Col span={12}>
title="止损价" <div className="risk-item">
value={selectedFuture.tradingAdvice.stopLoss} <div className="risk-label">波动率</div>
valueStyle={{ color: '#ff4d4f' }} <Tag color={dataToDisplay.volatility === '高' ? 'red' : dataToDisplay.volatility === '中等' ? 'orange' : 'green'}>
/> {dataToDisplay.volatility}
</Col> </Tag>
<Col span={8}> </div>
<Statistic </Col>
title="目标价" </Row>
value={selectedFuture.tradingAdvice.target} <Alert
valueStyle={{ color: '#52c41a' }} message="风险提示"
description="期货交易具有高风险,请根据自身风险承受能力合理控制仓位,严格执行止损策略。"
type="warning"
showIcon
style={{ marginTop: 16 }}
/> />
</Col> </Card>
</Row> </>
</Card> )}
{/* 风险评估 */} {/* 无数据状态 */}
<Card {!loading && !dataToDisplay && !error && (
title={<span><AlertOutlined /> 风险评估</span>} <div className="error-container">
className="detail-card" <Alert message="未找到品种数据" type="error" />
> <Button type="primary" onClick={handleBack} style={{ marginTop: 16 }}>
<Row gutter={[16, 16]}> 返回主页
<Col span={12}> </Button>
<div className="risk-item"> </div>
<div className="risk-label">风险等级</div> )}
<Tag color={selectedFuture.riskLevel === '高' ? 'red' : selectedFuture.riskLevel === '中等' ? 'orange' : 'green'}>
{selectedFuture.riskLevel}
</Tag>
</div>
</Col>
<Col span={12}>
<div className="risk-item">
<div className="risk-label">波动率</div>
<Tag color={selectedFuture.volatility === '高' ? 'red' : selectedFuture.volatility === '中等' ? 'orange' : 'green'}>
{selectedFuture.volatility}
</Tag>
</div>
</Col>
</Row>
<Alert
message="风险提示"
description="期货交易具有高风险,请根据自身风险承受能力合理控制仓位,严格执行止损策略。"
type="warning"
showIcon
style={{ marginTop: 16 }}
/>
</Card>
</div> </div>
); );
}; };

@ -83,10 +83,12 @@ const futuresSlice = createSlice({
.addCase(fetchFutureDetail.fulfilled, (state, action) => { .addCase(fetchFutureDetail.fulfilled, (state, action) => {
state.loading = false; state.loading = false;
state.selectedFuture = action.payload; state.selectedFuture = action.payload;
console.log('fetchFutureDetail fulfilled with:', action.payload);
}) })
.addCase(fetchFutureDetail.rejected, (state, action) => { .addCase(fetchFutureDetail.rejected, (state, action) => {
state.loading = false; state.loading = false;
state.error = action.error.message; state.error = action.error.message;
console.log('fetchFutureDetail rejected with error:', action.error.message);
}) })
// 处理fetchRiskAlerts // 处理fetchRiskAlerts

Loading…
Cancel
Save