2026-06-25 21:34:23 +08:00
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, markRaw, ref, watch } from 'vue';
|
|
|
|
|
import { useAuth } from '@/hooks/business/auth';
|
|
|
|
|
import LoginLogTab from './login-log/index.vue';
|
|
|
|
|
import OperateLogTab from './operate-log/index.vue';
|
|
|
|
|
import ApiAccessLogTab from './api-access-log/index.vue';
|
|
|
|
|
import ApiErrorLogTab from './api-error-log/index.vue';
|
|
|
|
|
import { LOG_TABS, type LogTabKey } from './shared';
|
|
|
|
|
|
|
|
|
|
defineOptions({ name: 'LogManagement' });
|
|
|
|
|
|
|
|
|
|
const { hasAuth } = useAuth();
|
|
|
|
|
const activeTab = ref<LogTabKey>('login-log');
|
|
|
|
|
|
|
|
|
|
const visibleTabs = computed(() => LOG_TABS.filter(tab => hasAuth(tab.queryPermission)));
|
|
|
|
|
const activeTabMeta = computed(() => visibleTabs.value.find(tab => tab.name === activeTab.value) || null);
|
|
|
|
|
|
|
|
|
|
const scopeOptions = computed(() =>
|
|
|
|
|
visibleTabs.value.map(tab => ({
|
|
|
|
|
label: tab.label,
|
|
|
|
|
value: tab.name
|
|
|
|
|
}))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const componentMap: Record<LogTabKey, object> = {
|
|
|
|
|
'login-log': markRaw(LoginLogTab),
|
|
|
|
|
'operate-log': markRaw(OperateLogTab),
|
|
|
|
|
'api-access-log': markRaw(ApiAccessLogTab),
|
|
|
|
|
'api-error-log': markRaw(ApiErrorLogTab)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
visibleTabs,
|
|
|
|
|
tabs => {
|
|
|
|
|
if (!tabs.length) return;
|
|
|
|
|
if (!tabs.some(tab => tab.name === activeTab.value)) {
|
|
|
|
|
activeTab.value = tabs[0].name;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="log-management-page">
|
|
|
|
|
<ElCard class="log-management-page__context" body-class="log-management-page__context-body">
|
|
|
|
|
<div v-if="visibleTabs.length" class="log-management-page__context-layout">
|
|
|
|
|
<div class="log-management-page__context-controls">
|
|
|
|
|
<ElSegmented v-model="activeTab" :options="scopeOptions" class="log-management-page__segmented" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="log-management-page__context-info">
|
|
|
|
|
<div class="log-management-page__context-main">
|
|
|
|
|
<div class="log-management-page__context-item">
|
|
|
|
|
<span class="log-management-page__context-label">当前日志</span>
|
|
|
|
|
<strong class="log-management-page__context-value">{{ activeTabMeta?.label || '--' }}</strong>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p class="log-management-page__context-desc">
|
|
|
|
|
{{ activeTabMeta?.description || '当前查看系统日志数据。' }}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<ElEmpty v-else description="暂无可查看的日志权限" />
|
|
|
|
|
</ElCard>
|
|
|
|
|
|
|
|
|
|
<div v-if="activeTabMeta" class="log-management-page__content">
|
2026-07-01 17:15:12 +08:00
|
|
|
<div class="log-management-page__pane">
|
|
|
|
|
<KeepAlive>
|
|
|
|
|
<component :is="componentMap[activeTab]" class="log-management-page__tab" />
|
|
|
|
|
</KeepAlive>
|
|
|
|
|
</div>
|
2026-06-25 21:34:23 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.log-management-page {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 16px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context {
|
|
|
|
|
border: 1px solid var(--el-border-color-light);
|
|
|
|
|
background: var(--el-fill-color-blank);
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.log-management-page__context-body) {
|
|
|
|
|
padding: 16px 18px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-layout {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-controls {
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.log-management-page__segmented) {
|
|
|
|
|
padding: 6px;
|
|
|
|
|
background: var(--el-fill-color-light);
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.log-management-page__segmented .el-segmented__item) {
|
|
|
|
|
min-width: 128px;
|
|
|
|
|
min-height: 40px;
|
|
|
|
|
padding: 0 24px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-info {
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-width: 0;
|
|
|
|
|
padding-left: 20px;
|
|
|
|
|
border-left: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-main {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
gap: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
min-width: 180px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-label {
|
|
|
|
|
color: var(--el-text-color-secondary);
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-value {
|
|
|
|
|
color: var(--el-text-color-primary);
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-desc {
|
|
|
|
|
margin: 10px 0 0;
|
|
|
|
|
color: var(--el-text-color-regular);
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__content {
|
2026-07-01 17:15:12 +08:00
|
|
|
display: flex;
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-height: 0;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__pane {
|
|
|
|
|
display: flex;
|
2026-06-25 21:34:23 +08:00
|
|
|
flex: 1;
|
2026-07-01 17:15:12 +08:00
|
|
|
min-width: 0;
|
|
|
|
|
min-height: 0;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.log-management-page__tab) {
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-width: 0;
|
2026-06-25 21:34:23 +08:00
|
|
|
min-height: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (width <= 1200px) {
|
|
|
|
|
.log-management-page__context-layout {
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.log-management-page__context-info {
|
|
|
|
|
padding-left: 0;
|
|
|
|
|
padding-top: 14px;
|
|
|
|
|
border-left: none;
|
|
|
|
|
border-top: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|