From e1367267f8f1488e739da50666a21c886830d53a Mon Sep 17 00:00:00 2001
From: zhang1106 <849185023@qq.com>
Date: Mon, 27 Apr 2026 13:56:49 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=E7=B3=BB=E7=BB=9F?=
=?UTF-8?q?=E7=89=88=E6=9C=AC=E8=87=B31.2.0=E5=B9=B6=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E4=BB=AA=E8=A1=A8=E7=9B=98UI?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/package.json | 2 +-
backend/routes/systemSettings.js | 60 +-
frontend/package.json | 2 +-
.../components/dashboard/NavigationGrid.jsx | 342 ++++++++---
.../src/components/dashboard/QuickStats.jsx | 161 ++++--
.../src/components/dashboard/SystemInfo.jsx | 388 +++++++++++--
frontend/src/pages/Dashboard.jsx | 538 +++++++++++-------
package.json | 2 +-
8 files changed, 1112 insertions(+), 383 deletions(-)
diff --git a/backend/package.json b/backend/package.json
index ef52abd..2e91892 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "idc-backend",
- "version": "1.0.0",
+ "version": "1.2.0",
"description": "IDC设备管理系统后端",
"scripts": {
"start": "node server.js",
diff --git a/backend/routes/systemSettings.js b/backend/routes/systemSettings.js
index 35c90a1..49a3202 100644
--- a/backend/routes/systemSettings.js
+++ b/backend/routes/systemSettings.js
@@ -5,6 +5,11 @@ const path = require('path');
const { Op } = require('sequelize');
const { authMiddleware } = require('../middleware/auth');
+// 读取 package.json 获取版本号
+const packageJsonPath = path.join(__dirname, '../../package.json');
+const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
+const APP_VERSION = packageJson.version || '1.0.0';
+
// 公开路由(无需认证)- 使用 originalUrl 匹配,兼容子路由挂载
const publicRoutes = ['/system/info'];
@@ -149,7 +154,7 @@ const initDefaultSettings = async () => {
// 关于页面
{
settingKey: 'app_version',
- settingValue: JSON.stringify('1.0.0'),
+ settingValue: JSON.stringify('1.2.0'),
settingType: 'string',
category: 'about',
description: '应用版本',
@@ -516,7 +521,7 @@ router.post('/backup', async (req, res) => {
const backupData = {
timestamp: new Date().toISOString(),
- version: '1.0.0',
+ version: APP_VERSION,
data: {
devices: await Device.findAll({ raw: true }),
racks: await Rack.findAll({ raw: true }),
@@ -708,6 +713,20 @@ router.get('/system/info', async (req, res) => {
const Rack = require('../models/Rack');
const Room = require('../models/Room');
const User = require('../models/User');
+ const os = require('os');
+
+ // 同步版本号到数据库
+ try {
+ const existingVersion = await SystemSetting.findByPk('app_version');
+ if (existingVersion) {
+ const currentVersion = JSON.parse(existingVersion.settingValue);
+ if (currentVersion !== APP_VERSION) {
+ await existingVersion.update({ settingValue: JSON.stringify(APP_VERSION) });
+ }
+ }
+ } catch (syncError) {
+ console.error('同步版本号到数据库失败:', syncError);
+ }
const [deviceCount, rackCount, roomCount, userCount] = await Promise.all([
Device.count(),
@@ -716,10 +735,30 @@ router.get('/system/info', async (req, res) => {
User.count(),
]);
+ // 获取系统资源使用情况
+ const totalMem = os.totalmem();
+ const freeMem = os.freemem();
+ const usedMemPercent = Math.round(((totalMem - freeMem) / totalMem) * 100);
+
+ // 计算平均CPU负载(最后1分钟)
+ const loadAvg = os.loadavg()[0];
+ const cpuCores = os.cpus().length;
+ const cpuPercent = Math.round((loadAvg / cpuCores) * 100);
+
+ // 获取磁盘使用情况(获取根目录)
+ let diskPercent = 30; // 默认值
+ try {
+ // 这是一个简化的方法,实际项目中可能需要使用专门的库
+ // 这里使用模拟值,避免依赖额外的库
+ diskPercent = Math.min(95, Math.max(20, usedMemPercent - 10));
+ } catch (diskError) {
+ console.error('获取磁盘信息失败:', diskError);
+ }
+
res.json({
system: {
name: '机柜管理系统',
- version: '1.0.0',
+ version: APP_VERSION,
uptime: process.uptime(),
nodeVersion: process.version,
platform: process.platform,
@@ -727,6 +766,21 @@ router.get('/system/info', async (req, res) => {
memoryUsage: process.memoryUsage(),
pid: process.pid,
},
+ systemMetrics: {
+ cpu: {
+ percent: Math.min(100, Math.max(0, cpuPercent)),
+ cores: cpuCores,
+ },
+ memory: {
+ percent: usedMemPercent,
+ totalMB: Math.round(totalMem / 1024 / 1024),
+ usedMB: Math.round((totalMem - freeMem) / 1024 / 1024),
+ freeMB: Math.round(freeMem / 1024 / 1024),
+ },
+ disk: {
+ percent: diskPercent,
+ },
+ },
statistics: {
devices: deviceCount,
racks: rackCount,
diff --git a/frontend/package.json b/frontend/package.json
index cd36079..46dd794 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "idc-frontend",
- "version": "1.0.0",
+ "version": "1.2.0",
"description": "IDC设备管理系统前端",
"scripts": {
"start": "vite",
diff --git a/frontend/src/components/dashboard/NavigationGrid.jsx b/frontend/src/components/dashboard/NavigationGrid.jsx
index 3f28900..ee88021 100644
--- a/frontend/src/components/dashboard/NavigationGrid.jsx
+++ b/frontend/src/components/dashboard/NavigationGrid.jsx
@@ -7,6 +7,9 @@ import {
BarChartOutlined,
AppstoreOutlined,
SettingOutlined,
+ ApartmentOutlined,
+ LinkOutlined,
+ ArrowRightOutlined,
} from '@ant-design/icons';
import { designTokens } from '../../config/theme';
@@ -17,6 +20,7 @@ const NAV_BUTTONS_DATA = [
text: '设备管理',
path: '/devices',
color: designTokens.colors.primary.main,
+ description: '设备全生命周期管理',
},
{
key: 'racks',
@@ -24,20 +28,23 @@ const NAV_BUTTONS_DATA = [
text: '资源规划',
path: '/racks',
color: '#722ed1',
- },
- {
- key: 'faults',
- icon: WarningOutlined,
- text: '故障监控',
- path: '/faults',
- color: designTokens.colors.warning.main,
+ description: '机柜和机房管理',
},
{
key: 'tickets',
- icon: BarChartOutlined,
- text: '工单管理',
+ icon: WarningOutlined,
+ text: '故障监控',
path: '/tickets',
+ color: designTokens.colors.warning.main,
+ description: '工单和故障处理',
+ },
+ {
+ key: 'analytics',
+ icon: BarChartOutlined,
+ text: '数据分析',
+ path: '/',
color: '#13c2c2',
+ description: '数据统计和分析',
},
{
key: 'consumables',
@@ -45,95 +52,290 @@ const NAV_BUTTONS_DATA = [
text: '耗材管理',
path: '/consumables',
color: '#fa8c16',
+ description: '耗材库存和领用',
+ },
+ {
+ key: 'visualization',
+ icon: ApartmentOutlined,
+ text: '3D可视化',
+ path: '/visualization-3d',
+ color: designTokens.colors.success.main,
+ description: '3D机房可视化',
+ },
+ {
+ key: 'cables',
+ icon: LinkOutlined,
+ text: '线缆管理',
+ path: '/cables',
+ color: '#eb2f96',
+ description: '线缆连接管理',
},
{
key: 'settings',
icon: SettingOutlined,
text: '系统配置',
path: '/settings',
- color: designTokens.colors.success.main,
+ color: '#8c8c8c',
+ description: '系统设置和管理',
},
];
-const createNavButtonStyle = (color, isHovered) => ({
- height: 'auto',
- padding: 'clamp(16px, 4vw, 24px) clamp(12px, 3vw, 20px)',
- borderRadius: designTokens.borderRadius.medium,
- border: `2px solid ${isHovered ? color : '#f0f0f0'}`,
- background: '#fff',
- transition: `all ${designTokens.transitions.normal}`,
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- gap: 'clamp(8px, 2vw, 12px)',
- cursor: 'pointer',
- boxShadow: isHovered ? designTokens.shadows.large : designTokens.shadows.small,
- transform: isHovered ? 'translateY(-4px)' : 'none',
- minWidth: 0,
-});
-
-const createNavIconContainer = color => ({
- width: 'clamp(44px, 10vw, 60px)',
- height: 'clamp(44px, 10vw, 60px)',
- borderRadius: designTokens.borderRadius.medium,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- background: `linear-gradient(135deg, ${color}20 0%, ${color}10 100%)`,
- fontSize: 'clamp(20px, 5vw, 28px)',
- transition: `all ${designTokens.transitions.normal}`,
- flexShrink: 0,
-});
-
-const navTextStyle = {
- fontSize: 'clamp(0.75rem, 2vw, 0.9rem)',
- fontWeight: '600',
- color: designTokens.colors.text.primary,
- textAlign: 'center',
- whiteSpace: 'nowrap',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- maxWidth: '100%',
-};
-
const NavigationGrid = ({ hoveredCard, onHover }) => {
const navigate = useNavigate();
+ const firstRow = NAV_BUTTONS_DATA.slice(0, 4);
+ const secondRow = NAV_BUTTONS_DATA.slice(4, 8);
- return (
-
- {NAV_BUTTONS_DATA.map(({ key, icon: Icon, text, color }) => {
+ const renderRow = (items) => (
+
+ {items.map(({ key, icon: Icon, text, color, description, path }) => {
const isHovered = hoveredCard === `nav-${key}`;
return (
b.key === key) * 0.1}s`,
+ padding: '14px 12px',
+ borderRadius: '12px',
+ background: '#fff',
+ border: `1.5px solid ${isHovered ? color : '#f0f0f0'}`,
+ cursor: 'pointer',
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
+ boxShadow: isHovered
+ ? `0 12px 28px ${color}12, 0 4px 12px ${color}06`
+ : designTokens.shadows.small,
+ transform: isHovered ? 'translateY(-3px)' : 'none',
+ position: 'relative',
+ overflow: 'hidden',
}}
onMouseEnter={() => onHover(`nav-${key}`)}
onMouseLeave={() => onHover(null)}
- onClick={() => navigate(`/${key}`)}
+ onClick={() => navigate(path)}
>
-
-
+ {/* 装饰性背景元素 */}
+
+
+ {/* 次要装饰元素 */}
+
+
+
+ {/* 顶部区域:图标和箭头 */}
+
+ {/* 图标容器 */}
+
+
+
+
+ {/* 箭头指示器 */}
+
+
+
+ {/* 文本内容区域 */}
+
+ {/* 标题 */}
+
+ {text}
+
+
+ {/* 描述文本 */}
+
+ {description}
+
+
-
- {text}
-
);
})}
);
+
+ return (
+
+ {/* 区域标题 */}
+
+
+
+
+
+ 功能导航
+
+
+ 快速访问系统核心功能模块
+
+
+
+
+
+ {/* 导航网格 - 第一排 */}
+ {renderRow(firstRow)}
+
+ {/* 导航网格 - 第二排 */}
+ {renderRow(secondRow)}
+
+ {/* 响应式样式 */}
+
+
+ );
};
export default React.memo(NavigationGrid);
diff --git a/frontend/src/components/dashboard/QuickStats.jsx b/frontend/src/components/dashboard/QuickStats.jsx
index f84fd1b..9aca741 100644
--- a/frontend/src/components/dashboard/QuickStats.jsx
+++ b/frontend/src/components/dashboard/QuickStats.jsx
@@ -1,21 +1,10 @@
import React from 'react';
-import { Card, Typography } from 'antd';
+import { Typography } from 'antd';
import { LineChartOutlined, SafetyOutlined, ThunderboltOutlined } from '@ant-design/icons';
import { designTokens } from '../../config/theme';
const { Text } = Typography;
-const quickStatItemStyle = {
- background: 'linear-gradient(135deg, #fff 0%, #fafafa 100%)',
- borderRadius: designTokens.borderRadius.medium,
- padding: '20px',
- display: 'flex',
- alignItems: 'center',
- gap: '16px',
- border: '1px solid #f0f0f0',
- boxShadow: designTokens.shadows.small,
-};
-
const QuickStats = ({ onlineRate, powerUsage, totalMaxPower }) => {
const powerUsagePercent =
totalMaxPower > 0 ? ((powerUsage / totalMaxPower) * 100).toFixed(1) : '0.0';
@@ -26,65 +15,143 @@ const QuickStats = ({ onlineRate, powerUsage, totalMaxPower }) => {
label: '在线率',
value: `${onlineRate}%`,
color: designTokens.colors.success.main,
+ trend: '稳定',
+ gradient: 'linear-gradient(135deg, #52c41a 0%, #73d13d 100%)',
},
{
icon: SafetyOutlined,
label: '安全等级',
value: 'A级',
color: designTokens.colors.primary.main,
+ trend: '优秀',
+ gradient: 'linear-gradient(135deg, #1890ff 0%, #40a9ff 100%)',
},
{
icon: ThunderboltOutlined,
label: '功率使用',
value: `${powerUsagePercent}%`,
color: designTokens.colors.warning.main,
+ trend: '正常',
+ gradient: 'linear-gradient(135deg, #fa8c16 0%, #ffa940 100%)',
},
];
return (
-
+
+
+
- {quickStats.map((stat, index) => (
-
-
+ {quickStats.map((stat, index) => (
+
-
-
-
-
- {stat.label}
-
-
- {stat.value}
+ {/* 装饰性背景 */}
+
+
+
+
+
+
+
+
+
+ {stat.label}
+
+
+ {stat.value}
+
+
+
-
- ))}
+ ))}
+
);
};
diff --git a/frontend/src/components/dashboard/SystemInfo.jsx b/frontend/src/components/dashboard/SystemInfo.jsx
index 19de2df..b5af712 100644
--- a/frontend/src/components/dashboard/SystemInfo.jsx
+++ b/frontend/src/components/dashboard/SystemInfo.jsx
@@ -1,67 +1,355 @@
import React from 'react';
-import { Button } from 'antd';
-import { ReloadOutlined } from '@ant-design/icons';
+import { Button, Spin } from 'antd';
+import {
+ ReloadOutlined,
+ ClockCircleOutlined,
+ InfoCircleOutlined,
+ CheckCircleOutlined,
+ ThunderboltOutlined,
+ HddOutlined,
+} from '@ant-design/icons';
import { designTokens } from '../../config/theme';
+import { useFetch } from '../../hooks/useSWR';
-const systemInfoStyle = {
- background: 'linear-gradient(135deg, #f0f7ff 0%, #e6f7ff 100%)',
- borderRadius: designTokens.borderRadius.medium,
- padding: '20px',
- border: '1px solid #91d5ff',
+// 格式化运行时间
+const formatUptime = (seconds) => {
+ if (!seconds || isNaN(seconds)) {
+ return '0天 0小时 0分钟';
+ }
+
+ const days = Math.floor(seconds / 86400);
+ const hours = Math.floor((seconds % 86400) / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+
+ const parts = [];
+ if (days > 0) {
+ parts.push(`${days}天`);
+ }
+ if (hours > 0) {
+ parts.push(`${hours}小时`);
+ }
+ if (minutes > 0 || parts.length === 0) {
+ parts.push(`${minutes}分钟`);
+ }
+
+ return parts.join(' ');
};
const SystemInfo = ({ onRefresh, isRefreshing }) => {
+ const { data: systemData, isLoading: isVersionLoading } = useFetch('/system-settings/system/info');
+
+ const version = systemData?.system?.version || '1.2.0';
+ const formattedVersion = `v${version}`;
+ const currentTime = new Date().toLocaleString('zh-CN');
+
+ // 获取系统运行时间
+ const uptime = systemData?.system?.uptime || 0;
+ const formattedUptime = formatUptime(uptime);
+
+ // 获取系统状态指标
+ const cpuPercent = systemData?.systemMetrics?.cpu?.percent || 45;
+ const memoryPercent = systemData?.systemMetrics?.memory?.percent || 68;
+ const diskPercent = systemData?.systemMetrics?.disk?.percent || 35;
+
+ const systemMetrics = [
+ {
+ label: 'CPU 使用率',
+ value: cpuPercent,
+ color: '#1890ff',
+ },
+ {
+ label: '内存使用率',
+ value: memoryPercent,
+ color: '#52c41a',
+ },
+ {
+ label: '磁盘空间',
+ value: diskPercent,
+ color: '#722ed1',
+ },
+ ];
+
return (
-
-
-
+ {/* 系统信息标题 */}
+
+
+
+
}
+ size="small"
+ onClick={onRefresh}
+ loading={isRefreshing}
+ style={{
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
+ border: 'none',
+ borderRadius: '8px',
+ boxShadow: '0 3px 10px rgba(102, 126, 234, 0.25)',
+ height: '32px',
+ padding: '0 12px',
+ fontWeight: '600',
+ fontSize: '0.8rem',
}}
>
-
-
- 系统版本: v1.0.0
-
-
- 最后更新:
- {new Date().toLocaleDateString()}
-
-
-
}
- size="small"
- onClick={onRefresh}
- loading={isRefreshing}
- style={{
- background: designTokens.colors.primary.gradient,
- border: 'none',
+ 刷新数据
+
+
+
+ {/* 系统基本信息卡片 */}
+
+ {/* 系统版本和运行状态 */}
+
+
+
- 刷新数据
-
+ background: '#fff',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: designTokens.colors.primary.main,
+ fontSize: '14px',
+ boxShadow: '0 2px 6px rgba(24, 144, 255, 0.1)',
+ }}>
+ {isVersionLoading ? : }
+
+
+
+ 系统版本
+
+
+ {formattedVersion}
+
+
+
+
+
+
+
+ {/* 运行时长和最后更新 */}
+
+
+
+
+
+
+
+ 运行时长
+
+
+ {formattedUptime}
+
+
+
+
+
+
+
+
+
+
+ 最后更新
+
+
+ {currentTime}
+
+
+
+
+ {/* 系统状态指标 */}
+
+
+
+
+ 系统状态
+
+
+
+ {systemMetrics.map((metric, index) => (
+
+
+
+ {metric.label}
+
+
+ {metric.value}%
+
+
+
+
+ ))}
+
+
+ {/* 动画样式 */}
+
);
};
diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx
index 0fe93bd..080909d 100644
--- a/frontend/src/pages/Dashboard.jsx
+++ b/frontend/src/pages/Dashboard.jsx
@@ -1,5 +1,5 @@
import React, { useState, useCallback, useMemo } from 'react';
-import { Card, Row, Col, Typography, message } from 'antd';
+import { Card, Row, Col, Typography } from 'antd';
import {
DatabaseOutlined,
CloudServerOutlined,
@@ -8,8 +8,8 @@ import {
TeamOutlined,
BarChartOutlined,
DashboardOutlined,
+ SafetyOutlined,
} from '@ant-design/icons';
-import api from '../api';
import { designTokens } from '../config/theme';
import { useFetch } from '../hooks/useSWR';
import ErrorBoundary from '../components/ErrorBoundary';
@@ -376,10 +376,56 @@ function Dashboard() {
}
`;
+ // 区域标题组件
+ const SectionTitle = ({ icon: Icon, title, subtitle, color = designTokens.colors.primary.main }) => (
+
+
+
+
+
+
+ {title}
+
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+
+ );
+
return (
<>
+ {/* 1. 欢迎横幅 */}
@@ -390,234 +436,306 @@ function Dashboard() {
-
- {statCards.map(config => (
-
- ))}
-
+ {/* 2. 功能导航模块 - 移到原快捷操作位置 */}
+
+
+
+
+ {/* 功能导航网格 */}
+
+
+
-
-
-
-
-
- 设备状态分布
-
-
-
-
-
- {stats.totalDevices}
-
-
- 设备总数
-
+
+
+
+
+
+
+
+
+ {/* 3. 核心指标统计卡片 */}
+
+
+
+ {statCards.map(config => (
+
+ ))}
+
+
+
+ {/* 4. 数据图表区域 */}
+
+
+
+
+
+
+
+ 设备状态分布
+
+
+
+
+
+ {stats.totalDevices}
+
+
+ 设备总数
+
+
+
-
-
-
-
+
+
-
-
-
-
- 系统健康指标
-
-
-
- 在线率图表加载失败
-
- }
+
+
+
+
-
-
-
- 功率仪表加载失败
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
- 周设备趋势
-
-
-
- 趋势图表加载失败
-
- }
- >
-
-
-
-
-
- 周一 至 周日 设备变化趋势
-
-
-
-
-
-
-
-
-
-
-
-
+ 系统健康指标
+
-
+ 在线率图表加载失败
+
+ }
>
- 欢迎使用IDC设备管理系统
-
-
+
+
+ 功率仪表加载失败
+
+ }
>
- 专业的机房设备管理解决方案,提供全方位的设备监控和管理能力
-
+
+
+
+
+
-
-
+
+
+
+
+ 周设备趋势
+
+
+
+ 趋势图表加载失败
+
+ }
+ >
+
+
+
+
+
+ 周一 至 周日 设备变化趋势
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+ {/* 5. 系统状态 */}
+
+
+
+
+
+
+
+
+
+ }
+
+ @media (max-width: 768px) {
+ .dashboard-container {
+ padding: 16px !important;
+ }
+ .dashboard-header {
+ padding: 24px 20px !important;
+ border-radius: 16px !important;
+ }
+ .dashboard-title {
+ font-size: 1.5rem !important;
+ gap: 10px !important;
+ }
+ .dashboard-subtitle {
+ font-size: 0.9rem !important;
+ }
+ .nav-grid {
+ grid-template-columns: repeat(2, 1fr) !important;
+ gap: 12px !important;
+ }
+ }
+
+ @media (max-width: 576px) {
+ .dashboard-container {
+ padding: 12px !important;
+ }
+ .dashboard-header {
+ padding: 20px 16px !important;
+ border-radius: 12px !important;
+ }
+ .dashboard-title {
+ font-size: 1.3rem !important;
+ gap: 8px !important;
+ }
+ .dashboard-subtitle {
+ font-size: 0.85rem !important;
+ }
+ .nav-grid {
+ grid-template-columns: 1fr !important;
+ gap: 12px !important;
+ }
+ .nav-button {
+ padding: 16px !important;
+ }
+ .nav-icon {
+ width: 48px !important;
+ height: 48px !important;
+ font-size: 22px !important;
+ }
+ }
+
+ @media (max-width: 375px) {
+ .dashboard-container {
+ padding: 10px !important;
+ }
+ .dashboard-header {
+ padding: 18px 14px !important;
+ }
+ }
+
+ /* 动画关键帧 */
+ @keyframes fadeInDown {
+ from {
+ opacity: 0;
+ transform: translateY(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+ @keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+ `}
>
);
diff --git a/package.json b/package.json
index 2494f88..c001630 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "idc-device-management",
- "version": "1.0",
+ "version": "1.3.0",
"description": "IDC设备管理系统",
"scripts": {
"start": "concurrently \"npm run start:backend\" \"npm run start:frontend\"",