import { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Card, Form, Button, Switch, message, Typography, Space, Radio, InputNumber, Divider, Spin, Select, Input } from 'antd' import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons' import { apiService } from '../services/api' import type { CopyTrading, CopyTradingUpdateRequest } from '../types' import { useTranslation } from 'react-i18next' const { Title } = Typography const { Option } = Select const CopyTradingEdit: React.FC = () => { const { t } = useTranslation() const navigate = useNavigate() const { id } = useParams<{ id: string }>() const [form] = Form.useForm() const [loading, setLoading] = useState(false) const [fetching, setFetching] = useState(true) const [copyTrading, setCopyTrading] = useState(null) const [copyMode, setCopyMode] = useState<'RATIO' | 'FIXED'>('RATIO') const [originalEnabled, setOriginalEnabled] = useState(true) useEffect(() => { if (id) { fetchCopyTrading(parseInt(id)) } }, [id]) const fetchCopyTrading = async (copyTradingId: number) => { setFetching(true) try { const response = await apiService.copyTrading.list({}) if (response.data.code === 0 && response.data.data) { const found = response.data.data.list.find((ct: CopyTrading) => ct.id === copyTradingId) if (found) { setCopyTrading(found) setCopyMode(found.copyMode) setOriginalEnabled(found.enabled) // 保存原始的enabled状态 // 填充表单数据 form.setFieldsValue({ accountId: found.accountId, leaderId: found.leaderId, copyMode: found.copyMode, copyRatio: found.copyRatio ? parseFloat(found.copyRatio) * 100 : 100, // 转换为百分比显示 fixedAmount: found.fixedAmount ? parseFloat(found.fixedAmount) : undefined, maxOrderSize: found.maxOrderSize ? parseFloat(found.maxOrderSize) : undefined, minOrderSize: found.minOrderSize ? parseFloat(found.minOrderSize) : undefined, maxDailyLoss: found.maxDailyLoss ? parseFloat(found.maxDailyLoss) : undefined, maxDailyOrders: found.maxDailyOrders, priceTolerance: found.priceTolerance ? parseFloat(found.priceTolerance) : undefined, delaySeconds: found.delaySeconds, pollIntervalSeconds: found.pollIntervalSeconds, useWebSocket: found.useWebSocket, websocketReconnectInterval: found.websocketReconnectInterval, websocketMaxRetries: found.websocketMaxRetries, supportSell: found.supportSell, minOrderDepth: found.minOrderDepth ? parseFloat(found.minOrderDepth) : undefined, maxSpread: found.maxSpread ? parseFloat(found.maxSpread) : undefined, minPrice: found.minPrice ? parseFloat(found.minPrice) : undefined, maxPrice: found.maxPrice ? parseFloat(found.maxPrice) : undefined, maxPositionValue: found.maxPositionValue ? parseFloat(found.maxPositionValue) : undefined, maxPositionCount: found.maxPositionCount, configName: found.configName || '', pushFailedOrders: found.pushFailedOrders ?? false }) } else { message.error(t('copyTradingEdit.fetchFailed') || '跟单配置不存在') navigate('/copy-trading') } } else { message.error(response.data.msg || t('copyTradingEdit.fetchFailed') || '获取跟单配置失败') navigate('/copy-trading') } } catch (error: any) { message.error(error.message || t('copyTradingEdit.fetchFailed') || '获取跟单配置失败') navigate('/copy-trading') } finally { setFetching(false) } } const handleCopyModeChange = (mode: 'RATIO' | 'FIXED') => { setCopyMode(mode) } const handleSubmit = async (values: any) => { // 前端校验 if (values.copyMode === 'FIXED') { if (!values.fixedAmount || Number(values.fixedAmount) < 1) { message.error('固定金额必须 >= 1') return } } if (values.copyMode === 'RATIO' && values.minOrderSize !== undefined && values.minOrderSize !== null && Number(values.minOrderSize) < 1) { message.error('最小金额必须 >= 1') return } if (!id) { message.error('配置ID不存在') return } setLoading(true) try { const request: CopyTradingUpdateRequest = { copyTradingId: parseInt(id), enabled: originalEnabled, // 保持原有的enabled状态,不修改 copyMode: values.copyMode, copyRatio: values.copyMode === 'RATIO' && values.copyRatio ? (values.copyRatio / 100).toString() : undefined, fixedAmount: values.copyMode === 'FIXED' ? values.fixedAmount?.toString() : undefined, maxOrderSize: values.maxOrderSize?.toString(), minOrderSize: values.minOrderSize?.toString(), maxDailyLoss: values.maxDailyLoss?.toString(), maxDailyOrders: values.maxDailyOrders, priceTolerance: values.priceTolerance?.toString(), delaySeconds: values.delaySeconds, pollIntervalSeconds: values.pollIntervalSeconds, useWebSocket: values.useWebSocket, websocketReconnectInterval: values.websocketReconnectInterval, websocketMaxRetries: values.websocketMaxRetries, supportSell: values.supportSell, minOrderDepth: values.minOrderDepth?.toString(), maxSpread: values.maxSpread?.toString(), minPrice: values.minPrice?.toString(), maxPrice: values.maxPrice?.toString(), maxPositionValue: values.maxPositionValue?.toString(), maxPositionCount: values.maxPositionCount, configName: values.configName?.trim() || undefined, pushFailedOrders: values.pushFailedOrders } const response = await apiService.copyTrading.update(request) if (response.data.code === 0) { message.success(t('copyTradingEdit.saveSuccess') || '更新跟单配置成功') navigate('/copy-trading') } else { message.error(response.data.msg || t('copyTradingEdit.saveFailed') || '更新跟单配置失败') } } catch (error: any) { message.error(error.message || t('copyTradingEdit.saveFailed') || '更新跟单配置失败') } finally { setLoading(false) } } if (fetching) { return (
) } if (!copyTrading) { return null } return (
{t('copyTradingEdit.title') || '编辑跟单配置'}
{/* 基础信息(只读) */} {t('copyTradingEdit.basicConfig') || '基础配置'} {/* 跟单金额模式 */} handleCopyModeChange(e.target.value)}> {t('copyTradingEdit.ratioMode') || '比例模式'} {t('copyTradingEdit.fixedAmountMode') || '固定金额模式'} {copyMode === 'RATIO' && ( )} {copyMode === 'FIXED' && ( { if (value !== undefined && value !== null && value !== '') { const amount = Number(value) if (isNaN(amount)) { return Promise.reject(new Error(t('copyTradingEdit.invalidNumber') || '请输入有效的数字')) } if (amount < 1) { return Promise.reject(new Error(t('copyTradingEdit.fixedAmountMin') || '固定金额必须 >= 1')) } } return Promise.resolve() } } ]} > = 1'} /> )} {copyMode === 'RATIO' && ( <> = 1'} rules={[ { validator: (_, value) => { if (value === undefined || value === null || value === '') { return Promise.resolve() } if (typeof value === 'number' && value < 1) { return Promise.reject(new Error(t('copyTradingEdit.minOrderSizeMin') || '最小金额必须 >= 1')) } return Promise.resolve() } } ]} > = 1(可选)'} /> )} {t('copyTradingEdit.priceRangeFilter') || '价格区间过滤'} - {t('copyTradingEdit.positionLimitFilter') || '最大仓位限制'} {t('copyTradingEdit.advancedSettings') || '高级设置'} {/* 跟单卖出 */} {/* 推送失败订单 */}
) } export default CopyTradingEdit