From e49aa09de109d01be92a49712bd59c8aaaadcef2 Mon Sep 17 00:00:00 2001 From: Sue <177699783@qq.com> Date: Tue, 11 Nov 2025 09:34:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B8=81=E5=AE=89?= =?UTF-8?q?=E7=99=BD=E5=90=8D=E5=8D=95IP=E5=A4=8D=E5=88=B6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=A4=B1=E6=95=88=E9=97=AE=E9=A2=98=20(#680)=20##=20?= =?UTF-8?q?=F0=9F=90=9B=20=E9=97=AE=E9=A2=98=E6=8F=8F=E8=BF=B0=20=E5=B8=81?= =?UTF-8?q?=E5=AE=89=E4=BA=A4=E6=98=93=E6=89=80=E9=85=8D=E7=BD=AE=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=B8=AD=E7=9A=84=E6=9C=8D=E5=8A=A1=E5=99=A8IP?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD=E6=97=A0=E6=B3=95=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E5=B7=A5=E4=BD=9C=20##=20=F0=9F=94=8D=20=E6=A0=B9?= =?UTF-8?q?=E5=9B=A0=E5=88=86=E6=9E=90=20=E5=8E=9F=E5=A7=8B=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E4=BB=85=E4=BD=BF=E7=94=A8=20navigator.clipboard.writ?= =?UTF-8?q?eText()=20API:=20-=20=E5=9C=A8=E6=9F=90=E4=BA=9B=E6=B5=8F?= =?UTF-8?q?=E8=A7=88=E5=99=A8=E7=8E=AF=E5=A2=83=E4=B8=8B=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E6=88=96=E8=A2=AB=E9=98=BB=E6=AD=A2=20-=20=E9=9C=80?= =?UTF-8?q?=E8=A6=81=20HTTPS=20=E6=88=96=20localhost=20=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=20-=20=E7=BC=BA=E5=B0=91=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=92=8C=E7=94=A8=E6=88=B7=E5=8F=8D=E9=A6=88=20##=20=E2=9C=85?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=E6=96=B9=E6=A1=88=201.=20**=E5=8F=8C?= =?UTF-8?q?=E9=87=8D=E9=99=8D=E7=BA=A7=E6=9C=BA=E5=88=B6**:=20=20=20=20-?= =?UTF-8?q?=20=E4=BC=98=E5=85=88=E4=BD=BF=E7=94=A8=E7=8E=B0=E4=BB=A3=20Cli?= =?UTF-8?q?pboard=20API=20=20=20=20-=20=E9=99=8D=E7=BA=A7=E5=88=B0?= =?UTF-8?q?=E4=BC=A0=E7=BB=9F=20execCommand=20=E6=96=B9=E6=B3=95=202.=20**?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86**:=20=20=20=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20try-catch=20=E9=94=99=E8=AF=AF=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=20=20=20=20-=20=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=8F=8B=E5=A5=BD=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=20=20=20=20-=20=E6=8F=90=E4=BE=9BIP=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E4=BE=9B=E7=94=A8=E6=88=B7=E6=89=8B=E5=8A=A8=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=203.=20**=E5=A4=9A=E8=AF=AD=E8=A8=80=E6=94=AF=E6=8C=81**:=20?= =?UTF-8?q?=20=20=20-=20=E6=B7=BB=E5=8A=A0=20copyIPFailed=20=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E9=94=AE(=E4=B8=AD=E8=8B=B1=E6=96=87)=20##=20?= =?UTF-8?q?=F0=9F=93=9D=20=E4=BF=AE=E6=94=B9=E6=96=87=E4=BB=B6=20-=20web/s?= =?UTF-8?q?rc/components/AITradersPage.tsx=20=20=20-=20handleCopyIP=20?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=87=8D=E6=9E=84=E4=B8=BA=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E5=87=BD=E6=95=B0=20=20=20-=20=E6=B7=BB=E5=8A=A0=E5=8F=8C?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E5=88=B6=E6=9C=BA=E5=88=B6=E5=92=8C=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86=20-=20web/src/i18n/translations.ts?= =?UTF-8?q?=20=20=20-=20=E6=B7=BB=E5=8A=A0=20copyIPFailed=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=8F=90=E7=A4=BA=E7=BF=BB=E8=AF=91=20##=20?= =?UTF-8?q?=F0=9F=A7=AA=20=E6=B5=8B=E8=AF=95=E9=AA=8C=E8=AF=81=20=E2=9C=85?= =?UTF-8?q?=20TypeScript=20=E7=BC=96=E8=AF=91=E9=80=9A=E8=BF=87=20?= =?UTF-8?q?=E2=9C=85=20Vite=20=E6=9E=84=E5=BB=BA=E6=88=90=E5=8A=9F=20?= =?UTF-8?q?=E2=9C=85=20=E6=94=AF=E6=8C=81=E7=8E=B0=E4=BB=A3=E5=92=8C?= =?UTF-8?q?=E4=BC=A0=E7=BB=9F=E6=B5=8F=E8=A7=88=E5=99=A8=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=20Co-authored-by:=20tinkle-community=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/AITradersPage.tsx | 40 ++++++++++++++++++++++++---- web/src/i18n/translations.ts | 2 ++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index e1af07f6..079a956d 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -1753,11 +1753,41 @@ function ExchangeConfigModal({ } }, [selectedExchangeId]) - const handleCopyIP = (ip: string) => { - navigator.clipboard.writeText(ip).then(() => { - setCopiedIP(true) - setTimeout(() => setCopiedIP(false), 2000) - }) + const handleCopyIP = async (ip: string) => { + try { + // 优先使用现代 Clipboard API + if (navigator.clipboard && navigator.clipboard.writeText) { + await navigator.clipboard.writeText(ip) + setCopiedIP(true) + setTimeout(() => setCopiedIP(false), 2000) + } else { + // 降级方案: 使用传统的 execCommand 方法 + const textArea = document.createElement('textarea') + textArea.value = ip + textArea.style.position = 'fixed' + textArea.style.left = '-999999px' + textArea.style.top = '-999999px' + document.body.appendChild(textArea) + textArea.focus() + textArea.select() + + try { + const successful = document.execCommand('copy') + if (successful) { + setCopiedIP(true) + setTimeout(() => setCopiedIP(false), 2000) + } else { + throw new Error('复制命令执行失败') + } + } finally { + document.body.removeChild(textArea) + } + } + } catch (err) { + console.error('复制失败:', err) + // 显示错误提示 + alert(t('copyIPFailed', language) || `复制失败: ${ip}\n请手动复制此IP地址`) + } } // 安全输入处理函数 diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts index 0b9ae9de..456005d8 100644 --- a/web/src/i18n/translations.ts +++ b/web/src/i18n/translations.ts @@ -373,6 +373,7 @@ export const translations = { serverIPAddresses: 'Server IP Addresses', copyIP: 'Copy', ipCopied: 'IP Copied', + copyIPFailed: 'Failed to copy IP address. Please copy manually', loadingServerIP: 'Loading server IP...', // Error Messages @@ -1143,6 +1144,7 @@ export const translations = { serverIPAddresses: '服务器IP地址', copyIP: '复制', ipCopied: 'IP已复制', + copyIPFailed: 'IP地址复制失败,请手动复制', loadingServerIP: '正在加载服务器IP...', // Error Messages