chore: refactor logs structure
This commit is contained in:
@@ -51,7 +51,7 @@ const router = createRouter({
|
|||||||
{ path: 'languages', name: 'languages', component: () => import('@/views/languages/Languages.vue') },
|
{ path: 'languages', name: 'languages', component: () => import('@/views/languages/Languages.vue') },
|
||||||
{ path: 'agents', name: 'agents', component: () => import('@/views/agents/Agents.vue') },
|
{ path: 'agents', name: 'agents', component: () => import('@/views/agents/Agents.vue') },
|
||||||
{ path: 'history', name: 'history', component: () => import('@/views/history/History.vue') },
|
{ path: 'history', name: 'history', component: () => import('@/views/history/History.vue') },
|
||||||
{ path: 'logs', name: 'logs', component: () => import('@/views/loginlogs/LoginLogs.vue') },
|
{ path: 'logs', name: 'logs', component: () => import('@/views/logs/MessageLogs.vue') },
|
||||||
{ path: 'terminal', name: 'terminal', component: () => import('@/views/terminal/Terminal.vue') },
|
{ path: 'terminal', name: 'terminal', component: () => import('@/views/terminal/Terminal.vue') },
|
||||||
{ path: 'notify', name: 'notify', component: () => import('@/views/notify/Notify.vue') },
|
{ path: 'notify', name: 'notify', component: () => import('@/views/notify/Notify.vue') },
|
||||||
{ path: 'settings', name: 'settings', component: () => import('@/views/settings/Settings.vue') }
|
{ path: 'settings', name: 'settings', component: () => import('@/views/settings/Settings.vue') }
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
// 消息日志总览入口控制器
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||||
import { Search, RefreshCw, Trash2 } from 'lucide-vue-next'
|
import { Search, RefreshCw, Trash2 } from 'lucide-vue-next'
|
||||||
import LoginLogTab from './tabs/LoginLogTab.vue'
|
import LoginLogTab from './tabs/LoginLogTab.vue'
|
||||||
import SystemEventTab from './tabs/SystemEventTab.vue'
|
import SystemEventTab from './tabs/SystemEventTab.vue'
|
||||||
import PushLog from '@/views/notify/components/PushLog.vue'
|
import PushLogTab from './tabs/PushLogTab.vue'
|
||||||
import { LOG_LEVEL, LOG_STATUS } from '@/api'
|
import { LOG_LEVEL, LOG_STATUS } from '@/api'
|
||||||
|
|
||||||
const activeTab = ref('system')
|
const activeTab = ref('system')
|
||||||
@@ -30,10 +30,20 @@ function handleSearch() {
|
|||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRefresh() {
|
const isRefreshing = ref(false)
|
||||||
if (activeTab.value === 'system') systemTabRef.value?.fetchLogs()
|
|
||||||
else if (activeTab.value === 'push') pushLogRef.value?.fetchLogs()
|
async function handleRefresh() {
|
||||||
else if (activeTab.value === 'login') loginTabRef.value?.loadLogs()
|
if (isRefreshing.value) return
|
||||||
|
isRefreshing.value = true
|
||||||
|
try {
|
||||||
|
if (activeTab.value === 'system') await systemTabRef.value?.fetchLogs()
|
||||||
|
else if (activeTab.value === 'push') await pushLogRef.value?.fetchLogs()
|
||||||
|
else if (activeTab.value === 'login') await loginTabRef.value?.loadLogs()
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => {
|
||||||
|
isRefreshing.value = false
|
||||||
|
}, 400)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClear() {
|
function handleClear() {
|
||||||
@@ -49,7 +59,7 @@ watch(activeTab, () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Tabs v-model="activeTab" class="space-y-6 h-full flex flex-col">
|
<div class="space-y-6 h-full flex flex-col">
|
||||||
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4 shrink-0 px-1">
|
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4 shrink-0 px-1">
|
||||||
<div class="flex flex-col shrink-0">
|
<div class="flex flex-col shrink-0">
|
||||||
<h2 class="text-xl sm:text-2xl font-bold tracking-tight">消息日志</h2>
|
<h2 class="text-xl sm:text-2xl font-bold tracking-tight">消息日志</h2>
|
||||||
@@ -123,28 +133,23 @@ watch(activeTab, () => {
|
|||||||
|
|
||||||
<!-- 操作区域 -->
|
<!-- 操作区域 -->
|
||||||
<div :class="[activeTab === 'login' ? 'flex-1 sm:flex-none' : 'w-full lg:w-auto', 'flex items-center gap-2']">
|
<div :class="[activeTab === 'login' ? 'flex-1 sm:flex-none' : 'w-full lg:w-auto', 'flex items-center gap-2']">
|
||||||
<Button variant="outline" size="icon" class="h-9 w-9 shrink-0 shadow-sm" @click="handleRefresh" title="刷新">
|
<button type="button" class="inline-flex items-center justify-center h-9 w-9 rounded-md border border-border bg-background hover:bg-accent hover:text-accent-foreground shrink-0 shadow-sm transition-all cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed" :disabled="isRefreshing" @click="handleRefresh">
|
||||||
<RefreshCw class="h-4 w-4" />
|
<RefreshCw class="h-4 w-4 block transition-transform" :class="{ 'animate-spin': isRefreshing }" />
|
||||||
</Button>
|
</button>
|
||||||
|
|
||||||
<Button v-if="activeTab !== 'login'" variant="outline"
|
<button v-if="activeTab !== 'login'" type="button" class="inline-flex items-center justify-center h-9 px-3 rounded-md border border-destructive/20 bg-background text-destructive hover:bg-destructive/10 shrink-0 shadow-sm transition-colors gap-1.5 cursor-pointer" @click="handleClear">
|
||||||
class="flex-1 lg:flex-none lg:px-3 h-9 shadow-sm text-destructive border-destructive/20 hover:bg-destructive/10"
|
<Trash2 class="h-4 w-4 block" />
|
||||||
@click="handleClear" title="清空记录">
|
<span class="text-sm font-medium" :class="activeTab !== 'login' ? '' : 'hidden'">清空记录</span>
|
||||||
<Trash2 class="h-4 w-4 lg:mr-2" /> <span class="ml-2 lg:inline" :class="activeTab !== 'login' ? '' : 'hidden'">清空记录</span>
|
</button>
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- 桌面端标签切换 -->
|
<!-- 桌面端标签切换 -->
|
||||||
<TabsList class="h-9 p-1 bg-muted/30 border shrink-0 hidden lg:flex">
|
<Tabs v-model="activeTab" class="w-auto">
|
||||||
<TabsTrigger value="system" class="px-4 h-7 text-sm">
|
<TabsList class="h-9 p-1 bg-muted/30 border shrink-0 hidden lg:flex">
|
||||||
系统事件
|
<TabsTrigger value="system" class="px-4 h-7 text-sm">系统事件</TabsTrigger>
|
||||||
</TabsTrigger>
|
<TabsTrigger value="push" class="px-4 h-7 text-sm">推送日志</TabsTrigger>
|
||||||
<TabsTrigger value="push" class="px-4 h-7 text-sm">
|
<TabsTrigger value="login" class="px-4 h-7 text-sm">登录日志</TabsTrigger>
|
||||||
推送日志
|
</TabsList>
|
||||||
</TabsTrigger>
|
</Tabs>
|
||||||
<TabsTrigger value="login" class="px-4 h-7 text-sm">
|
|
||||||
登录日志
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<!-- 移动端标签切换 (简易版) -->
|
<!-- 移动端标签切换 (简易版) -->
|
||||||
<div class="lg:hidden flex-1 shrink-0 min-w-0">
|
<div class="lg:hidden flex-1 shrink-0 min-w-0">
|
||||||
@@ -164,17 +169,17 @@ watch(activeTab, () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1 min-h-0">
|
<div class="flex-1 min-h-0">
|
||||||
<TabsContent value="system" class="mt-0">
|
<div v-show="activeTab === 'system'" class="h-full">
|
||||||
<SystemEventTab ref="systemTabRef" :filters="filters.system" />
|
<SystemEventTab ref="systemTabRef" :filters="filters.system" />
|
||||||
</TabsContent>
|
</div>
|
||||||
|
|
||||||
<TabsContent value="push" class="mt-0">
|
<div v-show="activeTab === 'push'" class="h-full">
|
||||||
<PushLog ref="pushLogRef" :filters="filters.push" />
|
<PushLogTab ref="pushLogRef" :filters="filters.push" />
|
||||||
</TabsContent>
|
</div>
|
||||||
|
|
||||||
<TabsContent value="login" class="mt-0">
|
<div v-show="activeTab === 'login'" class="h-full">
|
||||||
<LoginLogTab ref="loginTabRef" :username="filters.login.username" />
|
<LoginLogTab ref="loginTabRef" :username="filters.login.username" />
|
||||||
</TabsContent>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import PushLog from '@/views/notify/components/PushLog.vue'
|
||||||
|
|
||||||
|
defineOptions({ name: 'PushLogTabWrapper' })
|
||||||
|
|
||||||
|
// 显式声明必填的非可选属性,完全对齐 PushLog 子组件强类型要求
|
||||||
|
defineProps<{
|
||||||
|
filters: {
|
||||||
|
keyword: string
|
||||||
|
status: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const pushLogRef = ref()
|
||||||
|
|
||||||
|
// 暴露标准代理接口给父级控制器 MessageLogs.vue 统一调用
|
||||||
|
defineExpose({
|
||||||
|
fetchLogs: () => pushLogRef.value?.fetchLogs(),
|
||||||
|
showClearConfirm: {
|
||||||
|
get() { return pushLogRef.value?.showClearConfirm },
|
||||||
|
set(v: boolean) { if (pushLogRef.value) pushLogRef.value.showClearConfirm = v }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PushLog ref="pushLogRef" :filters="filters" v-bind="$attrs" />
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user