diff --git a/web/src/components/keys/GroupInfoCard.vue b/web/src/components/keys/GroupInfoCard.vue index ca20053..862d231 100644 --- a/web/src/components/keys/GroupInfoCard.vue +++ b/web/src/components/keys/GroupInfoCard.vue @@ -2,6 +2,7 @@ import { keysApi } from "@/api/keys"; import type { Group, GroupStatsResponse } from "@/types/models"; import { getGroupDisplayName } from "@/utils/display"; +import { copy } from "@/utils/clipboard"; import { Pencil, Trash } from "@vicons/ionicons5"; import { NButton, @@ -124,15 +125,16 @@ function formatPercentage(num: number): string { return `${(num * 100).toFixed(1)}%`; } -function copyUrl(url: string) { - navigator.clipboard - .writeText(url) - .then(() => { - window.$message.success("地址已复制到剪贴板"); - }) - .catch(() => { - window.$message.error("复制失败"); - }); +async function copyUrl(url: string) { + if (!url) { + return; + } + const success = await copy(url); + if (success) { + window.$message.success("地址已复制到剪贴板"); + } else { + window.$message.error("复制失败"); + } } function resetPage() { diff --git a/web/src/components/keys/KeyTable.vue b/web/src/components/keys/KeyTable.vue index b50bf27..c1a0d04 100644 --- a/web/src/components/keys/KeyTable.vue +++ b/web/src/components/keys/KeyTable.vue @@ -3,6 +3,7 @@ import { keysApi } from "@/api/keys"; import type { APIKey, Group, KeyStatus } from "@/types/models"; import { appState } from "@/utils/app-state"; import { getGroupDisplayName, maskKey } from "@/utils/display"; +import { copy } from "@/utils/clipboard"; import { AddCircleOutline, AlertCircleOutline, @@ -149,15 +150,13 @@ async function loadKeys() { } } -function copyKey(key: KeyRow) { - navigator.clipboard - .writeText(key.key_value) - .then(() => { - window.$message.success("密钥已复制到剪贴板"); - }) - .catch(() => { - window.$message.error("复制失败"); - }); +async function copyKey(key: KeyRow) { + const success = await copy(key.key_value); + if (success) { + window.$message.success("密钥已复制到剪贴板"); + } else { + window.$message.error("复制失败"); + } } async function testKey(_key: KeyRow) { diff --git a/web/src/utils/clipboard.ts b/web/src/utils/clipboard.ts new file mode 100644 index 0000000..618b987 --- /dev/null +++ b/web/src/utils/clipboard.ts @@ -0,0 +1,35 @@ +/** + * 复制文本 + */ +export async function copy(text: string): Promise { + // navigator.clipboard 仅在安全上下文(HTTPS)或 localhost 中可用 + if (navigator.clipboard && window.isSecureContext) { + try { + await navigator.clipboard.writeText(text); + return true; + } catch (e) { + console.error("使用 navigator.clipboard 复制失败:", e); + } + } + + // 后备方案:使用已弃用但兼容性更好的 execCommand + try { + const input = document.createElement("input"); + input.style.position = "fixed"; + input.style.opacity = "0"; + input.value = text; + document.body.appendChild(input); + input.select(); + const result = document.execCommand("copy"); + document.body.removeChild(input); + + if (!result) { + console.error("使用 execCommand 复制失败"); + return false; + } + return true; + } catch (e) { + console.error("后备复制方法执行出错:", e); + return false; + } +}