From 506e9c5277a89bc1b2f4c5eb5047d8ca128d72fb Mon Sep 17 00:00:00 2001 From: Ember <15190419+0xEmberZz@users.noreply.github.com> Date: Thu, 6 Nov 2025 12:25:25 +0800 Subject: [PATCH] bugfix/ fix delete AI Model issue (#594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复删除AI模型/交易所后UI未刷新的问题 问题描述: 在配置界面删除AI模型或交易所后,虽然后端数据已更新,但前端UI仍然显示已删除的配置项。 根本原因: React的状态更新机制可能无法检测到数组内容的变化,特别是当API返回的数据与之前的引用相同时。 修复方案: 在 handleDeleteModelConfig 和 handleDeleteExchangeConfig 中使用数组展开运算符 [...items] 创建新数组,确保React能够检测到状态变化并触发重新渲染。 修改文件: - web/src/components/AITradersPage.tsx 影响范围: - AI模型删除功能 - 交易所删除功能 Fixes #591 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community * fix: 删除重复的确认对话框 问题描述: 删除AI模型或交易所时,确认对话框会弹出两次 根本原因: 1. ModelConfigModal 的删除按钮 onClick 中有一个 confirm 2. handleDeleteConfig 函数内部也有一个 confirm 修复方案: 移除 Modal 组件中的 confirm,保留 handleDeleteConfig 内部的确认逻辑,因为它包含了更完整的依赖检查功能 修改内容: - 移除 ModelConfigModal 删除按钮中的 confirm - 移除 ExchangeConfigModal 删除按钮中的 confirm - 更新 title 属性为更合适的翻译键 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community --------- Co-authored-by: tinkle-community --- web/src/components/AITradersPage.tsx | 56 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index 74a2e9b6..c69956c6 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -132,19 +132,21 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { }, [user, token]) // 只显示已配置的模型和交易所(有API Key的才算配置过) - const configuredModels = allModels?.filter((m) => m.apiKey && m.apiKey.trim() !== '') || [] - const configuredExchanges = allExchanges?.filter((e) => { - // Aster 交易所检查特殊字段 - if (e.id === 'aster') { - return e.asterUser && e.asterUser.trim() !== '' - } - // Hyperliquid 只检查私钥 - if (e.id === 'hyperliquid') { + const configuredModels = + allModels?.filter((m) => m.apiKey && m.apiKey.trim() !== '') || [] + const configuredExchanges = + allExchanges?.filter((e) => { + // Aster 交易所检查特殊字段 + if (e.id === 'aster') { + return e.asterUser && e.asterUser.trim() !== '' + } + // Hyperliquid 只检查私钥 + if (e.id === 'hyperliquid') { + return e.apiKey && e.apiKey.trim() !== '' + } + // 其他交易所检查 apiKey return e.apiKey && e.apiKey.trim() !== '' - } - // 其他交易所检查 apiKey - return e.apiKey && e.apiKey.trim() !== '' - }) || [] + }) || [] // 只在创建交易员时使用已启用且配置完整的 const enabledModels = allModels?.filter((m) => m.enabled && m.apiKey) || [] @@ -185,9 +187,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { // 检查交易所是否正在被运行中的交易员使用(用于UI禁用) const isExchangeInUse = (exchangeId: string) => { - return ( - traders?.some((t) => t.exchange_id === exchangeId && t.is_running) - ) + return traders?.some((t) => t.exchange_id === exchangeId && t.is_running) } // 检查模型是否被任何交易员使用(包括停止状态的) @@ -414,7 +414,10 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { }), updateApi: api.updateModelConfigs, refreshApi: api.getModelConfigs, - setItems: setAllModels, + setItems: (items) => { + // 使用函数式更新确保状态正确更新 + setAllModels([...items]) + }, closeModal: () => { setShowModelModal(false) setEditingModel(null) @@ -526,7 +529,10 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { }), updateApi: api.updateExchangeConfigs, refreshApi: api.getExchangeConfigs, - setItems: setAllExchanges, + setItems: (items) => { + // 使用函数式更新确保状态正确更新 + setAllExchanges([...items]) + }, closeModal: () => { setShowExchangeModal(false) setEditingExchange(null) @@ -1442,14 +1448,10 @@ function ModelConfigModal({ {editingModelId && ( @@ -1801,17 +1803,13 @@ function ExchangeConfigModal({ {editingExchangeId && (