
拿到“node.js基于vue的五金工厂车间生产计划管理系统”这个题目时我第一反应是这不就是典型的制造业MES轻量化项目么。很多朋友做这类系统容易一头扎进代码里把精力全耗在搞华丽的前端组件上最后交付的却只是一个能增删改查的架子根本没法在车间里用。今天这篇文章我就以自己实际搭建这套系统的过程为例把从技术选型、数据库设计、后端接口、前端页面再到生产排程逻辑和排坑经验完整讲一遍。如果你正准备做Node.jsVue方向的项目或者需要快速落地一个车间管理应用这篇内容会给你一条很实在的路线。1. 先别急着写代码把业务边界理清楚1.1 五金工厂车间到底需要管理什么五金工厂的生产模式和流水线大厂不太一样往往是多品种、小批量、订单交期紧车间里同时跑着好几张工单。生产计划管理系统的核心不是简简单单记录“今天要做哪个产品”而是要把销售订单拆解成可执行的生产计划再进一步拆成不同工序的工单下发到班组让工人按工单报工管理人员能实时看到进度和异常。具体来说这套系统至少要覆盖以下几条链路生产计划制定根据订单交期、产品优先级制定月度或周生产计划。计划拆单派工一个生产计划对应一个产品而产品有多道工序所以计划要分解成多个工序工单派给对应的车间班组。进度上报操作工完成一定数量后上报合格数和不合格数。进度汇总看板车间主任或生产经理能够实时看到每个计划、每道工序的完成率、合格率。统计报表月底结算时能按产品、按班组汇总产量和不良数。很多初次接触这个项目的同学容易把需求做散。比如非要加上采购管理、仓库出入库、设备维保结果越做越大最后哪块都没做好。我建议第一版就咬死“计划-工单-报工-看板”这条主线把闭环打通这才是车间真正会用起来的功能。从技术角度讲这套系统非常典型的场景是几十个用户在局域网内同时访问数据量不大但要保证事务一致业务逻辑要清晰可扩展。用Node.js做后端APIVue做前端界面刚好是性价比很高的组合。1.2 为什么这个场景适合Node.js Vue很多人会问为什么不用Spring Boot Vue确实Java技术栈很成熟但在这种中轻量级的车间管理项目里Node.js的优势非常明显。第一Node.js基于事件驱动和异步I/O对于高并发但轻计算的接口请求处理能力很强车间里频繁的报工、查询场景正好匹配第二前后端都用JavaScript数据格式天然一致沟通成本低第三生态丰富Express、Sequelize这些库都很成熟开发速度快。前端选Vue而不是React主要看中Vue对国内开发者更友好文档中文完善Element Plus组件库开箱即用。做管理后台时像表格、表单弹窗、状态标签这类功能用Element Plus可以省掉大量造轮子的时间。而且Vue 3的组合式API配合Vite开发体验很好修改代码后秒级热更新。这里补充一个个人经验如果项目要求高并发、大数据量的复杂报表Node.js不是最优解可以配合Redis和消息队列来增强。但像五金工厂车间这种每天几千条报工记录的场景用MySQL加上合理的索引和分页完全够用。别过度设计。1.3 工程初始化与目录规划我习惯把项目分成server和web两个目录做成前后端分离的monorepo结构避免相互干扰。实际初始化时可以这样操作# 创建项目根目录 mkdir hardware-factory-plan cd hardware-factory-plan # 后端目录 mkdir server cd server npm init -y # 安装后端依赖 npm install express sequelize mysql2 jsonwebtoken bcryptjs cors dotenv # 回到根目录创建前端 cd .. npm create vitelatest web -- --template vue cd web npm install npm install axios vue-router pinia element-plus后端依赖说明一下express最常用的Node.js Web框架路由中间件生态丰富。sequelizeORM工具操作MySQL很舒服可以避免手写大量SQL。mysql2MySQL官方驱动Sequelize需要用到它。jsonwebtoken bcryptjs做登录认证和密码加密。cors解决前后端跨域问题。dotenv管理环境变量不把数据库密码写死在代码里。前端依赖我没用vue-element-admin这类脚手架一是它太重二是自己搭起来结构更清楚。Vue Router做路由Pinia做状态管理Element Plus做组件这就够了。环境方面Node.js建议使用18以上LTS版本我这里用的是18.20.4。如果你电脑上没装去官网下载安装包安装时注意勾选“Add to PATH”装完在终端执行node -v验证如果提示“node不是内部或外部命令”基本就是环境变量没配好检查一下系统PATH里有没有Node.js安装目录。2. 数据库设计一张好表胜过十次接口联调2.1 核心表结构设计与解读生产计划管理系统的数据库设计要抓住几组关键实体用户、产品、生产计划、工单、工序、报工记录。我设计的是六张核心表字段和用途如下。用户表usersCREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, real_name VARCHAR(50) NOT NULL, role ENUM(admin,manager,leader,worker) NOT NULL DEFAULT worker, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );角色这里我分了四层admin系统管理员、manager生产经理、leader车间班组长、worker操作工。不同角色登录后能看到的菜单和能操作的功能不一样这是后面权限控制的依据。产品表products存放五金产品的物料编码和规格参数CREATE TABLE products ( id INT AUTO_INCREMENT PRIMARY KEY, product_code VARCHAR(50) NOT NULL UNIQUE, product_name VARCHAR(100) NOT NULL, spec VARCHAR(255), unit VARCHAR(10) DEFAULT 件, is_active TINYINT DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );生产计划表plans是系统的核心主表CREATE TABLE plans ( id INT AUTO_INCREMENT PRIMARY KEY, plan_no VARCHAR(50) NOT NULL UNIQUE, product_id INT NOT NULL, quantity INT NOT NULL, start_date DATE NOT NULL, end_date DATE NOT NULL, priority TINYINT DEFAULT 3 COMMENT 1紧急 2高 3普通 4低, status ENUM(draft,released,in_progress,completed,cancelled) DEFAULT draft, creator_id INT, progress DECIMAL(5,2) DEFAULT 0 COMMENT 计划完成百分比, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (product_id) REFERENCES products(id), FOREIGN KEY (creator_id) REFERENCES users(id) );这里的progress字段很关键它不靠手工填写而是由下游报工数据汇总回写。后面我会讲这个回写逻辑。工序表processes记录产品的加工工艺路线CREATE TABLE processes ( id INT AUTO_INCREMENT PRIMARY KEY, process_name VARCHAR(50) NOT NULL, sort_order INT NOT NULL COMMENT 工序顺序, standard_hours DECIMAL(8,2) COMMENT 单件标准工时小时, capacity_per_hour INT DEFAULT 0 COMMENT 每小时产能, is_active TINYINT DEFAULT 1 );比如一个五金冲压件可能是“下料 - 冲压 - 去毛刺 - 检验”四道工序每个工序有标准工时和每小时产能这些数据用于后面的排程预估。工单表work_orders承接计划和工序的关联CREATE TABLE work_orders ( id INT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(50) NOT NULL UNIQUE, plan_id INT NOT NULL, process_id INT NOT NULL, assigned_team VARCHAR(50) COMMENT 负责班组, quantity INT NOT NULL COMMENT 本工单计划数量, completed_qty INT DEFAULT 0 COMMENT 已完成数量, status ENUM(pending,in_progress,done,paused) DEFAULT pending, plan_start_time DATETIME, plan_end_time DATETIME, actual_end_time DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (plan_id) REFERENCES plans(id), FOREIGN KEY (process_id) REFERENCES processes(id) );报工记录表production_logs记录每次上报的合格数和不合格数CREATE TABLE production_logs ( id INT AUTO_INCREMENT PRIMARY KEY, work_order_id INT NOT NULL, user_id INT NOT NULL, report_time DATETIME DEFAULT CURRENT_TIMESTAMP, qualified_qty INT NOT NULL DEFAULT 0, defective_qty INT NOT NULL DEFAULT 0, remark VARCHAR(255), FOREIGN KEY (work_order_id) REFERENCES work_orders(id), FOREIGN KEY (user_id) REFERENCES users(id) );这套表结构看起来不多但已经能把生产计划管理的主线完整跑通。需要注意在生产场景里数量字段全部用INT不要用FLOAT避免浮点精度问题。日期字段要统一格式前端传过来的日期字符串在写入数据库前做好转换。2.2 状态流转与数据闭环设计好表之后最重要的一步是把状态机定下来。我的设计思路如下计划状态draft草稿→ released已下发→ in_progress生产中→ completed已完成→ cancelled已取消。工单状态pending待开工→ in_progress进行中→ done已完成中间可以暂停。报工逻辑操作工每完成一批就上报合格数和不合格数系统同时完成三件事在production_logs中插入一条报工记录更新work_orders.completed_qty根据该计划所有工单的完成总量计算并更新plans.progress。这个数据闭环特别重要。很多新手会把“计划进度”当成一个让用户手填的字段结果数据各种对不上。正确的做法是进度是从报工数据里实时算出来的不让用户碰这样才能保证月底报表是对的。举个例子一张计划数量是1000件产品有4道工序。系统在计划下发时会生成4张工单每张工单计划数量1000件。操作工先在第一道工序上报500件合格工单1的completed_qty变成500。此时因为后续工序还没报工计划总进度可以按“已完工工序数量/总工序数”粗略计算也可以按“最后一道工序完成数/计划数”计算。我更推荐按最后关键工序来算否则包装工序没完你中间工序做得再多也不能算整单完成。这里需要根据工厂实际口径调整关键是逻辑要能解释清楚。2.3 RESTful接口规划与权限设计数据库设计完后接口要提前规划。我按照资源来划分POST /api/auth/login登录。GET /api/auth/profile获取当前用户信息。GET/POST /api/plans分页查询计划、创建计划。GET/PUT/DELETE /api/plans/:id计划详情、更新、删除。POST /api/plans/:id/release下发计划同时生成工单。GET /api/work-orders?planIdxxx查询工单。POST /api/work-orders/:id/report工单报工。GET /api/dashboard/overview看板统计。GET /api/reports/monthly月度报表。权限设计上JWT令牌里面带上用户id和角色后端写两个中间件authMiddleware负责验证Token有效性roleGuard接受一个角色数组判断当前用户是否允许访问。比如创建计划的接口只允许admin和manager调用操作工只允许调用报工接口。前端的菜单也要根据角色动态渲染避免出现操作工看到“计划管理”入口的情况。3. 后端核心实现Express Sequelize从登录到计划下发3.1 数据库连接与模型定义Express项目的入口文件不带app.js我习惯用src/server.js结构更清晰。数据库连接这块用Sequelize的实例化方式// src/models/index.js const { Sequelize } require(sequelize); const sequelize new Sequelize( process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, { host: process.env.DB_HOST, dialect: mysql, logging: false, timezone: 08:00, define: { charset: utf8mb4, collate: utf8mb4_general_ci } } ); module.exports sequelize;.env文件里保存数据库连接信息DB_HOSTlocalhost DB_PORT3306 DB_NAMEfactory_plan DB_USERroot DB_PASSWORDyourpassword JWT_SECRETyour-secret-key PORT3000特别注意连接参数里要加上timezone: 08:00不然MySQL的DATETIME在Node里读取会差8个小时报工时间会显示成前一天。模型定义方面我用了Sequelize定义User、Plan、WorkOrder等模型并在模型之间建立关联关系。比如// src/models/plan.js const { DataTypes } require(sequelize); const sequelize require(./index); const Plan sequelize.define(Plan, { planNo: { type: DataTypes.STRING(50), field: plan_no, allowNull: false, unique: true }, productId: { type: DataTypes.INTEGER, field: product_id, allowNull: false }, quantity: { type: DataTypes.INTEGER, allowNull: false }, startDate: { type: DataTypes.DATEONLY, field: start_date, allowNull: false }, endDate: { type: DataTypes.DATEONLY, field: end_date, allowNull: false }, priority: { type: DataTypes.TINYINT, defaultValue: 3 }, status: { type: DataTypes.ENUM(draft, released, in_progress, completed, cancelled), defaultValue: draft }, progress: { type: DataTypes.DECIMAL(5, 2), defaultValue: 0 } }, { tableName: plans, timestamps: true, createdAt: created_at, updatedAt: updated_at }); module.exports Plan;数据库表可以先用Sequelize的sequelize.sync()自动建等上线后建议改用迁移工具因为sync在字段变更时不会自动加列容易出问题。3.2 登录认证与权限中间件登录接口的逻辑不复杂但要注意密码加密方式。我用的bcryptjs密码哈希存储绝不允许明文。登录时先根据用户名查用户再用bcrypt.compareSync比对哈希值。比对通过后签发JWT Tokenconst jwt require(jsonwebtoken); const token jwt.sign( { userId: user.id, username: user.username, role: user.role }, process.env.JWT_SECRET, { expiresIn: 8h } );中间件验证Token时从请求头Authorization: Bearer token取出Token通过jwt.verify解析出用户信息并挂载到req.user上。roleGuard就简单了判断req.user.role是否在允许列表内。这里有个小坑很多同学会把前端传过来的Token原封不动存到MySQL里或者每次都查库验证搞得很慢。正确做法是无状态JWT后端只要验签即可不需要查库。角色变更的情况在这个系统里很少发生8小时过期后重新登录就行。3.3 计划下发与工单生成的业务逻辑一个容易出错的地方是计划创建和计划下发。我把它分成两步先存草稿再一键下发。下发时后端要用事务来保证“更新计划状态 生成多张工单”要么全成功要么全失败不能出现计划状态变成了released但工单只生成了一半的情况。核心代码如下// src/services/planService.js const { sequelize, Plan, WorkOrder, Process } require(../models); async function releasePlan(planId) { return sequelize.transaction(async (transaction) { const plan await Plan.findByPk(planId, { transaction }); if (plan.status ! draft) { throw new Error(只有草稿状态的计划才能下发); } const processes await Process.findAll({ where: { is_active: true }, order: [[sort_order, ASC]], transaction }); if (processes.length 0) { throw new Error(该产品未配置工序路线); } for (const process of processes) { const orderNo ${plan.planNo}-${String(process.sort_order).padStart(2, 0)}; await WorkOrder.create({ orderNo, planId: plan.id, processId: process.id, assignedTeam: 班组${process.sort_order}, quantity: plan.quantity, status: pending }, { transaction }); } plan.status released; await plan.save({ transaction }); return { plan, workOrders: processes.length }; }); }这里的processes是从工序表统一取的实际业务中产品与工序应该是关联表我在第一版简化成全局工序。如果要做得更精细可以加一张product_processes关联表每个产品单独配置工艺路线。3.4 报工接口与进度回写报工是整个系统的核心动作。接口接收工单id、合格数、不合格数、备注。逻辑上四步校验工单存在且状态不是done。插入报工记录。累加工单completed_qty如果累加到大于等于工单数量工单状态置为done。汇总该计划下所有已完成工单的合格数除以计划数量得到计划进度更新plans表。这里要特别提醒一点报工数量不能为负数也不能让工单超量完成。如果工人报多了应该提示“超量报工需要管理员审批”。我第一版没做这个限制结果工单完成数量大于计划数量统计报表出现负数不良率排查了半天才发现是超量报工导致的。所以在后端用事务写入之前先查一下当前已报数量const currentReported await ProductionLog.sum(qualified_qty, { where: { workOrderId: workOrderId }, transaction }); if (currentReported qualifiedQty workOrder.quantity) { throw new Error(本次报工后累计合格数不能超过工单数量); }进度回写这里再说一个实用细节在MySQL里执行更新生产进度时用一条UPDATE配合子查询比在Node层做多次查询再计算更简洁。但考虑到事务和代码可读性我建议分成两步先算再写。只要确保在事务里执行就不会出现并发写脏数据的问题。4. 前端页面实现Vue 3 Element Plus做出真正能用的界面4.1 前端项目结构与基础配置Vite创建的项目默认结构比较简洁我在此基础上增加了一些目录src/api所有接口请求封装。src/router路由配置。src/storesPinia状态管理。src/views页面组件。src/components通用组件。main.js里做的事情包括创建app、注册router、pinia、element-plus并引入全局样式。import { createApp } from vue; import { createPinia } from pinia; import ElementPlus from element-plus; import element-plus/dist/index.css; import App from ./App.vue; import router from ./router; const app createApp(App); app.use(createPinia()); app.use(router); app.use(ElementPlus); app.mount(#app);Element Plus默认是按需自动导入的如果直接全量引入打包体积会大一些但对这种内部管理系统影响不大开发时省事很多。4.2 axios封装与登录状态持久化axios封装是前端基础我习惯在src/api/request.js里创建一个axios实例设置baseURL为/api并添加请求拦截器和响应拦截器import axios from axios; import { ElMessage } from element-plus; import router from ../router; const request axios.create({ baseURL: /api, timeout: 10000 }); request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }); request.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token); router.push(/login); } ElMessage.error(error.response?.data?.message || 请求失败); return Promise.reject(error); } ); export default request;有了这个拦截器所有接口都不用手动带Token了登录页保存Token后就能直接跳转到首页。Vite开发模式下跨域问题用server.proxy解决不需要后端开启CORS生产环境里如果前后端分开部署可以用Nginx把/api反向代理到后端服务。4.3 计划管理页面从表格到弹窗计划管理页面是整个后台使用频率最高的页面。我用Element Plus的el-table展示计划列表列包括计划编号、产品名称、数量、起止日期、优先级、状态、进度、操作。表格上方放搜索条件计划编号模糊查询、产品下拉选择、状态下拉选择、日期范围选择。新增计划用el-dialog嵌套el-form表单校验不能少计划数量必须是正整数结束日期不能早于开始日期。提交成功后刷新列表。下发计划按钮在操作列里点击后调POST /api/plans/:id/release成功后弹出提示“计划已下发已生成N张工单”同时刷新表格。这里的前端交互虽然简单但有一个体验细节下发操作可能会比较耗时比如生成了多张工单按钮上应该加上loading状态防止用户重复点击导致重复下发。4.4 车间看板与报工界面车间看板优先考虑大屏化放在产线旁边的电视上循环展示。我实现的看板包含三个核心块今日计划总量、已完成总量、当前完成率下方是各工单的进度条按完成率从低到高排序让车间主任一眼就能看到异常工单。看板数据实时性要求高我最初用了WebSocket推送但考虑到系统部署在局域网内用户量几十人WebSocket反而增加了维护成本就改成了前端每5秒钟轮询一次/api/dashboard/overview。如果未来要扩展到跨车间实时大屏再换成Socket.io也不迟。报工页面做成一个简洁的弹窗操作工输入工单号系统自动带出产品、工序、班组和计划数量然后输入合格数、不良数和备注点击提交。为了避免误操作提交成功后立即刷新看板数据并且清空表单。5. 生产排程的简单实现不用算法也能做出合理排产5.1 基于优先级和产能的启发式排程提到“排程”很多人以为要上APS算法。实际上五金车间这个规模用简单的启发式规则就够了。我的做法是在计划下发时给每张工单计算建议开始时间和结束时间规则是按计划优先级排序紧急插单的优先排。每张工单的计划开始时间不能早于当天。根据工序的每小时产能用“计划数量 / 每小时产能”得到预计加工小时数。按工艺路线顺序排后道工序的开始时间等于前道工序的结束时间加半天到一天的周转缓冲。假设数量是1000件冲压工序产能每小时200件那么预计加工1000/2005小时。如果车间单班制每天8小时工单计划的开始时间为当天8:00结束时间为当天13:00。后道工序去毛刺产能每小时50件预计20小时可能就要排到第二天才能完成。这些计算的代码并不复杂我在后端写了一个scheduleWorkOrders函数在计划下发时调用把结果写入work_orders的plan_start_time和plan_end_time字段。前端展示时可以按时间轴排列成简易甘特图。5.2 前端简易甘特图设计完整的甘特图组件网上有很多但集成进来总要改。如果不想花太多时间推荐用纯CSS加flex布局做一个简易时间条左侧是工单名称右侧是排期条宽度根据天数比例动态计算。做出来效果足够演示和内部使用。我给前端设计的甘特图组件思路是获取计划开始日和结束日计算总共N天。每行对应一个工单排期条的left百分比 (工单开始日期 - 计划开始日期) / N * 100。排期条的width百分比 工单持续时间 / N * 100。背景色用当前状态控制待开工灰色、进行中蓝色、已完成绿色。这种实现方案灵活度高不用引入重依赖。如果后面想升级可以接vue-ganttastic之类的库但至少MVP阶段不需要。6. 上线踩坑实录Node.js安装、联调和前端问题一次说清6.1 Node.js版本与依赖安装的坑很多同学第一个坑就挂在环境上。我在帮别人调试时见过最典型的问题是同时装了多个Node版本命令行执行node -v是旧的而编辑器里用的是新的导致依赖安装报错。建议用nvm管理Node版本统一到18 LTS然后执行nvm use 18。还有一个高频坑是安装node-sass失败。新项目建议直接用Vite依赖里根本不需要node-sass。如果老项目必须用也要注意Node 16以上版本和node-sass的兼容性不如换成dart-sass省心很多。另外npm默认源下载慢建议用npm config set registry https://registry.npmmirror.com能省不少时间。6.2 前后端联调时的跨域与会话问题前后端分离项目最常见的问题就是跨域。开发环境用Vite代理是最干净的方案在vite.config.js中配置server: { port: 5173, proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } }这样前端所有/api请求都会被转发到后端浏览器里看不到跨域也不需要后端配cors。但要注意生产环境部署后不能只靠这个代理。如果前端和后端部署在同一台服务器用Nginx配置一个反向代理location /api { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }还有登录状态问题。JWT是放在localStorage里的如果用户通过旧域名访问Token存到了别的域名下会出现反复登录的情况。排查时打开浏览器开发者工具看Network面板里请求头Authorization是否存在不存在说明前端没带上Token多半是因为跳转时把Token清掉了。6.3 数据库时区、中文乱码和Socket占用数据库时区问题我前面提过接口返回的时间全部差8小时这种问题很隐蔽因为页面不报错就是数据对不上。排查方法很简单用MySQL客户端直接查库看数据如果数据库里时间正常接口返回不正常基本就是Sequelize连接时区配置的问题。中文乱码一般是因为表没有使用utf8mb4字符集。建库的时候就要设置好CREATE DATABASE factory_plan DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;如果已经建好可以用ALTER TABLE修改。前端页面若出现中文问号还有一种可能是后端HTTP响应头没加Content-Type: application/json; charsetutf-8Express默认响应已经带了但如果你手动res.send一个中文对象时最好显式设置。端口占用也是个老问题启动后端时提示3000端口被占用执行netstat -ano | findstr 3000找到对应PID然后结束进程。开发时用nodemon监听文件改动自动重启比手动重启效率高很多。6.4 数据统计和报表毛刺最后说一个比较容易被忽略的点报表统计毛刺。月度报表里经常出现计划完成率超过100%或者不良率计算异常多数是因为报工数据包含已经取消的计划。SQL聚合时一定要加上WHERE status ! cancelled这类过滤条件。前端展示百分比时也要做边界处理比如除以零的情况显示为0%而不是NaN或无限大。我实际遇到过一次某天看板完成率突然变成130%查下来是因为操作工把上一张已完成工单又误报了一次导致completed_qty翻倍。后来我在报工接口加了工单状态校验只有非done状态的工单才能报工问题就解决了。这种边界校验虽然看起来只是几行代码但在生产环境里就是救命的东西。最后说几句实在话这套系统从头做到上线最花时间的不是写代码而是反复理清业务口径。比如“计划完成率到底怎么算”“不合格品怎么处理”“急单插单怎么调整交期”这些在需求阶段没讲清楚开发阶段就会反复改。我个人的建议是做这类系统时先把手画线框图给车间主任和班组长看哪怕是一个原型草图也比直接闷头写一星期代码再给他们看要高效得多。如果你现在准备动手做这个项目我希望你能把重点放在“进度闭环”上计划能够下发、工单能够报工、看板能够更新、报表能够统计这条链路通了系统就算立住了。至于界面做得多么炫酷反而是次要的。最后再分享一个小技巧在开发阶段把所有报工接口都打印出完整的请求体和响应体调试的时候能省掉大量时间去猜数据从哪一步开始不对。这是我每次开发管理系统都保留的习惯。