五金车间最像打仗的地方不是生产线而是计划员那张桌子。我刚做完的这套基于 node.js 和 vue 的五金工厂车间生产计划管理系统想解决的正是这个问题把销售订单变成可执行的车间计划再把计划和执行之间的信息差抹平。做之前我以为最难的是排产算法做之后才发现最难的是让计划员、车间主任和工人对同一组数据有一个统一的认识。这篇文章我会从业务背景、技术选型、模块设计、数据库与后端细节、前端落地再到上线踩坑完整复盘一遍适合正在考虑自研或选型工厂管理系统的团队参考。1. 五金车间的排产痛点Excel、ERP 之间的那块空地1.1 五金车间生产管理的业务特征五金工厂和电子厂、汽配厂的管理重点差别很大。五金件常见的工艺是冲压、拉伸、机加工、抛光、电镀或者氧化工序数量不多但它是典型的多品种、小批量、插单频繁的业态。一个车间里同时可能有几十个在制订单每一张订单又可能拆成三五个规格每个规格对应一套模具或者一个加工程序。这种业态下真正难管的地方反而不是工艺而是“什么时候开哪台机、用哪套模具、做多少个、做完给谁”。冲压车间换一次模可能需要半小时如果排程不合理一天的有效产出直接打六折。机加工车间则要错开不同订单对同一台设备的争抢但交期晚一天客户就催。我接触过不少五金厂计划员手上同时维护三样东西一张 Excel 总排程表、一块写在白板上的插单信息、以及手机里各种微信群里的临时通知。Excel 表本身没有约束力插单一进来整张表就要重新拖一遍白板上的内容没人归档到了月底就说不清上个月到底做过什么。1.2 现有工具的断层Excel 灵活但不可控ERP 重但适配差不是所有人都在用 ERP用 ERP 的五金厂也未必用好。Excel 的优势是灵活任何规则都能硬排进去但它的劣势同样致命交期撞车它不报警库存不足它不提示两个计划员各排各的版本也没有冲突检测最后装进车间主任脑子里的排程永远和 Excel 里那个版本对不上。ERP 是另一种极端。它适合业务规范、流程固定的大型厂能管到采购、财务、成本、MRP 这些环节。但中小五金厂的流程往往没有那么标准很多物料连编码都没统一。上 ERP 意味着车间每个动作要被录进系统操作繁琐、界面复杂、权限死板工人一抗拒系统里的数据很快就失真了。中间其实有一块空地一个只负责“订单 → 计划 → 工单 → 报工 → 看板”的管理系统比 Excel 多约束、多实时性比 ERP 轻量、贴近车间真实习惯。这套 node.js vue 的系统定位就在这个位置不碰财务和总账把车间计划这条主线的信息同步问题解决掉。1.3 写代码前最重要的一件事先把数据理清楚很多人拿到这个需求第一反应是建表写接口但实操中第一个拦住项目的往往是基础数据。物料编码有没有统一BOM 是不是最新版工艺路线里的工时是拍脑袋还是实测过我开始时吃过这个亏。厂里仓库管料叫“黄铜套”工艺那边叫“HPb59-1 毛坯”采购单上又是另一个名称一套系统里三种叫法等于没上系统。后来项目组做的第一件事是把所有常用物料和产品编码重新编了一遍编好规则再导入系统主数据。如果你也要做类似系统我的建议是先花一到两周梳理物料编码、BOM、工序和设备的清单再动技术框架。数据是排程的地基地基歪了后面所有报表都是数字游戏。2. 为什么这个系统押注 Node.js Vue一次完整的技术选型复盘2.1 前后端同构对中小项目团队的意义技术选型那天会议室里其实吵过一轮。有人提议 Spring Boot Vue理由是 Java 稳定、招人容易也有人想用 Python Vue图开发快。最后定的还是 Node.js Vue这是基于团队规模和使用场景综合考量后的结果。最直接的收益是前后端同构。项目组就三四个人前端用 Vue后端用 Node.js两边都是 JavaScript/TypeScript一个全栈工程师就能独立把一个模块从接口写到页面。Java 项目常见的前端工程师看不懂后端、后端工程师不愿意碰前端的隔阂在这个项目里少了很多。加上 Vue 的生态确实适合做管理后台。Element Plus 组件库把表格、表单、弹窗、标签页这些高频元素都封装好了开发效率比从零写快非常多。这类车间管理系统本质上是大量 CRUD 和状态流转的组合Vue 的响应式数据模型和组件复用能力正好踩在这个需求点上。2.2 Node.js 的非阻塞模型恰好匹配车间高频小请求车间上报进度的场景很特殊数量大、单次请求小、频率高。一台设备每完成一批就要点一次“完工”或者用扫码枪扫一次工单号设备一多服务器面对的是每秒几十上百个轻量请求每个请求业务逻辑不重但并发量不小。Node.js 基于事件循环和非阻塞 I/O对这种 I/O 密集的小请求处理起来很顺手单进程能扛住比传统同步模型高很多的并发连接。再加上 Socket.io 做 WebSocket 推送看板数据可以直接从服务端推到车间大屏不需要轮询实时性也更有保障。要注意的是这不代表 Node.js 万能。如果系统里涉及大量复杂的报表聚合计算、多表关联的复杂事务Node.js 写起来会比 Spring Boot 更费劲。所以在架构上我把重统计接口都放到独立服务里配合 Redis 缓存主业务接口保持轻量。2.3 和 Spring Boot、Python 方案的真实对比不少同行问为什么不直接用 Spring Boot。能用而且很多工厂项目确实这么选。但如果你的团队本来就不是 Java 背景为了一个小系统专门去搭一套 Java 技术栈Maven、JVM 调优、类库版本冲突这些维护成本会很快吞掉开发效率。Spring Boot 的强项是大团队、长周期、重事务我们的场景显得杀鸡用牛刀。Python Django 也评估过。开发原型确实快管理后台能现成生成但实时推送和并发处理没有 Node.js 顺手而且一门后端语言和前端割裂小团队维护起来两头都要管。我把三套方案的差异整理成了表格方便大家在类似项目里做判断。技术栈优势在这个场景下的劣势Spring Boot Vue事务成熟、大团队规范、资料丰富部署重、开发节奏慢、团队要求高Python Vue原型快、后端起手容易实时推送一般、前后端异构Node.js Vue同构、轻量、并发好、部署简单复杂事务要小心、生态偏前端这个项目最终选择 Node.js Vue不是因为它比其他方案高级而是它和最真实的资源情况匹配团队小、周期紧、并发特点明显、部署环境只有一台服务器。2.4 环境搭建时容易被忽略的版本细节Node.js 版本建议直接选 LTS。项目里用的是 18.20.4生产环境不要追最新版等一个版本在社区里沉淀半年以上再上能少踩很多坑。Vue 这边用的是 Vue 3 Vite Element Plus开发依赖用 pnpm 管理依赖比 npm 更快也更省磁盘空间。开发环境搭建的完整动作大概是这样的# 安装 nvm用它管理 Node 版本 nvm install 18.20.4 nvm use 18.20.4 node -v # 创建 Vue 项目 npm create vuelatest npm install npm run dev这里有个容易踩的小细节Vue 3 的响应式包装和 Vue 2 差别很大如果团队之前熟的是 Vue 2 选项式 API接手 Vue 3 组合式 API 需要一点适应期。后面讲到前端组件时我会再展开。3. 业务模块拆解计划、工单、物料、看板是如何串成一条闭环的3.1 主数据物料编码、BOM 与工艺路线系统里的主数据是后面所有模块的地基。我拆成三张核心表来聊产品表存产品编码、名称、图号、规格、版本号。五金件经常会改图纸产品版本不管理好工单下发后车间做的可能还是老版本这个问题我在项目里见过不止一次。所以每个产品必须带版本号工单生成时把产品版本快照到工单上避免后续改版把历史工单也改了。物料清单也就是 BOM记录每个产品需要哪些原材料、标准件数量是多少。注意五金件会有边角料和损耗率我在 BOM 里专门加了一个 plan_loss_rate 字段冲压的首件调试废料就通过这个字段消化而不是让工人把损耗记到成品头上。工艺路线是每类产品经过的工序集合包括工序号、工序名、使用设备类型、标准工时、每小时产出等。排程能排多细完全取决于工艺路线维护到什么程度。至少要维护到“工序级”不然甘特图只能排到订单排不到设备。3.2 计划生成逻辑净需求计算和合并规则计划员从销售订单勾选一批订单点击“生成计划”系统自动算出净需求。公式不复杂但每项含义要跟业务确认清楚净需求 订单数量 - 可用库存 - 在制订单对应数量 - 已下达工单未完工数量这里“在制订单对应数量”是指已经进入生产但还没完工入库的数量如果漏算计划员会把已经生产的量再排一遍造成重复生产。算出净需求后系统按交期和客户优先级排序。排列组合这里有个优化点尽量把批量小、同材质同规格的产品合并成一张工单。五金车间最大的浪费在换模一张工单做 50 件和做 500 件准备时间可能差不多所以排程时优先合并相同产品编号、相近交期的需求减少模具切换次数。3.3 排程与工单下发从计划到可执行的过程计划生成后进入排程界面我用的是前端甘特图组件。横轴是设备或者产线纵轴是时间工单就是一个方块计划员可以拖动调整开工时间。系统排程时会自动检查设备占用冲突时间重叠了会标红提示。排程完成后计划员选中工单点击“下发”。这一步我特意做成了有条件的操作系统先跑一次物料齐套检查缺料的工单不能下发。这个约束在纸质时代是计划员凭记忆做的系统化之后变成了硬规则实际运行中帮业务方挡住了很多次缺料开工导致停工等待的问题。工单核心字段包括工单号、产品、数量、计划开始时间、计划结束时间、使用的工序路线、优先级、状态。工单号我用的是独立生成的业务编号比如 WO 年月日 流水号而不是数据库自增 ID这个习惯后面帮了大忙打印条码、跨部门沟通时都能一眼识别。3.4 物料需求计算与领料退料工单下发后系统根据 BOM 自动展开物料需求工单数量乘以 BOM 里每个物料的单件用量再乘上计划损耗率得到物料需求量。和库存实时比对生成缺料清单。五金厂的领料比电子厂粗放经常是车间一次性领一批材料放到工位月底再退。所以这里我没有按“领料单严格倒冲”的精细模型而是采用“大领大退”模式车间可以批量开领料单完工后退回余料系统记录一个物料批次去向做到批次可追溯即可。对五金车间来说追溯粒度控制在“工单 物料批次”级别就够用了太细反而增加工人操作负担系统会被抵制。3.5 车间报工与进度看板的实时刷新报工是整个系统使用频率最高的功能工人扫工单条码后进入报工页输入本次完工数量和不良数量点击提交。系统累加到工单的 completed_quantity 和 defective_quantity 上同时计算剩余量。每次报工数据变化后服务端通过 WebSocket 把工单进度和设备状态推到车间看板。看板大屏只显示三块内容今天的计划任务列表、每张工单的进度条、以及设备状态运行中/空闲/故障。不要放太多花哨图表车间里真正有用的就是这几项。4. 后端与数据库的严谨性设计生产数据不能靠“感觉”4.1 核心表结构设计与字段注意事项数据库用的是 MySQL 8.0字符集 utf8mb4。核心表我列一下表名用途关键字段products产品主数据id, product_code(唯一索引), name, drawing_no, version, unitbom_items物料清单id, product_id, material_id, qty, plan_loss_rate, is_key_materialprocess_routes工艺路线id, product_id, seq_no, process_name, device_type_id, standard_hour, output_per_hourwork_orders工单id, work_order_no(唯一索引), product_id, qty, completed_qty, defective_qty, status, versionwork_order_logs报工日志id, work_order_id, user_id, report_qty, defective_qty, created_atmaterials物料id, material_code(唯一索引), name, spec, safe_stock, stock_qtyinventory_transactions库存流水id, material_id, work_order_id, type(in/out), qty, created_atusers用户id, username, password_hash, role两个字段设计的细节值得说。第一所有业务编号如 work_order_no、product_code、material_code 都要建唯一索引业务操作按编号查找不要按自增主键找。第二hard-delete 禁止全部逻辑删除生产中一张工单报错了要能追溯物理删数据在工厂系统里是禁忌。4.2 后端分层与参数校验后端我用的 Express路由层只做参数接收和校验业务逻辑放到 service 层数据库访问放到 dal 层。别把业务逻辑堆在路由回调里后面改起来会非常痛苦。参数校验用 Joi每个接口定义 schema。比如报工接口的校验const reportSchema Joi.object({ quantity: Joi.number().integer().min(1).required(), defectiveQty: Joi.number().integer().min(0).max(Joi.ref(quantity)).default(0), });这里有个容易忽略的点defectiveQty 不应该超过本次报工数量 quantity如果不校验一次手误就能把不良率刷成 200%。机器校验看起来只是一个小约束但实际维护数据质量最有效的就是这类小约束。4.3 乐观锁解决报工冲突车间报工最典型的并发问题是两三个人同时给同一张工单报工。比如 A 工人扫了工单号输入 50 件B 工人也同时报 30 件如果代码只是先查后改再写回最后数据库里 completed_qty 可能只是最后一次写入的数值而不是 80 件。解决方案是用乐观锁。给 work_orders 表加一个 version 字段每次更新都带版本号UPDATE work_orders SET completed_qty completed_qty 50, version version 1 WHERE id 123 AND version 5;如果影响行数是 0说明版本过期接口直接返回“页面数据已变更请刷新后重试”。车间环境里这种提示比后台去悄悄合并数据更可靠因为工人能立刻发现别人也在报工避免漏报。4.4 权限模型与登录会话工厂系统权限不用做得很复杂角色就四种管理员、计划员、车间主任、工人。工人登录后只能看到自己工序的工单和报工入口计划员能看全部计划和工单管理员管基础数据和用户配置。密码用 bcrypt 加盐哈希保存绝对不能存明文。前端用 Vue Router 路由守卫做页面级权限判断后端每个接口再用中间件做角色拦截两层一起缺一不可。登录态我用的是 JWT但会在第 6 节专门说它的坑。5. 前端页面怎么做到让车间工人愿意用5.1 页面结构与组件划分前端项目按菜单拆模块计划管理、工单管理、物料管理、进度看板、基础数据、系统设置。计划管理页面是计划员每天打开的第一个页面。左侧列出未排程订单中间是甘特图排程区域右侧显示设备占用情况。这个页面我拆成三个组件PlanGantt.vue 负责甘特图渲染OrderListPanel.vue 负责待排订单列表DeviceTimeline.vue 负责设备时间轴。工单管理页面是车间主任的主战场列表用卡片而不是表格因为卡片可以放大显示工单号、产品、数量、状态一眼扫过去就能找到自己要跟的工单。卡片组件是 WorkOrderCard.vue状态变化后用动画高亮提示避免车间主任翻半天看不到新增工单。5.2 车间平板端的大字体交互系统要给车间配平板或者工控机交互设计和办公室完全不一样。工人戴着手套、车间光线差、站着操作按钮必须够大文字不能太小。报工页面我把设计模式定为“信息最小化”屏幕上只显示当前工单的产品、规格、计划数量、已完成数量下面三个大按钮“完工 N 件”“不良 N 件”“结束”。数量输入我用的是数字键盘弹层不用原生软键盘因为原生的键盘在平板上会把页面顶上去体验很差。而且尽量减少点击次数能扫码就扫码产品编码和工单号都不允许手动输入防止输错一个字符找半天。5.3 看板可视化不是炫技是直观车间看板用的是 ECharts但真正生效的不是图表样式而是指标选择。我只保留三个维度计划完成率、设备利用率、不良率趋势。计划完成率用仪表盘和进度条展示设备利用率用堆叠柱状图按设备分组不良率趋势用折线图看最近 14 天走向。看板的数据通过 Socket.io 推送服务端在每次报工事件后广播最新数据前端订阅后更新对应组件。这个链路不复杂但要注意做好断线重连车间网络有时候不稳定WebSocket 掉了要自动重连并拉取一次全量数据兜底。5.4 移动端和外部系统衔接车间里还有一类操作需要移动端比如仓库盘点、车间主任现场巡检。我在架构里预留了一个 H5 的轻量入口同一个 Vue 项目里通过路由区分手机扫码打开后进入移动布局。另外实际情况里很多工厂已经在用企业微信沟通可以和现有企业微信账号体系打通做完单点登录后工人不需要记住密码直接在企业微信里打开应用就能看到自己名下待办工单。项目里也把关键事件比如缺料提醒、工单下发通知通过企业微信消息推给相关人员实测下来比短信通知成本低而且触达率高。腾讯地图这类能力在配送场景更常用这里用不上就不过度设计了。6. 上线落地阶段最扎心的那些坑6.1 服务器 Node.js 版本和系统库不匹配项目上线时遇到最无语的一个问题是 Linux 服务器上 Node.js 直接启动失败。本地开发用的 Node 18 好好的但服务器是 CentOS 7.9系统 glibc 版本偏旧Node.js 18 的官方二进制需要较新的 GLIBC结果一启动就报错。解法是用 nvm 安装与系统匹配的版本同时确认系统的运行库ldd --version nvm install 18.20.4 nvm use 18.20.4后来我学到的教训是生产环境的 Node.js 版本必须在项目文档里固定并且用 .nvmrc 或 volta 锁版本。团队里任何一个人本地升大版本都可能出现“本地正常、服务器跑不了”的诡异问题。6.2 前后端分离的跨域和 Nginx 配置开发环境用 Vite 的 proxy 解决跨域简单省事// vite.config.js server: { proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } }生产环境我直接用 Nginx 反向代理让前端页面和后端接口看起来同源不要去用 CORS 做一堆白名单配置同源之后 cookie 和 JWT 的处理都干净很多。location /api/ { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }这里有个细节WebSocket 也要走同一个 Nginx必须单独配置 Upgrade 和 Connection 头否则看板推送在生产环境会失效。6.3 JWT 过期与车间工人的“长期在线”需求JWT 最大的坑是过期问题。车间工人早上登录一次经常挂着到下班如果 token 只有两小时有效期下午就突然没法报工了。又不能让他反复输入密码工人在机台旁边停下来找管理员重置密码是灾难。我的做法是双 token 方案短期 access token 两小时过期长期 refresh token 七天有效。axios 响应拦截器里判断 401自动用 refresh token 换新 token对工人完全无感。service.interceptors.response.use( res res, async (error) { const original error.config; if (error.response?.status 401 !original._retry) { original._retry true; await refreshToken(); return service(original); } return Promise.reject(error); } );这个方案要考虑多标签页同时抢刷新令牌的问题我当时做了一个简单的并发锁确保多个请求同时 401 时只发一次刷新请求避免 token 被反复刷新导致后续全部失效。6.4 扫码枪输入法干扰与批量报工扫码枪本质上就是键盘扫出来的字符串以键盘事件形式输入最后再补一个回车。问题在于部分国产输入法在中文状态下会拦截扫码内容本来应该扫出“WO20240515001”结果变成一段乱码进到输入框。解决办法是使用全局监听 keypress 事件拼接缓冲区不走输入框的普通 keydown 路径let buffer ; let lastTime Date.now(); window.addEventListener(keypress, (e) { buffer e.key; if (Date.now() - lastTime 100) buffer ; lastTime Date.now(); if (e.key Enter) { handleScan(buffer.trim()); buffer ; e.preventDefault(); } });注意加一个时间判断防止工人手工敲键盘也被误判成扫码。扫码设备录入的连续按键间隔通常小于 30ms手工输入很难做到那么快时间阈值可以调。最后还有一个容易被忽略的问题同一张工单多人同时扫码报工。所以我在报工接口上做了防重复提交同一个工单同一个用户 5 秒内重复提交会被忽略前端也会弹个小提示告诉工人“刚才已经提交过了”。如果让我重新做一遍这个系统我会先做“计划 - 工单 - 报工 - 看板”这条主线跑顺了再往两边加物料、设备和成本。给车间主任留一个 Excel 导出功能特别重要它不是妥协而是它给不愿意马上切换到系统的人一个缓冲通道等数据准确到大家开始依赖看板了Excel 导出自然就没那么多人用了。业务编号规则也要提前设计好别用自增 ID 做单号这个决策越早做后面打印条码、跨部门沟通、排查问题的时候就越省心。
阅读完成 · 觉得有帮助?