Skip to content

Commit ed2d9f0

Browse files
committed
feat: 分组信息显示代理密钥
1 parent 74a7293 commit ed2d9f0

File tree

3 files changed

+99
-7
lines changed

3 files changed

+99
-7
lines changed

web/src/components/common/ProxyKeysInput.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,7 @@ function handleInput(value: string) {
168168
/>
169169
</div>
170170
<div style="color: #999; font-size: 12px; line-height: 1.4">
171-
<p style="margin: 0">密钥格式:sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
172-
<p style="margin: 4px 0 0 0">生成的密钥将会插入到当前输入框内容的后面,以逗号分隔</p>
171+
<p>生成的密钥将会插入到当前输入框内容的后面,以逗号分隔</p>
173172
</div>
174173
</n-space>
175174
</n-modal>

web/src/components/keys/GroupInfoCard.vue

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { keysApi } from "@/api/keys";
33
import type { Group, GroupConfigOption, GroupStatsResponse } from "@/types/models";
44
import { appState } from "@/utils/app-state";
55
import { copy } from "@/utils/clipboard";
6-
import { getGroupDisplayName } from "@/utils/display";
7-
import { Pencil, Trash } from "@vicons/ionicons5";
6+
import { getGroupDisplayName, maskProxyKeys } from "@/utils/display";
7+
import { CopyOutline, EyeOffOutline, EyeOutline, Pencil, Trash } from "@vicons/ionicons5";
88
import {
99
NButton,
10+
NButtonGroup,
1011
NCard,
1112
NCollapse,
1213
NCollapseItem,
@@ -20,7 +21,7 @@ import {
2021
NTooltip,
2122
useDialog,
2223
} from "naive-ui";
23-
import { onMounted, ref, watch } from "vue";
24+
import { computed, onMounted, ref, watch } from "vue";
2425
import GroupFormModal from "./GroupFormModal.vue";
2526
2627
interface Props {
@@ -43,6 +44,30 @@ const showEditModal = ref(false);
4344
const delLoading = ref(false);
4445
const expandedName = ref<string[]>([]);
4546
const configOptions = ref<GroupConfigOption[]>([]);
47+
const showProxyKeys = ref(false);
48+
49+
const proxyKeysDisplay = computed(() => {
50+
if (!props.group?.proxy_keys) {
51+
return "-";
52+
}
53+
if (showProxyKeys.value) {
54+
return props.group.proxy_keys.replace(/,/g, "\n");
55+
}
56+
return maskProxyKeys(props.group.proxy_keys);
57+
});
58+
59+
async function copyProxyKeys() {
60+
if (!props.group?.proxy_keys) {
61+
return;
62+
}
63+
const keysToCopy = props.group.proxy_keys.replace(/,/g, "\n");
64+
const success = await copy(keysToCopy);
65+
if (success) {
66+
window.$message.success("代理密钥已复制到剪贴板");
67+
} else {
68+
window.$message.error("复制失败");
69+
}
70+
}
4671
4772
onMounted(() => {
4873
loadStats();
@@ -385,10 +410,41 @@ function resetPage() {
385410
{{ group?.validation_endpoint }}
386411
</n-form-item>
387412
</n-grid-item>
388-
<n-grid-item>
413+
<n-grid-item :span="2">
414+
<n-form-item label="代理密钥:">
415+
<div class="proxy-keys-content">
416+
<span class="key-text">{{ proxyKeysDisplay }}</span>
417+
<n-button-group size="small" class="key-actions" v-if="group?.proxy_keys">
418+
<n-tooltip trigger="hover">
419+
<template #trigger>
420+
<n-button quaternary circle @click="showProxyKeys = !showProxyKeys">
421+
<template #icon>
422+
<n-icon
423+
:component="showProxyKeys ? EyeOffOutline : EyeOutline"
424+
/>
425+
</template>
426+
</n-button>
427+
</template>
428+
{{ showProxyKeys ? "隐藏密钥" : "显示密钥" }}
429+
</n-tooltip>
430+
<n-tooltip trigger="hover">
431+
<template #trigger>
432+
<n-button quaternary circle @click="copyProxyKeys">
433+
<template #icon>
434+
<n-icon :component="CopyOutline" />
435+
</template>
436+
</n-button>
437+
</template>
438+
复制密钥
439+
</n-tooltip>
440+
</n-button-group>
441+
</div>
442+
</n-form-item>
443+
</n-grid-item>
444+
<n-grid-item :span="2">
389445
<n-form-item label="描述:">
390446
<div class="description-content">
391-
{{ group?.description }}
447+
{{ group?.description || "-" }}
392448
</div>
393449
</n-form-item>
394450
</n-grid-item>
@@ -613,6 +669,28 @@ function resetPage() {
613669
color: #374151;
614670
}
615671
672+
.proxy-keys-content {
673+
display: flex;
674+
align-items: flex-start;
675+
justify-content: space-between;
676+
width: 100%;
677+
gap: 8px;
678+
}
679+
680+
.key-text {
681+
flex-grow: 1;
682+
font-family: monospace;
683+
white-space: pre-wrap;
684+
word-break: break-all;
685+
line-height: 1.5;
686+
padding-top: 4px; /* Align with buttons */
687+
color: #374151;
688+
}
689+
690+
.key-actions {
691+
flex-shrink: 0;
692+
}
693+
616694
/* 配置项tooltip样式 */
617695
.config-label {
618696
display: inline-flex;

web/src/utils/display.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,18 @@ export function maskKey(key: string): string {
4949
}
5050
return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
5151
}
52+
53+
/**
54+
* Masks a comma-separated string of keys.
55+
* @param keys The comma-separated keys string.
56+
* @returns The masked keys string.
57+
*/
58+
export function maskProxyKeys(keys: string): string {
59+
if (!keys) {
60+
return "";
61+
}
62+
return keys
63+
.split(",")
64+
.map(key => maskKey(key.trim()))
65+
.join(", ");
66+
}

0 commit comments

Comments
 (0)