c20e0138df
后端变更: - 添加最大仓位金额(maxPositionValue)和最大仓位数量(maxPositionCount)配置字段 - 实现按市场检查仓位限制的过滤逻辑 - 添加数据库迁移脚本 V11__add_max_position_config.sql 前端变更: - 重构账户导入和Leader添加为可复用组件(AccountImportForm, LeaderAddForm) - 在CopyTradingAdd页面集成账户导入和Leader添加Modal - 在CopyTradingAdd/CopyTradingEdit页面添加最大仓位限制配置项 - 补充所有多语言文件中的缺失键,确保zh-CN/zh-TW/en三种语言文件一致 功能说明: - 支持设置单个市场的最大仓位金额限制(USDC) - 支持设置单个市场的最大仓位数量限制 - 两个限制可以同时启用,下单前会检查当前市场仓位是否超过限制
137 lines
4.3 KiB
TypeScript
137 lines
4.3 KiB
TypeScript
import { useState } from 'react'
|
|
import { Form, Input, Button, Space } from 'antd'
|
|
import { apiService } from '../services/api'
|
|
import { useMediaQuery } from 'react-responsive'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { isValidWalletAddress } from '../utils'
|
|
|
|
interface LeaderAddFormProps {
|
|
form: any
|
|
onSuccess?: (leaderId: number) => void
|
|
onCancel?: () => void
|
|
showCancelButton?: boolean
|
|
}
|
|
|
|
const LeaderAddForm: React.FC<LeaderAddFormProps> = ({
|
|
form,
|
|
onSuccess,
|
|
onCancel,
|
|
showCancelButton = true
|
|
}) => {
|
|
const { t } = useTranslation()
|
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const handleSubmit = async (values: any) => {
|
|
setLoading(true)
|
|
try {
|
|
const response = await apiService.leaders.add({
|
|
leaderAddress: values.leaderAddress.trim(),
|
|
leaderName: values.leaderName?.trim() || undefined,
|
|
remark: values.remark?.trim() || undefined,
|
|
website: values.website?.trim() || undefined
|
|
})
|
|
|
|
if (response.data.code === 0) {
|
|
if (response.data.data && onSuccess) {
|
|
onSuccess(response.data.data.id)
|
|
}
|
|
return Promise.resolve()
|
|
} else {
|
|
return Promise.reject(new Error(response.data.msg || t('leaderAdd.addFailed') || '添加 Leader 失败'))
|
|
}
|
|
} catch (error: any) {
|
|
return Promise.reject(error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Form
|
|
form={form}
|
|
layout="vertical"
|
|
onFinish={handleSubmit}
|
|
size={isMobile ? 'middle' : 'large'}
|
|
>
|
|
<Form.Item
|
|
label={t('leaderAdd.leaderAddress') || 'Leader 钱包地址'}
|
|
name="leaderAddress"
|
|
rules={[
|
|
{ required: true, message: t('leaderAdd.leaderAddressRequired') || '请输入 Leader 钱包地址' },
|
|
{
|
|
validator: (_, value) => {
|
|
if (!value) {
|
|
return Promise.reject(new Error(t('leaderAdd.leaderAddressRequired') || '请输入 Leader 钱包地址'))
|
|
}
|
|
if (!isValidWalletAddress(value.trim())) {
|
|
return Promise.reject(new Error(t('leaderAdd.leaderAddressInvalid') || '钱包地址格式不正确(必须是 0x 开头的 42 位地址)'))
|
|
}
|
|
return Promise.resolve()
|
|
}
|
|
}
|
|
]}
|
|
tooltip={t('leaderAdd.leaderAddressTooltip') || '被跟单者的钱包地址,系统将监控该地址的交易并自动跟单'}
|
|
>
|
|
<Input placeholder="0x..." style={{ fontFamily: 'monospace' }} />
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
label={t('leaderAdd.leaderName') || 'Leader 名称'}
|
|
name="leaderName"
|
|
tooltip={t('leaderAdd.leaderNameTooltip') || '可选,用于标识 Leader,方便管理'}
|
|
>
|
|
<Input placeholder={t('leaderAdd.leaderNamePlaceholder') || '可选,用于标识 Leader'} />
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
label={t('leaderAdd.remark') || 'Leader 备注'}
|
|
name="remark"
|
|
tooltip={t('leaderAdd.remarkTooltip') || '可选,用于记录 Leader 的备注信息'}
|
|
>
|
|
<Input.TextArea
|
|
placeholder={t('leaderAdd.remarkPlaceholder') || '可选,用于记录 Leader 的备注信息'}
|
|
rows={3}
|
|
maxLength={500}
|
|
showCount
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
label={t('leaderAdd.website') || 'Leader 网站'}
|
|
name="website"
|
|
tooltip={t('leaderAdd.websiteTooltip') || '可选,Leader 的网站链接'}
|
|
rules={[
|
|
{
|
|
type: 'url',
|
|
message: t('leaderAdd.websiteInvalid') || '请输入有效的 URL 地址'
|
|
}
|
|
]}
|
|
>
|
|
<Input placeholder={t('leaderAdd.websitePlaceholder') || '可选,例如:https://example.com'} />
|
|
</Form.Item>
|
|
|
|
<Form.Item>
|
|
<Space>
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
loading={loading}
|
|
size={isMobile ? 'middle' : 'large'}
|
|
>
|
|
{t('leaderAdd.add') || '添加 Leader'}
|
|
</Button>
|
|
{showCancelButton && onCancel && (
|
|
<Button onClick={onCancel}>
|
|
{t('common.cancel')}
|
|
</Button>
|
|
)}
|
|
</Space>
|
|
</Form.Item>
|
|
</Form>
|
|
)
|
|
}
|
|
|
|
export default LeaderAddForm
|
|
|