# IDC设备资产系统 - Code Wiki > 版本:2.0.0 | 更新日期:2026-05-07 | 项目地址:[GitHub](https://github.com/gituib/idc_assest) --- ## 目录 1. [系统概述](#1-系统概述) 2. [整体架构](#2-整体架构) 3. [前端模块结构](#3-前端模块结构) 4. [后端模块结构](#4-后端模块结构) 5. [数据模型关系](#5-数据模型关系) 6. [API接口规范](#6-api接口规范) 7. [关键模块详解](#7-关键模块详解) 8. [依赖关系](#8-依赖关系) 9. [运行环境与配置](#9-运行环境与配置) 10. [部署指南](#10-部署指南) 11. [系统关系图](#11-系统关系图) --- ## 1. 系统概述 ### 1.1 项目简介 IDC设备资产系统(IDC Device Management System)是一个现代化的数据中心设备全生命周期管理平台,提供机房、机柜、设备的完整管理能力,并具备3D可视化展示功能。 ### 1.2 技术栈概览 | 层级 | 技术选型 | 版本 | |------|----------|------| | **前端框架** | React + Vite | 18.2.0 / 4.4.9 | | **UI组件库** | Ant Design | 5.8.6 | | **3D渲染** | Three.js + @react-three/fiber | 0.183.2 / 8.18.0 | | **后端框架** | Express | 4.18.2 | | **ORM框架** | Sequelize | 6.37.8 | | **数据库** | SQLite / MySQL | 5.1.7 / 8.0+ | | **认证** | JWT | 9.0.3 | ### 1.3 核心功能模块 | 模块 | 功能描述 | 页面入口 | |------|----------|----------| | **机房管理** | 多机房分类、平面图可视化 | /rooms | | **机柜管理** | 机柜CRUD、容量统计、3D可视化 | /racks | | **设备管理** | 设备全生命周期、批量导入导出 | /devices | | **端口管理** | 设备端口配置、网卡绑定 | /ports | | **线缆管理** | 机柜间线缆连接可视化追踪 | /cables | | **网络拓扑** | ReactFlow拓扑可视化 | - | | **工单管理** | 故障报修、维护工单全流程 | /tickets | | **耗材管理** | 库存、领用、SN序列号追踪 | /consumables | | **盘点管理** | 盘点计划、任务分配、盘盈设备 | /inventory | | **数据看板** | 实时监控、趋势图表、功率监控 | / | | **3D可视化** | Three.js机柜可视化、LOD优化 | /visualization-3d | | **备份管理** | 本地/远程备份、定时任务 | /backup | | **操作日志** | 审计日志、统计分析 | /operation-logs | | **用户权限** | RBAC角色控制 | /users | --- ## 2. 整体架构 ### 2.1 系统架构图 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ 客户端层 (Client) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 浏览器 │ │ 移动端 │ │ Web App │ │ PWA │ │ │ │ (Chrome) │ │ (响应式) │ │ (SPA) │ │ (可选) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 前端层 (Frontend) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ React 18 + Vite │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ 页面组件 │ │ 3D组件 │ │ 通用组件 │ │ Hooks │ │ │ │ │ │ /pages │ │ /3d │ │/components│ │ /hooks │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ Context │ │ API │ │ Utils │ │ Config │ │ │ │ │ │状态管理 │ │封装 │ │工具函数 │ │配置中心 │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ │ RESTful API │ │ /api/* │ └───────────────┬───────────────┘ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ 后端层 (Backend) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Express.js Server │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │中间件层 │ │路由层 │ │业务逻辑 │ │数据访问 │ │ │ │ │ │/middleware│ │/routes │ │/routes │ │/models │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │验证层 │ │认证授权 │ │日志审计 │ │备份恢复 │ │ │ │ │ │/validation│ │/middleware│ │/utils │ │/utils │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 数据层 (Data Layer) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ SQLite │ │ MySQL │ │ │ │ (开发环境) │◄────────────────►│ (生产环境) │ │ │ │ idc_management.db│ │ MySQL 8.0+ │ │ │ └─────────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### 2.2 前端项目结构 ``` frontend/ ├── public/ # 静态公共资源 │ ├── assets/ │ │ └── 3d/ │ │ └── env.hdr # 3D环境贴图 │ └── png/ # 设备图标资源 │ ├── 服务器.png │ ├── 交换机.png │ ├── 路由器.png │ └── 防火墙.png ├── src/ # 源代码目录 │ ├── api/ # API接口封装 │ │ ├── index.js # Axios实例、API方法 │ │ └── cache.js # 请求缓存管理 │ ├── components/ # React组件库 │ │ ├── 3d/ # 3D可视化组件 │ │ │ ├── materials/ # 3D材质组件 │ │ │ │ ├── TextureCache.js # 纹理缓存管理 │ │ │ │ ├── constants.jsx # 3D常量定义 │ │ │ │ ├── devicePanel.jsx # 设备信息面板 │ │ │ │ ├── index.jsx # 材质导出 │ │ │ │ ├── rackFrame.jsx # 机柜框架材质 │ │ │ │ └── utils.jsx # 3D工具函数 │ │ │ ├── CascadingRackPanel.jsx # 级联机柜面板 │ │ │ ├── DeviceModel.jsx # 设备3D模型 │ │ │ ├── LODManager.jsx # LOD细节层次管理 │ │ │ ├── RackModel.jsx # 机柜3D模型 │ │ │ ├── RackSelectorHeader.jsx # 机柜选择器 │ │ │ └── Scene.jsx # 3D主场景 │ │ ├── dashboard/ # 数据看板组件 │ │ │ ├── AnimatedCounter.jsx # 数字动画 │ │ │ ├── CircularProgress.jsx # 环形进度 │ │ │ ├── DeviceTrendChart.jsx # 设备趋势图 │ │ │ ├── NavigationGrid.jsx # 导航网格 │ │ │ ├── PowerGauge.jsx # 功率仪表 │ │ │ ├── QuickStats.jsx # 快速统计 │ │ │ ├── StatCard.jsx # 统计卡片 │ │ │ ├── StatusLegend.jsx # 状态图例 │ │ │ └── SystemInfo.jsx # 系统信息 │ │ ├── device/ # 设备管理组件 │ │ │ ├── BatchStatusModal.jsx # 批量状态修改 │ │ │ ├── DeviceDetailModal.jsx # 设备详情 │ │ │ ├── DeviceFormModal.jsx # 设备表单 │ │ │ ├── ExportModal.jsx # 导出弹窗 │ │ │ ├── FieldConfigModal.jsx # 字段配置 │ │ │ ├── ImportModal.jsx # 导入弹窗 │ │ │ └── ResizableTitle.jsx # 可调整标题 │ │ ├── floorplan/ # 机房平面图组件 │ │ │ ├── canvas/ # Canvas渲染 │ │ │ │ ├── CanvasConstants.js │ │ │ │ ├── CanvasInteraction.js │ │ │ │ ├── CanvasRenderer.js │ │ │ │ ├── FloorPlanCanvas.jsx │ │ │ │ └── index.js │ │ │ ├── panels/ # 侧边面板 │ │ │ ├── toolbar/ # 工具栏 │ │ │ ├── index.js │ │ │ └── styles.js │ │ ├── rack/ # 机柜组件 │ │ ├── topology/ # 网络拓扑组件 │ │ │ ├── hooks/ # 拓扑Hooks │ │ │ │ ├── useTopologyData.js │ │ │ │ └── useTopologyLayout.js │ │ │ └── nodes/ # 拓扑节点 │ │ ├── CableCreateModal.jsx # 线缆创建 │ │ ├── CableWizardModal.jsx # 线缆向导 │ │ ├── DeviceDetailDrawer.jsx # 设备详情抽屉 │ │ ├── ErrorBoundary.jsx # 错误边界 │ │ ├── NetworkCardPanel.jsx # 网卡面板 │ │ ├── PortManagementPanel.jsx # 端口管理面板 │ │ ├── ProtectedRoute.jsx # 路由保护 │ │ └── VirtualDeviceList.jsx # 虚拟设备列表 │ ├── config/ # 配置文件 │ │ ├── api.js # API基础配置 │ │ ├── dangerousOperationConfig.js # 危险操作配置 │ │ └── theme.js # 主题配置 │ ├── constants/ # 常量定义 │ │ └── deviceManagementConstants.js │ ├── context/ # React Context │ │ ├── AuthContext.jsx # 认证上下文 │ │ ├── ConfigContext.jsx # 配置上下文 │ │ ├── FloorPlanContext.jsx # 平面图上下文 │ │ └── Scene3DContext.jsx # 3D场景上下文 │ ├── hooks/ # 自定义Hooks │ │ ├── floorplan/ # 平面图Hooks │ │ │ ├── useFloorPlanContext.js │ │ │ └── useFloorPlanData.js │ │ ├── useApi.js # API请求Hook │ │ ├── useDangerousOperation.js # 危险操作Hook │ │ ├── useDebounce.js # 防抖Hook │ │ ├── useDesignTokens.js # 设计令牌Hook │ │ ├── useIdleTimeout.js # 空闲超时Hook │ │ ├── useResponsiveLayout.js # 响应式布局Hook │ │ ├── useSWR.js # SWR数据请求Hook │ │ └── useSortedRacks.js # 机柜排序Hook │ ├── pages/ # 页面组件 │ │ ├── Dashboard.jsx # 数据看板主页 │ │ ├── Login.jsx # 登录页 │ │ ├── RoomManagement.jsx # 机房管理 │ │ ├── RoomFloorPlan.jsx # 机房平面图 │ │ ├── RackManagement.jsx # 机柜管理 │ │ ├── DeviceManagement.jsx # 设备管理 │ │ ├── DeviceFieldManagement.jsx # 设备字段管理 │ │ ├── IdleDeviceManagement.jsx # 空闲设备管理 │ │ ├── PendingDeviceManagement.jsx # 待审核设备 │ │ ├── PortManagement.jsx # 端口管理 │ │ ├── CableManagement.jsx # 线缆管理 │ │ ├── TicketManagement.jsx # 工单管理 │ │ ├── TicketCategoryManagement.jsx # 工单分类 │ │ ├── TicketFieldManagement.jsx # 工单字段 │ │ ├── TicketStatistics.jsx # 工单统计 │ │ ├── ConsumableManagement.jsx # 耗材管理 │ │ ├── CategoryManagement.jsx # 耗材分类 │ │ ├── ConsumableLogs.jsx # 耗材日志 │ │ ├── ConsumableStatistics.jsx # 耗材统计 │ │ ├── InventoryManagement.jsx # 盘点管理 │ │ ├── InventoryTaskExecution.jsx # 盘点任务执行 │ │ ├── OperationLogs.jsx # 操作日志 │ │ ├── UserManagement.jsx # 用户管理 │ │ ├── SystemSettings.jsx # 系统设置 │ │ ├── BackupManagement.jsx # 备份管理 │ │ ├── AutoBackupSettings.jsx # 自动备份设置 │ │ ├── RemoteBackupSettings.jsx # 远程备份设置 │ │ ├── Rack3DVisualization.jsx # 3D可视化 │ │ └── ErrorBoundaryTest.jsx # 错误边界测试 │ ├── styles/ # 样式文件 │ │ └── deviceManagementStyles.js │ ├── utils/ # 工具函数 │ │ ├── common.js # 通用工具 │ │ ├── crypto.js # 加密工具 │ │ ├── deviceUtils.jsx # 设备相关工具 │ │ ├── logger.js # 日志工具 │ │ └── secureStorage.js # 安全存储 │ ├── App.jsx # 应用入口 │ ├── main.jsx # 渲染入口 │ └── index.css # 全局样式 ├── vite.config.mjs # Vite配置 ├── package.json # 前端依赖 └── .env.example # 环境变量示例 ``` ### 2.3 后端项目结构 ``` backend/ ├── config/ # 配置模块 │ ├── index.js # 配置统一导出 │ ├── constants.js # 常量配置 │ ├── routes.js # 路由注册配置 │ ├── security.js # 安全配置 │ ├── auto-backup-settings.json # 自动备份设置 │ └── remote-backup-configs.json # 远程备份配置 ├── middleware/ # 中间件 │ ├── auth.js # JWT认证中间件 │ ├── maintenance.js # 维护模式中间件 │ ├── requestLogger.js # 请求日志中间件 │ └── validation.js # 验证中间件 ├── models/ # Sequelize数据模型 │ ├── index.js # 模型关联定义 │ ├── Room.js # 机房模型 │ ├── Rack.js # 机柜模型 │ ├── Device.js # 设备模型 │ ├── DeviceField.js # 设备字段模型 │ ├── DevicePort.js # 设备端口模型 │ ├── NetworkCard.js # 网卡模型 │ ├── Cable.js # 线缆模型 │ ├── Ticket.js # 工单模型 │ ├── TicketField.js # 工单字段模型 │ ├── TicketCategory.js # 工单分类模型 │ ├── TicketOperationRecord.js # 工单操作记录 │ ├── FaultCategory.js # 故障分类模型 │ ├── Consumable.js # 耗材模型 │ ├── ConsumableCategory.js # 耗材分类模型 │ ├── ConsumableRecord.js # 耗材领用记录 │ ├── ConsumableLog.js # 耗材日志模型 │ ├── ConsumableLogArchive.js # 耗材日志归档 │ ├── InventoryPlan.js # 盘点计划模型 │ ├── InventoryTask.js # 盘点任务模型 │ ├── InventoryRecord.js # 盘点记录模型 │ ├── User.js # 用户模型 │ ├── Role.js # 角色模型 │ ├── Permission.js # 权限模型 │ ├── UserRole.js # 用户角色关联 │ ├── SystemSetting.js # 系统设置模型 │ ├── PendingDevice.js # 待审核设备模型 │ ├── OperationLog.js # 操作日志模型 │ ├── BackupLog.js # 备份日志模型 │ ├── Warehouse.js # 仓库模型 │ ├── Business.js # 业务模型 │ ├── DeviceBusiness.js # 设备业务关联 │ └── ticketIndex.js # 工单索引模型 ├── routes/ # API路由 │ ├── auth.js # 认证路由 │ ├── rooms.js # 机房路由 │ ├── racks.js # 机柜路由 │ ├── devices.js # 设备路由 │ ├── deviceFields.js # 设备字段路由 │ ├── devicePorts.js # 设备端口路由 │ ├── networkCards.js # 网卡路由 │ ├── cables.js # 线缆路由 │ ├── tickets.js # 工单路由 │ ├── ticketCategories.js # 工单分类路由 │ ├── ticketFields.js # 工单字段路由 │ ├── consumables.js # 耗材路由 │ ├── consumableCategories.js # 耗材分类路由 │ ├── consumableRecords.js # 耗材记录路由 │ ├── consumableImport.js # 耗材导入路由 │ ├── inventory.js # 盘点路由 │ ├── users.js # 用户路由 │ ├── roles.js # 角色路由 │ ├── systemSettings.js # 系统设置路由 │ ├── background.js # 背景配置路由 │ ├── backup.js # 备份管理路由 │ ├── statistics.js # 统计分析路由 │ ├── operationLogs.js # 操作日志路由 │ ├── idleDevices.js # 空闲设备路由 │ ├── warehouses.js # 仓库路由 │ ├── dangerousOperations.js # 危险操作路由 │ └── topology.js # 拓扑路由 ├── scripts/ # 数据库脚本 │ ├── init-database.js # 数据库初始化 │ ├── migrate-all.js # 执行所有迁移 │ ├── fix-foreign-keys.js # 外键修复 │ ├── backup.js # 备份脚本 │ ├── restore.js # 恢复脚本 │ ├── create_indexes.js # 创建索引 │ ├── generate-rack-import-template.js # 生成导入模板 │ └── archive/ # 归档迁移脚本 │ ├── migrate-v2.js │ ├── migrate-consumable-logs.js │ ├── migrate-consumable-version.js │ ├── migrate-consumable-log-decouple.js │ ├── migrate-consumable-log-archive.js │ ├── remove-consumable-log-fk.js │ └── migrate-add-pending-status.js ├── utils/ # 工具函数 │ ├── autoBackupScheduler.js # 自动备份调度器 │ ├── backup.js # 备份工具 │ ├── remoteBackup.js # 远程备份 │ ├── remoteBackupConfig.js # 远程备份配置 │ ├── backupLog.js # 备份日志 │ ├── dangerousOperationLogger.js # 危险操作日志 │ ├── errorHandler.js # 错误处理器 │ ├── healthCheck.js # 健康检查 │ ├── idGenerator.js # ID生成器 │ ├── importJobManager.js # 导入任务管理 │ ├── logger.js # Winston日志 │ ├── maintenanceMode.js # 维护模式 │ ├── operationLogger.js # 操作日志 │ └── routeLoader.js # 路由加载器 ├── validation/ # Joi验证Schema │ ├── deviceSchema.js │ ├── rackSchema.js │ └── roomSchema.js ├── uploads/ # 文件上传目录 │ └── avatars/ # 用户头像 ├── tests/ # 测试文件 ├── temp/ # 临时文件目录 ├── server.js # 服务入口 ├── db.js # 数据库连接 ├── initConfig.js # 初始化配置 ├── initDeviceFields.js # 初始化设备字段 ├── initTicketFields.js # 初始化工单字段 ├── swagger.js # Swagger配置 ├── swagger_docs.yaml # Swagger文档 ├── swagger_index.html # Swagger页面 ├── package.json # 后端依赖 ├── .env.example # 环境变量示例 └── jest.config.js # Jest配置 ``` --- ## 3. 前端模块结构 ### 3.1 组件架构 前端采用**组件化架构**,核心组件分类如下: #### 3.1.1 页面组件 (pages/) | 页面组件 | 文件路径 | 功能描述 | |----------|----------|----------| | Dashboard | pages/Dashboard.jsx | 数据看板主页,展示统计卡片、趋势图、功率仪表 | | Login | pages/Login.jsx | 用户登录/注册页面 | | RoomManagement | pages/RoomManagement.jsx | 机房增删改查,支持图片上传 | | RackManagement | pages/RackManagement.jsx | 机柜管理,支持批量导入导出 | | DeviceManagement | pages/DeviceManagement.jsx | 设备全生命周期管理 | | PortManagement | pages/PortManagement.jsx | 设备端口配置管理 | | CableManagement | pages/CableManagement.jsx | 线缆连接管理 | | TicketManagement | pages/TicketManagement.jsx | 工单全流程管理 | | ConsumableManagement | pages/ConsumableManagement.jsx | 耗材库存管理 | | InventoryManagement | pages/InventoryManagement.jsx | 盘点计划与执行 | | Rack3DVisualization | pages/Rack3DVisualization.jsx | Three.js 3D可视化 | | RoomFloorPlan | pages/RoomFloorPlan.jsx | Canvas机房平面图 | | BackupManagement | pages/BackupManagement.jsx | 数据库备份恢复 | | UserManagement | pages/UserManagement.jsx | 用户与权限管理 | #### 3.1.2 3D可视化组件 (components/3d/) | 组件 | 文件 | 功能描述 | |------|------|----------| | Scene | Scene.jsx | Three.js主场景,管理相机、灯光、渲染器 | | RackModel | RackModel.jsx | 机柜3D模型,支持LOD | | DeviceModel | DeviceModel.jsx | 设备3D模型,根据类型渲染 | | LODManager | LODManager.jsx | 细节层次管理,优化性能 | | CascadingRackPanel | CascadingRackPanel.jsx | 级联机柜信息面板 | | TextureCache | materials/TextureCache.js | 纹理缓存,减少加载时间 | | devicePanel | materials/devicePanel.jsx | 设备悬停信息面板 | #### 3.1.3 数据看板组件 (components/dashboard/) | 组件 | 功能描述 | |------|----------| | StatCard | 统计卡片,展示单个指标 | | AnimatedCounter | 数字动画组件 | | CircularProgress | 环形进度指示器 | | DeviceTrendChart | 设备趋势图表(ECharts) | | PowerGauge | 功率监控仪表盘 | | StatusLegend | 设备状态图例 | | NavigationGrid | 快捷导航网格 | | SystemInfo | 系统运行信息 | ### 3.2 Context状态管理 ```javascript // AuthContext - 认证状态管理 AuthContext { user: Object, // 当前用户信息 token: String, // JWT令牌 loading: Boolean, // 加载状态 initialized: Boolean, // 初始化完成 login(), // 登录方法 register(), // 注册方法 logout(), // 登出方法 hasPermission(), // 权限检查 } // ConfigContext - 全局配置管理 ConfigContext { config: Object, // 系统配置 updateConfig(), // 更新配置 } // Scene3DContext - 3D场景状态 Scene3DContext { scene: Object, // Three.js场景 camera: Object, // 相机 selectedRack: Object, // 选中机柜 setSelectedRack(), // 设置选中 } // FloorPlanContext - 平面图状态 FloorPlanContext { canvas: Object, // Canvas对象 roomData: Object, // 机房数据 racks: Array, // 机柜列表 } ``` ### 3.3 关键Hooks | Hook | 文件 | 功能描述 | |------|------|----------| | useApi | hooks/useApi.js | 封装API请求,支持 loading/error 状态 | | useSWR | hooks/useSWR.js | SWR数据获取与缓存 | | useDebounce | hooks/useDebounce.js | 防抖处理 | | useIdleTimeout | hooks/useIdleTimeout.js | 空闲超时检测 | | useDangerousOperation | hooks/useDangerousOperation.js | 危险操作二次确认 | | useDesignTokens | hooks/useDesignTokens.js | Ant Design主题令牌 | | useResponsiveLayout | hooks/useResponsiveLayout.js | 响应式布局 | | useSortedRacks | hooks/useSortedRacks.js | 机柜排序 | ### 3.4 API封装 (api/index.js) ```javascript // Axios实例配置 const api = axios.create({ baseURL: '/api', // API基础URL timeout: 30000, // 超时30秒 headers: { 'Content-Type': 'application/json' } }); // 请求拦截器 - 自动添加Token api.interceptors.request.use(config => { const token = secureStorage.get(TOKEN_KEY); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); // 响应拦截器 - 统一错误处理 api.interceptors.response.use( response => response.data, error => { if (error.response?.status === 401) { // Token过期,跳转登录 } return Promise.reject(error); } ); // API模块导出 export const authAPI = { login, register, getProfile, ... }; export const deviceAPI = { list, get, create, update, delete, ... }; export const ticketAPI = { list, get, create, assign, process, ... }; export const backupAPI = { list, create, restore, download, ... }; // ... 更多API模块 ``` --- ## 4. 后端模块结构 ### 4.1 服务入口 (server.js) ```javascript // server.js - 应用入口流程 async function initializeApp() { // 1. 数据库同步 await syncDatabase(); // 连接并同步表结构 // 2. 初始化设备字段 await initDeviceFields(); // 3. 初始化工单字段 await initTicketFields(); // 4. 初始化工单模型关联 await initTicketModels(); // 5. 同步耗材模型 await syncConsumableModels(); // 6. 同步盘点模型 await syncInventoryModels(); // 7. 初始化系统设置 await initDefaultSystemSettings(); // 8. 初始化故障分类 await initFaultCategories(); // 9. 初始化自动备份调度器 await initAutoBackupScheduler(); } ``` ### 4.2 数据库连接 (db.js) ```javascript // 支持 SQLite 和 MySQL 双数据库 const DB_TYPE = process.env.DB_TYPE || 'sqlite'; if (DB_TYPE === 'mysql') { sequelize = new Sequelize({ dialect: 'mysql', host: process.env.MYSQL_HOST, port: process.env.MYSQL_PORT, database: process.env.MYSQL_DATABASE, username: process.env.MYSQL_USERNAME, password: process.env.MYSQL_PASSWORD, pool: { max: 10, min: 2, acquire: 30000, idle: 10000 } }); } else { sequelize = new Sequelize({ dialect: 'sqlite', storage: process.env.DB_PATH || './idc_management.db' }); } ``` ### 4.3 中间件层 | 中间件 | 文件 | 功能描述 | |--------|------|----------| | authMiddleware | middleware/auth.js | JWT令牌验证、用户认证 | | maintenanceMiddleware | middleware/maintenance.js | 维护模式拦截 | | requestLogger | middleware/requestLogger.js | HTTP请求日志记录 | | validationMiddleware | middleware/validation.js | Joi数据验证 | ### 4.4 路由模块 (routes/) | 路由模块 | 基础路径 | 功能描述 | |----------|----------|----------| | auth | /api/auth | 登录、注册、Token管理 | | rooms | /api/rooms | 机房CRUD | | racks | /api/racks | 机柜CRUD | | devices | /api/devices | 设备CRUD、批量操作 | | deviceFields | /api/deviceFields | 设备自定义字段 | | devicePorts | /api/device-ports | 设备端口管理 | | networkCards | /api/network-cards | 网卡管理 | | cables | /api/cables | 线缆连接管理 | | tickets | /api/tickets | 工单全流程 | | consumables | /api/consumables | 耗材管理 | | inventory | /api/inventory | 盘点管理 | | users | /api/users | 用户管理 | | roles | /api/roles | 角色权限 | | systemSettings | /api/system-settings | 系统配置 | | backup | /api/backup | 备份恢复 | | statistics | /api/statistics | 统计分析 | | operationLogs | /api/operation-logs | 操作审计 | | topology | /api/topology | 网络拓扑 | --- ## 5. 数据模型关系 ### 5.1 核心模型关系图 ``` ┌─────────────┐ │ Room │ ──1:N──► ┌─────────┐ │ (机房) │ │ Rack │ └─────────────┘ │ (机柜) │ │ └────┬────┘ │ │ │ │ 1:N │ ▼ │ ┌─────────┐ │ │ Device │ │ │ (设备) │ │ └────┬────┘ │ │ │ ┌───────────┼───────────┐ │ │ │ │ │ ▼ ▼ ▼ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │NetworkCard│ │DevicePort│ │DeviceField│ │ │ (网卡) │ │ (端口) │ │ (字段) │ │ └────┬─────┘ └────┬─────┘ └──────────┘ │ │ │ │ │ │ N:1 │ │ ▼ │ │ ┌──────────┐ └──────────┼─────►│ Cable │ │ │ (线缆) │ │ └──────────┘ │ ▼ ┌──────────────┐ │ Ticket │ │ (工单) │ └──────────────┘ ┌──────────────┐ ┌──────────────┐ │ User │ ─N:M─► │ Role │ │ (用户) │ │ (角色) │ └──────────────┘ └──────────────┘ ┌──────────────┐ ┌──────────────┐ │ Consumable │ ─N:M─► │ConsumableCat │ │ (耗材) │ │ (分类) │ └──────┬───────┘ └──────────────┘ │ ▼ ┌──────────────┐ │ConsumableLog │ │ (日志) │ └──────────────┘ ┌──────────────┐ │InventoryPlan │ ─1:N──► ┌──────────────┐ │ (盘点计划) │ │InventoryTask │ └──────────────┘ │ (盘点任务) │ └──────┬───────┘ │ ▼ ┌──────────────┐ │InventoryRecord│ │ (盘点记录) │ └──────────────┘ ``` ### 5.2 主要数据模型 #### 5.2.1 机房模型 (Room) ```javascript // backend/models/Room.js Room.init({ roomId: { type: DataTypes.STRING, primaryKey: true }, // 机房ID name: { type: DataTypes.STRING, allowNull: false }, // 机房名称 location: DataTypes.STRING, // 地理位置 area: DataTypes.FLOAT, // 面积(平方米) manager: DataTypes.STRING, // 负责人 contact: DataTypes.STRING, // 联系方式 status: DataTypes.ENUM('active', 'inactive'), // 状态 description: DataTypes.TEXT, // 描述 imageUrl: DataTypes.STRING, // 机房图片 floorPlanData: DataTypes.JSON, // 平面图数据 }, { tableName: 'rooms', timestamps: true, }); // 关联关系 Room.hasMany(Rack, { foreignKey: 'roomId', as: 'Racks' }); ``` #### 5.2.2 机柜模型 (Rack) ```javascript // backend/models/Rack.js Rack.init({ rackId: { type: DataTypes.STRING, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false }, roomId: { type: DataTypes.STRING, references: { model: 'rooms' } }, totalU: { type: DataTypes.INTEGER, defaultValue: 42 }, // 总U数 usedU: { type: DataTypes.INTEGER, defaultValue: 0 }, // 已用U数 powerCapacity: { type: DataTypes.FLOAT }, // 功率容量 currentPower: { type: DataTypes.FLOAT }, // 当前功率 status: DataTypes.ENUM('active', 'maintenance', 'offline'), positionX: DataTypes.FLOAT, // 平面图X坐标 positionY: DataTypes.FLOAT, // 平面图Y坐标 }, { tableName: 'racks', timestamps: true, }); // 关联 Rack.belongsTo(Room, { foreignKey: 'roomId' }); Rack.hasMany(Device, { foreignKey: 'rackId', as: 'Devices' }); ``` #### 5.2.3 设备模型 (Device) ```javascript // backend/models/Device.js Device.init({ deviceId: { type: DataTypes.STRING, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false }, type: DataTypes.ENUM('server', 'switch', 'router', 'storage', 'firewall', 'other'), brand: DataTypes.STRING, // 品牌 model: DataTypes.STRING, // 型号 serialNumber: DataTypes.STRING, // 序列号 rackId: { type: DataTypes.STRING, references: { model: 'racks' } }, position: DataTypes.INTEGER, // U位 height: { type: DataTypes.INTEGER, defaultValue: 1 }, // 设备高度(U) status: DataTypes.ENUM('purchasing', 'pending', 'running', 'maintenance', 'scrapped'), ipAddress: DataTypes.STRING, // IP地址 macAddress: DataTypes.STRING, // MAC地址 powerConsumption: DataTypes.FLOAT, // 功率(W) purchaseDate: DataTypes.DATE, // 采购日期 warrantyExpiry: DataTypes.DATE, // 保修到期 customFields: DataTypes.JSON, // 自定义字段 }, { tableName: 'devices', timestamps: true, }); // 关联 Device.belongsTo(Rack, { foreignKey: 'rackId' }); Device.hasMany(DevicePort, { foreignKey: 'deviceId' }); Device.hasMany(NetworkCard, { foreignKey: 'deviceId' }); Device.hasMany(Cable, { foreignKey: 'sourceDeviceId' }); Device.hasMany(Cable, { foreignKey: 'targetDeviceId' }); ``` #### 5.2.4 工单模型 (Ticket) ```javascript // backend/models/Ticket.js Ticket.init({ ticketId: { type: DataTypes.STRING, primaryKey: true }, title: { type: DataTypes.STRING, allowNull: false }, description: DataTypes.TEXT, type: DataTypes.ENUM('fault', 'maintenance', 'change', 'other'), priority: DataTypes.ENUM('urgent', 'high', 'medium', 'low'), status: DataTypes.ENUM('open', 'assigned', 'processing', 'resolved', 'closed', 'reopened'), categoryId: DataTypes.STRING, // 故障分类ID reporterId: { type: DataTypes.STRING, references: { model: 'users' } }, assigneeId: { type: DataTypes.STRING, references: { model: 'users' } }, deviceId: { type: DataTypes.STRING, references: { model: 'devices' } }, customFields: DataTypes.JSON, // 自定义字段 rating: DataTypes.INTEGER, // 评价(1-5) resolution: DataTypes.TEXT, // 解决方案 resolvedAt: DataTypes.DATE, closedAt: DataTypes.DATE, }, { tableName: 'tickets', timestamps: true, }); ``` #### 5.2.5 耗材模型 (Consumable) ```javascript // backend/models/Consumable.js Consumable.init({ consumableId: { type: DataTypes.STRING, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false }, categoryId: { type: DataTypes.STRING, references: { model: 'consumable_categories' } }, sku: DataTypes.STRING, // SKU编码 unit: DataTypes.STRING, // 单位 stock: { type: DataTypes.INTEGER, defaultValue: 0 }, // 库存 minStock: { type: DataTypes.INTEGER, defaultValue: 0 }, // 最低库存 location: DataTypes.STRING, // 存放位置 warehouseId: { type: DataTypes.STRING, references: { model: 'warehouses' } }, price: DataTypes.FLOAT, // 单价 snList: DataTypes.JSON, // SN序列号列表 version: { type: DataTypes.INTEGER, defaultValue: 0 }, // 乐观锁版本 }, { tableName: 'consumables', timestamps: true, }); ``` ### 5.3 模型关联初始化 (models/index.js) ```javascript // backend/models/index.js const Room = require('./Room'); const Rack = require('./Rack'); const Device = require('./Device'); const DevicePort = require('./DevicePort'); const NetworkCard = require('./NetworkCard'); const Cable = require('./Cable'); const Ticket = require('./Ticket'); const InventoryRecord = require('./InventoryRecord'); const Warehouse = require('./Warehouse'); // 建立核心关联 Room.hasMany(Rack, { foreignKey: 'roomId', as: 'Racks' }); Rack.belongsTo(Room, { foreignKey: 'roomId' }); Rack.hasMany(Device, { foreignKey: 'rackId', as: 'Devices' }); Device.belongsTo(Rack, { foreignKey: 'rackId' }); // 设备关联端口和网卡 Device.hasMany(DevicePort, { foreignKey: 'deviceId', as: 'Ports' }); Device.hasMany(NetworkCard, { foreignKey: 'deviceId', as: 'NetworkCards' }); // 线缆关联 Device.hasMany(Cable, { foreignKey: 'sourceDeviceId', as: 'SourceCables' }); Device.hasMany(Cable, { foreignKey: 'targetDeviceId', as: 'TargetCables' }); module.exports = { Room, Rack, Device, DevicePort, NetworkCard, Cable, Ticket, InventoryRecord, Warehouse }; ``` --- ## 6. API接口规范 ### 6.1 接口基础规范 | 项目 | 规范 | |------|------| | 基础URL | `http://localhost:8000/api` | | 认证方式 | JWT Bearer Token | | Content-Type | `application/json` | | 编码 | UTF-8 | ### 6.2 主要API模块 #### 6.2.1 设备管理API (/devices) ```javascript // GET /api/devices - 获取设备列表 // Query: keyword, status, type, rackId, roomId, page, pageSize // Response: { success, data: { list, total, page, pageSize } } // GET /api/devices/all - 获取所有设备(不分页,最大50000条) GET /api/devices/all?keyword=&status=&type=&rackId=&roomId= // GET /api/devices/:deviceId - 获取设备详情 // Response: { success, data: device } // POST /api/devices - 创建设备 // Body: { name, type, rackId, position, height, ... } // PUT /api/devices/:deviceId - 更新设备 // DELETE /api/devices/:deviceId - 删除设备 // POST /api/devices/check-position - 检查U位可用性 // Body: { rackId, position, height, excludeDeviceId? } // POST /api/devices/import-preview - 导入预览 // Body: FormData (csvFile) // POST /api/devices/import - 执行导入 // GET /api/devices/import-template - 下载导入模板 // GET /api/devices/export - 导出设备 // Query: format(csv|xlsx), keyword, status, type, rackId, roomId ``` #### 6.2.2 工单管理API (/tickets) ```javascript // GET /api/tickets - 获取工单列表 // Query: status, priority, categoryId, assigneeId, page, pageSize // GET /api/tickets/:ticketId - 获取工单详情 // POST /api/tickets - 创建工单 // Body: { title, description, type, priority, categoryId, deviceId } // PUT /api/tickets/:ticketId - 更新工单 // PUT /api/tickets/:ticketId/assign - 分配工单 // Body: { assigneeId } // PUT /api/tickets/:ticketId/process - 处理工单 // Body: { resolution, nextStep? } // PUT /api/tickets/:ticketId/close - 关闭工单 // PUT /api/tickets/:ticketId/reopen - 重开工单 // GET /api/tickets/:ticketId/operations - 获取操作记录 ``` #### 6.2.3 备份管理API (/backup) ```javascript // GET /api/backup/list - 获取备份列表 // POST /api/backup - 创建备份 // Body: { name?, description? } // GET /api/backup/validate/:filename - 验证备份文件 // POST /api/backup/restore - 恢复备份 // Body: { filename, options? } // GET /api/backup/download/:filename - 下载备份 // DELETE /api/backup/:filename - 删除备份 // POST /api/backup/upload - 上传备份文件 // Body: FormData (backup) // GET /api/backup/info - 获取备份信息 // 自动备份 // GET /api/backup/auto/status - 获取自动备份状态 // POST /api/backup/auto/settings - 更新自动备份设置 // POST /api/backup/auto/execute - 立即执行备份 ``` #### 6.2.4 统计分析API (/statistics) ```javascript // GET /api/statistics/overview - 获取概览统计 // Response: { deviceCount, roomCount, rackCount, ticketStats } // GET /api/statistics/devices - 设备统计 // Query: roomId?, rackId?, type?, period? // GET /api/statistics/tickets - 工单统计 // Query: period?, categoryId? // GET /api/statistics/consumables - 耗材统计 ``` ### 6.3 响应格式 ```javascript // 成功响应 { "success": true, "data": { ... }, "message": "操作成功" } // 失败响应 { "success": false, "message": "错误描述", "code": "ERROR_CODE" } // 分页响应 { "success": true, "data": { "list": [...], "total": 100, "page": 1, "pageSize": 20 } } ``` --- ## 7. 关键模块详解 ### 7.1 认证模块 #### 7.1.1 后端认证 (middleware/auth.js) ```javascript // JWT认证中间件 const authMiddleware = async (req, res, next) => { // 1. 从请求头获取Token const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) { return res.status(401).json({ success: false, message: '未提供认证令牌' }); } // 2. 验证Token try { const decoded = jwt.verify(token, process.env.JWT_SECRET); // 3. 获取用户信息 const User = require('../models/User'); const user = await User.findByPk(decoded.userId, { include: [{ model: Role, as: 'roles' }] }); if (!user) { return res.status(401).json({ success: false, message: '用户不存在' }); } // 4. 挂载用户到请求对象 req.user = user; next(); } catch (error) { if (error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '令牌已过期' }); } return res.status(401).json({ success: false, message: '无效的认证令牌' }); } }; ``` #### 7.1.2 前端认证 (context/AuthContext.jsx) ```javascript // 认证Provider export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); const [token, setToken] = useState(null); // 初始化 - 从本地存储恢复认证状态 useEffect(() => { const initializeAuth = async () => { const storedToken = await secureStorage.loadFromStorage(TOKEN_KEY); if (storedToken) { setToken(storedToken); // 验证Token有效性 const response = await authAPI.getProfile(); if (response.success) { setUser(response.data.user); } } }; initializeAuth(); }, []); const login = async (username, password) => { const response = await authAPI.login({ username, password }); if (response.success) { await secureStorage.set(TOKEN_KEY, response.data.token); setToken(response.data.token); setUser(response.data.user); } return response; }; const logout = () => { secureStorage.remove(TOKEN_KEY); setToken(null); setUser(null); }; const hasPermission = (permission) => { if (!user) return false; const roles = user.roles || []; if (roles.some(r => r.roleCode === 'admin')) return true; return roles.some(r => r.roleCode === permission); }; return ( {children} ); }; ``` ### 7.2 3D可视化模块 #### 7.2.1 Three.js场景 (components/3d/Scene.jsx) ```javascript // 3D主场景组件 const Scene = () => { const { selectedRack, setSelectedRack } = useContext(Scene3DContext); return ( {/* 灯光 */} {/* 机柜模型 */} {racks.map(rack => ( setSelectedRack(rack)} /> ))} {/* OrbitControls */} ); }; ``` #### 7.2.2 机柜模型 (components/3d/RackModel.jsx) ```javascript // 机柜3D模型 const RackModel = ({ rack, isSelected, onSelect }) => { const [hovered, setHovered] = useState(false); return ( {/* 机柜框架 */} setHovered(true)} onPointerOut={() => setHovered(false)} > {/* 设备模型 */} {rack.devices?.map(device => ( ))} {/* LOD优化 - 远处隐藏细节 */} ); }; ``` ### 7.3 备份模块 #### 7.3.1 本地备份 (utils/backup.js) ```javascript // 备份工具 const backupDatabase = async (options = {}) => { const { DB_TYPE, dbDialect } = require('../db'); if (dbDialect === 'mysql') { // MySQL备份 const { MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USERNAME, MYSQL_PASSWORD } = process.env; const filename = `backup_${dayjs().format('YYYYMMDD_HHmmss')}.sql`; const filepath = path.join(BACKUP_DIR, filename); // mysqldump命令 const command = `mysqldump -h${MYSQL_HOST} -P${MYSQL_PORT} -u${MYSQL_USERNAME}${MYSQL_PASSWORD ? `-p${MYSQL_PASSWORD}` : ''} ${MYSQL_DATABASE} > ${filepath}`; await exec(command); return { filename, filepath }; } else { // SQLite备份 - 复制数据库文件 const filename = `backup_${dayjs().format('YYYYMMDD_HHmmss')}.db`; const filepath = path.join(BACKUP_DIR, filename); await fs.copy( process.env.DB_PATH || './idc_management.db', filepath ); return { filename, filepath }; } }; ``` #### 7.3.2 远程备份 (utils/remoteBackup.js) ```javascript // 支持多种协议的远程备份 const uploadToRemote = async (localFile, config) => { const { protocol, host, port, username, password, path: remotePath } = config; switch (protocol) { case 'ftp': const ftpClient = require('basic-ftp'); const ftp = new ftpClient(); await ftp.access({ host, port, user: username, password }); await ftp.uploadFrom(localFile, `${remotePath}/${path.basename(localFile)}`); await ftp.close(); break; case 'sftp': const sftpClient = require('ssh2-sftp-client'); const sftp = new sftpClient(); await sftp.connect({ host, port, username, password }); await sftp.put(localFile, `${remotePath}/${path.basename(localFile)}`); await sftp.end(); break; case 'webdav': const { WebDAVClient } = require('webdav'); const webdav = new WebDAVClient(`http://${host}:${port}`); await webdav.putFileContents( `${remotePath}/${path.basename(localFile)}`, fs.createReadStream(localFile) ); break; case 'smb': const SMB2 = require('smb2'); const smb = new SMB2({ share: `\\\\${host}\\${remotePath}` }); await smb.writeFile(path.basename(localFile), fs.readFileSync(localFile)); break; } }; ``` ### 7.4 操作日志模块 #### 7.4.1 后端操作日志 (utils/operationLogger.js) ```javascript // 操作日志记录 const logDeviceOperation = async (req, action, deviceData, userId) => { const OperationLog = require('../models/OperationLog'); await OperationLog.create({ logId: generateId({ prefix: 'LOG' }), userId, module: 'device', action, targetId: deviceData.deviceId, targetName: deviceData.name, details: { before: deviceData.before, after: deviceData.after, ip: req.ip, userAgent: req.get('user-agent') }, result: 'success' }); }; // 生成设备变更描述 const generateDeviceDescription = (action, deviceData) => { const descriptions = { create: `创建设备「${deviceData.name}」`, update: `更新设备「${deviceData.name}」信息`, delete: `删除设备「${deviceData.name}」`, move: `移动设备「${deviceData.name}」到新位置`, status: `修改设备「${deviceData.name}」状态为${deviceData.status}` }; return descriptions[action] || `${action}设备「${deviceData.name}」`; }; ``` ### 7.5 设备导入模块 #### 7.5.1 导入预览验证 (routes/devices.js) ```javascript // POST /api/devices/import-preview router.post('/import-preview', upload.single('csvFile'), async (req, res) => { const results = []; const errors = []; const warnings = []; // 1. 解析CSV await new Promise((resolve, reject) => { fs.createReadStream(req.file.path) .pipe(csv()) .on('data', (row) => results.push(row)) .on('end', resolve) .on('error', reject); }); // 2. 逐行验证 for (let i = 0; i < results.length; i++) { const row = results[i]; const rowNum = i + 2; // 跳过表头 // 必填字段检查 if (!row.name) { errors.push({ row: rowNum, field: 'name', message: '设备名称不能为空' }); } // 格式验证 if (row.position && !/^\d+$/.test(row.position)) { errors.push({ row: rowNum, field: 'position', message: 'U位必须是数字' }); } // 冲突检查 if (row.rackId && row.position) { const { available, reason } = await checkPositionAvailable( row.rackId, row.position, row.height || 1 ); if (!available) { warnings.push({ row: rowNum, message: reason }); } } } // 3. 返回预览结果 res.json({ success: true, data: { total: results.length, errors: errors.slice(0, 20), // 最多返回20条错误 warnings: warnings.slice(0, 20), preview: results.slice(0, PREVIEW_COUNT) } }); }); ``` --- ## 8. 依赖关系 ### 8.1 前端依赖 (frontend/package.json) | 依赖 | 版本 | 用途 | |------|------|------| | react | ^18.2.0 | 前端框架 | | react-dom | ^18.2.0 | DOM渲染 | | react-router-dom | ^6.15.0 | 路由管理 | | antd | ^5.8.6 | UI组件库 | | @ant-design/icons | ^6.1.0 | 图标库 | | axios | ^1.13.6 | HTTP客户端 | | three | ^0.183.2 | 3D渲染引擎 | | @react-three/fiber | ^8.18.0 | React Three.js集成 | | @react-three/drei | ^9.122.0 | Three.js工具库 | | reactflow | ^11.11.4 | 流程图/拓扑图 | | swr | ^2.4.0 | 数据请求与缓存 | | styled-components | ^6.3.9 | CSS-in-JS | | framer-motion | ^12.34.0 | 动画库 | | dayjs | ^1.11.19 | 日期处理 | | xlsx | ^0.18.5 | Excel处理 | | papaparse | ^5.5.3 | CSV解析 | | dagre | ^0.8.5 | 图形布局算法 | ### 8.2 后端依赖 (backend/package.json) | 依赖 | 版本 | 用途 | |------|------|------| | express | ^4.18.2 | Web框架 | | sequelize | ^6.37.8 | ORM框架 | | sqlite3 | ^5.1.7 | SQLite驱动 | | mysql2 | ^3.19.1 | MySQL驱动 | | jsonwebtoken | ^9.0.3 | JWT认证 | | bcryptjs | ^3.0.3 | 密码加密 | | winston | ^3.19.0 | 日志管理 | | winston-daily-rotate-file | ^5.0.0 | 日志轮转 | | joi | ^18.0.2 | 数据验证 | | multer | ^2.1.1 | 文件上传 | | express-fileupload | ^1.5.2 | 文件上传中间件 | | cors | ^2.8.5 | 跨域资源共享 | | node-cron | ^4.2.1 | 定时任务 | | swagger-jsdoc | ^6.2.8 | Swagger文档生成 | | swagger-ui-express | ^5.0.1 | Swagger UI | | xlsx | ^0.18.5 | Excel处理 | | csv-parser | ^3.2.0 | CSV解析 | | csv-writer | ^1.6.0 | CSV生成 | | basic-ftp | ^5.0.3 | FTP客户端 | | ssh2-sftp-client | ^9.1.0 | SFTP客户端 | | webdav | ^5.3.1 | WebDAV客户端 | | smb2 | ^0.2.2 | SMB客户端 | | dayjs | ^1.11.19 | 日期处理 | | dotenv | ^17.2.3 | 环境变量 | ### 8.3 依赖关系图 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 项目根目录 │ │ (concurrently ^9.2.1) │ └────────────────────────────┬────────────────────────────────────┘ │ ┌─────────────────┴─────────────────┐ │ │ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ frontend/ │ │ backend/ │ │ ^2.0.0 │ │ ^2.0.0 │ ├─────────────────────┤ ├─────────────────────┤ │ React 18.2.0 │ │ Express 4.18.2 │ │ ├─ react-router-dom │ │ ├─ sequelize 6.37 │ │ ├─ antd 5.8.6 │ │ │ ├─ sqlite3 │ │ │ └─ @ant-design │ │ │ └─ mysql2 │ │ ├─ three.js 0.183 │ │ ├─ jsonwebtoken │ │ │ ├─ @react-three │ │ ├─ bcryptjs │ │ │ └─ @react-three │ │ ├─ winston │ │ ├─ axios 1.13 │─────────────│ ├─ axios │ │ ├─ swr 2.4 │ 共享HTTP │ ├─ dayjs │ │ └─ styled-components│ │ └─ xlsx │ │ │ │ │ │ 开发依赖: │ │ 开发依赖: │ │ ├─ vite 4.4 │ │ ├─ nodemon │ │ ├─ eslint │ │ ├─ jest │ │ └─ vitest 4.0 │ │ └─ supertest │ └─────────────────────┘ └─────────────────────┘ ``` --- ## 9. 运行环境与配置 ### 9.1 环境要求 | 项目 | 最低要求 | 推荐配置 | |------|----------|----------| | 操作系统 | Windows 10, macOS 12, Ubuntu 20.04 | 同最低 | | Node.js | ≥14.0.0 | 20.x LTS | | npm | ≥6.0.0 | 10.x | | 内存 | 4GB | 8GB+ | | 磁盘空间 | 2GB | 10GB+ | ### 9.2 环境变量配置 #### 9.2.1 前端环境变量 (frontend/.env) ```bash # 前端环境配置 VITE_API_BASE_URL=http://localhost:8000/api VITE_APP_TITLE=IDC设备管理系统 VITE_APP_VERSION=2.0.0 ``` #### 9.2.2 后端环境变量 (backend/.env) ```bash # 服务配置 NODE_ENV=development PORT=8000 # 数据库配置 DB_TYPE=sqlite # sqlite 或 mysql DB_PATH=./idc_management.db # SQLite数据库路径 # MySQL配置 (当DB_TYPE=mysql时) MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=idc_management MYSQL_USERNAME=root MYSQL_PASSWORD=your_password # JWT配置 JWT_SECRET=your_jwt_secret_key_here JWT_EXPIRES_IN=7d # 文件上传 FILE_UPLOAD_MAX_SIZE=10485760 # 10MB # 备份配置 BACKUP_DIR=./backups AUTO_BACKUP_ENABLED=false AUTO_BACKUP_CRON=0 2 * * * # 每天凌晨2点 # 远程备份 (可选) REMOTE_BACKUP_ENABLED=false REMOTE_BACKUP_PROTOCOL=ftp REMOTE_BACKUP_HOST= REMOTE_BACKUP_PORT=21 REMOTE_BACKUP_USERNAME= REMOTE_BACKUP_PASSWORD= REMOTE_BACKUP_PATH=/backups ``` ### 9.3 启动方式 #### 9.3.1 一键启动 (开发环境) ```bash # 在项目根目录 npm start # 效果等同于同时运行: # - 后端: cd backend && npm run dev (端口8000) # - 前端: cd frontend && npm run dev (端口3000) ``` #### 9.3.2 分别启动 ```bash # 终端1: 启动后端 cd backend npm run dev # 监听端口: http://localhost:8000 # 终端2: 启动前端 cd frontend npm run dev # 监听端口: http://localhost:3000 ``` #### 9.3.3 生产环境部署 ```bash # 1. 构建前端 cd frontend npm run build # 2. 使用PM2启动后端 cd ../backend pm2 start server.js --name idc-backend # 3. 使用Nginx反向代理 # 或使用PM2 serve提供静态文件 pm2 serve ./frontend/dist 3000 --name idc-frontend ``` --- ## 10. 部署指南 ### 10.1 生产环境部署流程 #### 10.1.1 数据库配置 ```bash # 1. 安装MySQL 8.0+ # Ubuntu sudo apt update sudo apt install mysql-server # 2. 创建数据库 mysql -u root -p CREATE DATABASE idc_management CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'idc_user'@'localhost' IDENTIFIED BY 'your_password'; GRANT ALL PRIVILEGES ON idc_management.* TO 'idc_user'@'localhost'; FLUSH PRIVILEGES; ``` #### 10.1.2 Nginx配置 ```nginx # /etc/nginx/sites-available/idc server { listen 80; server_name your_domain.com; # 前端静态文件 root /var/www/idc/frontend/dist; index index.html; # Gzip压缩 gzip on; gzip_types text/plain text/css application/json application/javascript; # 前端路由 location / { try_files $uri $uri/ /index.html; } # API代理 location /api { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } # 上传文件 location /uploads { alias /var/www/idc/backend/uploads; autoindex on; } # Swagger文档 location /api-docs { proxy_pass http://127.0.0.1:8000; } } # HTTPS配置 (推荐) server { listen 443 ssl http2; server_name your_domain.com; ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem; # ... 同上配置 } ``` #### 10.1.3 PM2进程管理 ```bash # 安装PM2 npm install -g pm2 # 启动后端服务 cd backend pm2 start server.js --name idc-backend \ --env production \ --max-memory-restart 1G # 配置负载均衡 (多核CPU) pm2 start server.js -i max --name idc-backend # 保存进程列表 pm2 save # 设置开机自启 pm2 startup pm2 install ubuntu-upstart # Ubuntu ``` ### 10.2 Docker部署 (可选) ```dockerfile # backend/Dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 8000 CMD ["node", "server.js"] ``` ```yaml # docker-compose.yml version: '3.8' services: backend: build: ./backend ports: - "8000:8000" environment: - NODE_ENV=production - DB_TYPE=mysql - MYSQL_HOST=db depends_on: - db frontend: build: ./frontend ports: - "3000:80" depends_on: - backend db: image: mysql:8.0 environment: MYSQL_DATABASE: idc_management MYSQL_ROOT_PASSWORD: root_password volumes: - mysql_data:/var/lib/mysql volumes: mysql_data: ``` --- ## 11. 系统关系图 ### 11.1 整体架构关系图 ``` ┌────────────────────────────────────────────────────┐ │ 用户交互层 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 浏览器 │ │ 管理员 │ │ 运维人员 │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ └───────┼────────────┼────────────┼────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 前端应用层 (React + Vite) │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 页面组件 (Pages) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │Dashboard│ │Devices │ │ Racks │ │Tickets │ │Backup │ │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ └───────┼──────────┼──────────┼──────────┼──────────┼────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 通用组件 (Components) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ 3D组件 │ │看板组件 │ │设备组件 │ │拓扑组件 │ │表单组件 │ │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ └───────┼──────────┼──────────┼──────────┼──────────┼────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 状态管理与Hooks │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │AuthContext│ │ConfigCtx │ │ useApi │ │ useSWR │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ HTTP/REST API ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 后端服务层 (Express.js) │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 中间件层 (Middleware) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ 认证 │ │ 授权 │ │ 验证 │ │ 日志 │ │ 维护 │ │ │ │ │ │ Middle │ │ Middle │ │ Middle │ │ Middle │ │ Middle │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 路由层 (Routes) │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ /auth │ │/devices│ │ /racks │ │/tickets│ │ /backup│ │/stats │ │ │ │ │ └────┬───┘ └────┬───┘ └────┬───┘ └────┬───┘ └────┬───┘ └────┬───┘ │ │ │ └───────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────────────┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 业务逻辑层 (Services) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ 设备服务 │ │ 工单服务 │ │ 备份服务 │ │ 统计服务 │ │ 导入服务 │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 数据访问层 (Sequelize ORM) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Device │ │ Ticket │ │Consumable│ │ User │ │ Rack │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 数据存储层 (Database) │ │ │ │ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ │ │ SQLite │ │ MySQL │ │ │ │ (开发环境) │◄──►│ (生产环境) │ │ │ │ idc_management.db │ │ MySQL 8.0+ │ │ │ └─────────────────────────────┘ └─────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ 数据备份层 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ 本地备份 │ │ FTP备份 │ │ SFTP备份 │ │WebDAV备份│ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘ ``` ### 11.2 数据模型ER图 ``` ┌──────────────────┐ ┌──────────────────┐ │ Room │ │ Rack │ ├──────────────────┤ ├──────────────────┤ │ PK roomId │──1:N──│ FK roomId │ │ name │ │ PK rackId │ │ location │ │ name │ │ area │ │ totalU │ │ manager │ │ usedU │ │ status │ │ powerCapacity │ │ floorPlanData │ │ status │ └──────────────────┘ │ positionX │ │ │ positionY │ │ └────────┬─────────┘ │ │ │ │ 1:N │ ▼ │ ┌──────────────────┐ │ │ Device │ │ ├──────────────────┤ │ │ PK deviceId │ │ │ FK rackId │ │ │ name │ │ │ type │ │ │ status │ │ │ position │ │ │ height │ │ │ serialNumber │ │ │ customFields │ │ └────────┬─────────┘ │ │ │ ┌──────────────┼──────────────┐ │ │ │ │ │ ▼ ▼ ▼ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ NetworkCard │ │ DevicePort │ │ DeviceField │ │ ├──────────────┤ ├──────────────┤ ├──────────────┤ │ │ PK nicId │ │ PK portId │ │ PK fieldId │ │ │ FK deviceId │ │ FK deviceId │ │ FK deviceId │ │ │ name │ │ FK nicId │ │ name │ │ │ type │ │ name │ │ type │ │ │ speed │ │ status │ │ value │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ N:1 │ │ ▼ │ │ ┌──────────────┐ │ └────►│ Cable │ │ ├──────────────┤ │ │ PK cableId │ │ │ FK sourceId │ │ │ FK targetId │ │ │ type │ │ │ length │ │ │ status │ │ └──────────────┘ ┌──────────────────┐ ┌──────────────────┐ │ User │ │ Role │ ├──────────────────┤ ├──────────────────┤ │ PK userId │──N:M──│ PK roleId │ │ username │ │ name │ │ password │ │ code │ │ email │ │ description │ │ status │ └──────────────────┘ │ isSystem │ │ └──────────────────┘ │ │ │ │ ▼ │ ┌──────────────────┐ │ │ Permission │ │ ├──────────────────┤ │ │ PK permissionId │ │ │ FK roleId │ │ │ resource │ │ │ action │ │ └──────────────────┘ ┌──────────────────┐ ┌──────────────────┐ │ Ticket │ │ TicketCategory │ ├──────────────────┤ ├──────────────────┤ │ PK ticketId │──N:1──│ PK categoryId │ │ title │ │ name │ │ description │ │ priority │ │ type │ └──────────────────┘ │ priority │ │ status │ ┌──────────────────┐ │ FK reporterId │ │ FaultCategory │ │ FK assigneeId │ ├──────────────────┤ │ FK deviceId │ │ PK categoryId │ │ FK categoryId │ │ name │ │ rating │ │ priority │ │ resolution │ │ solutions │ └──────────────────┘ └──────────────────┘ ┌──────────────────┐ ┌──────────────────┐ │ Consumable │ │ConsumableCategory│ ├──────────────────┤ ├──────────────────┤ │ PK consumableId │──N:1──│ PK categoryId │ │ name │ │ name │ │ FK categoryId │ │ parentId │ │ sku │ │ description │ │ unit │ └──────────────────┘ │ stock │ │ minStock │ ┌──────────────────┐ │ price │ │ ConsumableLog │ │ snList │ ├──────────────────┤ │ version │ │ PK logId │ └──────────────────┘──1:N───│ FK consumableId │ │ action │ │ quantity │ │ operatorId │ │ createdAt │ └──────────────────┘ ┌──────────────────┐ ┌──────────────────┐ │ InventoryPlan │ │ InventoryTask │ ├──────────────────┤ ├──────────────────┤ │ PK planId │──1:N──│ PK taskId │ │ name │ │ FK planId │ │ startDate │ │ FK assigneeId │ │ endDate │ │ FK rackId │ │ status │ │ status │ │ description │ │ progress │ └──────────────────┘ └──────────────────┘ ``` ### 11.3 API调用流程图 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ 前端组件 (React) │ │ │ │ const DeviceList = () => { │ │ const { data, error, isLoading } = useSWR('/api/devices', fetcher); │ │ // ... │ │ }; │ └────────────────────────────────┬────────────────────────────────────────┘ │ useSWR('/api/devices') ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ API层 (axios + interceptor) │ │ │ │ api.get('/devices') │ │ │ │ │ ├──► 请求拦截器 │ │ │ ├─ 添加 Authorization: Bearer {token} │ │ │ └─ 添加 Content-Type: application/json │ │ │ │ │ ▼ │ │ └──► 发送HTTP请求到 /api/devices │ └────────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Express路由 (routes/devices.js) │ │ │ │ router.get('/devices', async (req, res) => { │ │ │ │ │ ▼ │ │ ├─► 中间件链: auth → validation → logging │ │ │ │ │ ▼ │ │ └─► 控制器函数: getDevices(req, res) │ │ │ │ │ ▼ │ │ ├─► 参数验证 (Joi schema) │ │ │ │ │ ▼ │ │ ├─► 调用Service层 │ │ │ │ │ ▼ │ │ └─► 返回JSON响应 │ └────────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Service层 (业务逻辑) │ │ │ │ async function getDevices(params) { │ │ │ │ │ ▼ │ │ ├─► 构建查询条件 (Sequelize Op) │ │ │ { where: { status, type, ... } } │ │ │ │ │ ▼ │ │ ├─► 分页处理 │ │ │ { limit, offset } │ │ │ │ │ ▼ │ │ └─► 调用DAO层 │ └────────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ DAO层 (Sequelize ORM) │ │ │ │ Device.findAndCountAll({ │ │ where: conditions, │ │ include: [Room, Rack, NetworkCard, ...], │ │ limit, │ │ offset, │ │ order: [['createdAt', 'DESC']] │ │ }) │ │ │ │ │ ▼ │ │ └─► 执行SQL查询 │ └────────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 数据库 (SQLite / MySQL) │ │ │ │ SELECT * FROM devices │ │ JOIN racks ON devices.rackId = racks.rackId │ │ JOIN rooms ON racks.roomId = rooms.roomId │ │ WHERE ... │ │ ORDER BY createdAt DESC │ │ LIMIT 20 OFFSET 0 │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### 11.4 用户权限控制流程 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ 用户权限控制流程 │ │ │ │ ┌─────────────┐ │ │ │ 用户登录 │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ JWT Token 生成 │ │ │ │ jwt.sign({ userId, roles: [...] }, secret, { expiresIn: '7d' }) │ │ │ └──────┬────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 请求API资源 │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ Auth Middleware │ │ │ │ 1. 提取 Authorization Header │ │ │ │ 2. 验证 JWT Token │ │ │ │ 3. 从数据库加载用户信息和角色 │ │ │ │ 4. 挂载 req.user │ │ │ └──────┬────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 权限检查 (hasPermission) │ │ │ │ │ │ │ │ User.roles = [Role{code: 'admin'}, Role{code: 'device_manager'}]│ │ │ │ │ │ │ │ hasPermission('admin') → true (拥有admin角色) │ │ │ │ hasPermission('device_mgr') → true (拥有device_manager角色) │ │ │ │ hasPermission('system') → false (无此角色) │ │ │ │ │ │ │ │ // 权限层级 │ │ │ │ admin > device_manager > operator > viewer │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 允许访问 │ │ 拒绝访问 │ │ 404 Not │ │ │ │ 返回数据 │ │ 403 Forbidden│ │ Found │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### 11.5 备份恢复流程 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ 备份恢复系统架构 │ │ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 备份触发机制 │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ 手动触发 │ │ 定时触发 │ │ 远程同步触发 │ │ │ │ │ │ /backup │ │ node-cron │ │ webhook │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ │ │ │ └─────────┼─────────────────┼─────────────────┼────────────────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 备份管理器 (BackupManager) │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ 本地备份 │ │ 远程备份 │ │ 备份日志 │ │ │ │ │ │ backup.js │ │ remoteBackup.js│ │ backupLog.js │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────────────────┐│ │ │ │ │ 支持的远程协议 ││ │ │ │ │ FTP │ SFTP │ WebDAV │ SMB/CIFS │ Amazon S3 │ 阿里云OSS │ ││ │ │ │ └──────────────────────────────────────────────────────────────┘│ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 备份存储层 │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ │ │ 备份文件 │ │ │ │ │ │ backup_YYYYMMDD_HHmmss.sql (MySQL) │ │ │ │ │ │ backup_YYYYMMDD_HHmmss.db (SQLite) │ │ │ │ │ │ │ │ │ │ │ │ 存储位置: │ │ │ │ │ │ ├── 本地: ./backups/ │ │ │ │ │ │ ├── FTP: /remote/backups/ │ │ │ │ │ │ ├── SFTP: /var/backups/ │ │ │ │ │ │ └── OSS: oss://idc-backup/ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ │ │ 备份元数据 │ │ │ │ │ │ { │ │ │ │ │ │ filename: "backup_20260507_120000.sql", │ │ │ │ │ │ size: 1048576, │ │ │ │ │ │ createdAt: "2026-05-07T12:00:00Z", │ │ │ │ │ │ database: "idc_management", │ │ │ │ │ │ tables: ["devices", "racks", "tickets", ...], │ │ │ │ │ │ status: "completed" │ │ │ │ │ │ } │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────────────┐ │ 恢复执行流程 │ │ │ │ POST /api/backup/restore │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 1. 验证备份文件 │ │ │ │ GET /api/backup/validate/:filename │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 2. 创建临时恢复点 (可选) │ │ │ │ - 备份当前数据库状态 │ │ │ │ - 确保可回滚 │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 3. 关闭现有连接 │ │ │ │ - await sequelize.close() │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 4. 执行恢复 │ │ │ │ │ │ │ │ MySQL: │ │ │ │ mysql -u user -p dbname < backup_xxx.sql │ │ │ │ │ │ │ │ SQLite: │ │ │ │ cp backup_xxx.db idc_management.db │ │ │ │ │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 5. 重建连接 │ │ │ │ sequelize = new Sequelize(...) │ │ │ │ await sequelize.authenticate() │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 6. 验证数据完整性 │ │ │ │ - 检查关键表是否存在 │ │ │ │ - 验证记录数 │ │ │ └──────────────────────────┬───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 7. 返回恢复结果 │ │ │ │ { success: true, message: "恢复成功", backupId: "xxx" } │ │ │ └──────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ``` --- ## 附录 ### A. 常用命令 ```bash # 安装依赖 npm run install:all # 启动开发环境 npm start # 后端测试 cd backend && npm test # 前端构建 cd frontend && npm run build # 代码检查 cd backend && npm run lint cd frontend && npm run lint # 数据库迁移 cd backend && node scripts/migrate-all.js ``` ### B. 目录约定 | 目录 | 说明 | |------|------| | frontend/src/components | React组件 | | frontend/src/pages | 页面组件 | | frontend/src/hooks | 自定义Hooks | | frontend/src/context | Context状态管理 | | backend/models | Sequelize模型 | | backend/routes | Express路由 | | backend/middleware | Express中间件 | | backend/utils | 工具函数 | | backend/scripts | 数据库脚本 | ### C. 命名约定 | 类型 | 约定 | 示例 | |------|------|------| | 组件文件 | PascalCase.jsx | DeviceManagement.jsx | | 工具文件 | camelCase.js | secureStorage.js | | 数据模型 | PascalCase | Device.js | | 数据库表 | snake_case | device_ports | | API路径 | camelCase | /api/devices | | Context | PascalCase | AuthContext.jsx | | Hooks | use{camelCase}.js | useApi.js | --- **文档维护说明:** - 本文档由Code Wiki自动生成工具维护 - 更新日期:2026-05-07 - 版本:2.0.0 - 如有更新建议,请提交Issue