fix: 增加自选模块

master
Lxy 3 months ago
parent 2ace0e35ef
commit 3263f3ebcb

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Card, Row, Col, Statistic, Button, Select, Tag, message, Spin, Alert, Dropdown, Menu } from 'antd'; import { Card, Row, Col, Statistic, Button, Select, Tag, message, Spin, Alert } from 'antd';
import { ReloadOutlined, ArrowUpOutlined, ArrowDownOutlined, FireOutlined, AlertOutlined, RobotOutlined } from '@ant-design/icons'; import { ReloadOutlined, ArrowUpOutlined, ArrowDownOutlined, FireOutlined, AlertOutlined, RobotOutlined } from '@ant-design/icons';
import { fetchFuturesOverview, fetchRiskAlerts, fetchAIMarketAnalysis, toggleWatchlist } from '../../store/futuresSlice'; import { fetchFuturesOverview, fetchRiskAlerts, fetchAIMarketAnalysis, toggleWatchlist } from '../../store/futuresSlice';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -11,10 +11,9 @@ const { Option } = Select;
const Dashboard = () => { const Dashboard = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { overview, riskAlerts, aiAnalysis, loading, watchlists, currentWatchlist } = useSelector(state => state.futures); const { overview, riskAlerts, aiAnalysis, loading } = useSelector(state => state.futures);
const [filterType, setFilterType] = useState('all'); const [filterType, setFilterType] = useState('all');
const [sortBy, setSortBy] = useState('winRate'); const [sortBy, setSortBy] = useState('winRate');
const [showWatchlistMenu, setShowWatchlistMenu] = useState(null);
useEffect(() => { useEffect(() => {
dispatch(fetchFuturesOverview()); dispatch(fetchFuturesOverview());
@ -35,21 +34,8 @@ const Dashboard = () => {
const handleToggleWatchlist = (future, e) => { const handleToggleWatchlist = (future, e) => {
e.stopPropagation(); e.stopPropagation();
if (watchlists.length > 1 && !future.isInWatchlist) { dispatch(toggleWatchlist(future.code));
//
setShowWatchlistMenu(future.code);
} else {
//
dispatch(toggleWatchlist({ code: future.code, watchlistId: currentWatchlist }));
message.success(future.isInWatchlist ? '已从自选移除' : '已添加到自选'); message.success(future.isInWatchlist ? '已从自选移除' : '已添加到自选');
}
};
const handleAddToWatchlist = (code, watchlistId, e) => {
e.stopPropagation();
dispatch(toggleWatchlist({ code, watchlistId }));
message.success('已添加到自选');
setShowWatchlistMenu(null);
}; };
const getChangeColor = (changePercent) => { const getChangeColor = (changePercent) => {
@ -316,32 +302,6 @@ const Dashboard = () => {
<Button type="primary" className="detail-button-new" onClick={() => handleFutureClick(item)}> <Button type="primary" className="detail-button-new" onClick={() => handleFutureClick(item)}>
查看详细分析 查看详细分析
</Button> </Button>
{watchlists.length > 1 && !item.isInWatchlist ? (
<Dropdown
open={showWatchlistMenu === item.code}
onOpenChange={(open) => {
if (open) {
setShowWatchlistMenu(item.code);
} else {
setShowWatchlistMenu(null);
}
}}
overlay={
<Menu>
{watchlists.map(watchlist => (
<Menu.Item key={watchlist.id} onClick={(e) => handleAddToWatchlist(item.code, watchlist.id, e)}>
{watchlist.name}
</Menu.Item>
))}
</Menu>
}
trigger={['click']}
>
<Button type="dashed" className="watchlist-button-new">
添加自选
</Button>
</Dropdown>
) : (
<Button <Button
type={item.isInWatchlist ? "default" : "dashed"} type={item.isInWatchlist ? "default" : "dashed"}
className="watchlist-button-new" className="watchlist-button-new"
@ -350,7 +310,6 @@ const Dashboard = () => {
> >
{item.isInWatchlist ? '已添加' : '添加自选'} {item.isInWatchlist ? '已添加' : '添加自选'}
</Button> </Button>
)}
</div> </div>
</Card> </Card>
</Col> </Col>

@ -9,21 +9,6 @@
margin-bottom: 24px; margin-bottom: 24px;
} }
.watchlist-header-left {
display: flex;
align-items: center;
gap: 16px;
}
.watchlist-selector {
margin-left: 16px;
}
.watchlist-header-actions {
display: flex;
gap: 16px;
}
.watchlist-header h2 { .watchlist-header h2 {
margin: 0; margin: 0;
color: #262626; color: #262626;

@ -1,8 +1,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Card, Row, Col, Button, Select, Tag, message, Spin, Input, Modal, Popconfirm } from 'antd'; import { Card, Row, Col, Button, Select, Tag, message, Spin } from 'antd';
import { ReloadOutlined, ArrowUpOutlined, ArrowDownOutlined, StarOutlined, DeleteOutlined, PlusOutlined, MoreOutlined } from '@ant-design/icons'; import { ReloadOutlined, ArrowUpOutlined, ArrowDownOutlined, StarOutlined, DeleteOutlined } from '@ant-design/icons';
import { fetchFuturesOverview, toggleWatchlist, createWatchlist, selectWatchlist, deleteWatchlist } from '../../store/futuresSlice'; import { fetchFuturesOverview, toggleWatchlist } from '../../store/futuresSlice';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import './Watchlist.css'; import './Watchlist.css';
@ -11,10 +11,8 @@ const { Option } = Select;
const Watchlist = () => { const Watchlist = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { overview, watchlists, currentWatchlist, loading } = useSelector(state => state.futures); const { overview, watchlist, loading } = useSelector(state => state.futures);
const [filterType, setFilterType] = useState('all'); const [filterType, setFilterType] = useState('all');
const [showCreateModal, setShowCreateModal] = useState(false);
const [newWatchlistName, setNewWatchlistName] = useState('');
useEffect(() => { useEffect(() => {
dispatch(fetchFuturesOverview()); dispatch(fetchFuturesOverview());
@ -29,32 +27,11 @@ const Watchlist = () => {
navigate(`/detail/${future.code}`); navigate(`/detail/${future.code}`);
}; };
const handleToggleWatchlist = (future, e) => { const handleToggleWatchlist = (future) => {
e.stopPropagation(); dispatch(toggleWatchlist(future.code));
dispatch(toggleWatchlist({ code: future.code, watchlistId: currentWatchlist }));
message.success(future.isInWatchlist ? '已从自选移除' : '已添加到自选'); message.success(future.isInWatchlist ? '已从自选移除' : '已添加到自选');
}; };
const handleCreateWatchlist = () => {
if (newWatchlistName.trim()) {
dispatch(createWatchlist({ name: newWatchlistName.trim() }));
message.success('新自选组合创建成功');
setShowCreateModal(false);
setNewWatchlistName('');
} else {
message.error('请输入自选组合名称');
}
};
const handleSelectWatchlist = (watchlistId) => {
dispatch(selectWatchlist(watchlistId));
};
const handleDeleteWatchlist = (watchlistId) => {
dispatch(deleteWatchlist(watchlistId));
message.success('自选组合删除成功');
};
const getChangeColor = (changePercent) => { const getChangeColor = (changePercent) => {
return changePercent >= 0 ? '#52c41a' : '#ff4d4f'; return changePercent >= 0 ? '#52c41a' : '#ff4d4f';
}; };
@ -70,9 +47,7 @@ const Watchlist = () => {
}; };
const getWatchlistData = () => { const getWatchlistData = () => {
const currentWl = watchlists.find(wl => wl.id === currentWatchlist); return overview.filter(item => watchlist.includes(item.code));
if (!currentWl) return [];
return overview.filter(item => currentWl.codes.includes(item.code));
}; };
if (loading && overview.length === 0) { if (loading && overview.length === 0) {
@ -89,31 +64,8 @@ const Watchlist = () => {
<div className="watchlist"> <div className="watchlist">
{/* 页面头部 */} {/* 页面头部 */}
<div className="watchlist-header"> <div className="watchlist-header">
<div className="watchlist-header-left">
<h2>自选合约</h2> <h2>自选合约</h2>
<div className="watchlist-selector">
<Select
value={currentWatchlist}
onChange={handleSelectWatchlist}
style={{ width: 200, marginLeft: 16 }}
>
{watchlists.map(watchlist => (
<Option key={watchlist.id} value={watchlist.id}>
{watchlist.name}
</Option>
))}
</Select>
</div>
</div>
<div className="watchlist-header-actions"> <div className="watchlist-header-actions">
<Button
type="default"
icon={<PlusOutlined />}
onClick={() => setShowCreateModal(true)}
style={{ marginRight: 16 }}
>
新建自选组合
</Button>
<Button <Button
type="primary" type="primary"
icon={<ReloadOutlined />} icon={<ReloadOutlined />}
@ -245,28 +197,6 @@ const Watchlist = () => {
</Row> </Row>
</> </>
)} )}
{/* 创建新自选组合模态框 */}
<Modal
title="创建新自选组合"
open={showCreateModal}
onCancel={() => setShowCreateModal(false)}
footer={[
<Button key="cancel" onClick={() => setShowCreateModal(false)}>
取消
</Button>,
<Button key="create" type="primary" onClick={handleCreateWatchlist}>
创建
</Button>
]}
>
<Input
placeholder="请输入自选组合名称"
value={newWatchlistName}
onChange={(e) => setNewWatchlistName(e.target.value)}
style={{ marginBottom: 16 }}
/>
</Modal>
</div> </div>
); );
}; };

@ -50,14 +50,7 @@ const futuresSlice = createSlice({
aiAnalysis: null, aiAnalysis: null,
loading: false, loading: false,
error: null, error: null,
watchlists: [ watchlist: []
{
id: 'default',
name: '默认自选',
codes: []
}
],
currentWatchlist: 'default'
}, },
reducers: { reducers: {
selectFuture: (state, action) => { selectFuture: (state, action) => {
@ -67,46 +60,21 @@ const futuresSlice = createSlice({
state.selectedFuture = null; state.selectedFuture = null;
}, },
toggleWatchlist: (state, action) => { toggleWatchlist: (state, action) => {
const { code, watchlistId = state.currentWatchlist } = action.payload; const code = action.payload;
const targetWatchlist = state.watchlists.find(wl => wl.id === watchlistId); const index = state.watchlist.indexOf(code);
if (targetWatchlist) {
const index = targetWatchlist.codes.indexOf(code);
if (index > -1) { if (index > -1) {
targetWatchlist.codes.splice(index, 1); state.watchlist.splice(index, 1);
} else { } else {
targetWatchlist.codes.push(code); state.watchlist.push(code);
}
} }
// 更新overview中每个合约的自选状态 // 更新overview中每个合约的自选状态
state.overview = state.overview.map(item => ({ state.overview = state.overview.map(item => ({
...item, ...item,
isInWatchlist: state.watchlists.some(wl => wl.codes.includes(item.code)) isInWatchlist: state.watchlist.includes(item.code)
})); }));
// 更新selectedFuture的自选状态 // 更新selectedFuture的自选状态
if (state.selectedFuture && state.selectedFuture.code === code) { if (state.selectedFuture && state.selectedFuture.code === code) {
state.selectedFuture.isInWatchlist = state.watchlists.some(wl => wl.codes.includes(code)); state.selectedFuture.isInWatchlist = state.watchlist.includes(code);
}
},
createWatchlist: (state, action) => {
const { name } = action.payload;
const newWatchlist = {
id: `wl-${Date.now()}`,
name,
codes: []
};
state.watchlists.push(newWatchlist);
state.currentWatchlist = newWatchlist.id;
},
selectWatchlist: (state, action) => {
state.currentWatchlist = action.payload;
},
deleteWatchlist: (state, action) => {
const watchlistId = action.payload;
if (watchlistId !== 'default') {
state.watchlists = state.watchlists.filter(wl => wl.id !== watchlistId);
if (state.currentWatchlist === watchlistId) {
state.currentWatchlist = 'default';
}
} }
} }
}, },
@ -122,7 +90,7 @@ const futuresSlice = createSlice({
// 更新overview数据并添加自选状态 // 更新overview数据并添加自选状态
state.overview = action.payload.map(item => ({ state.overview = action.payload.map(item => ({
...item, ...item,
isInWatchlist: state.watchlists.some(wl => wl.codes.includes(item.code)) isInWatchlist: state.watchlist.includes(item.code)
})); }));
}) })
.addCase(fetchFuturesOverview.rejected, (state, action) => { .addCase(fetchFuturesOverview.rejected, (state, action) => {
@ -140,7 +108,7 @@ const futuresSlice = createSlice({
// 更新selectedFuture数据并添加自选状态 // 更新selectedFuture数据并添加自选状态
state.selectedFuture = { state.selectedFuture = {
...action.payload, ...action.payload,
isInWatchlist: state.watchlists.some(wl => wl.codes.includes(action.payload.code)) isInWatchlist: state.watchlist.includes(action.payload.code)
}; };
console.log('fetchFutureDetail fulfilled with:', action.payload); console.log('fetchFutureDetail fulfilled with:', action.payload);
}) })
@ -180,5 +148,5 @@ const futuresSlice = createSlice({
} }
}); });
export const { selectFuture, clearSelectedFuture, toggleWatchlist, createWatchlist, selectWatchlist, deleteWatchlist } = futuresSlice.actions; export const { selectFuture, clearSelectedFuture, toggleWatchlist } = futuresSlice.actions;
export default futuresSlice.reducer; export default futuresSlice.reducer;

Loading…
Cancel
Save