ForcePilot/web/src/components/DebugComponent.vue

726 lines
18 KiB
Vue
Raw Normal View History

2024-08-25 20:29:24 +08:00
<template>
2025-03-11 00:03:29 +08:00
<div :class="['log-viewer', { fullscreen: state.isFullscreen }]" ref="logViewer">
<div class="control-panel">
<div class="button-group">
2025-06-29 15:43:40 +08:00
<a-button @click="fetchLogs" :loading="state.fetching" :icon="h(ReloadOutlined)" class="icon-only">
2025-03-11 00:03:29 +08:00
</a-button>
2025-06-29 15:43:40 +08:00
<a-button @click="clearLogs" :icon="h(ClearOutlined)" class="icon-only">
2025-03-11 00:03:29 +08:00
</a-button>
<a-button @click="printSystemConfig">
2025-03-11 00:03:29 +08:00
<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>
智能体配置
2025-03-11 00:03:29 +08:00
</a-button>
<a-button @click="toggleDebugMode" :type="infoStore.debugMode ? 'primary' : 'default'">
<template #icon><BugOutlined /></template>
Debug 模式: {{ infoStore.debugMode ? '开启' : '关闭' }}
</a-button>
2025-03-11 00:03:29 +08:00
<a-button @click="toggleFullscreen">
<template #icon>
<FullscreenOutlined v-if="!state.isFullscreen" />
<FullscreenExitOutlined v-else />
</template>
{{ state.isFullscreen ? '退出全屏' : '全屏' }}
</a-button>
<a-tooltip :title="state.autoRefresh ? '点击停止自动刷新' : '点击开启自动刷新'">
2025-05-04 21:04:01 +08:00
<a-button
2025-03-11 00:03:29 +08:00
:type="state.autoRefresh ? 'primary' : 'default'"
:class="{ 'auto-refresh-button': state.autoRefresh }"
2025-03-11 00:03:29 +08:00
@click="toggleAutoRefresh(!state.autoRefresh)"
>
<template #icon>
<SyncOutlined :spin="state.autoRefresh" />
</template>
自动刷新
<span v-if="state.autoRefresh" class="refresh-interval">(5s)</span>
</a-button>
</a-tooltip>
</div>
<div class="filter-group">
<a-input-search
v-model:value="state.searchText"
placeholder="搜索日志..."
style="width: 200px; height: 32px;"
2025-03-11 00:03:29 +08:00
@search="onSearch"
/>
<div class="log-level-selector">
<div class="multi-select-cards">
<div
v-for="level in logLevels"
:key="level.value"
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>
2025-03-11 00:03:29 +08:00
</div>
2024-08-25 20:29:24 +08:00
</div>
<div ref="logContainer" class="log-container">
2025-03-11 00:03:29 +08:00
<div v-if="processedLogs.length" class="log-lines">
<div
v-for="(log, index) in processedLogs"
:key="index"
:class="['log-line', `level-${log.level.toLowerCase()}`]"
>
<span class="timestamp">{{ formatTimestamp(log.timestamp) }}</span>
<span class="level">{{ log.level }}</span>
<span class="module">{{ log.module }}</span>
<span class="message">{{ log.message }}</span>
</div>
</div>
<div v-else class="empty-logs">暂无日志</div>
</div>
<p v-if="error" class="error">{{ error }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onActivated, onUnmounted, nextTick, reactive, computed, h, toRaw } from 'vue';
import { useConfigStore } from '@/stores/config';
2025-05-04 21:04:01 +08:00
import { useUserStore } from '@/stores/user';
import { useDatabaseStore } from '@/stores/database';
import { useAgentStore } from '@/stores/agent';
import { useInfoStore } from '@/stores/info';
import { useThrottleFn } from '@vueuse/core';
2025-05-04 21:04:01 +08:00
import { message } from 'ant-design-vue';
import {
FullscreenOutlined,
2025-03-11 00:03:29 +08:00
FullscreenExitOutlined,
ReloadOutlined,
ClearOutlined,
SettingOutlined,
SyncOutlined,
CheckCircleOutlined,
PlusCircleOutlined,
UserOutlined,
DatabaseOutlined,
RobotOutlined,
BugOutlined
2025-03-11 00:03:29 +08:00
} from '@ant-design/icons-vue';
import dayjs from '@/utils/time';
import { configApi } from '@/apis/system_api';
import { checkAdminPermission } from '@/stores/user';
2024-08-25 20:29:24 +08:00
const configStore = useConfigStore()
2025-05-04 21:04:01 +08:00
const userStore = useUserStore();
const databaseStore = useDatabaseStore();
const agentStore = useAgentStore();
const infoStore = useInfoStore();
const config = configStore.config;
2024-08-25 20:29:24 +08:00
2025-05-04 21:04:01 +08:00
2025-03-11 00:03:29 +08:00
// 定义日志级别
const logLevels = [
{ value: 'INFO', label: 'INFO' },
{ value: 'ERROR', label: 'ERROR' },
{ value: 'DEBUG', label: 'DEBUG' },
{ value: 'WARNING', label: 'WARNING' }
];
const logViewer = ref(null);
// 状态管理
const state = reactive({
fetching: false,
autoRefresh: false,
2025-03-11 00:03:29 +08:00
searchText: '',
selectedLevels: logLevels.map(l => l.value),
rawLogs: [],
isFullscreen: false,
});
2025-03-11 00:03:29 +08:00
const error = ref('');
const logContainer = ref(null);
2025-03-11 00:03:29 +08:00
let autoRefreshInterval = null;
2025-03-11 00:03:29 +08:00
// 解析日志行
const parseLogLine = (line) => {
// 支持两种时间戳格式:带毫秒和不带毫秒
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*(.+)$/);
2025-03-11 00:03:29 +08:00
if (match) {
return {
timestamp: match[1],
level: match[2],
module: match[3].trim(),
message: match[4].trim(),
raw: line
};
}
return null;
};
// 格式化时间戳
const formatTimestamp = (timestamp) => {
try {
// 处理带毫秒的格式:将 "2025-03-10 08:26:37,269" 转换为 "2025-03-10 08:26:37.269"
let normalizedTimestamp = timestamp.replace(',', '.');
// 如果没有毫秒,添加 .000
if (!/\.\d{3}$/.test(normalizedTimestamp)) {
normalizedTimestamp += '.000';
}
2025-03-11 00:03:29 +08:00
const date = dayjs(normalizedTimestamp);
return date.isValid() ? date.format('HH:mm:ss.SSS') : timestamp;
} catch (err) {
console.error('时间戳格式化错误:', err);
return timestamp;
}
};
// 处理日志显示
const processedLogs = computed(() => {
return state.rawLogs
.map(parseLogLine)
.filter(log => log !== null)
.filter(log => {
if (!state.searchText) return true;
return log.raw.toLowerCase().includes(state.searchText.toLowerCase());
});
});
// 获取日志数据
const fetchLogs = async () => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
state.fetching = true;
try {
error.value = '';
// 将选中的日志级别转换为逗号分隔的字符串传递给后端
const levelsParam = state.selectedLevels.join(',');
const logData = await configApi.getLogs(levelsParam);
2025-05-04 21:04:01 +08:00
state.rawLogs = logData.log.split('\n').filter(line => line.trim());
await nextTick();
const scrollToBottom = useThrottleFn(() => {
2024-08-25 20:29:24 +08:00
if (logContainer.value) {
logContainer.value.scrollTop = logContainer.value.scrollHeight;
}
}, 100);
scrollToBottom();
} catch (err) {
2025-03-11 00:03:29 +08:00
error.value = `错误: ${err.message}`;
} finally {
state.fetching = false;
}
};
2025-03-11 00:03:29 +08:00
// 清空日志
const clearLogs = () => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
2025-03-11 00:03:29 +08:00
state.rawLogs = [];
};
// 搜索功能
const onSearch = () => {
// 搜索会通过computed自动触发
};
// 日志级别选择相关方法
const isLogLevelSelected = (level) => {
return state.selectedLevels.includes(level);
};
const toggleLogLevel = (level) => {
const currentLevels = [...state.selectedLevels];
const index = currentLevels.indexOf(level);
if (index > -1) {
// 如果取消选中后没有选中的级别,默认全选
if (currentLevels.length === 1) {
return;
}
currentLevels.splice(index, 1);
} else {
currentLevels.push(level);
}
state.selectedLevels = currentLevels;
// 切换日志级别后重新获取数据
fetchLogs();
};
2025-03-11 00:03:29 +08:00
// 自动刷新
const toggleAutoRefresh = (value) => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
2025-03-11 00:03:29 +08:00
if (value) {
autoRefreshInterval = setInterval(fetchLogs, 5000);
state.autoRefresh = true;
} else {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = null;
}
state.autoRefresh = false;
}
};
// 全屏切换
const toggleFullscreen = async () => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
2025-03-11 00:03:29 +08:00
try {
if (!state.isFullscreen) {
if (logViewer.value.requestFullscreen) {
await logViewer.value.requestFullscreen();
} else if (logViewer.value.webkitRequestFullscreen) {
await logViewer.value.webkitRequestFullscreen();
} else if (logViewer.value.msRequestFullscreen) {
await logViewer.value.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
await document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
await document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
await document.msExitFullscreen();
}
}
} catch (err) {
console.error('全屏切换失败:', err);
}
};
// 监听全屏变化
const handleFullscreenChange = () => {
state.isFullscreen = Boolean(
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
);
};
onMounted(() => {
2025-05-04 21:04:01 +08:00
if (checkAdminPermission()) {
fetchLogs();
}
2025-03-11 00:03:29 +08:00
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
document.addEventListener('msfullscreenchange', handleFullscreenChange);
});
2024-08-25 20:29:24 +08:00
onActivated(() => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
if (state.autoRefresh) {
toggleAutoRefresh(true);
} else {
2024-08-25 20:29:24 +08:00
fetchLogs();
}
});
2024-08-25 20:29:24 +08:00
2025-03-11 00:03:29 +08:00
onUnmounted(() => {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
2025-03-11 00:03:29 +08:00
autoRefreshInterval = null;
}
2025-03-11 00:03:29 +08:00
document.removeEventListener('fullscreenchange', handleFullscreenChange);
document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);
document.removeEventListener('msfullscreenchange', handleFullscreenChange);
});
2024-08-25 20:29:24 +08:00
// 打印系统配置
const printSystemConfig = () => {
2025-05-04 21:04:01 +08:00
if (!checkAdminPermission()) return;
console.log('=== 系统配置 ===');
console.log(config);
};
// 打印用户信息
const printUserInfo = () => {
if (!checkAdminPermission()) return;
console.log('=== 用户信息 ===');
const userInfo = {
token: userStore.token ? '*** (已隐藏)' : null,
userId: userStore.userId,
username: userStore.username,
userIdLogin: userStore.userIdLogin,
phoneNumber: userStore.phoneNumber,
avatar: userStore.avatar,
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('=== 知识库信息 ===');
console.log('基本信息:', {
databaseId: databaseStore.databaseId,
databaseName: databaseStore.database.name,
databaseDesc: databaseStore.database.description,
fileCount: Object.keys(databaseStore.database.files || {}).length
});
console.log('状态信息:', {
databaseLoading: databaseStore.state.databaseLoading,
refrashing: databaseStore.state.refrashing,
searchLoading: databaseStore.state.searchLoading,
lock: databaseStore.state.lock,
autoRefresh: databaseStore.state.autoRefresh,
queryParamsLoading: databaseStore.state.queryParamsLoading
});
console.log('查询参数:', {
queryParams: databaseStore.queryParams,
meta: databaseStore.meta,
selectedFileCount: databaseStore.selectedRowKeys.length
});
} catch (error) {
console.error('获取知识库信息失败:', error);
message.error('获取知识库信息失败: ' + error.message);
}
};
// 切换Debug模式
const toggleDebugMode = () => {
if (!checkAdminPermission()) return;
infoStore.toggleDebugMode();
};
// 打印智能体配置
const printAgentConfig = async () => {
if (!checkAdminPermission()) return;
try {
console.log('=== 智能体配置信息 ===');
// Store状态信息
console.log('Store 状态:', {
isInitialized: agentStore.isInitialized,
selectedAgentId: agentStore.selectedAgentId,
defaultAgentId: agentStore.defaultAgentId,
agentCount: agentStore.agentsList.length,
loadingStates: {
isLoadingAgents: agentStore.isLoadingAgents,
isLoadingConfig: agentStore.isLoadingConfig,
isLoadingTools: agentStore.isLoadingTools
},
error: agentStore.error,
hasConfigChanges: agentStore.hasConfigChanges
});
// 智能体列表信息
console.log('智能体列表:', {
count: agentStore.agentsList.length,
agents: toRaw(agentStore.agentsList)
});
// 当前选中智能体信息
if (agentStore.selectedAgent) {
console.log('当前选中智能体:', {
agent: toRaw(agentStore.selectedAgent),
isDefault: agentStore.isDefaultAgent,
configurableItemsCount: Object.keys(agentStore.configurableItems).length
});
// 当前智能体配置(仅管理员可见)
if (userStore.isAdmin) {
console.log('当前智能体配置:', {
current: toRaw(agentStore.agentConfig),
original: toRaw(agentStore.originalAgentConfig),
hasChanges: agentStore.hasConfigChanges
});
} else {
console.log('智能体配置: 需要管理员权限查看详细配置');
}
}
// 工具信息
const toolsList = agentStore.availableTools ? Object.values(agentStore.availableTools) : [];
console.log('可用工具:', {
count: toolsList.length,
tools: toolsList
});
// 配置项信息(管理员可见)
if (userStore.isAdmin && agentStore.selectedAgent) {
console.log('可配置项:', toRaw(agentStore.configurableItems));
}
} catch (error) {
console.error('获取智能体配置失败:', error);
message.error('获取智能体配置失败: ' + error.message);
}
};
</script>
<style scoped>
2025-03-11 00:03:29 +08:00
.log-viewer.fullscreen {
padding: 16px;
}
.control-panel {
margin-bottom: 16px;
}
.button-group {
display: flex;
gap: 8px;
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);
2025-06-29 15:43:40 +08:00
&.icon-only {
min-width: 32px;
padding: 0;
}
&:hover {
border-color: var(--main-color);
color: var(--main-color);
}
&.ant-btn-primary {
background-color: var(--main-color);
border-color: var(--main-color);
Add dark/light theme toggle feature (#343) * Add dark/light theme toggle feature * update: refine dark/light theme and related components * 调整语义化主题变量,优化暗/亮模式切换效果 * Revert "调整语义化主题变量,优化暗/亮模式切换效果" This reverts commit 85d9373297686fdbacb252a880b2847d20a39641. * 深色模式适配:减少 !important,迁移 CSS 变量,优化布局 * style: 替换硬编码颜色值为CSS变量以支持主题切换 将多处硬编码的颜色值(如#fff、#f0f0f0等)替换为CSS变量(如--gray-0、--gray-150等),统一管理颜色样式,便于主题切换和样式维护。主要修改包括背景色、边框色、文字色等视觉元素,同时移除不再需要的深色模式适配代码。 * style: 使用CSS变量替换硬编码颜色值 * refactor(theme): 重构主题系统,统一使用CSS变量并优化暗色模式实现 - 移除冗余的theme.js配置文件,将主题配置集中到theme store - 使用ant-design-vue的darkAlgorithm实现暗色模式 - 在多个组件中替换硬编码颜色值为CSS变量 - 优化用户信息组件,整合文档中心和主题切换功能 - 更新基础CSS样式,完善颜色系统和滚动条样式 * reset: 恢复被覆盖的修改(96d257a7ace38c94e2b113d56472d211d1141087) * feat(theme): 实现深色主题支持并重构样式系统 重构颜色变量系统,添加深色主题支持 移除硬编码颜色值,统一使用CSS变量 优化图表组件以响应主题切换 清理无用样式代码,提升可维护性 * docs: 更新开发规范文档 * style: 调整边框和背景颜色样式 --------- Co-authored-by: Wenjie Zhang <xerrors@163.com>
2025-11-23 01:39:44 +08:00
color: var(--gray-0);
&:hover,
&:focus {
background-color: var(--main-color);
border-color: var(--main-color);
Add dark/light theme toggle feature (#343) * Add dark/light theme toggle feature * update: refine dark/light theme and related components * 调整语义化主题变量,优化暗/亮模式切换效果 * Revert "调整语义化主题变量,优化暗/亮模式切换效果" This reverts commit 85d9373297686fdbacb252a880b2847d20a39641. * 深色模式适配:减少 !important,迁移 CSS 变量,优化布局 * style: 替换硬编码颜色值为CSS变量以支持主题切换 将多处硬编码的颜色值(如#fff、#f0f0f0等)替换为CSS变量(如--gray-0、--gray-150等),统一管理颜色样式,便于主题切换和样式维护。主要修改包括背景色、边框色、文字色等视觉元素,同时移除不再需要的深色模式适配代码。 * style: 使用CSS变量替换硬编码颜色值 * refactor(theme): 重构主题系统,统一使用CSS变量并优化暗色模式实现 - 移除冗余的theme.js配置文件,将主题配置集中到theme store - 使用ant-design-vue的darkAlgorithm实现暗色模式 - 在多个组件中替换硬编码颜色值为CSS变量 - 优化用户信息组件,整合文档中心和主题切换功能 - 更新基础CSS样式,完善颜色系统和滚动条样式 * reset: 恢复被覆盖的修改(96d257a7ace38c94e2b113d56472d211d1141087) * feat(theme): 实现深色主题支持并重构样式系统 重构颜色变量系统,添加深色主题支持 移除硬编码颜色值,统一使用CSS变量 优化图表组件以响应主题切换 清理无用样式代码,提升可维护性 * docs: 更新开发规范文档 * style: 调整边框和背景颜色样式 --------- Co-authored-by: Wenjie Zhang <xerrors@163.com>
2025-11-23 01:39:44 +08:00
color: var(--gray-0);
}
}
.anticon {
font-size: 14px;
}
}
2025-03-11 00:03:29 +08:00
.refresh-interval {
font-size: 12px;
opacity: 0.8;
margin-left: 2px;
}
.auto-refresh-button {
Add dark/light theme toggle feature (#343) * Add dark/light theme toggle feature * update: refine dark/light theme and related components * 调整语义化主题变量,优化暗/亮模式切换效果 * Revert "调整语义化主题变量,优化暗/亮模式切换效果" This reverts commit 85d9373297686fdbacb252a880b2847d20a39641. * 深色模式适配:减少 !important,迁移 CSS 变量,优化布局 * style: 替换硬编码颜色值为CSS变量以支持主题切换 将多处硬编码的颜色值(如#fff、#f0f0f0等)替换为CSS变量(如--gray-0、--gray-150等),统一管理颜色样式,便于主题切换和样式维护。主要修改包括背景色、边框色、文字色等视觉元素,同时移除不再需要的深色模式适配代码。 * style: 使用CSS变量替换硬编码颜色值 * refactor(theme): 重构主题系统,统一使用CSS变量并优化暗色模式实现 - 移除冗余的theme.js配置文件,将主题配置集中到theme store - 使用ant-design-vue的darkAlgorithm实现暗色模式 - 在多个组件中替换硬编码颜色值为CSS变量 - 优化用户信息组件,整合文档中心和主题切换功能 - 更新基础CSS样式,完善颜色系统和滚动条样式 * reset: 恢复被覆盖的修改(96d257a7ace38c94e2b113d56472d211d1141087) * feat(theme): 实现深色主题支持并重构样式系统 重构颜色变量系统,添加深色主题支持 移除硬编码颜色值,统一使用CSS变量 优化图表组件以响应主题切换 清理无用样式代码,提升可维护性 * docs: 更新开发规范文档 * style: 调整边框和背景颜色样式 --------- Co-authored-by: Wenjie Zhang <xerrors@163.com>
2025-11-23 01:39:44 +08:00
color: var(--gray-0);
}
2025-03-11 00:03:29 +08:00
}
.filter-group {
display: flex;
gap: 16px;
align-items: flex-start;
flex-wrap: wrap;
height: 32px;
@media (max-width: 768px) {
flex-direction: column;
gap: 12px;
}
}
2024-08-25 20:29:24 +08:00
.error {
color: var(--color-error-500);
}
.log-container {
height: calc(80vh - 200px);
2025-03-11 00:03:29 +08:00
overflow-y: auto;
background: var(--gray-0);
color: var(--gray-1000);
2025-03-11 00:03:29 +08:00
border-radius: 5px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
2025-03-11 00:03:29 +08:00
}
2025-03-11 00:03:29 +08:00
.log-lines {
padding: 8px;
}
.log-line {
padding: 2px 4px;
display: flex;
gap: 8px;
line-height: 1.4;
}
.log-line:hover {
background: rgba(255, 255, 255, 0.05);
}
.timestamp {
color: var(--color-success-500);
2025-03-11 00:03:29 +08:00
min-width: 80px;
}
.level {
min-width: 40px;
font-weight: bold;
}
.module {
color: var(--color-info-500);
2025-03-11 00:03:29 +08:00
min-width: 30px;
}
.message {
flex: 1;
white-space: pre-wrap;
word-break: break-all;
}
.level-info {
.level { color: var(--color-success-500); }
2025-03-11 00:03:29 +08:00
}
.level-error {
.level { color: var(--color-error-500); }
2025-03-11 00:03:29 +08:00
}
.level-debug {
.level { color: var(--color-info-500); }
2025-03-11 00:03:29 +08:00
}
2024-08-25 20:29:24 +08:00
2025-03-11 00:03:29 +08:00
.level-warning {
.level { color: var(--color-warning-500); }
2025-03-11 00:03:29 +08:00
}
.empty-logs {
padding: 16px;
text-align: center;
Add dark/light theme toggle feature (#343) * Add dark/light theme toggle feature * update: refine dark/light theme and related components * 调整语义化主题变量,优化暗/亮模式切换效果 * Revert "调整语义化主题变量,优化暗/亮模式切换效果" This reverts commit 85d9373297686fdbacb252a880b2847d20a39641. * 深色模式适配:减少 !important,迁移 CSS 变量,优化布局 * style: 替换硬编码颜色值为CSS变量以支持主题切换 将多处硬编码的颜色值(如#fff、#f0f0f0等)替换为CSS变量(如--gray-0、--gray-150等),统一管理颜色样式,便于主题切换和样式维护。主要修改包括背景色、边框色、文字色等视觉元素,同时移除不再需要的深色模式适配代码。 * style: 使用CSS变量替换硬编码颜色值 * refactor(theme): 重构主题系统,统一使用CSS变量并优化暗色模式实现 - 移除冗余的theme.js配置文件,将主题配置集中到theme store - 使用ant-design-vue的darkAlgorithm实现暗色模式 - 在多个组件中替换硬编码颜色值为CSS变量 - 优化用户信息组件,整合文档中心和主题切换功能 - 更新基础CSS样式,完善颜色系统和滚动条样式 * reset: 恢复被覆盖的修改(96d257a7ace38c94e2b113d56472d211d1141087) * feat(theme): 实现深色主题支持并重构样式系统 重构颜色变量系统,添加深色主题支持 移除硬编码颜色值,统一使用CSS变量 优化图表组件以响应主题切换 清理无用样式代码,提升可维护性 * docs: 更新开发规范文档 * style: 调整边框和背景颜色样式 --------- Co-authored-by: Wenjie Zhang <xerrors@163.com>
2025-11-23 01:39:44 +08:00
color: var(--gray-500);
}
@media (prefers-color-scheme: dark) {
2024-08-25 20:29:24 +08:00
.log-container {
background: var(--gray-900);
2024-08-25 20:29:24 +08:00
}
}
2025-03-11 00:03:29 +08:00
:fullscreen .log-container {
height: calc(100vh - 160PX);
2025-03-11 00:03:29 +08:00
}
:-webkit-full-screen .log-container {
height: calc(100vh - 160PX);
2025-03-11 00:03:29 +08:00
}
:-ms-fullscreen .log-container {
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);
}
2025-03-11 00:03:29 +08:00
}
</style>