feat: 分组信息显示代理密钥
This commit is contained in:
@@ -168,8 +168,7 @@ function handleInput(value: string) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style="color: #999; font-size: 12px; line-height: 1.4">
|
<div style="color: #999; font-size: 12px; line-height: 1.4">
|
||||||
<p style="margin: 0">密钥格式:sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
|
<p>生成的密钥将会插入到当前输入框内容的后面,以逗号分隔</p>
|
||||||
<p style="margin: 4px 0 0 0">生成的密钥将会插入到当前输入框内容的后面,以逗号分隔</p>
|
|
||||||
</div>
|
</div>
|
||||||
</n-space>
|
</n-space>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
|
@@ -3,10 +3,11 @@ import { keysApi } from "@/api/keys";
|
|||||||
import type { Group, GroupConfigOption, GroupStatsResponse } from "@/types/models";
|
import type { Group, GroupConfigOption, GroupStatsResponse } from "@/types/models";
|
||||||
import { appState } from "@/utils/app-state";
|
import { appState } from "@/utils/app-state";
|
||||||
import { copy } from "@/utils/clipboard";
|
import { copy } from "@/utils/clipboard";
|
||||||
import { getGroupDisplayName } from "@/utils/display";
|
import { getGroupDisplayName, maskProxyKeys } from "@/utils/display";
|
||||||
import { Pencil, Trash } from "@vicons/ionicons5";
|
import { CopyOutline, EyeOffOutline, EyeOutline, Pencil, Trash } from "@vicons/ionicons5";
|
||||||
import {
|
import {
|
||||||
NButton,
|
NButton,
|
||||||
|
NButtonGroup,
|
||||||
NCard,
|
NCard,
|
||||||
NCollapse,
|
NCollapse,
|
||||||
NCollapseItem,
|
NCollapseItem,
|
||||||
@@ -20,7 +21,7 @@ import {
|
|||||||
NTooltip,
|
NTooltip,
|
||||||
useDialog,
|
useDialog,
|
||||||
} from "naive-ui";
|
} from "naive-ui";
|
||||||
import { onMounted, ref, watch } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import GroupFormModal from "./GroupFormModal.vue";
|
import GroupFormModal from "./GroupFormModal.vue";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -43,6 +44,30 @@ const showEditModal = ref(false);
|
|||||||
const delLoading = ref(false);
|
const delLoading = ref(false);
|
||||||
const expandedName = ref<string[]>([]);
|
const expandedName = ref<string[]>([]);
|
||||||
const configOptions = ref<GroupConfigOption[]>([]);
|
const configOptions = ref<GroupConfigOption[]>([]);
|
||||||
|
const showProxyKeys = ref(false);
|
||||||
|
|
||||||
|
const proxyKeysDisplay = computed(() => {
|
||||||
|
if (!props.group?.proxy_keys) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
if (showProxyKeys.value) {
|
||||||
|
return props.group.proxy_keys.replace(/,/g, "\n");
|
||||||
|
}
|
||||||
|
return maskProxyKeys(props.group.proxy_keys);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function copyProxyKeys() {
|
||||||
|
if (!props.group?.proxy_keys) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keysToCopy = props.group.proxy_keys.replace(/,/g, "\n");
|
||||||
|
const success = await copy(keysToCopy);
|
||||||
|
if (success) {
|
||||||
|
window.$message.success("代理密钥已复制到剪贴板");
|
||||||
|
} else {
|
||||||
|
window.$message.error("复制失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadStats();
|
loadStats();
|
||||||
@@ -385,10 +410,41 @@ function resetPage() {
|
|||||||
{{ group?.validation_endpoint }}
|
{{ group?.validation_endpoint }}
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-grid-item>
|
</n-grid-item>
|
||||||
<n-grid-item>
|
<n-grid-item :span="2">
|
||||||
|
<n-form-item label="代理密钥:">
|
||||||
|
<div class="proxy-keys-content">
|
||||||
|
<span class="key-text">{{ proxyKeysDisplay }}</span>
|
||||||
|
<n-button-group size="small" class="key-actions" v-if="group?.proxy_keys">
|
||||||
|
<n-tooltip trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button quaternary circle @click="showProxyKeys = !showProxyKeys">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon
|
||||||
|
:component="showProxyKeys ? EyeOffOutline : EyeOutline"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
{{ showProxyKeys ? "隐藏密钥" : "显示密钥" }}
|
||||||
|
</n-tooltip>
|
||||||
|
<n-tooltip trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button quaternary circle @click="copyProxyKeys">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="CopyOutline" />
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
复制密钥
|
||||||
|
</n-tooltip>
|
||||||
|
</n-button-group>
|
||||||
|
</div>
|
||||||
|
</n-form-item>
|
||||||
|
</n-grid-item>
|
||||||
|
<n-grid-item :span="2">
|
||||||
<n-form-item label="描述:">
|
<n-form-item label="描述:">
|
||||||
<div class="description-content">
|
<div class="description-content">
|
||||||
{{ group?.description }}
|
{{ group?.description || "-" }}
|
||||||
</div>
|
</div>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-grid-item>
|
</n-grid-item>
|
||||||
@@ -613,6 +669,28 @@ function resetPage() {
|
|||||||
color: #374151;
|
color: #374151;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.proxy-keys-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-text {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-family: monospace;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding-top: 4px; /* Align with buttons */
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-actions {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 配置项tooltip样式 */
|
/* 配置项tooltip样式 */
|
||||||
.config-label {
|
.config-label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@@ -49,3 +49,18 @@ export function maskKey(key: string): string {
|
|||||||
}
|
}
|
||||||
return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
|
return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a comma-separated string of keys.
|
||||||
|
* @param keys The comma-separated keys string.
|
||||||
|
* @returns The masked keys string.
|
||||||
|
*/
|
||||||
|
export function maskProxyKeys(keys: string): string {
|
||||||
|
if (!keys) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
.split(",")
|
||||||
|
.map(key => maskKey(key.trim()))
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user