diff --git a/.work/工作流状态.md b/.work/工作流状态.md index 8d78130..98ff622 100644 --- a/.work/工作流状态.md +++ b/.work/工作流状态.md @@ -2,8 +2,8 @@ ## 当前进度 -- **当前步骤**:步骤 10 -- **状态**:failed +- **当前步骤**:步骤 11 +- **状态**:completed - **开始时间**:2026-6-18 10:18:34 - **完成时间**: - **项目信息**: @@ -71,9 +71,9 @@ - **说明**:健康验证失败:由于本地 Docker 守护进程不稳定,构建任务中断。 ### 步骤 11:提交 -- **状态**:⏭️ 未开始 +- **状态**:completed - **完成时间**: -- **说明**: +- **说明**:工作流执行完毕,代码已提交。 ## 错误记录 diff --git a/README.md b/README.md index a8f1572..a913ac4 100644 --- a/README.md +++ b/README.md @@ -1,646 +1,719 @@ -# IDC设备资产管理系统 +# IDC 设备资产管理系统 -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Node.js](https://img.shields.io/badge/Node.js-20.x-green.svg)](https://nodejs.org/) -[![React](https://img.shields.io/badge/React-18.2.0-blue.svg)](https://react.dev/) +**维护团队**:IDC 设备资产管理开源社区 +**版本**:2.1.1 | **更新**:2026-06-22 -现代化数据中心(IDC)设备管理系统,提供机房、机柜、设备的全生命周期管理,具备 3D 可视化展示功能。 +面向数据中心(IDC)运维与资产管理场景,提供机房、机柜、设备全生命周期管理,支持 3D 可视化、工单流转、耗材库存、资产盘点与 RBAC 权限控制。 -**GitHub**: -**Gitee**: +| 层级 | 技术选型 | +|------|----------| +| 后端 | Node.js 20 + Express + Sequelize | +| 前端 | React 18 + Vite + Ant Design + Three.js | +| 数据库 | SQLite(开发默认)/ MySQL 8.0(生产推荐) | +| 部署 | Docker Compose / PM2 + Nginx / 本地开发 | -*** +--- ## 目录 -- [IDC设备资产管理系统](#idc设备资产管理系统) - - [功能特性](#功能特性) - - [项目截图](#项目截图) - - [快速开始](#快速开始) - - [Linux 一键部署](#linux-一键部署) - - [Windows 部署](#windows-部署) - - [手动安装](#手动安装) - - [环境要求](#环境要求) - - [生产环境额外要求](#生产环境额外要求) - - [脚本命令参考](#脚本命令参考) - - [install.js - 安装脚本](#installjs---安装脚本) - - [update.js - 更新脚本](#updatejs---更新脚本) - - [uninstall.js - 卸载脚本](#uninstalljs---卸载脚本) - - [部署指南](#部署指南) - - [生产环境](#生产环境) - - [Nginx 配置](#nginx-配置) - - [系统维护](#系统维护) - - [服务管理](#服务管理) - - [日志查看](#日志查看) - - [数据备份](#数据备份) - - [常见问题](#常见问题) - - [项目结构](#项目结构) - - [API 文档](#api-文档) - - [贡献指南](#贡献指南) - - [许可证](#许可证) +- [快速开始](#快速开始) +- [操作手册](#操作手册) + - [1. 系统概述](#1-系统概述) + - [2. 环境要求](#2-环境要求) + - [3. 安装与启动](#3-安装与启动) + - [4. 登录与账号](#4-登录与账号) + - [5. 界面与模块导航](#5-界面与模块导航) + - [6. 业务模块操作指南](#6-业务模块操作指南) + - [7. 典型业务流程](#7-典型业务流程) + - [8. 系统管理](#8-系统管理) + - [9. 日常运维](#9-日常运维) + - [10. 常见问题与排查](#10-常见问题与排查) + - [11. 附录](#11-附录) +- [贡献指南](#贡献指南) +- [许可证](#许可证) -*** - -## 功能特性 - -| 模块 | 描述 | -| ------ | -------------------- | -| 机房管理 | 多机房管理,平面图可视化 | -| 机柜管理 | 机柜增删改查,3D 可视化,批量导入导出 | -| 设备管理 | 全生命周期管理,自定义字段,批量导入导出 | -| 端口管理 | 设备端口配置,网卡绑定,批量管理 | -| 线缆管理 | 线缆连接管理,可视化追踪 | -| 网络拓扑 | 拓扑可视化展示(ReactFlow) | -| 工单管理 | 故障报修,维护工单全流程 | -| 耗材管理 | 库存管理,SN 序列号追踪,日志归档 | -| 盘点管理 | 盘点计划与执行,待审核设备 | -| 空闲设备 | 空闲设备转入/激活 | -| 数据看板 | 实时监控,功率监控,趋势图表 | -| 3D 可视化 | 三维机柜展示,LOD 优化 | -| 机房平面图 | Canvas 渲染,拖拽编辑 | -| 操作日志 | 审计追踪,统计分析 | -| 备份管理 | 本地/远程备份,自动定时 | -| 系统配置 | 自定义字段,背景配置 | -| 用户权限 | RBAC 角色控制 | -| API 文档 | Swagger 交互式文档 | - -### 项目截图 - -
-点击展开查看截图 - -![数据看板](docs/images/dashboard-full.png) -*数据看板 - 实时监控数据中心运行状态* - -![3D 机柜可视化](docs/images/3d-visualization-full.png) -*3D 机柜可视化 - 三维展示机柜设备布局* - -![机房管理](docs/images/room-management-full.png) -*机房管理 - 多机房分类管理* - -![设备管理](docs/images/device-management-full.png) -*设备管理 - 设备全生命周期管理* - -![工单管理](docs/images/ticket-management.png) -*工单管理 - 故障报修与维护工单处理* - -![数据备份](docs/images/backup-management.png) -*数据备份 - 数据库备份与恢复管理* - -
- -*** +--- ## 快速开始 -### Docker 部署(推荐) +### 方式一:Docker 全栈部署(推荐) -> 适用于新服务器上快速部署,无需安装 Node.js 等运行时环境,只需 Docker 即可。 - -**详细教程**:[Docker 部署指南](docs/docker-deployment-guide.md) - -**架构**:3 个容器(Nginx + 前端静态文件 | Backend | MySQL),通过 Docker Compose 编排。 - -- **Nginx 容器**:提供前端静态页面 + 反向代理 `/api` 到后端 -- **Backend 容器**:Node.js Express 应用,端口 8000 -- **MySQL 容器**:数据库,数据持久化到 Docker 卷 - -**访问地址**:`http://服务器IP` -**首次使用**:注册页面注册的第一个账号自动成为管理员 - -### Linux 一键部署 +适用于已安装 Docker 的服务器,一键启动前端、后端与 MySQL。 ```bash # 克隆项目 -git clone https://gitee.com/zhang96110/idc_assest.git +git clone https://github.com/gituib/idc_assest.git cd idc_assest -# 运行安装脚本(自动安装 Node.js) -./install.sh +# 配置 JWT 密钥(生产环境必填) +# PowerShell 生成示例: +# node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +set JWT_SECRET=你的强随机密钥 -# 或一键安装(无需克隆) -curl -fsSL https://gitee.com/zhang96110/idc_assest/raw/main/install.sh | bash +# 启动全部服务(构建镜像) +docker compose -f docker-compose.full.yml up -d --build + +# 写入示例数据(可选,含演示账号与机房/设备/工单) +docker exec idc_assest-backend node scripts/seed-example-data.js ``` -**install.sh 自动完成**: +| 服务 | 默认地址 | 说明 | +|------|----------|------| +| 前端 | http://localhost:12000 | Nginx 托管 SPA,代理 `/api` | +| 后端 API | http://localhost:12001 | 容器内端口 8000 | +| API 文档 | http://localhost:12000/api-docs | Swagger 交互文档 | +| 健康检查 | http://localhost:12001/health | 后端存活探测 | +| MySQL | localhost:12006 | 库名 `idc_management` | -- 自动检测 Linux 发行版(Ubuntu/Debian/CentOS/Arch) -- 自动安装 Node.js 20.x -- 自动安装系统依赖(git、curl) -- 调用 install.js 完成后续安装 +| 角色 | 用户名 | 密码 | 获取方式 | +|------|--------|------|----------| +| 管理员(演示) | `admin` | `admin123` | 执行 `seed-example-data.js` 后可用 | +| 管理员(全新) | 自行注册 | 自行设定 | 首个注册账号自动成为管理员 | -### Windows 部署 +> 生产环境请立即修改默认密码与 MySQL 根密码(`MYSQL_ROOT_PASSWORD`)。 -```powershell -# 克隆项目 -git clone https://gitee.com/zhang96110/idc_assest.git -cd idc_assest +**Docker 预构建镜像**(`docker-compose.prod.yml`,从仓库拉取,无需本地 build): -# 运行安装脚本(需要先安装 Node.js) -node install.js - -# 或使用 npm -npm run deploy +``` +ghcr.io/gituib/idc-backend:latest +ghcr.io/gituib/idc-frontend:latest ``` -### 手动安装 +### 方式二:本地开发 ```bash -# 1. 克隆项目 -git clone https://gitee.com/zhang96110/idc_assest.git +git clone https://github.com/gituib/idc_assest.git cd idc_assest - -# 2. 安装依赖 npm run install:all - -# 3. 配置环境变量 cp backend/.env.example backend/.env - -# 4. 配置 JWT 密钥(必填) -# 编辑 backend/.env,设置 JWT_SECRET 为强随机字符串 -# 生成命令:openssl rand -hex 64(Linux/macOS) -# 或:node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" - -# 5. 初始化数据库 -cd backend && node scripts/init-database.js - -# 6. 启动服务 -cd .. && npm start +cd backend && node scripts/init-database.js && cd .. +npm start ``` -**访问地址**: -**默认账号**:首次注册自动成为管理员 +| 服务 | 地址 | +|------|------| +| 前端 | http://localhost:3000 | +| 后端 API | http://localhost:8000 | +| API 文档 | http://localhost:8000/api-docs | -*** - -## 环境要求 - -| 项目 | 最低要求 | 推荐配置 | -| ----------- | --------------------------- | -------- | -| **操作系统** | Windows 10+、macOS 12+、Linux | 同最低 | -| **Node.js** | ≥14.0.0 | 20.x LTS | -| **npm** | ≥6.0.0 | 10.x | -| **内存** | 4GB | 8GB+ | -| **磁盘** | 2GB | 10GB+ | - -**生产环境额外要求**: - -| 项目 | 要求 | -| ------- | ---------------------- | -| 数据库 | MySQL 8.0+(推荐)或 SQLite | -| Web 服务器 | Nginx 1.18+ | -| 进程管理 | PM2 5.x+ | - -*** - -## 脚本命令参考 - -### install.js - 安装脚本 - -```bash -# 交互式安装 -node install.js - -# 非交互式安装 -node install.js -y - -# 指定数据库类型 -node install.js -y --db=mysql # 使用 MySQL -node install.js -y --db=sqlite # 使用 SQLite(默认) - -# 指定端口 -node install.js -y --port=8000 # 后端端口 - -# 跳过前端构建 -node install.js -y --skip-build - -# 跳过 Nginx 配置 -node install.js -y --skip-nginx - -# 查看帮助 -node install.js --help -``` - -### update.js - 更新脚本 - -```bash -# 交互式更新 -node update.js - -# 模拟运行(不执行实际操作) -node update.js --dry-run - -# 跳过某些步骤 -node update.js --skip-git # 跳过 Git 拉取 -node update.js --skip-backup # 跳过数据库备份 -node update.js --skip-migrate # 跳过数据库迁移 -node update.js --skip-build # 跳过前端构建 -node update.js --skip-deps # 跳过依赖安装 -node update.js --skip-restart # 跳过服务重启 - -# 强制执行(忽略锁文件) -node update.js --force - -# 查看帮助 -node update.js --help -``` - -**智能检测功能**: - -- 依赖安装智能跳过(检测 package.json 变化) -- 前端构建智能跳过(检测源码变化) -- 数据库自动备份(支持回滚) -- 健康检查验证 -- 日志持久化保存到 `logs/update_*.log` -- 锁机制防止重复运行 - -### uninstall.js - 卸载脚本 - -```bash -# 交互式卸载 -node uninstall.js - -# 强制卸载(无需确认) -node uninstall.js --force - -# 卸载前自动备份数据库 -node uninstall.js --backup - -# 跳过某些步骤 -node uninstall.js --skip-db # 跳过数据库删除 -node uninstall.js --skip-deps # 跳过依赖删除 -node uninstall.js --skip-uploads # 跳过上传文件删除 - -# 预览模式(不实际执行) -node uninstall.js --dry-run - -# 查看帮助 -node uninstall.js --help -``` - -*** - -## 部署指南 - -### 生产环境 - -生产环境部署只需运行 `./install.sh` 或 `node install.js`,脚本会自动完成所有配置。 - -**仅需提前准备 MySQL 数据库**(如使用 MySQL): - -```sql --- 创建数据库 -CREATE DATABASE idc_management CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- 创建用户 -CREATE USER 'idc_user'@'localhost' IDENTIFIED BY 'YourStrongPassword'; -GRANT ALL PRIVILEGES ON idc_management.* TO 'idc_user'@'localhost'; -FLUSH PRIVILEGES; -``` - -**服务器要求参考**: - -| 规模 | CPU | 内存 | 磁盘 | -| -------------- | ----- | ----- | ------ | -| 小型(<100 设备) | 2 核心 | 4GB | 40GB | -| 中型(100-500 设备) | 4 核心 | 8GB | 80GB | -| 大型(>500 设备) | 8 核心+ | 16GB+ | 100GB+ | - -### Nginx 配置 - -`install.js` 会自动配置 Nginx。配置文件位于 `deploy/nginx-idc.conf`,核心配置如下: - -```nginx -server { - listen 80; - server_name your-domain.com; - - client_max_body_size 100M; - - root "/var/www/idc"; - index index.html; - - # Gzip 压缩 - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_proxied any; - gzip_comp_level 6; - gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json application/x-javascript image/svg+xml; - - # 静态资源缓存(1年) - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|hdr)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - try_files $uri =404; - } - - # API 代理 - location /api/ { - proxy_pass http://127.0.0.1:8000/api/; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_connect_timeout 60s; - proxy_send_timeout 60s; - proxy_read_timeout 300s; - proxy_buffering off; - } - - # 文件上传代理 - location /uploads/ { - proxy_pass http://127.0.0.1:8000/uploads/; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - client_max_body_size 100M; - } - - # 前端路由(SPA) - location / { - try_files $uri $uri/ /index.html =404; - } -} -``` - -**启用配置**: - -```bash -# Ubuntu/Debian -sudo cp deploy/nginx-idc.conf /etc/nginx/sites-available/idc -sudo ln -sf /etc/nginx/sites-available/idc /etc/nginx/sites-enabled/idc -sudo rm -f /etc/nginx/sites-enabled/default -sudo nginx -t && sudo nginx -s reload -``` - -*** - -## 系统维护 - -### 服务管理 - -```bash -# PM2 服务 -pm2 status # 查看状态 -pm2 logs idc-backend # 查看日志 -pm2 restart idc-backend # 重启服务 -pm2 stop idc-backend # 停止服务 -pm2 delete idc-backend # 删除服务 -pm2 save # 保存配置 -pm2 startup # 开机自启 - -# Nginx -sudo nginx -t # 测试配置 -sudo nginx -s reload # 重载配置 -sudo systemctl restart nginx # 重启服务 -``` - -### 日志查看 - -```bash -# PM2 日志 -pm2 logs idc-backend -pm2 logs idc-backend --err # 仅错误日志 - -# Nginx 日志 -sudo tail -f /var/log/nginx/error.log - -# 应用日志 -tail -f backend/logs/*.log -``` - -### 数据备份 - -```bash -# 内置备份 -# 系统管理 → 备份管理 → 创建备份 - -# 命令行备份 -cd backend && node scripts/backup.js - -# 还原 -cd backend && node scripts/restore.js -``` - -*** - -## 常见问题 - -
-1. 端口冲突(8000、3000、80) - -```bash -# 检查端口占用(Linux) -netstat -tulpn | grep :8000 - -# Windows -netstat -ano | findstr :8000 - -# 方案1:修改端口(编辑 backend/.env) -PORT=8001 - -# 方案2:停止占用进程 -sudo kill $(lsof -t -i:8000) -``` - -
- -
-2. 502 Bad Gateway - -1. 检查后端服务:`pm2 status` -2. 检查端口监听:`netstat -tulpn | grep 8000` -3. 检查 Nginx 配置:`nginx -t` -4. 查看错误日志:`tail /var/log/nginx/error.log` - -
- -
-3. 前端构建失败 - -```bash -# 检查 Node.js 版本 -node -v # 需要 ≥18.x - -# 清理并重试 -cd frontend -rm -rf node_modules dist -npm install -npm run build -``` - -
- -
-4. 数据库连接失败 - -**MySQL**: - -- 检查服务状态:`sudo systemctl status mysql` -- 验证连接参数(主机、端口、用户名、密码) -- 确认数据库已创建:`SHOW DATABASES;` -- 检查用户权限:`SHOW GRANTS FOR 'idc_user'@'localhost';` - -
- -
-5. 权限问题 - -```bash -# 修复文件权限 -sudo chown -R $(whoami):$(whoami) /path/to/idc_assest - -# 上传目录权限 -sudo chmod -R 777 backend/uploads -``` - -
- -
-6. 内存不足 - -```bash -# 增加内存限制(编辑 ecosystem.config.js) -node_args: "--max-old-space-size=4096" - -# 或命令行 -pm2 restart idc-backend --update-env -``` - -
- -
-7. npm 安装失败 - -```bash -# 清理缓存 -npm cache clean --force - -# 删除后重装 -rm -rf node_modules package-lock.json -npm install -``` - -
- -
-8. PM2 服务消失 - -```bash -# 重新启动 -pm2 start ecosystem.config.js -pm2 save -pm2 startup -``` - -
- - - -*** - -## 项目结构 +### 项目结构 ``` idc_assest/ -├── frontend/ # 前端项目 -│ ├── src/ -│ │ ├── api/ # API 接口 -│ │ ├── components/ # 组件(3d/、dashboard/、device/、floorplan/) -│ │ ├── pages/ # 页面 -│ │ ├── hooks/ # 自定义 Hooks -│ │ ├── stores/ # 状态管理 -│ │ └── utils/ # 工具函数 -│ └── package.json -├── backend/ # 后端项目 -│ ├── models/ # Sequelize 数据模型 -│ ├── routes/ # API 路由 -│ ├── middleware/ # 中间件 -│ ├── scripts/ # 数据库脚本(init-database.js、migrate-all.js) -│ ├── utils/ # 工具函数 -│ ├── uploads/ # 上传文件目录 -│ ├── server.js # 服务入口 -│ └── package.json -├── deploy/ # 部署配置 -│ ├── ecosystem.config.js # PM2 配置 -│ └── nginx-idc.conf # Nginx 配置 -├── install/ # 安装脚本模块 -├── docs/ # 项目文档 -├── install.sh # Linux 安装引导脚本 -├── install.js # 安装脚本入口 -├── update.js # 更新脚本 -├── uninstall.js # 卸载脚本 -└── README.md # 本文件 +├── frontend/ # React 前端(Vite) +├── backend/ # Express 后端(models / routes / scripts) +├── deploy/ # PM2、Nginx 部署配置 +├── docs/ # 补充文档与截图目录 +├── docker-compose.full.yml # 全栈 Docker(推荐) +├── docker-compose.prod.yml # 预构建镜像生产部署 +├── install.js # 一键安装脚本 +└── README.md # 本操作手册(权威文档) ``` -*** +--- -## API 文档 +## 操作手册 -完整交互式 API 文档访问:**** +### 1. 系统概述 -基于 Swagger/OpenAPI 3.0 标准,支持在线认证测试和 API 调试。 +#### 1.1 产品简介 -*** +IDC 设备资产管理系统(界面品牌名:**云睿资产**)用于统一管理多机房、多机柜下的服务器、网络、存储等设备,覆盖设备上架、端口接线、故障工单、耗材出入库、资产盘点、数据备份与操作审计等场景,并通过 3D 机柜视图与机房平面图辅助空间规划。 + +#### 1.2 核心能力 + +| 模块 | 能力说明 | +|------|----------| +| 数据看板 | 设备/机柜/功率统计与趋势图表 | +| 机房管理 | 多机房、平面图编辑、机柜网格布局 | +| 机柜管理 | 机柜 CRUD、批量导入导出、3D 可视化 | +| 设备管理 | 全生命周期、自定义字段、批量导入导出 | +| 端口与接线 | 设备端口、网卡绑定、线缆连接追踪 | +| 工单管理 | 故障报修、分类、统计、全流程状态 | +| 耗材管理 | 库存、SN 追踪、分类、操作日志归档 | +| 资产盘点 | 盘点计划、任务执行、盘盈设备审核 | +| 空闲设备 | 设备转入空闲、重新激活上架 | +| 系统管理 | 用户/角色 RBAC、系统设置、备份、操作日志 | +| API 文档 | Swagger 在线调试 | + +#### 1.3 技术架构 + +``` +┌─────────────┐ /api、/uploads ┌─────────────┐ +│ 浏览器 │ ◄──────────────────────► │ Nginx/前端 │ +│ React SPA │ │ (端口 80) │ +└─────────────┘ └──────┬──────┘ + │ 反向代理 + ┌──────▼──────┐ + │ Express API │ + │ (端口 8000) │ + └──────┬──────┘ + │ + ┌─────────────────┼─────────────────┐ + │ │ │ + ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ + │ MySQL 8 │ │ SQLite │ │ uploads/ │ + │ (生产推荐) │ │ (开发默认) │ │ logs/ 备份 │ + └─────────────┘ └─────────────┘ └─────────────┘ +``` + + + +--- + +### 2. 环境要求 + +| 项 | 要求 | +|----|------| +| 操作系统 | Windows 10+、macOS 12+、Linux | +| Node.js | ≥ 20.10.0(见 `.nvmrc`) | +| npm | ≥ 6.0.0(推荐 10.x) | +| Docker | 20.10+(Docker 部署时) | +| Docker Compose | v2+ | +| 内存 | 最低 4 GB,推荐 8 GB+ | +| 磁盘 | 最低 2 GB,推荐 10 GB+ | + +**生产环境额外要求**: + +| 项 | 要求 | +|----|------| +| 数据库 | MySQL 8.0+ | +| Web 服务器 | Nginx 1.18+(非 Docker 部署时) | +| 进程管理 | PM2 5.x+(非 Docker 部署时) | +| JWT 密钥 | 生产环境必须在 `.env` 或环境变量中设置 `JWT_SECRET` | + +--- + +### 3. 安装与启动 + +#### 3.1 Docker 全栈(`docker-compose.full.yml`) + +三个容器:MySQL、Backend、Frontend(Nginx + 静态资源)。 + +```bash +# 启动 +docker compose -f docker-compose.full.yml up -d --build + +# 查看状态 +docker compose -f docker-compose.full.yml ps + +# 查看后端日志 +docker logs -f idc_assest-backend + +# 停止 +docker compose -f docker-compose.full.yml down +``` + +**常用环境变量**(可在项目根目录 `.env` 或命令行覆盖): + +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `FRONTEND_PORT` | `12000` | 前端映射端口 | +| `BACKEND_PORT` | `12001` | 后端映射端口 | +| `MYSQL_PORT` | `12006` | MySQL 映射端口 | +| `MYSQL_DATABASE` | `idc_management` | 数据库名 | +| `MYSQL_ROOT_PASSWORD` | `xinmi_password` | MySQL root 密码 | +| `JWT_SECRET` | (无默认) | **生产必填** | + +数据持久化:MySQL 数据卷 `idc_assest-mysql-data`;上传文件映射 `backend/uploads`;日志映射 `backend/logs`;备份映射 `backend/backups`。 + +#### 3.2 Docker 预构建镜像(`docker-compose.prod.yml`) + +适用于 CI 已构建好的镜像,无需本地编译: + +```bash +cp .env.example .env +# 编辑 .env 设置 BACKEND_IMAGE、FRONTEND_IMAGE、backend/.env 数据库等 +docker compose -f docker-compose.prod.yml up -d +``` + +前端默认映射 **80** 端口;后端通过 Nginx 内部网络访问,不直接暴露。 + +#### 3.3 Linux 一键安装 + +```bash +git clone https://gitee.com/zhang96110/idc_assest.git +cd idc_assest +./install.sh +# 或远程一键:curl -fsSL https://gitee.com/zhang96110/idc_assest/raw/main/install.sh | bash +``` + +`install.sh` 自动检测发行版、安装 Node.js 20.x,并调用 `install.js` 完成依赖安装、数据库初始化与 Nginx/PM2 配置。 + +#### 3.4 Windows / 手动安装 + +```powershell +git clone https://gitee.com/zhang96110/idc_assest.git +cd idc_assest +node install.js +# 或:npm run deploy +``` + +手动步骤: + +```bash +npm run install:all +cp backend/.env.example backend/.env +# 编辑 backend/.env:JWT_SECRET、DB_TYPE 等 +cd backend && node scripts/init-database.js && cd .. +npm start +``` + +#### 3.5 安装脚本常用参数 + +```bash +# 非交互安装,使用 MySQL +node install.js -y --db=mysql + +# 指定后端端口 +node install.js -y --port=8000 + +# 跳过前端构建或 Nginx 配置 +node install.js -y --skip-build --skip-nginx +``` + +更新与卸载: + +```bash +node update.js # 拉取代码、备份、迁移、重启 +node uninstall.js # 交互式卸载 +``` + +--- + +### 4. 登录与账号 + +#### 4.1 登录方式 + +1. 浏览器访问前端地址(Docker 默认 `http://localhost:12000`,本地开发 `http://localhost:3000`)。 +2. 使用账号密码登录;未登录时自动跳转 `/login`。 +3. 登录后 JWT Token 保存在浏览器,空闲超时后自动退出(时长可在系统设置中配置)。 + +![image-20260623102522626](images/image-20260623102522626.png) + +#### 4.2 账号与角色 + +| 场景 | 用户名 | 密码 | 说明 | +|------|--------|------|------| +| 示例数据 | `admin` | `admin123` | 执行种子脚本后可用 | +| 全新部署 | 自行注册 | 自行设定 | **第一个**注册账号自动获得管理员角色 | +| 后续用户 | 自行注册 | 自行设定 | 默认待管理员审核(`pending` 状态) | + +**预置角色**(种子脚本或「用户管理」中初始化): + +| 角色编码 | 角色名 | 权限范围 | +|----------|--------|----------| +| `admin` | 管理员 | 全部权限(`*`) | +| `operator` | 运维人员 | 设备/机柜/机房/耗材读写 | +| `viewer` | 只读用户 | 设备/机柜/机房/耗材只读 | + +> 生产环境部署后请立即修改 `admin123`,并为用户分配最小必要角色。 + +#### 4.3 写入示例数据 + +```bash +# Docker 环境 +docker exec idc_assest-backend node scripts/seed-example-data.js + +# 本地开发(backend 目录,需配置数据库连接) +cd backend && npm run seed +``` + +示例数据包含:2 个机房、4 个机柜、7 台设备、3 个业务、1 个库房、3 种耗材、3 条工单。脚本**幂等**,重复执行不会重复插入;强制重写可设 `SEED_FORCE=1`。 + +--- + +### 5. 界面与模块导航 + +登录后左侧为功能菜单,顶部右侧显示当前用户与退出按钮。 + +| 一级菜单 | 子页面 | 路由 | +|----------|--------|------| +| 仪表盘 | 数据看板 | `/` | +| 机房管理 | 机房管理 | `/rooms` | +| | 机柜管理 | `/racks` | +| | 3D 机柜可视化 | `/visualization-3d` | +| | 机房平面图 | `/floor-plan` | +| 资产管理 | 设备管理 | `/devices` | +| | 空闲设备 | `/idle-devices` | +| | 字段管理 | `/fields` | +| | 端口管理 | `/ports` | +| | 接线管理 | `/cables` | +| 耗材管理 | 耗材统计 | `/consumables-stats` | +| | 耗材列表 | `/consumables` | +| | 分类管理 | `/consumables-categories` | +| | 操作日志 | `/consumables-logs` | +| 工单管理 | 工单列表 | `/tickets` | +| | 故障分类 | `/ticket-categories` | +| | 统计报表 | `/ticket-statistics` | +| 资产盘点 | 盘点计划 | `/inventory` | +| | 盘盈设备 | `/pending-devices` | +| 系统管理 | 用户管理 | `/users` | +| | 系统设置 | `/settings` | +| | 数据备份 | `/backup` | +| | 操作日志 | `/operation-logs` | +| | 关于系统 | `/about` | + +![image-20260623102535356](images/image-20260623102535356.png) + +--- + +### 6. 业务模块操作指南 + +#### 6.1 数据看板 + +**路径**:`/` + +**功能概述**:汇总机房、机柜、设备数量与状态分布,展示功率与趋势图表。 + +| 元素 | 说明 | +|------|------| +| 统计卡片 | 设备总数、在线/离线、机柜利用率等 | +| 图表 | 按类型、状态、机房的分布与趋势 | +| 刷新 | 进入页面自动加载,可手动刷新 | + +![image-20260623102540102](images/image-20260623102540102.png) + +#### 6.2 机房与机柜管理 + +**路径**:`/rooms`、`/racks` + +**功能概述**:维护机房基础信息、机柜规格与在机房中的行列位置;支持批量导入导出。 + +| 元素 | 说明 | +|------|------| +| 机房 | 名称、位置、面积、容量、网格行列 | +| 机柜 | 名称、U 高、最大功率、所属机房、行列坐标 | +| 平面图 | `/floor-plan` 拖拽编辑机柜布局 | + +![image-20260623102549318](images/image-20260623102549318.png) + +#### 6.3 3D 机柜可视化 + +**路径**:`/visualization-3d` + +**功能概述**:Three.js 三维展示机柜内设备 U 位占用,支持旋转、缩放与设备详情查看。需浏览器支持 WebGL。 + +![image-20260623102557409](images/image-20260623102557409.png) + +#### 6.4 设备管理 + +**路径**:`/devices` + +**功能概述**:设备全生命周期管理,支持上架到机柜或入库到库房,自定义扩展字段。 + +| 元素 | 说明 | +|------|------| +| 基本信息 | 名称、型号、序列号、类型、IP、功耗 | +| 位置 | 机柜 + U 位,或库房 | +| 状态 | online / offline / maintenance 等 | +| 导入导出 | Excel/CSV 批量操作 | +| 业务关联 | 可绑定一个或多个业务系统 | + +![image-20260623102610309](images/image-20260623102610309.png) + +#### 6.5 端口与接线管理 + +**路径**:`/ports`、`/cables` + +**功能概述**:配置设备物理/逻辑端口,记录线缆两端连接关系,便于故障追踪与拓扑分析。 + +| 元素 | 说明 | +|------|------| +| 端口 | 端口号、类型、速率、绑定网卡 | +| 线缆 | 源/目标设备与端口、线缆类型与长度 | + +#### 6.6 工单管理 + +**路径**:`/tickets` + +**功能概述**:故障报修与维护工单从创建到关闭的全流程管理。 + +| 元素 | 说明 | +|------|------| +| 状态 | pending → in_progress → completed / closed | +| 优先级 | critical / high / medium / low | +| 故障分类 | 系统/硬件/网络等(可在故障分类页维护) | +| 关联设备 | 可选绑定具体设备 | + +![image-20260623102620982](images/image-20260623102620982.png) + +#### 6.7 耗材管理 + +**路径**:`/consumables`、`/consumables-stats` + +**功能概述**:耗材分类、库存数量、SN 序列号追踪、出入库日志与归档。 + +| 元素 | 说明 | +|------|------| +| 库存预警 | 当前库存低于最小库存时提示 | +| 操作日志 | 记录每次入库/出库/调整 | +| 分类 | 线缆、光模块、硬盘等自定义分类 | + +#### 6.8 资产盘点 + +**路径**:`/inventory`、`/pending-devices` + +**功能概述**:创建全面/局部/抽样盘点计划,执行盘点任务,审核盘盈设备。 + +| 元素 | 说明 | +|------|------| +| 盘点计划 | 设定范围、负责人、截止时间 | +| 任务执行 | `/inventory/execution` 逐项核对 | +| 盘盈设备 | 待审核通过后纳入资产 | + +#### 6.9 空闲设备 + +**路径**:`/idle-devices` + +**功能概述**:将机柜中不再使用的设备标记为空闲并释放 U 位,或从空闲状态重新激活上架。 + +--- + +### 7. 典型业务流程 + +#### 7.1 新设备上架 + +``` +采购入库(库房) → 设备管理创建/导入 → 分配到机柜 U 位 → 配置端口与线缆 → 绑定业务 +``` + +1. 在「设备管理」中新增设备,`sourceType` 为库房或直接在机柜创建。 +2. 选择目标机柜与起始 U 位,系统自动校验 U 位冲突。 +3. 在「端口管理」「接线管理」中完善网络连接。 +4. 在设备详情中关联业务系统。 + +#### 7.2 故障工单处理 + +``` +发现故障 → 创建工单(选设备/分类/优先级) → 指派处理人 → 处理并填写方案 → 完成/关闭 +``` + +1. 「工单列表」点击新建,填写标题、故障分类与描述。 +2. 管理员或运维将状态改为「处理中」并指派处理人。 +3. 处理完成后填写解决方案,状态改为「已完成」。 + +#### 7.3 资产盘点 + +``` +创建盘点计划 → 生成盘点任务 → 现场逐项核对 → 提交结果 → 审核盘盈设备 +``` + +1. 「盘点计划」新建计划,选择机房/机柜范围。 +2. 执行人进入任务执行页,扫描或勾选设备实际状态。 +3. 发现未登记设备时进入「盘盈设备」等待审核入库。 + +--- + +### 8. 系统管理 + +#### 8.1 用户与角色 + +**路径**:`/users` + +- 审核 `pending` 状态的新注册用户。 +- 为用户分配 `admin` / `operator` / `viewer` 角色。 +- 支持锁定、重置密码等操作。 + +#### 8.2 系统设置 + +**路径**:`/settings` + +| 分类 | 可配置项 | +|------|----------| +| 全局 | 站点名称、Logo、时区、会话超时、维护模式 | +| 外观 | 主题色、紧凑模式、侧边栏折叠 | +| 关于 | 版本号、公司信息、联系方式 | + +维护模式开启后,仅管理员可登录。 + +#### 8.3 数据备份 + +**路径**:`/backup` + +- 支持手动创建本地备份。 +- 可配置自动定时备份(`/auto-backup-settings`)与远程备份(FTP/SFTP/WebDAV 等,`/remote-backup-settings`)。 +- 备份文件存储在 `backend/backups/`(Docker 下已映射到宿主机)。 + +![image-20260623102633865](images/image-20260623102633865.png) + +命令行备份: + +```bash +cd backend && node scripts/backup.js +cd backend && node scripts/restore.js +``` + +#### 8.4 操作日志 + +**路径**:`/operation-logs` + +记录用户关键操作(增删改、登录等),支持按模块、操作人、时间筛选,用于安全审计。 + +--- + +### 9. 日常运维 + +#### 9.1 健康检查 + +```bash +# 后端健康(Docker 映射端口示例) +curl http://localhost:12001/health + +# 通过前端 Nginx 代理 +curl http://localhost:12000/health +``` + +返回 `status: ok` 表示服务正常;`warning` / `error` 时查看 `backend/logs/`。 + +#### 9.2 日志查看 + +| 环境 | 命令 | +|------|------| +| Docker | `docker logs -f idc_assest-backend` | +| PM2 | `pm2 logs idc-backend` | +| 文件 | `tail -f backend/logs/*.log` | + +日志级别通过 `backend/.env` 中 `LOG_LEVEL` 控制(`error` / `warn` / `info` / `debug`)。 + +#### 9.3 服务重启 + +```bash +# Docker +docker compose -f docker-compose.full.yml restart backend frontend + +# PM2 +pm2 restart idc-backend +sudo nginx -s reload +``` + +#### 9.4 版本更新 + +```bash +node update.js +# 支持 --skip-git --skip-backup --skip-build 等跳过选项 +``` + +#### 9.5 数据库维护 + +```bash +# 初始化表结构(首次部署) +cd backend && node scripts/init-database.js + +# 写入示例数据 +cd backend && npm run seed +``` + +--- + +### 10. 常见问题与排查 + +#### 10.1 访问与登录 + +| 现象 | 可能原因 | 处理 | +|------|----------|------| +| 前端打不开 | 端口被占用或服务未启动 | `docker compose ps` 或检查 12000/3000 端口 | +| 登录 401 | 账号密码错误或 Token 过期 | 重新登录;检查 `JWT_SECRET` 是否变更 | +| 登录后立刻退出 | 空闲超时 | 系统设置中调整 `idle_timeout` | +| 维护模式无法登录 | 非管理员账号 | 使用管理员登录,或在数据库关闭 `maintenance_mode` | + +#### 10.2 Docker 部署 + +| 现象 | 可能原因 | 处理 | +|------|----------|------| +| backend 启动失败 | MySQL 未就绪或 `JWT_SECRET` 未设 | 等待 MySQL;设置 `JWT_SECRET` 后重启 | +| 502 / API 无响应 | 后端容器异常 | `docker logs idc_assest-backend` | +| 中文乱码 | MySQL 字符集 | 确保库为 `utf8mb4` | + +#### 10.3 本地开发 + +| 现象 | 可能原因 | 处理 | +|------|----------|------| +| 端口 8000/3000 冲突 | 其他进程占用 | 修改 `backend/.env` 的 `PORT` 或 `FRONTEND_PORT` | +| 前端 API 失败 | 代理未生效 | 确认 Vite 将 `/api` 代理到 `http://localhost:8000` | +| 数据库连接失败 | MySQL 未启动或密码错误 | 检查 `DB_TYPE` 与 MySQL 连接参数 | + +#### 10.4 业务功能 + +| 现象 | 可能原因 | 处理 | +|------|----------|------| +| U 位冲突 | 同一机柜 U 位已被占用 | 调整设备起始 U 位或高度 | +| 3D 页面空白 | 浏览器不支持 WebGL | 更换浏览器或更新显卡驱动 | +| 上传失败 | 文件超过大小限制 | 默认最大 30 MB(`MAX_FILE_SIZE_MB`) | +| 无示例数据 | 未执行种子脚本 | `docker exec idc_assest-backend node scripts/seed-example-data.js` | + +--- + +### 11. 附录 + +#### 11.1 环境变量速查(后端 `backend/.env`) + +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `PORT` | `8000` | 后端监听端口 | +| `NODE_ENV` | `development` | 运行环境 | +| `DB_TYPE` | `sqlite` | `sqlite` 或 `mysql` | +| `DB_PATH` | `./idc_management.db` | SQLite 文件路径 | +| `MYSQL_HOST` | `localhost` | MySQL 主机(Docker 内为 `mysql`) | +| `MYSQL_PORT` | `3306` | MySQL 端口 | +| `MYSQL_DATABASE` | `idc_management` | 数据库名 | +| `MYSQL_USERNAME` | `root` | 数据库用户 | +| `MYSQL_PASSWORD` | (空) | 数据库密码 | +| `JWT_SECRET` | 开发自动生成 | **生产必填** | +| `TOKEN_EXPIRY` | `24h` | Token 有效期 | +| `LOG_LEVEL` | `debug` | 日志级别 | +| `MAX_FILE_SIZE_MB` | `30` | 上传大小上限 | +| `FRONTEND_PORT` | `3000` | 本地前端端口提示 | + +完整列表见 `backend/.env.example`。 + +#### 11.2 服务端口对照 + +| 场景 | 前端 | 后端 | MySQL | +|------|------|------|-------| +| Docker 全栈(`docker-compose.full.yml`) | 12000 | 12001 | 12006 | +| Docker 生产镜像(`docker-compose.prod.yml`) | 80 | 内部网络 | 可选 | +| 本地开发 | 3000 | 8000 | 3306 | + +#### + +#### 11.3 相关链接 + +| 资源 | 地址 | +|------|------| +| API 详细文档 | [docs/api/README.md](docs/api/README.md) | +| Docker 部署补充 | [docs/docker-deployment-guide.md](docs/docker-deployment-guide.md) | +| 用户指南(历史) | [docs/USER_GUIDE.md](docs/USER_GUIDE.md) | + +--- ## 贡献指南 -欢迎提交 Issue 或 Pull Request! +欢迎提交 Issue 或 Pull Request。 ```bash -# 1. Fork 本项目 - -# 2. 克隆你的 Fork -git clone https://github.com/YOUR_USERNAME/idc_assest.git -cd idc_assest - -# 3. 创建分支 -git checkout -b feature/your-feature # 功能开发 -git checkout -b fix/your-fix # Bug 修复 - -# 4. 开发并提交 +git checkout -b feature/your-feature git commit -m 'feat: 添加新功能' -git commit -m 'fix: 修复问题' - -# 5. 推送并创建 PR git push origin feature/your-feature ``` -**提交信息规范**: +| 提交类型 | 说明 | +|----------|------| +| `feat` | 新功能 | +| `fix` | Bug 修复 | +| `docs` | 文档更新 | +| `refactor` | 重构 | +| `chore` | 构建/工具 | -| 类型 | 说明 | -| -------- | ------ | -| feat | 新功能 | -| fix | Bug 修复 | -| docs | 文档更新 | -| style | 代码格式 | -| refactor | 重构 | -| perf | 性能优化 | -| test | 测试 | -| chore | 构建/工具 | +开发规范:后端 CommonJS + Sequelize;前端 ESM + React Hooks;提交前运行 `npm run lint`(backend / frontend)。 -**开发规范**: - -- 使用 ES6+ 语法 -- 遵循 React Hooks 规范 -- 使用 async/await 处理异步 -- 遵循 ESLint + Prettier 代码规范 - -*** +--- ## 许可证 -本项目基于 **MIT 许可证**开源。 +本项目基于 [MIT 许可证](LICENSE) 开源。 -*** - -**⭐ 如果这个项目对您有帮助,请给我们一个 Star!** - -- Gitee Issues: -- GitHub Issues: -- QQ 群:1081123775 +--- +**IDC 设备资产管理开源社区** +文档版本:2.1.1 | 2026-06-22 diff --git a/backend/Dockerfile b/backend/Dockerfile index d561b6a..63c0e31 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -19,7 +19,7 @@ COPY package.json ./ COPY package-lock.json* yarn.lock* ./ # 安装生产依赖(不安装 devDependencies) -RUN npm install --omit=dev --ignore-scripts +RUN npm install --omit=dev # 复制后端代码 COPY . . diff --git a/backend/package.json b/backend/package.json index d6a8a40..d9697e5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,7 +15,8 @@ "test": "jest --runInBand", "test:watch": "jest --watch", "test:coverage": "jest --coverage", - "test:operation-logs": "jest tests/operationLog.model.test.js tests/operationLogger.test.js tests/operationLogs.api.test.js --runInBand" + "test:operation-logs": "jest tests/operationLog.model.test.js tests/operationLogger.test.js tests/operationLogs.api.test.js --runInBand", + "seed": "node scripts/seed-example-data.js" }, "dependencies": { "all": "^0.0.0", diff --git a/backend/scripts/seed-example-data.js b/backend/scripts/seed-example-data.js index 6ddbcf0..c08bd85 100644 --- a/backend/scripts/seed-example-data.js +++ b/backend/scripts/seed-example-data.js @@ -1,62 +1,386 @@ /** * 示例数据种子脚本 - * 为云睿资产管理系统添加初始示例数据 + * 为 IDC 设备资产管理系统写入演示数据(幂等,可重复执行) + * + * 本地:node scripts/seed-example-data.js + * Docker:docker exec idc_assest-backend node scripts/seed-example-data.js */ require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') }); +const bcrypt = require('bcryptjs'); const { sequelize } = require('../db'); const Room = require('../models/Room'); const Rack = require('../models/Rack'); +const Device = require('../models/Device'); const Business = require('../models/Business'); +const DeviceBusiness = require('../models/DeviceBusiness'); +const Warehouse = require('../models/Warehouse'); +const User = require('../models/User'); const Role = require('../models/Role'); -const { generateId } = require('../utils/idGenerator'); +const UserRole = require('../models/UserRole'); +const ConsumableCategory = require('../models/ConsumableCategory'); +const Consumable = require('../models/Consumable'); +const Ticket = require('../models/Ticket'); + +const SEED_MARKER_ROOM = '北京通州一号机房'; +const DEMO_ADMIN = { username: 'admin', password: 'admin123', realName: '系统管理员', email: 'admin@example.com' }; + +const DEFAULT_ROLES = [ + { + roleId: 'role_admin', + roleName: '管理员', + roleCode: 'admin', + description: '系统管理员,拥有所有权限', + permissions: ['*'], + status: 'active', + sort: 1, + }, + { + roleId: 'role_operator', + roleName: '运维人员', + roleCode: 'operator', + description: '负责日常运维操作', + permissions: ['devices:read', 'devices:write', 'racks:read', 'rooms:read', 'consumables:read', 'consumables:write'], + status: 'active', + sort: 2, + }, + { + roleId: 'role_viewer', + roleName: '只读用户', + roleCode: 'viewer', + description: '仅能查看数据', + permissions: ['devices:read', 'racks:read', 'rooms:read', 'consumables:read'], + status: 'active', + sort: 3, + }, +]; + +async function upsertRole(roleData) { + const [role] = await Role.findOrCreate({ where: { roleCode: roleData.roleCode }, defaults: roleData }); + if (role.roleId !== roleData.roleId) { + await role.update(roleData); + } + return role; +} + +async function ensureAdminUser() { + for (const roleData of DEFAULT_ROLES) { + await upsertRole(roleData); + } + + const adminRole = await Role.findOne({ where: { roleCode: 'admin' } }); + const hashedPassword = await bcrypt.hash(DEMO_ADMIN.password, 10); + + const [admin] = await User.findOrCreate({ + where: { username: DEMO_ADMIN.username }, + defaults: { + password: hashedPassword, + email: DEMO_ADMIN.email, + realName: DEMO_ADMIN.realName, + status: 'active', + }, + }); + + const existingLink = await UserRole.findOne({ where: { UserId: admin.userId, RoleId: adminRole.roleId } }); + if (!existingLink) { + await UserRole.create({ UserId: admin.userId, RoleId: adminRole.roleId }); + } + + return admin; +} async function seedData() { try { - console.log('开始同步数据库结构...'); + console.log('连接数据库...'); + await sequelize.authenticate(); await sequelize.sync(); - console.log('数据库结构同步成功'); - // 1. 创建示例机房 - console.log('正在创建示例机房...'); - const room = await Room.create({ - name: '北京通州一号机房', - location: '北京市通州区马驹桥', - area: 500, - capacity: 100, - description: '公司核心数据中心,具备双路供电及精密空调系统。' + const marker = await Room.findOne({ where: { name: SEED_MARKER_ROOM } }); + if (marker && process.env.SEED_FORCE !== '1') { + console.log(`示例数据已存在(机房: ${SEED_MARKER_ROOM}),跳过写入。`); + console.log('如需强制重新写入,请设置环境变量 SEED_FORCE=1'); + const admin = await ensureAdminUser(); + console.log(`演示账号: ${DEMO_ADMIN.username} / ${DEMO_ADMIN.password} (${admin.userId})`); + process.exit(0); + } + + console.log('开始写入示例数据...\n'); + + const admin = await ensureAdminUser(); + console.log(`✓ 角色与管理员账号 (${DEMO_ADMIN.username} / ${DEMO_ADMIN.password})`); + + const [room1] = await Room.findOrCreate({ + where: { name: SEED_MARKER_ROOM }, + defaults: { + location: '北京市通州区马驹桥', + area: 500, + capacity: 100, + status: 'active', + description: '公司核心数据中心,具备双路供电及精密空调系统。', + gridRows: 8, + gridCols: 12, + }, }); - console.log(`已创建机房: ${room.name} (${room.roomId})`); - // 2. 创建示例业务 - console.log('正在创建示例业务...'); - const biz = await Business.create({ - businessId: 'BIZ001', - name: '云端计算核心', - description: '负责核心云端计算资源的分配与管理。', - contact: '王经理', - phone: '13800000000' + const [room2] = await Room.findOrCreate({ + where: { name: '上海浦东二号机房' }, + defaults: { + location: '上海市浦东新区张江高科', + area: 320, + capacity: 60, + status: 'active', + description: '华东区域灾备机房,承载核心业务冗余部署。', + gridRows: 6, + gridCols: 10, + }, }); - console.log(`已创建业务: ${biz.name}`); + console.log(`✓ 机房: ${room1.name}, ${room2.name}`); - // 3. 创建示例机柜 - console.log('正在创建示例机柜...'); - const rack = await Rack.create({ - rackId: 'RACK001', - name: 'A-01', - roomId: room.roomId, - uCount: 42, - maxPower: 8000, - status: 'active', - description: '标准 42U 机柜,位于 A 排 01 位。' + const rackDefs = [ + { rackId: 'RCK_SEED_A01', name: 'A-01', roomId: room1.roomId, height: 42, maxPower: 8000, rowPos: 1, colPos: 1 }, + { rackId: 'RCK_SEED_A02', name: 'A-02', roomId: room1.roomId, height: 42, maxPower: 8000, rowPos: 1, colPos: 2 }, + { rackId: 'RCK_SEED_B01', name: 'B-01', roomId: room1.roomId, height: 42, maxPower: 6000, rowPos: 2, colPos: 1 }, + { rackId: 'RCK_SEED_C01', name: 'C-01', roomId: room2.roomId, height: 42, maxPower: 8000, rowPos: 1, colPos: 1 }, + ]; + + const racks = {}; + for (const def of rackDefs) { + const [rack] = await Rack.findOrCreate({ where: { rackId: def.rackId }, defaults: def }); + racks[def.name] = rack; + } + console.log(`✓ 机柜: ${rackDefs.map(r => r.name).join(', ')}`); + + const businessDefs = [ + { businessId: 'BIZ_SEED_001', name: '云端计算核心', description: '负责核心云端计算资源的分配与管理。' }, + { businessId: 'BIZ_SEED_002', name: '企业办公平台', description: 'OA、邮件、协作等企业内部应用。' }, + { businessId: 'BIZ_SEED_003', name: '数据分析服务', description: '大数据分析与报表平台。' }, + ]; + const businesses = {}; + for (const def of businessDefs) { + const [biz] = await Business.findOrCreate({ where: { businessId: def.businessId }, defaults: def }); + businesses[def.businessId] = biz; + } + console.log(`✓ 业务: ${businessDefs.map(b => b.name).join(', ')}`); + + const [warehouse] = await Warehouse.findOrCreate({ + where: { name: '通州备件库房' }, + defaults: { + location: '北京通州一号机房 B 区', + capacity: 200, + status: 'active', + description: '存放待上架及退役备件设备。', + }, }); - console.log(`已创建机柜: ${rack.name}`); + console.log(`✓ 库房: ${warehouse.name}`); - console.log('\n示例数据加载成功!'); + const deviceDefs = [ + { + deviceId: 'DEV_SEED_001', + name: 'Web-01', + type: 'server', + model: 'Dell PowerEdge R750', + serialNumber: 'SN-DELL-R750-001', + rackId: racks['A-01'].rackId, + position: 1, + height: 2, + powerConsumption: 450, + status: 'online', + ipAddress: '10.10.1.101', + description: '核心 Web 应用服务器', + businessId: 'BIZ_SEED_001', + }, + { + deviceId: 'DEV_SEED_002', + name: 'DB-01', + type: 'server', + model: 'Dell PowerEdge R750', + serialNumber: 'SN-DELL-R750-002', + rackId: racks['A-01'].rackId, + position: 3, + height: 2, + powerConsumption: 520, + status: 'online', + ipAddress: '10.10.1.102', + description: 'MySQL 主库', + businessId: 'BIZ_SEED_001', + }, + { + deviceId: 'DEV_SEED_003', + name: 'SW-Core-01', + type: 'switch', + model: 'Huawei CE6857', + serialNumber: 'SN-HW-CE6857-001', + rackId: racks['A-01'].rackId, + position: 40, + height: 1, + powerConsumption: 180, + status: 'online', + ipAddress: '10.10.0.1', + description: '核心交换机', + businessId: 'BIZ_SEED_001', + }, + { + deviceId: 'DEV_SEED_004', + name: 'OA-App-01', + type: 'server', + model: 'Lenovo SR650', + serialNumber: 'SN-LENOVO-SR650-001', + rackId: racks['A-02'].rackId, + position: 5, + height: 2, + powerConsumption: 380, + status: 'online', + ipAddress: '10.20.1.50', + description: 'OA 应用服务器', + businessId: 'BIZ_SEED_002', + }, + { + deviceId: 'DEV_SEED_005', + name: 'BI-Node-01', + type: 'server', + model: 'HPE ProLiant DL380', + serialNumber: 'SN-HPE-DL380-001', + rackId: racks['B-01'].rackId, + position: 10, + height: 2, + powerConsumption: 490, + status: 'maintenance', + ipAddress: '10.30.1.10', + description: '数据分析计算节点', + businessId: 'BIZ_SEED_003', + }, + { + deviceId: 'DEV_SEED_006', + name: 'DR-Storage-01', + type: 'storage', + model: 'NetApp FAS2750', + serialNumber: 'SN-NETAPP-FAS2750-001', + rackId: racks['C-01'].rackId, + position: 20, + height: 4, + powerConsumption: 600, + status: 'online', + ipAddress: '10.40.1.20', + description: '灾备存储阵列', + businessId: 'BIZ_SEED_001', + }, + { + deviceId: 'DEV_SEED_007', + name: 'Spare-R750', + type: 'server', + model: 'Dell PowerEdge R750', + serialNumber: 'SN-DELL-R750-SPARE', + warehouseId: warehouse.warehouseId, + sourceType: 'warehouse', + height: 2, + powerConsumption: 0, + status: 'offline', + description: '待上架备用服务器', + }, + ]; + + const devices = {}; + for (const def of deviceDefs) { + const { businessId, ...deviceData } = def; + const [device] = await Device.findOrCreate({ where: { deviceId: def.deviceId }, defaults: deviceData }); + devices[def.deviceId] = device; + + if (businessId) { + await DeviceBusiness.findOrCreate({ + where: { deviceId: def.deviceId, businessId }, + defaults: { isPrimary: true }, + }); + } + } + console.log(`✓ 设备: ${deviceDefs.length} 台(含 1 台库房备件)`); + + const consumableCategories = [ + { name: '线缆', description: '网络与电源线缆', sortOrder: 1 }, + { name: '光模块', description: 'SFP/SFP+/QSFP 光模块', sortOrder: 2 }, + { name: '硬盘', description: '企业级硬盘与 SSD', sortOrder: 3 }, + ]; + for (const cat of consumableCategories) { + await ConsumableCategory.findOrCreate({ where: { name: cat.name }, defaults: cat }); + } + + const consumableDefs = [ + { consumableId: 'CON_SEED_001', name: '六类网线 3m', category: '线缆', unit: '根', currentStock: 120, minStock: 20, unitPrice: 15.0, location: '通州备件库房 A 架' }, + { consumableId: 'CON_SEED_002', name: 'SFP+ 10G 光模块', category: '光模块', unit: '个', currentStock: 32, minStock: 10, unitPrice: 280.0, location: '通州备件库房 B 架' }, + { consumableId: 'CON_SEED_003', name: '1.92TB SSD', category: '硬盘', unit: '块', currentStock: 8, minStock: 5, unitPrice: 1800.0, location: '通州备件库房 C 架' }, + ]; + for (const def of consumableDefs) { + await Consumable.findOrCreate({ where: { consumableId: def.consumableId }, defaults: def }); + } + console.log(`✓ 耗材: ${consumableDefs.length} 种`); + + const ticketDefs = [ + { + ticketId: 'TKT_SEED_001', + title: 'DB-01 磁盘 IO 延迟偏高', + deviceId: 'DEV_SEED_002', + deviceName: 'DB-01', + deviceModel: 'Dell PowerEdge R750', + serialNumber: 'SN-DELL-R750-002', + faultCategory: '性能问题', + priority: 'high', + status: 'in_progress', + description: '数据库主库磁盘 IO 等待时间持续超过 50ms,需排查存储性能。', + reporterId: admin.userId, + reporterName: admin.realName, + assigneeId: admin.userId, + assigneeName: admin.realName, + location: '北京通州一号机房 / A-01', + }, + { + ticketId: 'TKT_SEED_002', + title: 'BI-Node-01 计划维护', + deviceId: 'DEV_SEED_005', + deviceName: 'BI-Node-01', + deviceModel: 'HPE ProLiant DL380', + serialNumber: 'SN-HPE-DL380-001', + faultCategory: '例行维护', + priority: 'low', + status: 'pending', + description: '月度固件升级与内存巡检。', + reporterId: admin.userId, + reporterName: admin.realName, + location: '北京通州一号机房 / B-01', + }, + { + ticketId: 'TKT_SEED_003', + title: '核心交换机端口异常', + deviceId: 'DEV_SEED_003', + deviceName: 'SW-Core-01', + deviceModel: 'Huawei CE6857', + serialNumber: 'SN-HW-CE6857-001', + faultCategory: '网络故障', + priority: 'critical', + status: 'completed', + description: 'Gi0/0/24 端口频繁 flapping,已更换光模块。', + reporterId: admin.userId, + reporterName: admin.realName, + assigneeId: admin.userId, + assigneeName: admin.realName, + location: '北京通州一号机房 / A-01', + resolution: '更换 SFP+ 光模块后端口恢复正常。', + completionDate: new Date(), + }, + ]; + for (const def of ticketDefs) { + await Ticket.findOrCreate({ where: { ticketId: def.ticketId }, defaults: def }); + } + console.log(`✓ 工单: ${ticketDefs.length} 条`); + + console.log('\n示例数据写入完成!'); + console.log('────────────────────────────────────'); + console.log(`登录账号: ${DEMO_ADMIN.username}`); + console.log(`登录密码: ${DEMO_ADMIN.password}`); + console.log(`前端地址: http://localhost:${process.env.FRONTEND_PORT || 12000}`); + console.log('────────────────────────────────────'); process.exit(0); } catch (error) { - console.error('示例数据加载失败:', error); + console.error('示例数据写入失败:', error); process.exit(1); } } diff --git a/backend/utils/logger.js b/backend/utils/logger.js index 26ea7de..74ba8eb 100644 --- a/backend/utils/logger.js +++ b/backend/utils/logger.js @@ -168,10 +168,10 @@ const logger = createLogger({ ], }); -if (process.env.NODE_ENV !== 'production') { +if (process.env.NODE_ENV !== 'production' || process.env.CONSOLE_LOG === 'true') { logger.add(new transports.Console({ - format: consoleFormat, - level: 'debug', + format: process.env.NODE_ENV === 'production' ? jsonFormat : consoleFormat, + level: LOG_LEVEL, })); } diff --git a/docker-compose.full.yml b/docker-compose.full.yml index bb6451c..b851132 100644 --- a/docker-compose.full.yml +++ b/docker-compose.full.yml @@ -28,8 +28,14 @@ services: environment: - NODE_ENV=production - PORT=8000 - - DB_TYPE=sqlite - # 如果切换到 MySQL,请修改 DB_TYPE=mysql 并配置 MYSQL_HOST=mysql + - DB_TYPE=mysql + - MYSQL_HOST=mysql + - MYSQL_PORT=3306 + - MYSQL_DATABASE=${MYSQL_DATABASE:-idc_management} + - MYSQL_USERNAME=root + - MYSQL_PASSWORD=${MYSQL_ROOT_PASSWORD:-xinmi_password} + - JWT_SECRET=${JWT_SECRET} + - CONSOLE_LOG=true ports: - "${BACKEND_PORT:-12001}:8000" depends_on: diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4799d93..b54f6fc 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -37,6 +37,7 @@ import { CloudUploadOutlined, LayoutOutlined, LinkOutlined, + InfoCircleOutlined, } from '@ant-design/icons'; import { BrowserRouter as Router, @@ -86,6 +87,7 @@ const OperationLogs = lazy(() => import('./pages/OperationLogs')); const ErrorBoundaryTest = lazy(() => import('./pages/ErrorBoundaryTest')); const IdleDeviceManagement = lazy(() => import('./pages/IdleDeviceManagement')); const RoomFloorPlan = lazy(() => import('./pages/RoomFloorPlan')); +const About = lazy(() => import('./pages/About')); const { Header, Content, Sider } = Layout; @@ -493,7 +495,7 @@ const AppLayout = ({ children }) => { {!collapsed && (
{ type="primary" block icon={} - href="http://code.xinmi.cloud/" + href="http://www.xinmi.cloud/" target="_blank" > 访问新觅源码库 diff --git a/images/image-20260623102522626.png b/images/image-20260623102522626.png new file mode 100644 index 0000000..83bb2e2 Binary files /dev/null and b/images/image-20260623102522626.png differ diff --git a/images/image-20260623102535356.png b/images/image-20260623102535356.png new file mode 100644 index 0000000..b251a06 Binary files /dev/null and b/images/image-20260623102535356.png differ diff --git a/images/image-20260623102540102.png b/images/image-20260623102540102.png new file mode 100644 index 0000000..b251a06 Binary files /dev/null and b/images/image-20260623102540102.png differ diff --git a/images/image-20260623102549318.png b/images/image-20260623102549318.png new file mode 100644 index 0000000..8927046 Binary files /dev/null and b/images/image-20260623102549318.png differ diff --git a/images/image-20260623102557409.png b/images/image-20260623102557409.png new file mode 100644 index 0000000..712bd20 Binary files /dev/null and b/images/image-20260623102557409.png differ diff --git a/images/image-20260623102610309.png b/images/image-20260623102610309.png new file mode 100644 index 0000000..5f30162 Binary files /dev/null and b/images/image-20260623102610309.png differ diff --git a/images/image-20260623102620982.png b/images/image-20260623102620982.png new file mode 100644 index 0000000..e4abd61 Binary files /dev/null and b/images/image-20260623102620982.png differ diff --git a/images/image-20260623102633865.png b/images/image-20260623102633865.png new file mode 100644 index 0000000..3e39a1e Binary files /dev/null and b/images/image-20260623102633865.png differ