diff --git a/frontend/src/components/ConfigPanel.jsx b/frontend/src/components/ConfigPanel.jsx
index 555dd40..1bdf42e 100644
--- a/frontend/src/components/ConfigPanel.jsx
+++ b/frontend/src/components/ConfigPanel.jsx
@@ -47,7 +47,7 @@ const ConfigPanel = ({ currentUser }) => {
const [snapshotText, setSnapshotText] = useState('')
const [snapshotIncludeSecrets, setSnapshotIncludeSecrets] = useState(false)
const [snapshotBusy, setSnapshotBusy] = useState(false)
-
+
// 预设方案配置
// 注意:百分比配置使用整数形式(如8.0表示8%),在应用时会转换为小数(0.08)
const presets = {
@@ -351,12 +351,16 @@ const ConfigPanel = ({ currentUser }) => {
useEffect(() => {
loadConfigs()
checkFeasibility()
- loadSystemStatus()
+ if (isAdmin) {
+ loadSystemStatus()
+ }
loadBackendStatus()
loadAccountTradingStatus()
const timer = setInterval(() => {
- loadSystemStatus()
+ if (isAdmin) {
+ loadSystemStatus()
+ }
loadBackendStatus()
loadAccountTradingStatus()
}, 3000)
@@ -401,7 +405,7 @@ const ConfigPanel = ({ currentUser }) => {
}, 1000)
return () => clearInterval(timer)
}, [accountId])
-
+
const checkFeasibility = async () => {
setCheckingFeasibility(true)
try {
@@ -525,21 +529,21 @@ const ConfigPanel = ({ currentUser }) => {
preset_detected: detectCurrentPreset(),
system_status: systemStatus
? {
- running: !!systemStatus.running,
- pid: systemStatus.pid || null,
- program: systemStatus.program || null,
- state: systemStatus.state || null,
- }
+ running: !!systemStatus.running,
+ pid: systemStatus.pid || null,
+ program: systemStatus.program || null,
+ state: systemStatus.state || null,
+ }
: null,
feasibility_check_summary: feasibilityCheck
? {
- feasible: !!feasibilityCheck.feasible,
- account_balance: feasibilityCheck.account_balance ?? null,
- base_leverage: feasibilityCheck.base_leverage ?? feasibilityCheck.leverage ?? null,
- max_leverage: feasibilityCheck.max_leverage ?? null,
- use_dynamic_leverage: feasibilityCheck.use_dynamic_leverage ?? null,
- min_margin_usdt: feasibilityCheck.current_config?.min_margin_usdt ?? null,
- }
+ feasible: !!feasibilityCheck.feasible,
+ account_balance: feasibilityCheck.account_balance ?? null,
+ base_leverage: feasibilityCheck.base_leverage ?? feasibilityCheck.leverage ?? null,
+ max_leverage: feasibilityCheck.max_leverage ?? null,
+ use_dynamic_leverage: feasibilityCheck.use_dynamic_leverage ?? null,
+ min_margin_usdt: feasibilityCheck.current_config?.min_margin_usdt ?? null,
+ }
: null,
configs: entries,
}
@@ -593,7 +597,7 @@ const ConfigPanel = ({ currentUser }) => {
// 检测当前配置匹配哪个预设方案
const detectCurrentPreset = () => {
if (!configs || Object.keys(configs).length === 0) return null
-
+
for (const [presetKey, preset] of Object.entries(presets)) {
let match = true
for (const [key, expectedValue] of Object.entries(preset.configs)) {
@@ -602,7 +606,7 @@ const ConfigPanel = ({ currentUser }) => {
match = false
break
}
-
+
// 获取当前值(处理百分比转换)
let currentValue = currentConfig.value
if (key.includes('PERCENT') || key.includes('PCT')) {
@@ -613,7 +617,7 @@ const ConfigPanel = ({ currentUser }) => {
currentValue = currentValue * 100
}
}
-
+
// 比较值(允许小的浮点数误差)
if (typeof expectedValue === 'number' && typeof currentValue === 'number') {
if (Math.abs(currentValue - expectedValue) > 0.01) {
@@ -625,19 +629,19 @@ const ConfigPanel = ({ currentUser }) => {
break
}
}
-
+
if (match) {
return presetKey
}
}
-
+
return null
}
const applyPreset = async (presetKey) => {
const preset = presets[presetKey]
if (!preset) return
-
+
setSaving(true)
setMessage('')
try {
@@ -677,7 +681,7 @@ const ConfigPanel = ({ currentUser }) => {
type = 'number'
category = 'scan'
}
-
+
const detail = typeof getConfigDetail === 'function' ? getConfigDetail(key) : ''
const desc =
detail && typeof detail === 'string' && !detail.includes('暂无详细说明')
@@ -706,7 +710,7 @@ const ConfigPanel = ({ currentUser }) => {
description: config.description
}
}).filter(Boolean)
-
+
const response = await api.updateConfigsBatch(configItems)
setMessage(response.message || `已应用${preset.name}`)
if (response.note) {
@@ -795,345 +799,345 @@ const ConfigPanel = ({ currentUser }) => {
{/* 系统控制:清缓存 / 启停 / 重启(supervisor) */}
{isAdmin ? (
-
-
-
系统控制
-
-
- {systemStatus?.running ? '运行中' : '未运行'}
+
+
+
系统控制
+
+
+ {systemStatus?.running ? '运行中' : '未运行'}
+
+ {systemStatus?.pid ? PID: {systemStatus.pid} : null}
+ {systemStatus?.program ? 程序: {systemStatus.program} : null}
+ {systemStatus?.meta?.requested_at ? 上次重启: {systemStatus.meta.requested_at} : null}
+
+
+
+
+
+
+
+
+
+
+
+ 后端 {backendStatus?.running ? '运行中' : '未知'}
- {systemStatus?.pid ? PID: {systemStatus.pid} : null}
- {systemStatus?.program ? 程序: {systemStatus.program} : null}
- {systemStatus?.meta?.requested_at ? 上次重启: {systemStatus.meta.requested_at} : null}
+ {backendStatus?.pid ? PID: {backendStatus.pid} : null}
+ {backendStatus?.meta?.requested_at ? 上次重启: {backendStatus.meta.requested_at} : null}
+
+
+ 建议流程:先更新配置里的 Key → 点击“清除缓存” → 点击“重启交易系统”,确保不再使用旧账号下单。
-
-
-
-
-
-
-
-
-
- 后端 {backendStatus?.running ? '运行中' : '未知'}
-
- {backendStatus?.pid ? PID: {backendStatus.pid} : null}
- {backendStatus?.meta?.requested_at ? 上次重启: {backendStatus.meta.requested_at} : null}
-
-
- 建议流程:先更新配置里的 Key → 点击“清除缓存” → 点击“重启交易系统”,确保不再使用旧账号下单。
-
-
) : null}
{/* 账号管理(超管) */}
{isAdmin ? (
-
-
-
账号管理(多账号)
-
-
-
+
+
+
账号管理(多账号)
+
+
+
+
-
- {showAccountsAdmin ? (
-
-
-
-
-
账号列表
-
- {(accountsAdmin || []).length ? (
-
-
-
- | ID |
- 名称 |
- 状态 |
- 测试网 |
- API KEY |
- SECRET |
- 操作 |
-
-
-
- {accountsAdmin.map((a) => (
-
- | #{a.id} |
- {a.name || '-'} |
-
-
- {a.status === 'active' ? '启用' : '禁用'}
-
- |
- {a.use_testnet ? '是' : '否'} |
- {a.api_key_masked || (a.has_api_key ? '已配置' : '未配置')} |
- {a.has_api_secret ? '已配置' : '未配置'} |
-
-
-
- |
-
- ))}
-
-
- ) : (
-
暂无账号(默认账号 #1 会自动存在)
- )}
-
-
-
- {credEditId ? (
+ {showAccountsAdmin ? (
+
-
更新账号 #{credEditId} 的密钥
+
新增账号
+
+
-
- ) : null}
-
- ) : null}
-
+
+
+
账号列表
+
+ {(accountsAdmin || []).length ? (
+
+
+
+ | ID |
+ 名称 |
+ 状态 |
+ 测试网 |
+ API KEY |
+ SECRET |
+ 操作 |
+
+
+
+ {accountsAdmin.map((a) => (
+
+ | #{a.id} |
+ {a.name || '-'} |
+
+
+ {a.status === 'active' ? '启用' : '禁用'}
+
+ |
+ {a.use_testnet ? '是' : '否'} |
+ {a.api_key_masked || (a.has_api_key ? '已配置' : '未配置')} |
+ {a.has_api_secret ? '已配置' : '未配置'} |
+
+
+
+ |
+
+ ))}
+
+
+ ) : (
+
暂无账号(默认账号 #1 会自动存在)
+ )}
+
+
+
+ {credEditId ? (
+
+
更新账号 #{credEditId} 的密钥
+
+
+ ) : null}
+
+ ) : null}
+
) : null}
-
+
{/* 预设方案快速切换 */}
@@ -1233,7 +1237,7 @@ const ConfigPanel = ({ currentUser }) => {
})()}
-
+
{/* 配置可行性检查提示 */}
{feasibilityCheck && (
@@ -1241,8 +1245,8 @@ const ConfigPanel = ({ currentUser }) => {
{feasibilityCheck.feasible ? '✓ 配置可行' : '⚠ 配置冲突'}
-
- 账户余额: {feasibilityCheck.account_balance?.toFixed(2) || 'N/A'} USDT |
+ 账户余额: {feasibilityCheck.account_balance?.toFixed(2) || 'N/A'} USDT |
基础杠杆: {feasibilityCheck.base_leverage || feasibilityCheck.leverage || 'N/A'}x
{feasibilityCheck.use_dynamic_leverage && feasibilityCheck.max_leverage && (
<> | 最大杠杆: {feasibilityCheck.max_leverage}x>
- )} |
+ )} |
最小保证金: {feasibilityCheck.current_config?.min_margin_usdt?.toFixed(2) || 'N/A'} USDT
{!feasibilityCheck.feasible && (
- 需要保证金占比: {feasibilityCheck.calculated_values?.required_position_percent?.toFixed(1)}% |
+ 需要保证金占比: {feasibilityCheck.calculated_values?.required_position_percent?.toFixed(1)}% |
最大允许保证金占比: {feasibilityCheck.calculated_values?.max_allowed_position_percent?.toFixed(1)}%
{feasibilityCheck.calculated_values?.actual_min_margin !== undefined && (
- 最小保证金占比可提供保证金: {feasibilityCheck.calculated_values.actual_min_margin.toFixed(2)} USDT
- (MIN_POSITION_PERCENT={feasibilityCheck.calculated_values.min_position_percent?.toFixed(1)}%) |
+ 最小保证金占比可提供保证金: {feasibilityCheck.calculated_values.actual_min_margin.toFixed(2)} USDT
+ (MIN_POSITION_PERCENT={feasibilityCheck.calculated_values.min_position_percent?.toFixed(1)}%) |
最小保证金要求: {feasibilityCheck.current_config?.min_margin_usdt?.toFixed(2)} USDT
)}
@@ -1317,7 +1321,7 @@ const ConfigPanel = ({ currentUser }) => {
)
}
-
+
// 普通建议
return (
@@ -1353,13 +1357,13 @@ const ConfigPanel = ({ currentUser }) => {
)}
)}
-
+
{message && (
{message}
)}
-
+
{Object.entries(configCategories).map(([category, label]) => (
{label}
@@ -1465,7 +1469,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
}
return val === null || val === undefined ? '' : val
}
-
+
const [value, setValue] = useState(config.value)
const [localValue, setLocalValue] = useState(getInitialDisplayValue(config.value))
const [isEditing, setIsEditing] = useState(false)
@@ -1485,7 +1489,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
const handleSave = () => {
setIsEditing(false)
-
+
// 处理localValue可能是字符串的情况
let processedValue = localValue
if (config.type === 'number') {
@@ -1494,7 +1498,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
setLocalValue(value)
return
}
-
+
// 处理字符串形式的数字输入(包括部分输入如 "0." 或 ".")
let numValue
if (typeof localValue === 'string') {
@@ -1515,7 +1519,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
} else {
numValue = localValue
}
-
+
if (isNaN(numValue)) {
// 如果输入无效,恢复原值
const restoreValue = isPercentKey
@@ -1524,7 +1528,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
setLocalValue(restoreValue)
return
}
-
+
processedValue = numValue
// 百分比配置
if (isPercentKey) {
@@ -1546,7 +1550,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
} else if (config.type === 'boolean') {
processedValue = localValue === 'true' || localValue === true
}
-
+
// 只有当值真正发生变化时才保存
if (processedValue !== value) {
onUpdate(processedValue)
@@ -1577,7 +1581,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
{config.description && (
-
)}
-