refactor(debug): 更新调试组件,增强系统配置和用户信息打印功能
- 修改 DebugComponent.vue,重命名打印配置函数为 printSystemConfig,并新增打印用户信息、知识库信息和智能体配置的功能。 - 更新日志级别选择的实现方式,采用多选卡片样式,提升用户体验。 - 调整样式以优化界面布局,确保在不同屏幕尺寸下的适配性。 - 在 AppLayout.vue 中移除调试面板的浮动按钮,改为使用模态框展示调试组件。
This commit is contained in:
parent
9bc5b086f9
commit
105ade5273
@ -10,9 +10,21 @@
|
|||||||
<template #icon><ClearOutlined /></template>
|
<template #icon><ClearOutlined /></template>
|
||||||
清空
|
清空
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="printConfig">
|
<a-button @click="printSystemConfig">
|
||||||
<template #icon><SettingOutlined /></template>
|
<template #icon><SettingOutlined /></template>
|
||||||
打印配置
|
系统配置
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="printUserInfo">
|
||||||
|
<template #icon><UserOutlined /></template>
|
||||||
|
用户信息
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="printDatabaseInfo">
|
||||||
|
<template #icon><DatabaseOutlined /></template>
|
||||||
|
知识库信息
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="printAgentConfig">
|
||||||
|
<template #icon><RobotOutlined /></template>
|
||||||
|
智能体配置
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="toggleFullscreen">
|
<a-button @click="toggleFullscreen">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -24,6 +36,7 @@
|
|||||||
<a-tooltip :title="state.autoRefresh ? '点击停止自动刷新' : '点击开启自动刷新'">
|
<a-tooltip :title="state.autoRefresh ? '点击停止自动刷新' : '点击开启自动刷新'">
|
||||||
<a-button
|
<a-button
|
||||||
:type="state.autoRefresh ? 'primary' : 'default'"
|
:type="state.autoRefresh ? 'primary' : 'default'"
|
||||||
|
:class="{ 'auto-refresh-button': state.autoRefresh }"
|
||||||
@click="toggleAutoRefresh(!state.autoRefresh)"
|
@click="toggleAutoRefresh(!state.autoRefresh)"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -38,16 +51,31 @@
|
|||||||
<a-input-search
|
<a-input-search
|
||||||
v-model:value="state.searchText"
|
v-model:value="state.searchText"
|
||||||
placeholder="搜索日志..."
|
placeholder="搜索日志..."
|
||||||
style="width: 200px"
|
style="width: 200px; height: 32px;"
|
||||||
@search="onSearch"
|
@search="onSearch"
|
||||||
/>
|
/>
|
||||||
<a-select
|
<div class="log-level-selector">
|
||||||
v-model:value="state.selectedLevels"
|
<div class="multi-select-cards">
|
||||||
mode="multiple"
|
<div
|
||||||
placeholder="选择日志级别"
|
v-for="level in logLevels"
|
||||||
:options="logLevels"
|
:key="level.value"
|
||||||
@change="filterLogs"
|
class="option-card"
|
||||||
/>
|
:class="{
|
||||||
|
'selected': isLogLevelSelected(level.value),
|
||||||
|
'unselected': !isLogLevelSelected(level.value)
|
||||||
|
}"
|
||||||
|
@click="toggleLogLevel(level.value)"
|
||||||
|
>
|
||||||
|
<div class="option-content">
|
||||||
|
<span class="option-text">{{ level.label }}</span>
|
||||||
|
<div class="option-indicator">
|
||||||
|
<CheckCircleOutlined v-if="isLogLevelSelected(level.value)" />
|
||||||
|
<PlusCircleOutlined v-else />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="logContainer" class="log-container">
|
<div ref="logContainer" class="log-container">
|
||||||
@ -73,6 +101,7 @@
|
|||||||
import { ref, onMounted, onActivated, onUnmounted, nextTick, reactive, computed } from 'vue';
|
import { ref, onMounted, onActivated, onUnmounted, nextTick, reactive, computed } from 'vue';
|
||||||
import { useConfigStore } from '@/stores/config';
|
import { useConfigStore } from '@/stores/config';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
|
import { useDatabaseStore } from '@/stores/database';
|
||||||
import { useThrottleFn } from '@vueuse/core';
|
import { useThrottleFn } from '@vueuse/core';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
import {
|
import {
|
||||||
@ -81,13 +110,20 @@ import {
|
|||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
ClearOutlined,
|
ClearOutlined,
|
||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
SyncOutlined
|
SyncOutlined,
|
||||||
|
CheckCircleOutlined,
|
||||||
|
PlusCircleOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
DatabaseOutlined,
|
||||||
|
RobotOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { logApi } from '@/apis/admin_api';
|
import { logApi, systemConfigApi } from '@/apis/admin_api';
|
||||||
|
import { chatApi } from '@/apis/auth_api';
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const databaseStore = useDatabaseStore();
|
||||||
const config = configStore.config;
|
const config = configStore.config;
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
@ -126,7 +162,8 @@ let autoRefreshInterval = null;
|
|||||||
|
|
||||||
// 解析日志行
|
// 解析日志行
|
||||||
const parseLogLine = (line) => {
|
const parseLogLine = (line) => {
|
||||||
const match = line.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) - (\w+) - ([^-]+) - (.+)$/);
|
// 支持两种时间戳格式:带毫秒和不带毫秒
|
||||||
|
const match = line.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:,\d{3})?)\s*-\s*(\w+)\s*-\s*([^-]+?)\s*-\s*(.+)$/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return {
|
return {
|
||||||
timestamp: match[1],
|
timestamp: match[1],
|
||||||
@ -142,8 +179,14 @@ const parseLogLine = (line) => {
|
|||||||
// 格式化时间戳
|
// 格式化时间戳
|
||||||
const formatTimestamp = (timestamp) => {
|
const formatTimestamp = (timestamp) => {
|
||||||
try {
|
try {
|
||||||
// 将 "2025-03-10 08:26:37,269" 格式转换为 "2025-03-10 08:26:37.269"
|
// 处理带毫秒的格式:将 "2025-03-10 08:26:37,269" 转换为 "2025-03-10 08:26:37.269"
|
||||||
const normalizedTimestamp = timestamp.replace(',', '.');
|
let normalizedTimestamp = timestamp.replace(',', '.');
|
||||||
|
|
||||||
|
// 如果没有毫秒,添加 .000
|
||||||
|
if (!/\.\d{3}$/.test(normalizedTimestamp)) {
|
||||||
|
normalizedTimestamp += '.000';
|
||||||
|
}
|
||||||
|
|
||||||
const date = dayjs(normalizedTimestamp);
|
const date = dayjs(normalizedTimestamp);
|
||||||
return date.isValid() ? date.format('HH:mm:ss.SSS') : timestamp;
|
return date.isValid() ? date.format('HH:mm:ss.SSS') : timestamp;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -204,6 +247,24 @@ const filterLogs = () => {
|
|||||||
// 过滤会通过computed自动触发
|
// 过滤会通过computed自动触发
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 日志级别选择相关方法
|
||||||
|
const isLogLevelSelected = (level) => {
|
||||||
|
return state.selectedLevels.includes(level);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleLogLevel = (level) => {
|
||||||
|
const currentLevels = [...state.selectedLevels];
|
||||||
|
const index = currentLevels.indexOf(level);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
currentLevels.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
currentLevels.push(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.selectedLevels = currentLevels;
|
||||||
|
};
|
||||||
|
|
||||||
// 自动刷新
|
// 自动刷新
|
||||||
const toggleAutoRefresh = (value) => {
|
const toggleAutoRefresh = (value) => {
|
||||||
if (!checkAdminPermission()) return;
|
if (!checkAdminPermission()) return;
|
||||||
@ -285,16 +346,80 @@ onUnmounted(() => {
|
|||||||
document.removeEventListener('msfullscreenchange', handleFullscreenChange);
|
document.removeEventListener('msfullscreenchange', handleFullscreenChange);
|
||||||
});
|
});
|
||||||
|
|
||||||
const printConfig = () => {
|
// 打印系统配置
|
||||||
|
const printSystemConfig = () => {
|
||||||
if (!checkAdminPermission()) return;
|
if (!checkAdminPermission()) return;
|
||||||
console.log('Current config:', config);
|
console.log('=== 系统配置 ===');
|
||||||
|
console.log(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打印用户信息
|
||||||
|
const printUserInfo = () => {
|
||||||
|
if (!checkAdminPermission()) return;
|
||||||
|
console.log('=== 用户信息 ===');
|
||||||
|
const userInfo = {
|
||||||
|
token: userStore.token ? '*** (已隐藏)' : null,
|
||||||
|
userId: userStore.userId,
|
||||||
|
username: userStore.username,
|
||||||
|
userRole: userStore.userRole,
|
||||||
|
isLoggedIn: userStore.isLoggedIn,
|
||||||
|
isAdmin: userStore.isAdmin,
|
||||||
|
isSuperAdmin: userStore.isSuperAdmin
|
||||||
|
};
|
||||||
|
console.log(JSON.stringify(userInfo, null, 2));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打印知识库信息
|
||||||
|
const printDatabaseInfo = async () => {
|
||||||
|
if (!checkAdminPermission()) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('=== 知识库信息 ===');
|
||||||
|
|
||||||
|
// 直接调用API获取最新的数据库信息
|
||||||
|
await databaseStore.refreshDatabase();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取知识库信息失败:', error);
|
||||||
|
message.error('获取知识库信息失败: ' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打印智能体配置
|
||||||
|
const printAgentConfig = async () => {
|
||||||
|
if (!checkAdminPermission()) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('=== 智能体配置 ===');
|
||||||
|
|
||||||
|
// 获取智能体列表
|
||||||
|
const agentsData = await chatApi.getAgents();
|
||||||
|
console.log('智能体列表:', JSON.stringify(agentsData.agents, null, 2));
|
||||||
|
|
||||||
|
// 获取默认智能体
|
||||||
|
const defaultAgent = await chatApi.getDefaultAgent();
|
||||||
|
console.log('默认智能体:', JSON.stringify(defaultAgent, null, 2));
|
||||||
|
|
||||||
|
// 获取每个智能体的配置
|
||||||
|
for (const agent of agentsData.agents) {
|
||||||
|
try {
|
||||||
|
const agentConfig = await systemConfigApi.getAgentConfig(agent.name);
|
||||||
|
console.log(`智能体 "${agent.name}" 配置:`, JSON.stringify(agentConfig, null, 2));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`智能体 "${agent.name}" 配置获取失败:`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取智能体配置失败:', error);
|
||||||
|
message.error('获取智能体配置失败: ' + error.message);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.log-viewer {
|
.log-viewer {
|
||||||
background: white;
|
background: white;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-viewer.fullscreen {
|
.log-viewer.fullscreen {
|
||||||
@ -303,24 +428,68 @@ const printConfig = () => {
|
|||||||
|
|
||||||
.control-panel {
|
.control-panel {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--gray-50);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.button-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
min-width: 80px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
border-color: var(--gray-300);
|
||||||
|
color: var(--gray-700);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--main-color);
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-btn-primary {
|
||||||
|
background-color: var(--main-color);
|
||||||
|
border-color: var(--main-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--main-600);
|
||||||
|
border-color: var(--main-600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.refresh-interval {
|
.refresh-interval {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auto-refresh-button {
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-group {
|
.filter-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 16px;
|
||||||
margin-bottom: 10px;
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
@ -328,7 +497,7 @@ const printConfig = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.log-container {
|
.log-container {
|
||||||
height: calc(100vh - 200px);
|
height: calc(80vh - 200px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: #0C0C0C;
|
background: #0C0C0C;
|
||||||
color: #D1D1D1;
|
color: #D1D1D1;
|
||||||
@ -402,15 +571,95 @@ const printConfig = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:fullscreen .log-container {
|
:fullscreen .log-container {
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 160PX);
|
||||||
}
|
}
|
||||||
|
|
||||||
:-webkit-full-screen .log-container {
|
:-webkit-full-screen .log-container {
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 160PX);
|
||||||
}
|
}
|
||||||
|
|
||||||
:-ms-fullscreen .log-container {
|
:-ms-fullscreen .log-container {
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 160PX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.multi-select-cards {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.option-card {
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
background: var(--gray-0);
|
||||||
|
user-select: none;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--main-color);
|
||||||
|
background: var(--main-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border-color: var(--main-color);
|
||||||
|
background: var(--main-10);
|
||||||
|
|
||||||
|
.option-indicator {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
color: var(--main-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unselected {
|
||||||
|
.option-indicator {
|
||||||
|
color: var(--gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
color: var(--gray-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-indicator {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式适配 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.log-level-selector {
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multi-select-cards .options-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, KeepAlive, onMounted, computed } from 'vue'
|
import { ref, reactive, onMounted, useTemplateRef, shallowRef } from 'vue'
|
||||||
import { RouterLink, RouterView, useRoute } from 'vue-router'
|
import { RouterLink, RouterView, useRoute } from 'vue-router'
|
||||||
import {
|
import {
|
||||||
GithubOutlined,
|
GithubOutlined,
|
||||||
BugOutlined,
|
|
||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { Bot, Waypoints, LibraryBig, MessageSquareMore, Settings } from 'lucide-vue-next';
|
import { Bot, Waypoints, LibraryBig, Settings } from 'lucide-vue-next';
|
||||||
|
import { onLongPress } from '@vueuse/core'
|
||||||
|
|
||||||
import { useConfigStore } from '@/stores/config'
|
import { useConfigStore } from '@/stores/config'
|
||||||
import { useDatabaseStore } from '@/stores/database'
|
import { useDatabaseStore } from '@/stores/database'
|
||||||
import { useInfoStore } from '@/stores/info'
|
import { useInfoStore } from '@/stores/info'
|
||||||
import DebugComponent from '@/components/DebugComponent.vue'
|
|
||||||
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
||||||
|
import DebugComponent from '@/components/DebugComponent.vue'
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const databaseStore = useDatabaseStore()
|
const databaseStore = useDatabaseStore()
|
||||||
@ -109,28 +109,6 @@ const mainList = [{
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app-layout" :class="{ 'use-top-bar': layoutSettings.useTopBar }">
|
<div class="app-layout" :class="{ 'use-top-bar': layoutSettings.useTopBar }">
|
||||||
<div class="debug-panel" >
|
|
||||||
<a-float-button
|
|
||||||
@click="layoutSettings.showDebug = !layoutSettings.showDebug"
|
|
||||||
tooltip="调试面板"
|
|
||||||
:style="{
|
|
||||||
right: '12px',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<BugOutlined />
|
|
||||||
</template>
|
|
||||||
</a-float-button>
|
|
||||||
<a-drawer
|
|
||||||
v-model:open="layoutSettings.showDebug"
|
|
||||||
title="调试面板"
|
|
||||||
width="800"
|
|
||||||
:contentWrapperStyle="{ maxWidth: '100%'}"
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<DebugComponent />
|
|
||||||
</a-drawer>
|
|
||||||
</div>
|
|
||||||
<div class="header" :class="{ 'top-bar': layoutSettings.useTopBar }">
|
<div class="header" :class="{ 'top-bar': layoutSettings.useTopBar }">
|
||||||
<div class="logo circle">
|
<div class="logo circle">
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
@ -159,7 +137,10 @@ const mainList = [{
|
|||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill" style="flex-grow: 1;"></div>
|
<div
|
||||||
|
ref="htmlRefHook"
|
||||||
|
class="fill debug-trigger"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
|
||||||
<div class="github nav-item">
|
<div class="github nav-item">
|
||||||
@ -208,6 +189,20 @@ const mainList = [{
|
|||||||
</keep-alive>
|
</keep-alive>
|
||||||
<component :is="Component" v-else />
|
<component :is="Component" v-else />
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
||||||
|
<!-- Debug Modal -->
|
||||||
|
<a-modal
|
||||||
|
v-model:open="showDebugModal"
|
||||||
|
title="调试面板"
|
||||||
|
width="90%"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="handleDebugModalClose"
|
||||||
|
:maskClosable="true"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
class="debug-modal"
|
||||||
|
>
|
||||||
|
<DebugComponent />
|
||||||
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -261,6 +256,25 @@ div.header, #app-router-view {
|
|||||||
width: var(--header-width);
|
width: var(--header-width);
|
||||||
border-right: 1px solid var(--gray-300);
|
border-right: 1px solid var(--gray-300);
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
// height: 45px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加debug触发器样式
|
||||||
|
.debug-trigger {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 20px;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@ -373,15 +387,6 @@ div.header, #app-router-view {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .nav {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
height: 45px;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 520px) {
|
@media (max-width: 520px) {
|
||||||
.app-layout {
|
.app-layout {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user