mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-04 11:30:58 +08:00
bugfix/ fix delete AI Model issue (#594)
* 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 <tinklefund@gmail.com> * 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 <tinklefund@gmail.com> --------- Co-authored-by: tinkle-community <tinklefund@gmail.com>
This commit is contained in:
@@ -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 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (confirm(t('confirmDeleteModel', language))) {
|
||||
onDelete(editingModelId)
|
||||
}
|
||||
}}
|
||||
onClick={() => onDelete(editingModelId)}
|
||||
className="p-2 rounded hover:bg-red-100 transition-colors"
|
||||
style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}
|
||||
title={t('deleteConfigFailed', language)}
|
||||
title={t('delete', language)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
@@ -1801,17 +1803,13 @@ function ExchangeConfigModal({
|
||||
{editingExchangeId && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (confirm(t('confirmDeleteExchange', language))) {
|
||||
onDelete(editingExchangeId)
|
||||
}
|
||||
}}
|
||||
onClick={() => onDelete(editingExchangeId)}
|
||||
className="p-2 rounded hover:bg-red-100 transition-colors"
|
||||
style={{
|
||||
background: 'rgba(246, 70, 93, 0.1)',
|
||||
color: '#F6465D',
|
||||
}}
|
||||
title={t('deleteConfigFailed', language)}
|
||||
title={t('delete', language)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user