diff --git a/web/src/api/keys.ts b/web/src/api/keys.ts index 883506d..85c5e79 100644 --- a/web/src/api/keys.ts +++ b/web/src/api/keys.ts @@ -1,4 +1,11 @@ -import type { APIKey, Group, GroupConfigOption, KeyStatus, TaskInfo } from "@/types/models"; +import type { + APIKey, + Group, + GroupConfigOption, + GroupStats, + KeyStatus, + TaskInfo, +} from "@/types/models"; import http from "@/utils/http"; export const keysApi = { @@ -26,10 +33,16 @@ export const keysApi = { }, // 获取分组统计信息 - async getGroupStats(): Promise { - // 传参补充groupId + async getGroupStats(): Promise { await new Promise(resolve => setTimeout(resolve, 200)); - return {}; + return { + total_keys: 0, + active_keys: 0, + requests_1h: 0, + requests_24h: 0, + requests_7d: 0, + failure_rate_24h: 0, + } as GroupStats; }, // 获取分组可配置参数 diff --git a/web/src/components/keys/GroupFormModal.vue b/web/src/components/keys/GroupFormModal.vue index 0777faf..06ce565 100644 --- a/web/src/components/keys/GroupFormModal.vue +++ b/web/src/components/keys/GroupFormModal.vue @@ -45,8 +45,22 @@ const message = useMessage(); const loading = ref(false); const formRef = ref(); +// 表单数据接口 +interface GroupFormData { + name: string; + display_name: string; + description: string; + upstreams: UpstreamInfo[]; + channel_type: "openai" | "gemini"; + sort: number; + test_model: string; + param_overrides: string; + config: Record; + configItems: ConfigItem[]; +} + // 表单数据 -const formData = reactive({ +const formData = reactive({ name: "", display_name: "", description: "", @@ -241,7 +255,7 @@ async function handleSubmit() { // 将configItems转换为config对象 const config: Record = {}; - formData.configItems.forEach((item: any) => { + formData.configItems.forEach((item: ConfigItem) => { if (item.key && item.key.trim()) { config[item.key] = item.value; } @@ -256,7 +270,7 @@ async function handleSubmit() { channel_type: formData.channel_type, sort: formData.sort, test_model: formData.test_model, - param_overrides: formData.param_overrides ? paramOverrides : null, + param_overrides: formData.param_overrides ? paramOverrides : undefined, config, }; @@ -431,7 +445,7 @@ async function handleSubmit() { value: opt.key, disabled: formData.configItems - .map((item: any) => item.key) + .map((item: ConfigItem) => item.key) ?.includes(opt.key) && opt.key !== configItem.key, })) " diff --git a/web/src/components/keys/KeyTable.vue b/web/src/components/keys/KeyTable.vue index da25a80..3a641eb 100644 --- a/web/src/components/keys/KeyTable.vue +++ b/web/src/components/keys/KeyTable.vue @@ -22,6 +22,7 @@ import { NSpace, NSpin, useDialog, + type MessageReactive, } from "naive-ui"; import { ref, watch } from "vue"; import KeyCreateDialog from "./KeyCreateDialog.vue"; @@ -66,7 +67,7 @@ const moreOptions = [ { label: "验证所有密钥", key: "validateAll" }, ]; -let testingMsg: any = null; +let testingMsg: MessageReactive | null = null; const isDeling = ref(false); const isRestoring = ref(false); @@ -246,19 +247,29 @@ async function deleteKey(key: KeyRow) { } function formatRelativeTime(date: string) { + if (!date) { + return "从未"; + } const now = new Date(); const target = new Date(date); - const diff = now.getTime() - target.getTime(); - const hours = Math.floor(diff / (1000 * 60 * 60)); - const days = Math.floor(hours / 24); + const diffSeconds = Math.floor((now.getTime() - target.getTime()) / 1000); + const diffMinutes = Math.floor(diffSeconds / 60); + const diffHours = Math.floor(diffMinutes / 60); + const diffDays = Math.floor(diffHours / 24); - if (days > 0) { - return `${days}天前`; - } else if (hours > 0) { - return `${hours}小时前`; - } else { - return "刚刚"; + if (diffDays > 0) { + return `${diffDays}天前`; } + if (diffHours > 0) { + return `${diffHours}小时前`; + } + if (diffMinutes > 0) { + return `${diffMinutes}分钟前`; + } + if (diffSeconds > 0) { + return `${diffSeconds}秒前`; + } + return "刚刚"; } function getStatusClass(status: KeyStatus): string { diff --git a/web/src/types/models.ts b/web/src/types/models.ts index c4df297..10f257e 100644 --- a/web/src/types/models.ts +++ b/web/src/types/models.ts @@ -41,7 +41,7 @@ export interface Group { config: Record; api_keys?: APIKey[]; endpoint?: string; - param_overrides: any; + param_overrides: Record; created_at?: string; updated_at?: string; }