feat(channel-monitor): gate UI by feature switch + polish form UX
- AppSidebar 三处菜单项(管理端渠道监控、用户端/个人页渠道状态)按 channel_monitor_enabled 条件展开,关闭时隐藏 - ChannelStatusView setInterval 随开关启停:关闭 clearInterval, 开启/未知态自动启动,避免禁用功能后仍在轮询 - MonitorFormDialog provider Select 改为 3 色单选按钮 (openai=emerald / anthropic=orange / gemini=sky),i18n 文案 供应商 → 平台 / Provider → Platform - MonitorKeyPickerDialog 按钮列表改为 name/key/group 三列表格 + 搜索框,按 key.group.platform === provider 过滤,避免跨平台误选 - form.provider 变化时清空 api_key,修复切换平台仍保留旧 key 的 错配 bug - providerPickerClass 抽取到 useChannelMonitorFormat composable, 统一 emerald/orange/sky 颜色语义,消除硬编码 Tailwind class 重复 - maskApiKey 工具函数统一(utils/maskApiKey.ts),KeysView 与 MonitorKeyPickerDialog 共用 slice(0,6)...slice(-4) 策略 - bump version to 0.1.114.27
This commit is contained in:
@@ -160,14 +160,34 @@ watch(items, () => {
|
||||
void ensureDetailsForWindow()
|
||||
})
|
||||
|
||||
function startTimer() {
|
||||
if (countdownTimer !== undefined) return
|
||||
countdownTimer = setInterval(tick, 1000) as unknown as number
|
||||
}
|
||||
|
||||
function stopTimer() {
|
||||
if (countdownTimer !== undefined) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = undefined
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => appStore.cachedPublicSettings?.channel_monitor_enabled,
|
||||
(enabled) => {
|
||||
if (enabled === false) stopTimer()
|
||||
else startTimer()
|
||||
},
|
||||
)
|
||||
|
||||
// ── Lifecycle ──
|
||||
onMounted(() => {
|
||||
void reload(false)
|
||||
countdownTimer = setInterval(tick, 1000) as unknown as number
|
||||
if (appStore.cachedPublicSettings?.channel_monitor_enabled !== false) startTimer()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (countdownTimer !== undefined) clearInterval(countdownTimer)
|
||||
stopTimer()
|
||||
if (abortController) abortController.abort()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<template #cell-key="{ value, row }">
|
||||
<div class="flex items-center gap-2">
|
||||
<code class="code text-xs">
|
||||
{{ maskKey(value) }}
|
||||
{{ maskApiKey(value) }}
|
||||
</code>
|
||||
<button
|
||||
@click="copyToClipboard(value, row.id)"
|
||||
@@ -1072,6 +1072,7 @@ import TablePageLayout from '@/components/layout/TablePageLayout.vue'
|
||||
import type { Column } from '@/components/common/types'
|
||||
import type { BatchApiKeyUsageStats } from '@/api/usage'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
import { maskApiKey } from '@/utils/maskApiKey'
|
||||
|
||||
// Helper to format date for datetime-local input
|
||||
const formatDateTimeLocal = (isoDate: string): string => {
|
||||
@@ -1260,11 +1261,6 @@ const filteredGroupOptions = computed(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const maskKey = (key: string): string => {
|
||||
if (key.length <= 12) return key
|
||||
return `${key.slice(0, 8)}...${key.slice(-4)}`
|
||||
}
|
||||
|
||||
const copyToClipboard = async (text: string, keyId: number) => {
|
||||
const success = await clipboardCopy(text, t('keys.copied'))
|
||||
if (success) {
|
||||
|
||||
Reference in New Issue
Block a user