From 0e32e29ff6fff340ba91afe571b5b98bda9aeb69 Mon Sep 17 00:00:00 2001 From: chengqian Date: Tue, 4 Aug 2026 19:16:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(apikey):=E5=85=81=E8=AE=B8=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E5=A4=8D=E5=88=B6apikey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/tenant/src/views/service/ApiKeysPage.vue | 73 ++++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/web/tenant/src/views/service/ApiKeysPage.vue b/web/tenant/src/views/service/ApiKeysPage.vue index 6872288..e5510a5 100644 --- a/web/tenant/src/views/service/ApiKeysPage.vue +++ b/web/tenant/src/views/service/ApiKeysPage.vue @@ -32,6 +32,8 @@ interface ApiKey { const keys = ref([]) const loading = ref(false) +const copyingKeyId = ref(null) +const baseUrl = `${window.location.origin}/v1` const page = ref(1) const pageSize = ref(20) const total = ref(0) @@ -136,6 +138,40 @@ async function disableKey(keyId: number) { } } +async function copyKey(keyId: number) { + if (copyingKeyId.value !== null) return + + copyingKeyId.value = keyId + try { + const res: any = await request.get(`/tenant/api-keys/${keyId}/value`) + const plainKey = res.data?.data?.key + if (typeof plainKey !== 'string' || plainKey.length === 0) { + toast.error('未获取到 API Key') + return + } + + try { + await navigator.clipboard.writeText(plainKey) + toast.success('API Key 已复制到剪贴板') + } catch { + toast.error('复制失败,请检查浏览器剪贴板权限') + } + } catch { + // 请求错误由统一拦截器提示。 + } finally { + copyingKeyId.value = null + } +} + +async function copyBaseUrl() { + try { + await navigator.clipboard.writeText(baseUrl) + toast.success('Base URL 已复制到剪贴板') + } catch { + toast.error('复制失败,请检查浏览器剪贴板权限') + } +} + function formatDate(d: string | null): string { if (!d) return '永不过期' return d.replace('T', ' ').substring(0, 16) @@ -149,12 +185,25 @@ onMounted(() => {