简介基于C#与Vue构建的iMES工厂管家是一套面向制造企业生产管理场景的MES系统涵盖前后端完整源代码与数据库脚本适合需要快速搭建生产制造管理平台的开发人员、企业信息化工程师也适合想系统学习业务流程与前后端分离架构的进阶学习者。资源共1456个文件以982个C#源文件实现后端业务逻辑、156个Vue组件构建前端界面、130个JavaScript脚本处理交互另有数据库脚本、页面及项目配置文件压缩包整体仅7.06MB轻量且结构清晰。已有588人学习下载。资源不只是一份源码快照还附带一键启动、构建与安装脚本可帮助快速搭建运行环境核心业务基类与表服务代码则展示了通用封装方式便于理解系统架构并开展二次开发也可作为毕业设计或企业选型的参考。1. 基于C#和Vue的MES系统中小工厂也能落地的生产制造管理方案车间主任手里拿着一沓纸质工单走到哪问到哪昨天那批货到哪道工序了这种场景在中小型制造企业里太常见了。基于C#和Vue开发的MES系统制造执行系统就是用来解决这类问题的——把工单下发、工序流转、报工统计、质量检验这些日常动作从纸面搬到系统里让每一件在制品的位置和数量都能随时查到。这套iMES工厂管家采用前后端分离架构后端C#提供业务接口前端Vue搭建操作界面自带数据库脚本。它适合两类人计划上MES但预算有限的工厂以及想快速交付可运行项目的开发者。熟悉这套技术组合后续接ERP接口、做车间看板都有现成路径。但务必记住一点系统再完整现场执行不到位看板上的数据就只是数字。2. 从工厂痛点看架构选型C#后端、Vue前端与数据库表设计MES这类系统最关键的技术决策不在某个算法或框架上而在技术栈与工厂现场环境的匹配程度。选择C#和Vue的组合不是因为它最新潮而是它在制造企业里最不容易出问题。下面从三个层面拆开看。2.1 C#在MES后端的位置为什么这套技术栈在工厂里吃香先看制造企业的IT环境。绝大多数工厂的服务器和办公电脑都是Windows系统IT维护人员最熟悉的技术栈也是Windows生态下的老面孔。C#后端在这类环境里部署几乎不需要额外学习成本IIS挂一个站点或者直接用dotnet命令跑一个控制台服务Windows防火墙放行端口Web API就能对外提供接口。这一点在项目交付时特别重要因为工厂的IT负责人通常不希望引入一套需要Linux服务器、Docker容器、K8s编排才能跑起来的系统操作门槛越高验收和后续维护的阻力就越大。从开发效率上看C#搭配EF Core或Dapper操作SQL Server非常顺手。MES系统的业务模型核心是工单、工序、报工、质检这几张表的联动事务边界清晰用ORM映射实体再做仓储封装代码量比纯ADO.NET少很多。而且EF Core的迁移功能在工厂现场调整表结构时很实用加一个字段、加一张中间表几行迁移命令就能同步到生产库比手工执行一堆SQL脚本安全得多。还有一个容易被忽视但实际很重要的点MES系统往深了做一定要接设备数据。车间里的称重仪、扫码枪、防错料架、甚至部分PLC设备很多带有Windows下的SDK或串口通信协议。C#在串口通信、USB HID设备读取、Windows服务托管这些方面有天然的生态优势。我见过不少项目当初用其他技术栈做最后设备对接环节还是绕回来写一个C#的小服务中转数据。既然迟早要用不如一开始就用。性能方面不必担心。MES和互联网高并发场景完全不同一个工厂车间哪怕有几百个同时在线用户核心写操作的并发度也就是每秒几次到几十次。C#的异步接口和连接池完全够用。真正需要花精力的是业务逻辑的正确性——报工数量能不能和工单匹配、并发报工会不会导致数据覆盖——这些和编程语言无关和数据表设计有关。如果拿来对比替代方案用Java技术栈做MES的团队也不少Spring Boot生态同样成熟。但从项目交付和维护的角度看C#的取舍清晰工厂IT环境几乎不用额外配置部署包可以发布为单文件免安装数据库层面和SQL Server的配合度也优于其他组合。Vue和React比也是同样的逻辑React在组件生态和灵活性上不输Vue但Vue的组件库成熟度、对后台管理系统场景的贴合度对做交付的团队更友好。选型这门课上最贵的不是框架授权而是团队学习和客户维护的隐性成本。C#加Vue恰好把这两块成本压到了最低。2.2 Vue前端与传统车间操作习惯的匹配前端的选型逻辑同样要贴合使用场景。车间里的操作终端有几种典型形态办公室电脑上的管理端、生产线旁的工位屏、挂在墙上的生产看板。Vue在这三种形态下都有成熟的解决方案管理端用Vue加组件库做表格、表单、权限菜单工位屏用Vue做几个大字按钮的极简界面看板可以直接用Vue写一个自刷新页面接到大屏显示器上。一套前端工程覆盖三种场景维护成本可控。很多MES项目在拿需求时车间工人会对系统有天然的抵触——本来干得好好的为什么要花时间去点电脑。这个问题的解法一半靠制度另一半靠界面。Vue的组件化开发模式让二次开发时的交互调整成本很低字体调大、按钮调大、颜色区分异常状态、把鼠标点击改成扫码枪回车触发这些改动都落在组件内部不牵动全局逻辑。实际项目里我一般会建议在报工界面把默认字体做到16到18号以上按钮最小高度做到40像素以上因为车间环境光线强、操作者可能带着手套界面必须比普通后台管理系统更“粗放”。与后端的交互链路也比较标准Vue组件里通过axios调用C# Web API接口返回统一格式的JSON前端根据code字段判断业务成功还是失败。路由层面用Vue Router控制页面权限菜单根据登录用户的角色动态渲染。这套模式的好处是前端只关心展示和交互后端只关心业务规则和数据校验两边并行开发时只要把接口约定好就不会互相等待。有一点要提醒如果项目用的是Vue 2加组件库二次开发时注意不要直接把Vue 3生态的组件或写法搬进来两个版本在响应式原理和组件API上有不少差异混用会出很多难以排查的运行时问题。拿到源码后先看一下package.json里锁定的vue版本再决定能不能使用某些新语法。2.3 数据库表结构工单、工序、物料、报工记录怎么串起来数据库是整个MES系统的核心资产。功能可以之后再加但表结构设计不合理的系统越往后越难改。一套典型的MES数据库核心表通常包括产品表、物料表、工单主表、工单工序表、生产报工记录表、质量检验表、用户与角色表。我一般会建议按业务对象来划分表而不是按页面来划分。下面这个建表片段展示了工单主表和报工记录表最核心的结构-- 工单主表每一行代表一张生产工单 CREATE TABLE production_order ( id INT IDENTITY(1,1) PRIMARY KEY, order_no VARCHAR(30) NOT NULL UNIQUE, -- 工单号扫码枪扫的就是这个 product_id INT NOT NULL, -- 关联产品表 plan_qty INT NOT NULL, -- 计划数量 completed_qty INT DEFAULT 0, -- 已完成数量冗余字段用于列表展示 status TINYINT DEFAULT 0, -- 0:待排产 1:生产中 2:已完工 3:已关闭 plan_start_date DATETIME, -- 计划开始时间 plan_end_date DATETIME, -- 计划结束时间 create_by INT NOT NULL, -- 创建人关联用户表 create_time DATETIME DEFAULT GETDATE() ); -- 报工记录表每次报工写一行是所有统计的原始数据 CREATE TABLE production_report ( id INT IDENTITY(1,1) PRIMARY KEY, order_id INT NOT NULL, -- 关联工单主表 process_id INT NOT NULL, -- 关联工序表 report_qty INT NOT NULL, -- 本次报工数量 bad_qty INT DEFAULT 0, -- 本次不良数量 operator_id INT NOT NULL, -- 报工人操作工 work_date DATETIME NOT NULL, -- 报工日期 remark NVARCHAR(200), -- 备注 FOREIGN KEY (order_id) REFERENCES production_order(id) );这段建表逻辑里有几个值得注意的设计。completed_qty在工单主表里属于冗余字段它的值可以由production_report里的report_qty汇总得到但保留这个冗余字段能让列表查询少做一次聚合计算在数据量大时有实际性能收益。代价是每次报工写入时都要同步更新这个字段这两步操作必须放在同一个数据库事务里否则会出现工单显示数量和明细对不上的问题。工序与工单的关系是另一张表order_process每一行是“某张工单的某道工序”包含工序编号、工序名称、计划开始时间、完成数量、是否首检等信息。产品表和物料表按基础数据来设计产品表存产品编码、名称、规格、默认工艺路线物料表存原料编码、批次、库存数量物料与工单在发料环节产生关联。整体来看这套表结构的主线是“工单带工序工序带报工报工带质检”沿着这条主线就能追踪一件产品的完整生产过程。status字段用TINYINT而不是字符串一是查询效率高二是在代码里可以用枚举对应避免出现“生产中”“生产完成”“已完工”这种不统一的叫法。实际开发中状态流转一定要有约束——比如一张已关闭的工单不能被再做报工这个校验放在前端只是体验问题放在后端接口和数据库层才是底线。数据库约束能防住绕过页面的所有非法操作。3. 把源码跑起来开发环境、数据库还原与最小启动命令拿到源码包之后最常见的问题是不知道从哪里开始。我的建议是严格按照“数据库先行、后端其次、前端最后”的顺序来。因为前端页面依赖后端接口返回数据后端接口依赖数据库里有表结构和基础数据顺序反了会让人误以为系统有问题。3.1 开发环境清单版本搭配与安装顺序在动手前先把环境对齐能省掉很多莫名其妙的报错。以下是我实际部署这类项目常用的版本组合兼容性比较稳妥组件推荐版本用途与说明Visual Studio2022 社区版打开并编译C#后端解决方案免费.NET SDK6.0 或 8.0后端编译运行依赖两个版本都常见Node.js16.20 或 18.19前端npm安装依赖与构建SQL Server2019 或 2022 Express数据库Express版足够本机开发和并发不大的车间安装顺序上先装SQL Server再装Visual Studio是更稳的做法——VS在安装时会自动识别本机已有的SQL Server实例并集成部署工具。Node.js单独装就行没有冲突。需要注意Node版本不要装最新的20以上部分老版本Vue项目的依赖在最新Node下会报OpenSSL相关的错误这是前端构建里很经典的一个坑。3.2 还原数据库两种方式与连接字符串配置源码包里通常带有两种形态的数据库资源一种是独立的SQL脚本文件另一种是MDF数据库文件。两种方式都可以我优先推荐执行SQL脚本因为脚本能在新建数据库时把表结构、基础数据、索引和约束一次性建好避免MDF文件因版本或路径问题附加失败。用SQL Server Management Studio新建数据库后选中目标库执行脚本即可。命令行方式也可以# 在Windows命令行中执行SQL脚本还原 sqlcmd -S localhost -U sa -P your_password -d iMES_DB -i db_init.sql执行完成后验证一下核心表是否创建成功SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPEBASE TABLE;能看到production_order、production_report这些表就算成功了。接下来配置后端连接字符串。C#后端一般会把连接字符串放在appsettings.json里打开后找到ConnectionStrings节点改成对应环境{ ConnectionStrings: { Default: Serverlocalhost;DatabaseiMES_DB;User Idsa;Passwordyour_password;TrustServerCertificateTrue; } }连接字符串这里有两个细节要改Server字段如果是远程部署要把localhost换成数据库服务器的IP或计算机名Password字段换成实际密码。TrustServerCertificateTrue是.NET 6之后的版本必须有的否则本地开发默认证书不受信时会直接拒绝连接。3.3 启动后端与前端最小命令与验证方法后端和前端是两个独立进程启动顺序没有严格要求但为了排查方便我习惯先启动后端。后端启动在解决方案目录下执行dotnet restore dotnet run --project src/iMES.Api -p:ASPNETCORE_ENVIRONMENTDevelopment看到控制台输出“Now listening on: http://localhost:5000”说明API已经起来了。此时可以打开浏览器访问后端地址部分项目配置了Swagger的话还能看到接口文档页面逐个接口手动调用来验证数据库连接是否正常。前端启动在另一个终端里执行npm install npm run servenpm install第一次执行会比较慢如果出现网络超时换成镜像源再装一次。启动成功后控制台会输出前端访问地址一般是http://localhost:8080。浏览器打开登录页用系统预置的账号登录。首次进系统后先去两个地方一是看工单管理页面能否加载出工单数据二是看生产报工页面能否提交一条测试数据并回显。这两条验证通过说明数据库、后端、前端三层链路已经通了可以进入正常的二次开发和业务配置阶段。如果启动过程中端口被占用后端或前端会报错提示listen EADDRINUSE或bind失败。解决办法是在启动命令里指定端口后端开发时可以在launchSettings.json里改applicationUrl字段前端可以在vue.config.js里改devServer的port。这个细节在工厂现场特别容易遇到——车间局域网里可能有其他系统占用了8080端口提前改好能避免部署当天手忙脚乱。4. 核心业务模块拆解工单流转、报工与质检怎么联动MES的功能模块看起来很多但主线非常清晰工单从创建到关闭是一个生命周期报工是这个生命周期里最频繁的操作质检则是在关键节点把关的控制器。三个模块串在一起才构成完整的生产执行闭环。4.1 工单状态机从排产到完工的流转设计工单状态是整个系统的“交通信号灯”。生产计划员创建工单后工单进入待排产状态排产完成并下发给车间后变为生产中车间完成所有工序并质检合格后变为已完工最后经过入库或关闭处理变为已关闭。每次状态变更都意味着业务流程进入了一个新阶段。状态字段本身只是一个数字但状态之间的流转规则要靠代码保证。比如说订单还在待排产状态时车间就不能报工已关闭的工单不允许再追加数量状态回退必须有权限验证。前端可以控制按钮的显示和禁用但真正的防呆逻辑一定要在后端接口做二次校验// 报工前的状态校验 var order await _db.ProductionOrders.FindAsync(orderId); if (order.Status OrderStatus.Closed) { return BadRequest(new { code 400, message 工单已关闭无法报工 }); } if (order.Status ! OrderStatus.Running) { return BadRequest(new { code 400, message 工单未开工或已完工无法报工 }); }这段代码的逻辑很清楚状态不是生产中一律拒绝报工。很多翻车现场都出在这种地方——前端按钮虽然禁用了但有经验的用户换个接口工具照样能调通如果后端没有校验脏数据就进去了。4.2 报工接口从扫码输入到生产记录落库报工是车间里频次最高的操作也是最能体现MES价值的模块。操作工在工位屏上扫一下工单条码输入本次完成数量点击提交系统就需要在工单进度、报工明细、计件统计三个层面同步更新数据。报工方式在不同工厂差别很大。小批量多品种的工厂一台设备一天可能要切换十几张工单每个操作工的报工次数很频繁用电脑页面一张张点太慢。这种场景下扫码枪报工是绝对的主流——扫工单条码、输数量、回车三秒内完成一次报工。大批量少品种的工厂则更依赖设备联动报工通过计数器或PLC直接上报产量人只处理异常。MES系统的设计必须兼容这两种模式前一种把页面交互做到最简单后一种把接口设计成可被外部程序调用的形式。报工接口按DTO接收数据而不是依赖前端表单实体就是在为设备对接预留扩展空间。以下代码基于EF Core的DbContext写法展示后端报工接口的核心逻辑[HttpPost(api/report)] public async TaskIActionResult CreateReport([FromBody] ReportDto dto) { // 1. 校验参数合法性 if (dto.ReportQty 0 || dto.ReportQty 9999) return BadRequest(new { code 400, message 报工数量必须在1到9999之间 }); // 2. 开启事务保证工单更新与报工记录原子生效 using var tx await _db.Database.BeginTransactionAsync(); // 3. 查询工单并锁定行防止并发报工互相覆盖 var order await _db.ProductionOrders .FromSqlRaw(SELECT * FROM production_order WITH (UPDLOCK) WHERE id {0}, dto.OrderId) .FirstOrDefaultAsync(); if (order null || order.Status ! OrderStatus.Running) return BadRequest(new { code 400, message 工单不可报工 }); // 4. 插入报工明细 var record new ProductionReport { OrderId dto.OrderId, ProcessId dto.ProcessId, ReportQty dto.ReportQty, BadQty dto.BadQty, OperatorId dto.OperatorId, WorkDate DateTime.Now }; _db.ProductionReports.Add(record); // 5. 更新工单完成数量 order.CompletedQty dto.ReportQty; await _db.SaveChangesAsync(); await tx.CommitAsync(); return Ok(new { code 200, message 报工成功 }); }这里有几个参数和细节值得说明。dto.ReportQty是本次报工数量上限9999是一个简单的防错约束实际可以根据产品体型调整。第3步用UPDLOCK对工单行加锁是为了防止两个工人同时提交报工时后写覆盖先写的数值这在机加工车间里常有发生不加锁就会出现数量凭空变少的情况。整个报工和更新工单的操作放在同一个事务里任何一个步骤失败都会回滚不会出现报了工但工单进度不更新的半截数据。4.3 质量检验不合格品处置流程质检模块通常按检验节点分为来料检验、首件检验、过程巡检和完工检验。来料检验把关采购的原料和毛坯不经过检验确认就不能投入生产首件检验要求每班或每次换型后先做首件合格才允许批量生产过程巡检由质检员按频次到工位抽检完工检验是产品下线前的最后一道关。质检结果一般有三种处置动作合格放行、不合格返工、不合格报废。返工会让工单进入一个“返工”子状态返工完成后再重新检验报废数量会计入工单的损耗字段直接影响计划达成率的计算。整个处置流程都要保留记录方便后续追溯是哪一批原料、哪一道工序、谁的班次导致了不良。不合格品处置的逻辑上最容易出问题的是“返工回退”操作。一张已经流转到下一道工序的工单如果上一道工序被质检判了不合格是需要它把工序位置退回去的。不少项目在这一步只更新了工单状态没有同步更新工序指针结果就是看板显示上一道工序已完成、检验又不合格而工人不知道该回哪个工位处理。正确做法是在质检不合格且处置方式为返工时把该工序及其之后所有工序的完成状态重置为未完成并记录系统操作日志。质量数据积累下来就是很有价值的分析资产。按月统计各类不良的占比和趋势能定位是来料问题、工艺问题还是操作习惯问题。很多工厂最早对MES没抱太大期望但用了一个季度之后最离不开的反而是质量报表模块因为它是唯一能把“我觉得最近质量变差了”变成具体数据和趋势图的地方。5. 部署与二次开发中的避坑指南5个反复出现的翻车点这套系统在你自己的开发电脑上跑通和部署到工厂现场真正用起来中间隔着很多细节。下面这5个问题是这类项目里出现频率最高的有些甚至被老工程师称为玄学但按步骤排查基本都能定位。每条都按现象、原因、解决来记录建议部署前对照检查。5.1 数据库连接字符串本机能连、换台电脑就连不上现象开发者在自己电脑上跑得好好的把系统部署到工厂服务器后后端启动报错日志提示数据库连接失败。明明服务器上数据库服务已经启动了用管理工具也能连上。原因appsettings.json里的连接字符串用了localhost或127.0.0.1。localhost指当前进程所在的机器后端服务跑在服务器上数据库也跑在同一台服务器上表面上看起来没问题但如果连接字符串里写的是开发机IP或者服务器上SQL Server配置了不允许远程连接那部署后必然失败。解决先将连接字符串改为服务器本机名或数据库实际IP然后到SQL Server配置管理器中检查TCP/IP协议是否启用、监听端口是否为1433最后用sqlcmd在服务器上测试连接成功。这三步做完大部分连接问题都能排除。5.2 JWT密钥与过期时间车间电脑时间不准引发的401现象系统上线后的一段时间某个工位屏总是间歇性提示登录过期重新登录后正常几分钟又失效其他工位没有同样问题。原因排查后发现是这台工位屏的Windows系统时间比标准时间慢了几分钟。JWT令牌会校验签发时间和过期时间车间电脑时间偏差超过阈值时后端解析令牌就会判断为过期或未生效于是反复要求重新登录。解决把车间所有用作终端的电脑时间同步改为自动同步并在部署文档里注明这一点。同时在做二次开发时把令牌过期时间设置成合理的值——不要为了省事设成一天也不要设成几分钟一般半天到一天比较合适。5.3 上传文件路径写死图片和工艺文档部署后404现象开发环境上传产品图片、工艺图纸一切正常部署后上传功能还能用但图片无法在页面加载打开图片地址返回404。原因上传目录的绝对路径被写死成了开发机的某个盘符比如C:\Work\iMES\uploads。部署到服务器后路径不存在文件虽然写进了上传接口返回的地址但服务器上没有对应的物理位置。解决将上传路径改为相对路径基于当前运行目录动态拼接通常是Path.Combine(Environment.ContentRootPath, uploads)。同时要给这个目录设置写入权限否则图片传上来但保存失败界面却不一定会报错。5.4 前端打包后接口地址还指向localhost现象前端开发时接口请求正常npm run build打包部署到服务器之后所有页面请求全部失败打开浏览器控制台看到的接口地址仍然是http://localhost:5000。原因前端代码里的API基础地址写死在了环境配置文件里通常放在.env.development中而生产环境没有对应的环境变量构建时就直接把开发地址带进了产物。解决检查前端工程下有没有.env.production文件有就修改其中的VUE_APP_BASE_URL为服务器实际地址没有就新建一个。打包后用编辑器打开dist目录里的js文件搜索一下localhost确认没有残留再发布。这一步虽然简单但在现场翻车的概率极高。5.5 数据库排序规则导致的中文乱码与查不到数据现象系统录入的中文数据在列表页正常显示但按中文关键字搜索时查不到任何结果个别老数据甚至显示成问号。原因SQL Server数据库的排序规则不一致。常见情况是数据库用了区分大小写的排序规则或历史库的字符编码与当前系统的编码不一致。中文数据在录入时如果不强制使用NVARCHAR类型写入时就可能因为字符编码转换出现乱码。解决建表和脚本里字符串统一使用NVARCHAR而不是VARCHAR数据库排序规则设为Chinese_PRC_CI_AS。已经存在的库可以按下面脚本修改排序规则但注意要停掉应用服务避免写入冲突ALTER DATABASE iMES_DB COLLATE Chinese_PRC_CI_AS;改完之后对NVARCHAR字段的查询走的是新的规则中文模糊搜索基本就正常了。这两个细节在建库脚本阶段就做好后面能省掉不少麻烦。6. 二次开发的第一课把报工页面改成扫码枪无脑输入整个系统跑通之后第一次真正意义上的二次开发我建议从改报工页面入手因为它改动小、见效快而且直接关联车间日常操作。最常见的需求就是把报工页面改成扫码枪输入操作工扫一下工单条码系统自动带出工单和当前工序输入数量回车就提交。扫码枪的本质是一个模拟键盘的输入设备扫一段条码后自动输入字符并默认在末尾敲一个回车。所以前端改造的核心就是监听一个输入框的回车事件不用装任何驱动。以最常见的Vue 2工程为例先在模板里加一个扫码输入框template el-input refscanBox v-modelscanValue placeholder请扫描工单条码 sizelarge clearable keyup.enter.nativehandleScan / /template script export default { data() { return { scanValue: } }, methods: { // 扫码枪扫完码自动回车触发查询 handleScan() { const code this.scanValue.trim() if (!code) return this.loadOrderByCode(code) this.scanValue }, async loadOrderByCode(code) { const { data } await this.$http.get(/api/order/detail, { params: { code } }) if (data.code 200) { this.currentOrder data.data this.$message.success(工单已带出请核对数量) } else { this.$message.error(data.message || 未找到该工单) } } } } /script这段改动的核心逻辑很简单扫码后回车把条码作为工单号传给后端后端查出工单信息后回填到页面。注意handleScan里做了trim去空格因为有些扫码枪会在条码前后带上回车或换行符不去掉的话查询会失败。查询成功后再把输入框清空方便扫下一张。改完后验证时不用真的拿扫码枪在输入框里输入工单号再按回车效果完全一样。我在这类项目上的习惯是改完功能先自己按一遍再叫车间班组长在测试环境按几遍他们不按流程走的操作习惯往往会暴露你没有考虑到的边界情况。这个方向再往下走还可以在扫码后自动聚焦工位、校验设备和工单的匹配关系、扫码报工完成后自动打印标签每一条都是从“能用”到“好用”的进阶。MES项目做得越久越明白业务逻辑的复杂度永远不在代码本身而在现场每天发生的那些例外情况。希望这些经验能让你在第一次部署这套系统时少走一点弯路。本文还有配套的精品资源点击获取