first commit
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
// Settings 父路由组件,用于显示子路由
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Settings 父路由容器 */
|
||||
</style>
|
||||
@@ -0,0 +1,420 @@
|
||||
<template>
|
||||
<div class="system-info-container">
|
||||
<el-card class="info-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-icon class="header-icon"><InfoFilled /></el-icon>
|
||||
<span class="header-title">系统信息</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-loading="loading" class="info-content">
|
||||
<!-- 系统基本信息 -->
|
||||
<el-descriptions title="系统基本信息" :column="2" border class="info-section">
|
||||
<el-descriptions-item label="系统名称">
|
||||
<el-tag type="primary">{{ systemInfo.name || '云泽管理系统' }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="系统版本">
|
||||
<el-tag>{{ systemInfo.version || '1.0.0' }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运行环境">
|
||||
<el-tag type="success">{{ systemInfo.environment || 'Production' }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="系统时间">
|
||||
{{ currentTime }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运行时间">
|
||||
{{ systemInfo.uptime || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="时区">
|
||||
{{ systemInfo.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 服务器信息 -->
|
||||
<el-descriptions title="服务器信息" :column="2" border class="info-section">
|
||||
<el-descriptions-item label="服务器地址">
|
||||
{{ systemInfo.serverHost || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="API地址">
|
||||
{{ apiBaseUrl }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="操作系统">
|
||||
{{ systemInfo.os || clientInfo.os }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="CPU核心数">
|
||||
{{ systemInfo.cpuCores || clientInfo.cpuCores }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="内存使用">
|
||||
<el-progress
|
||||
:percentage="systemInfo.memoryUsage || 0"
|
||||
:color="getMemoryColor(systemInfo.memoryUsage)"
|
||||
:format="(percentage) => `${percentage}%`"
|
||||
/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="磁盘使用">
|
||||
<el-progress
|
||||
:percentage="systemInfo.diskUsage || 0"
|
||||
:color="getDiskColor(systemInfo.diskUsage)"
|
||||
:format="(percentage) => `${percentage}%`"
|
||||
/>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 数据库信息 -->
|
||||
<el-descriptions title="数据库信息" :column="2" border class="info-section">
|
||||
<el-descriptions-item label="数据库类型">
|
||||
<el-tag type="info">{{ systemInfo.dbType || 'MySQL' }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库版本">
|
||||
{{ systemInfo.dbVersion || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库状态">
|
||||
<el-tag :type="systemInfo.dbStatus === 'connected' ? 'success' : 'danger'">
|
||||
{{ systemInfo.dbStatus === 'connected' ? '已连接' : '未连接' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="连接数">
|
||||
{{ systemInfo.dbConnections || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 客户端信息 -->
|
||||
<el-descriptions title="客户端信息" :column="2" border class="info-section">
|
||||
<el-descriptions-item label="浏览器">
|
||||
{{ clientInfo.browser }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="浏览器版本">
|
||||
{{ clientInfo.browserVersion }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="操作系统">
|
||||
{{ clientInfo.os }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="屏幕分辨率">
|
||||
{{ clientInfo.screenResolution }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="设备类型">
|
||||
<el-tag :type="clientInfo.isMobile ? 'warning' : 'success'">
|
||||
{{ clientInfo.isMobile ? '移动设备' : '桌面设备' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户代理">
|
||||
<span class="user-agent">{{ clientInfo.userAgent }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 应用信息 -->
|
||||
<el-descriptions title="应用信息" :column="2" border class="info-section">
|
||||
<el-descriptions-item label="前端框架">
|
||||
<el-tag type="success">Vue 3</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="UI框架">
|
||||
<el-tag type="primary">Element Plus</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="构建工具">
|
||||
<el-tag type="info">Vite</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="Node版本">
|
||||
{{ clientInfo.nodeVersion || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" @click="refreshInfo" :loading="loading">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
刷新信息
|
||||
</el-button>
|
||||
<el-button @click="copySystemInfo">
|
||||
<el-icon><DocumentCopy /></el-icon>
|
||||
复制信息
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { InfoFilled, Refresh, DocumentCopy } from '@element-plus/icons-vue';
|
||||
|
||||
// 系统信息数据
|
||||
const loading = ref(false);
|
||||
const systemInfo = ref<any>({});
|
||||
const currentTime = ref(new Date().toLocaleString('zh-CN'));
|
||||
|
||||
// API基础地址
|
||||
const apiBaseUrl = computed(() => {
|
||||
return import.meta.env.VITE_API_BASE_URL || window.location.origin;
|
||||
});
|
||||
|
||||
// 客户端信息
|
||||
const clientInfo = computed(() => {
|
||||
const ua = navigator.userAgent;
|
||||
|
||||
// 检测浏览器
|
||||
let browser = 'Unknown';
|
||||
let browserVersion = '';
|
||||
if (ua.includes('Chrome') && !ua.includes('Edg')) {
|
||||
browser = 'Chrome';
|
||||
const match = ua.match(/Chrome\/([\d.]+)/);
|
||||
browserVersion = match ? match[1] : '';
|
||||
} else if (ua.includes('Firefox')) {
|
||||
browser = 'Firefox';
|
||||
const match = ua.match(/Firefox\/([\d.]+)/);
|
||||
browserVersion = match ? match[1] : '';
|
||||
} else if (ua.includes('Safari') && !ua.includes('Chrome')) {
|
||||
browser = 'Safari';
|
||||
const match = ua.match(/Version\/([\d.]+)/);
|
||||
browserVersion = match ? match[1] : '';
|
||||
} else if (ua.includes('Edg')) {
|
||||
browser = 'Edge';
|
||||
const match = ua.match(/Edg\/([\d.]+)/);
|
||||
browserVersion = match ? match[1] : '';
|
||||
}
|
||||
|
||||
// 检测操作系统
|
||||
let os = 'Unknown';
|
||||
if (ua.includes('Win')) os = 'Windows';
|
||||
else if (ua.includes('Mac')) os = 'macOS';
|
||||
else if (ua.includes('Linux')) os = 'Linux';
|
||||
else if (ua.includes('Android')) os = 'Android';
|
||||
else if (ua.includes('iOS')) os = 'iOS';
|
||||
|
||||
// 检测是否为移动设备
|
||||
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
|
||||
|
||||
return {
|
||||
browser,
|
||||
browserVersion,
|
||||
os,
|
||||
screenResolution: `${screen.width}x${screen.height}`,
|
||||
isMobile,
|
||||
userAgent: ua,
|
||||
cpuCores: navigator.hardwareConcurrency || '-',
|
||||
nodeVersion: '-', // Node.js 版本在浏览器环境中不可用
|
||||
};
|
||||
});
|
||||
|
||||
// 获取内存使用颜色
|
||||
const getMemoryColor = (usage: number | undefined) => {
|
||||
if (!usage) return '#3973ff';
|
||||
if (usage >= 90) return '#f56c6c';
|
||||
if (usage >= 70) return '#e6a23c';
|
||||
return '#67c23a';
|
||||
};
|
||||
|
||||
// 获取磁盘使用颜色
|
||||
const getDiskColor = (usage: number | undefined) => {
|
||||
if (!usage) return '#3973ff';
|
||||
if (usage >= 90) return '#f56c6c';
|
||||
if (usage >= 70) return '#e6a23c';
|
||||
return '#67c23a';
|
||||
};
|
||||
|
||||
// 获取系统信息
|
||||
async function fetchSystemInfo() {
|
||||
loading.value = true;
|
||||
try {
|
||||
// 如果有后端API,可以在这里调用
|
||||
// const res = await getSystemInfo();
|
||||
// if (res.success && res.data) {
|
||||
// systemInfo.value = res.data;
|
||||
// }
|
||||
|
||||
// 模拟数据(如果有API会替换)
|
||||
systemInfo.value = {
|
||||
name: '云泽管理系统',
|
||||
version: '1.0.0',
|
||||
environment: 'Production',
|
||||
uptime: '24天 5小时 30分钟',
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
serverHost: window.location.hostname,
|
||||
os: 'Linux',
|
||||
cpuCores: '4',
|
||||
memoryUsage: 65,
|
||||
diskUsage: 42,
|
||||
dbType: 'MySQL',
|
||||
dbVersion: '8.0',
|
||||
dbStatus: 'connected',
|
||||
dbConnections: 15,
|
||||
};
|
||||
} catch (err: any) {
|
||||
ElMessage.error('获取系统信息失败:' + (err.message || '未知错误'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新信息
|
||||
function refreshInfo() {
|
||||
fetchSystemInfo();
|
||||
currentTime.value = new Date().toLocaleString('zh-CN');
|
||||
ElMessage.success('信息已刷新');
|
||||
}
|
||||
|
||||
// 复制系统信息
|
||||
function copySystemInfo() {
|
||||
const infoText = `系统信息报告
|
||||
==================
|
||||
系统名称:${systemInfo.value.name || '-'}
|
||||
系统版本:${systemInfo.value.version || '-'}
|
||||
运行环境:${systemInfo.value.environment || '-'}
|
||||
系统时间:${currentTime.value}
|
||||
运行时间:${systemInfo.value.uptime || '-'}
|
||||
|
||||
服务器信息:
|
||||
- 服务器地址:${systemInfo.value.serverHost || '-'}
|
||||
- API地址:${apiBaseUrl.value}
|
||||
- 操作系统:${systemInfo.value.os || '-'}
|
||||
- CPU核心数:${systemInfo.value.cpuCores || '-'}
|
||||
- 内存使用:${systemInfo.value.memoryUsage || 0}%
|
||||
- 磁盘使用:${systemInfo.value.diskUsage || 0}%
|
||||
|
||||
数据库信息:
|
||||
- 数据库类型:${systemInfo.value.dbType || '-'}
|
||||
- 数据库版本:${systemInfo.value.dbVersion || '-'}
|
||||
- 数据库状态:${systemInfo.value.dbStatus === 'connected' ? '已连接' : '未连接'}
|
||||
- 连接数:${systemInfo.value.dbConnections || '-'}
|
||||
|
||||
客户端信息:
|
||||
- 浏览器:${clientInfo.value.browser} ${clientInfo.value.browserVersion}
|
||||
- 操作系统:${clientInfo.value.os}
|
||||
- 屏幕分辨率:${clientInfo.value.screenResolution}
|
||||
- 设备类型:${clientInfo.value.isMobile ? '移动设备' : '桌面设备'}
|
||||
|
||||
生成时间:${new Date().toLocaleString('zh-CN')}`;
|
||||
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(infoText).then(() => {
|
||||
ElMessage.success('系统信息已复制到剪贴板');
|
||||
}).catch(() => {
|
||||
ElMessage.error('复制失败,请手动复制');
|
||||
});
|
||||
} else {
|
||||
// 降级方案
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = infoText;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
ElMessage.success('系统信息已复制到剪贴板');
|
||||
} catch {
|
||||
ElMessage.error('复制失败,请手动复制');
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新时间
|
||||
let timeInterval: NodeJS.Timeout | null = null;
|
||||
onMounted(() => {
|
||||
fetchSystemInfo();
|
||||
// 每秒更新时间
|
||||
timeInterval = setInterval(() => {
|
||||
currentTime.value = new Date().toLocaleString('zh-CN');
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timeInterval) {
|
||||
clearInterval(timeInterval);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.system-info-container {
|
||||
padding: 24px;
|
||||
background-color: var(--el-bg-color-page);
|
||||
min-height: 100%;
|
||||
|
||||
.info-card {
|
||||
background: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.header-icon {
|
||||
font-size: 20px;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.info-content {
|
||||
.info-section {
|
||||
margin-bottom: 24px;
|
||||
|
||||
:deep(.el-descriptions__title) {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #4f84ff;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__label) {
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-regular);
|
||||
background-color: var(--el-fill-color-lighter);
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__content) {
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.user-agent {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-top: 32px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.system-info-container {
|
||||
padding: 12px;
|
||||
|
||||
.info-card {
|
||||
.info-content {
|
||||
.info-section {
|
||||
:deep(.el-descriptions) {
|
||||
:deep(.el-descriptions__table) {
|
||||
.el-descriptions__cell {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user