
接钢厂信息化项目前这套vuenodejsElementUi的生产系统设计思路你最好先看一遍前两年接了一个钢铁企业的生产管理系统开发需求技术栈定的是vue nodejs ElementUi业务覆盖生产计划、工单流转、质检判定、库存跟踪和报表看板。钢铁生产系统的难点不在技术本身而在业务流程的梳理一条产线从原料进厂到成品入库中间要经过炼钢、连铸、轧钢等多个工序节点每个节点都有数据回传和质量判定系统必须把这些环节串起来还要让车间操作工、质检员、生产调度、管理层各取所需。这篇文章就把这套系统的设计与实现过程完整拆一遍从技术选型、数据库设计、前后端实现到部署上线过程中踩过的坑都整理出来。如果你正在做类似的工业管理系统或者是刚接触 vue nodejs 全栈开发想找一个完整项目练手这篇文章可以直接作为参考。1. 技术选型与整体架构设计1.1 为什么是vue nodejs ElementUi这套组合做个工业管理系统技术栈的选择往往不是追求最新最炫而是综合考虑团队熟悉度、交付周期、后期维护成本。这套系统最终选型 vue nodejs ElementUi有几层考虑。前端用 Vue是因为这类系统的页面以表格、表单、弹窗、数据看板为主Vue 的响应式机制和组件化开发模式非常适合这种业务形态。ElementUi 则解决了 UI 组件的问题表格、分页、日期选择器、弹窗、表单校验这些都是现成的不用从零手写开发效率提升非常明显。后端用 Node.js主要是看中前后端语言统一。整个团队都是 JavaScript 技术栈前端同学可以无缝切换到后端写接口不需要额外维护 Java 或 C# 的技术线。对于钢铁生产系统这种内部管理系统来说Node.js 的异步 I/O 能力处理常规的业务接口绰绰有余配合 Express 框架路由组织和中间件机制都很清晰。有人可能会质疑钢铁企业对系统稳定性要求高Node.js 能不能扛住我负责任地说这种生产管理系统的并发量并不高核心场景是车间工位的操作员录入数据同时在线人数通常一两百人以内Node.js 完全能够胜任。真正要花心思的是业务逻辑的严谨性和数据的准确性而不是高并发架构。1.2 系统整体架构与模块划分整个系统采用前后端分离架构前端独立部署通过 HTTP 接口与后端服务通信。前后端分离的好处是车间大屏展示和办公区 PC 端可以复用同一套后端接口后期如果要出移动端也方便扩展。前端部分使用 Vue 全家桶Vue Router 负责页面路由Vuex 管理全局状态Axios 统一处理 HTTP 请求。ElementUi 提供基础 UI 组件。项目结构按照业务模块划分目录视图组件放在 views 下公共组件放在 components 下接口请求统一放在 api 目录中。后端部分使用 Express 搭建 RESTful API 服务按业务模块拆分配置路由使用 MySQL 存储业务数据通过 mysql2 连接池操作数据库。接口进行统一响应格式封装使用 JWT 做身份认证符合生产环境的基本要求。系统功能模块划分如下系统管理用户管理、角色管理、菜单权限配置基础数据物料档案、产线信息、设备台账、工序参数标准生产计划月度/周度计划录入、计划下达、计划变更生产工单工单生成、工序流转、完工汇报质量管理取样登记、检验数据录入、合格判定、不合格处理库存管理原料库存、半成品库存、成品库存、出入库记录报表看板生产日报、质量统计、计划完成率、产量趋势图2. 核心业务模块拆解与数据库设计2.1 钢铁生产核心业务流程梳理钢铁生产的工艺路线大致是这样的高炉炼铁产出铁水铁水经过转炉或电炉炼钢然后进入连铸工序浇铸成方坯或板坯最后通过轧钢工序轧制成不同规格的钢材产品。这个流程对应到系统里核心是两条线一条是计划线从销售订单或经营计划推导出生产计划再拆解成工单下发给各产线另一条是实绩线产线完成生产后在系统里填报完工数据质检环节录入检验结果系统根据检验结果判定合格与否合格的进入库存不合格的走评审或回炉流程。钢铁生产系统最核心的设计理念就是“计划-执行-反馈”的闭环。我在设计数据表时始终围绕这个闭环来建模每一张业务表都要能找到它对应的上下游单据。比如生产计划表下发的计划必须能够在工单表里看到拆解结果工单表的完成状态又必须关联到工序记录表和质检表中。2.2 关键数据表结构设计数据库设计的合理性直接决定系统开发的顺畅程度。我按照业务模块设计了以下核心数据表这里挑几张最有代表性的重点说明。第一张是生产工单表prod_work_order这是整个系统的中枢表。工单来源于生产计划的拆解承载着具体的生产批次信息。字段名类型说明idbigint主键order_novarchar工单编号唯一plan_idbigint关联生产计划IDproduct_codevarchar产品编码product_namevarchar产品名称specificationvarchar规格型号order_qtydecimal计划数量吨finished_qtydecimal完工数量吨product_line_idbigint产线IDstatustinyint状态1待生产 2生产中 3已完工 4已取消assign_uservarchar下达人assign_timedatetime下达时间finish_timedatetime完工时间remarkvarchar备注第二张是工序流转记录表prod_process_record记录工单在每个工序节点的报工情况。钢铁生产是多工序连续作业工序记录表设计的好坏直接影响生产过程的可追溯性。字段名类型说明idbigint主键work_order_idbigint关联工单IDprocess_codevarchar工序编码process_namevarchar工序名称input_qtydecimal投入数量output_qtydecimal产出数量scrap_qtydecimal废品数量report_uservarchar报工人report_timedatetime报工时间shiftvarchar班次remarkvarchar备注第三张是质检记录表qual_inspection保存每个工单批次的质量检验数据。钢铁产品的质检项一般包括化学成分、力学性能、表面质量等。字段名类型说明idbigint主键work_order_idbigint关联工单IDinspect_typevarchar检验类型入厂检/过程检/成品检inspect_itemvarchar检验项目inspect_valuevarchar检验结果值standard_valuevarchar标准值resulttinyint判定结果1合格 2不合格inspect_uservarchar检验员inspect_timedatetime检验时间handle_methodvarchar不合格处理方式数据库设计时要注意几个细节。金额和数量字段用 decimal 而不是 float避免精度丢失。状态字段用 tinyint 存数字码值配合字典表翻译成文字不要直接存中文否则后面改状态名称非常痛苦。所有表都加上 create_time 和 update_time 字段排查数据问题时能用作时间线依据。2.3 权限模型设计思路钢铁企业的组织架构和人员分工比较明确系统用户主要分为四类车间操作工、质检员、生产调度员、管理人员。他们的职责边界清晰因此权限模型采用 RBAC基于角色的访问控制即可。sys_user 用户表存账号密码和基本信息sys_role 角色表定义不同角色sys_user_role 关联用户和角色sys_menu 菜单表维护系统功能菜单和按钮权限码sys_role_menu 关联角色与菜单。前端的权限控制通过路由守卫实现登录时后端返回该用户拥有的菜单列表和按钮权限码前端动态生成可访问的路由表。按钮级别的控制比如只有质检员能看到“检验数据录入”按钮通过自定义指令 v-permission 判断权限码来控制。3. 前端实现要点与ElementUi实战3.1 前端工程搭建与环境配置前端项目我们用的是 Vue CLI 创建的 Vue 2 项目这里说明一下ElementUi 是配合 Vue 2 使用的如果你用的是 Vue 3那要对应 Element Plus两者 API 有些差异实际开发时别搞混了。Node.js 环境安装这里有个高频问题很多人在 Windows 上第一次运行 npm 命令会看到类似 “npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本” 的报错。这是因为 PowerShell 默认执行策略限制导致的解决办法有几种# 以管理员身份打开 PowerShell然后执行 Set-ExecutionPolicy RemoteSigned也可以直接在 cmd 或 Git Bash 里运行 npm 命令绕开 PowerShell 的执行策略限制。还有种懒人办法是查看当前策略状态用 Get-ExecutionPolicy 看输出如果是 Restricted改成 RemoteSigned 即可。创建项目的标准流程vue create steel-manage-system-frontend # 选择 Vue 2 预设手动选择 Router、Vuex cd steel-manage-system-frontend npm install element-ui --save npm install axios --save npm install sass sass-loader --save-dev项目目录结构建议这样规划src/ api/ # 接口请求定义 assets/ # 静态资源 components/ # 公共组件 directives/ # 自定义指令 router/ # 路由配置 store/ # 状态管理 styles/ # 全局样式 utils/ # 工具函数 views/ # 页面组件 system/ # 系统管理模块 plan/ # 生产计划模块 workorder/ # 生产工单模块 quality/ # 质量管理模块 inventory/ # 库存管理模块 report/ # 报表看板模块3.2 Axios请求封装与接口调用Axios 请求封装是前端开发的重要一环。直接在每个页面里写 this.$http.get(...) 会让代码非常散乱接口地址、错误处理、鉴权头到处重复。我做了一个统一的 request.js 工具模块。核心要点是请求拦截器和响应拦截器。请求拦截器里从 localStorage 取 token设置到请求头 Authorization 字段响应拦截器里统一处理 HTTP 状态码和业务状态码遇到 401 时清除登录状态并跳转登录页遇到业务错误就弹出 Message 提示。import axios from axios import { Message } from element-ui import router from /router const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }, error { return Promise.reject(error) }) service.interceptors.response.use(response { const res response.data if (res.code ! 200) { Message.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { if (error.response error.response.status 401) { Message.error(登录已过期请重新登录) router.push(/login) } else { Message.error(网络异常请稍后重试) } return Promise.reject(error) }) export default service登录流程是这样的用户输入账号密码前端调用登录接口后端校验通过后返回 token 和用户信息。前端把 token 存到 localStorage用户信息存入 Vuex。路由守卫里判断如果没有 token 就跳转登录页有 token 但本地没有用户信息就调 getUserInfo 接口拉取。3.3 ElementUi组件实战与应用技巧这套系统里用到的 ElementUi 组件非常集中Table 表格、Form 表单、Dialog 弹窗、Select 选择器、DatePicker 日期选择器、Pagination 分页、Tabs 选项卡。分享几个在实际使用中踩过的坑和技巧。第一个是表格固定列的透明问题。ElementUi 的 el-table 设置 fixed 属性将某些列固定在左侧或右侧滚动时可以发现固定列的内容有时候会变透明看起来像是渲染错乱。排查发现这是因为 el-table 为了让固定列覆盖在普通列上面给固定列设置了相对较高的 z-index但如果表格嵌套在滚动容器或者 Dialog 弹窗中多个层叠上下文叠加会导致样式异常表现为固定列背景色透明露底。解决办法是在全局样式中给固定列显式设置背景色并提升层级.el-table__fixed-right::before, .el-table__fixed::before { background-color: #fff; opacity: 1; } .el-table th.el-table__cell, .el-table td.el-table__cell { background-color: #fff; }第二种常见需求是单元格文字超出隐藏鼠标悬浮显示完整内容。ElementUi 的 el-table-column 自带 show-overflow-tooltip 属性设置后文字超出会自动省略悬浮时用 tooltip 展示完整内容。el-table-column propproductName label产品名称 width180 show-overflow-tooltip /el-table-column这个属性在 IE 浏览器下有些兼容性问题如果公司内部还在用老浏览器最好全局禁用改用 Tooltip 组件包裹的方式。第三种是 Dialog 弹窗配合 PDF 预览这个场景在质量部门很常见要查看某个批次的检验报告 PDF。可以直接用 iframe 嵌入 PDF 文件路径。不过如果 PDF 文件在服务器上需要鉴权后才能访问iframe 的 src 会带着浏览器默认请求不带自定义请求头这就得换方案。一个可行的方案是前端用 axios 以 blob 方式请求 PDF 文件拿到数据后通过 URL.createObjectURL 生成本地地址再传给 iframe 的 src。这样既解决了鉴权问题又不会暴露真实的文件地址。viewReport(row) { this.$http.get(/api/quality/report/ row.id, { responseType: blob }) .then(res { const blob new Blob([res.data], { type: application/pdf }) this.pdfUrl URL.createObjectURL(blob) this.dialogVisible true }) }第四种是视频监控流的接入。车间现场会有摄像头管理层希望在大屏上直接看到现场画面很多摄像头输出的是 m3u8 格式的 HLS 流。浏览器原生不支持播放 m3u8我用的 video.js 插件方案。npm install video.js然后在需要播放监控画面的页面引入并初始化。要注意的是video.js 播放 hls 流内部依赖 hls.js需要在相关配置中启用对应技术能力实际部署时使用 http-flv 格式比 m3u8 延迟更小如果摄像头支持同时输出多路协议优先用 http-flv在 web 端配合 flv.js 播放器延迟控制在 1-3 秒这个体验会好得多。3.4 大屏看板与报表实现报表看板模块是整个系统里最有“存在感”的页面管理层打开系统首先看的是这个页面。我用的是 ECharts 做图表展示配合 ElementUi 的 Card 组件和 el-row/el-col 栅格布局搭建看板页面。看板页面常见的图表包括最近 30 天产量趋势折线图、各产线计划完成率柱状图、产线班组产量排行、产品质量合格率饼图。ECharts 的引入方式按需加载避免整包引入导致页面加载慢。import * as echarts from echarts/core import { LineChart, BarChart, PieChart } from echarts/charts import { GridComponent, TooltipComponent, LegendComponent } from echarts/components import { CanvasRenderer } from echarts/renderers echarts.use([LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer])图表组件封装成公共组件通过 props 传入配置项组件内部负责实例化和 resize 处理。看板数据通过定时器每 5 分钟轮询一次后端接口前端不需要做复杂的实时推送。在页面销毁时记得移除定时器否则路由切换后定时器还在请求很容易造成页面卡死或内存泄漏。4. 后端接口设计与Node.js实现4.1 Express项目结构与中间件配置后端项目我用 Express 搭建目录结构按业务模块划分结构清晰很重要不然写到最后自己都找不到文件在哪儿。server/ app.js # 入口文件 config/ db.js # 数据库配置 jwt.js # JWT配置 routes/ user.routes.js # 用户模块路由 plan.routes.js # 计划模块路由 workorder.routes.js quality.routes.js inventory.routes.js report.routes.js controllers/ user.controller.js plan.controller.js workorder.controller.js services/ user.service.js workorder.service.js middlewares/ auth.js # 鉴权中间件 errorHandler.js # 全局异常处理 utils/ response.js # 统一响应封装 db.js # 数据库连接池很多 Node.js 初学者会犯一个错误就是把所有业务逻辑全写在路由回调里一个接口几百行代码。这样做刚开始很爽后面维护起来是灾难。我习惯把处理流程分成三层routes 只做路由映射controllers 负责参数校验和调用 services 层services 层专注操作数据库和业务逻辑。这样做的好处是当接口报错时能够快速定位是哪一层的问题如果后续要引入单元测试services 层的函数是纯逻辑比较容易测试。数据库连接用 mysql2 的 Promise 连接池配置放在 config/db.js。连接池的作用是避免频繁创建和销毁数据库连接浪费资源。const mysql require(mysql2/promise) const pool mysql.createPool({ host: process.env.DB_HOST || localhost, user: process.env.DB_USER || root, password: process.env.DB_PASSWORD || 123456, database: process.env.DB_NAME || steel_manage, waitForConnections: true, connectionLimit: 10, queueLimit: 0, charset: utf8mb4 }) module.exports pool要特别强调一点生产环境配置信息绝对不能硬编码在代码里应该通过环境变量或者配置文件管理。至少要做到 .env 文件与代码分离并且把 .env 文件加入 .gitignore防止数据库账号密码被提交到代码仓库。4.2 JWT身份认证与权限校验接口安全是工业系统不能忽视的环节。农机系统内部用的 JWT 方案流程是用户登录成功后后端签发一个 token 返回给前端前端在后续每个请求的请求头带上 token后端中间件校验 token 合法性。token 签发使用 jsonwebtoken 库密钥和过期时间从环境变量读取。const jwt require(jsonwebtoken) function generateToken(user) { return jwt.sign( { userId: user.id, username: user.username, roleId: user.roleId }, process.env.JWT_SECRET, { expiresIn: 12h } ) }鉴权中间件在需要登录态的接口上挂载解析 token 后把用户信息挂到 req 对象上后续接口可以直接拿到当前操作人信息。const auth async (req, res, next) { const token req.headers.authorization?.replace(Bearer , ) if (!token) { return res.status(401).json({ code: 401, message: 未登录 }) } try { const decoded jwt.verify(token, process.env.JWT_SECRET) req.user decoded next() } catch (err) { return res.status(401).json({ code: 401, message: token 无效或已过期 }) } }角色的权限校验在工单管理、质检判定这类接口上要用到。比如说生产工单的作废操作只有生产调度员有权限普通操作工不能随意作废工单。做法是在需要权限控制的接口单独添加一个 requireRole 中间件在路由配置时叠加使用。4.3 生产工单流转的接口设计生产工单接口是整个系统最复杂的部分我重点讲一条工单从创建到关闭的完整接口链路。POST /api/workorder 创建工单生产调度员选择生产计划、填写产品信息和计划数量后端校验计划是否存在、计划是否已下发然后生成工单编号并写入 prod_work_order 表。工单编号的生成规则做成流水号格式WO 日期 三位序列号比如 WO20250612001。PUT /api/workorder/:id/start 工单开工确认操作工接到工单后在系统点击开工将工单状态置为生产中同时记录开工时间。POST /api/workorder/:id/process 工序报工工单每完成一道工序操作工填报该工序的投入数量、产出数量、废品数量、班次等信息写入 prod_process_record 表。后端接口要做数据校验累计完工数量不能超过计划数量废品数量加合格数量不能超过投入数量。POST /api/workorder/:id/finish 工单完工所有工序报工完成后工单置为已完工更新完成时间和完工数量。此时系统自动触发库存更新逻辑把完工的成品种入库存表。这个链路设计完成后生产调度员在系统里可以实时看到每个工单流转到哪个工序了哪个产线的在制品数量最多计划完成度如何。4.4 服务端常见业务处理技巧后端开发中有些业务逻辑需要仔细设计这里分享几个具体的实现方案。第一个是做物料编码自动生成。钢铁企业的物料种类非常多包括原料、辅料、半成品、成品每种物料的编码规则不一样。我在基础数据模块里维护了编码规则表存储每种物料类型的编码前缀和流水号起始值。生成编码时先从规则表取出当前流水号拼接前缀后返回同时把流水号加一并更新回规则表。这里要注意并发问题使用 UPDATE 语句配合乐观锁来保证流水号不重复。第二个是报表模块的日期聚合统计。接口经常会返回按天、按周、按月统计的产量和合格率数据。SQL 里用 DATE_FORMAT 函数对时间字段做格式化再配合 GROUP BY 分组。MySQL 的日期函数在报表场景很好用前端只需要把后端返回的数据直接塞到 ECharts 配置里不需要复杂的二次处理。第三个是文件上传与预览。质检报告、设备点检表这类附件我用的方案是上传到服务器指定磁盘目录数据库记录文件相对路径预览时通过静态文件服务访问。不要直接把文件存到数据库的 BLOB 字段数据库会迅速膨胀备份和迁移都会变得很慢。5. 常见问题与排查技巧实录5.1 环境配置高频问题汇总开发过程中环境配置问题花的时间往往比写代码还多。我把遇到的高频问题和解决方案整理成一个速查表方便直接对照排查。问题现象原因分析解决办法npm.ps1 无法加载禁止运行脚本PowerShell执行策略限制管理员身份运行 Set-ExecutionPolicy RemoteSigned或用 cmd运行安装 Node.js 报错 2203安装包权限不足或注册表被占用用管理员权限运行安装程序关闭杀毒软件后重试npm install 速度很慢默认源在国外设置镜像源 npm config set registry https://registry.npmmirror.comvue 项目启动后端口被占用端口冲突修改 vue.config.js 的 devServer.port 或命令行参数 --portnpm 安装依赖时版本冲突依赖版本不兼容删除 node_modules 和 package-lock.json重新 install镜像源设置那个建议一上来就配好否则装依赖的耐心都会被耗尽。我在公司局域网环境下npm install 常常要等十几分钟换镜像源后基本一两分钟就完成了。5.2 Vue打包部署后的布局异常这里要专门说说 Vue 项目打包上线后的布局异常问题本地开发环境一切正常npm run build 后部署到服务器发现页面白屏或者样式错乱。最常见的原因有两个。第一个是打包路径配置不对vue.config.js 里的 publicPath 默认为 /如果部署在服务器子目录下js/css 资源引用路径会找不到。解决办法是把 publicPath 改为相对路径 ./或者在部署时把前端文件放在服务器根目录。第二个是路由模式问题Vue Router 默认是 hash 模式URL 里会有 # 号如果改为 history 模式直接访问某个路由地址时服务器没有配置 fallback就会返回 404。我的建议是内部管理系统直接用 hash 模式最省心不用牵扯到服务器配置。历史记录的问题通过路由的 scrollBehavior 来处理即可完全可以满足内部系统对 URL 的要求。另外还有一个容易被忽略的细节页面布局异常不是指只 CSS 问题检查一下线上环境的浏览器版本。ElementUi 对某些老浏览器的样式兼容性有问题项目做需求评审时最好明确要求使用 Chrome 内核浏览器。5.3 项目上线的几点经验系统开发完成后部署上线当时走了不少弯路把这几点经验写出来能帮你省掉不少事。部署方式我最终选择用 Nginx 同时托管前端静态文件并反向代理后端接口。前端打包后的 dist 目录拷贝到服务器的 /var/www/steel-manage 目录Nginx 里配置 location / 指向这个目录location /api 则代理到 Node.js 服务地址。上线前必须做数据备份演练先把数据库备份脚本写好并实际跑一次恢复流程确认可以恢复后再动生产环境。钢铁企业的数据非常敏感特别是质检数据和库存数据一旦丢失几乎不可挽回。还有一点是日志记录。上线初期我会把每个接口请求的耗时和错误信息记录到日志文件通过日志分析可以提前预判系统瓶颈。app.use((req, res, next) { const start Date.now() res.on(finish, () { const duration Date.now() - start console.log(${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms) }) next() })这样一些慢接口会很快浮出水面比如某个报表查询超过 3 秒通过日志看到耗时消耗在网络还是 SQL 查询可以有针对性地优化数据库索引或调整前端查询条件。系统上线后车间操作人员用得最多的功能其实就是那几个看当天工单、报工、查库存。之前我花了很多精力做复杂的图表联动展示结果领导看了觉得很好但一线操作工根本不打开那个页面。真正的价值在于把工单流转和库存数据弄准确、把报表查询做快生产调度用得顺手系统才算真正落地。如果后续要继续扩展可以往设备数据采集方向走通过工业网关把设备状态实时接入系统在现有页面上增加设备运行状态展示和报警功能。技术上还是基于现在的 vue nodejs 架构只需要增加数据采集服务和消息推送通道这也是目前钢铁企业数字化转型比较迫切的需求。我个人的建议是第一版先把业务闭环走通技术框架预留好扩展接口等业务跑顺了再逐步加功能这样风险最小。