
简介一套面向制造型企业的生产管理系统源代码覆盖生产计划、物料需求、库存管理、进度跟踪、质量控制、订单和报表等核心业务适合需要实现车间信息化、开展二次开发或学习传统ASP开发流程的技术人员参考。资源包共165个文件约1.33MB其中97个ASP文件承载主要业务逻辑配合JavaScript、CSS完成前端交互另有GIF/JPG图片、DB/MDB数据库、EXE程序及说明文档整体结构清晰便于按功能模块查找。目前已有2002人学习浏览。通过源码可了解MRP物料需求计算、库存出入库与预警、质检与不良品处理、订单状态流转等典型模块的实现思路数据库文件和可执行程序有助于在本地搭建演示环境快速验证并修改功能点。此外还可从页面布局、权限控制、数据表关系等维度学习传统ASP项目的分层组织方式为后续技术改造或功能扩展提供参考。1. 生产管理系统源代码有代码不等于能上线先想清楚车间怎么说话经营一个几十人规模的机加工厂最烧钱的往往不是设备而是每天下班前统计“今天到底干完了哪几张工单”。生产管理系统源代码这个词听起来像是一套现成的软件可真正要解决的是把车间里那张一直被手写、被拍照、被口头传递的派工单变成一台机器能读懂的流程。很多开发者拿到代码包跑通登录页就以为上线了结果用起来发现系统里的库存数和车间实物永远对不上。这篇笔记想聊的是拿到或准备做生产管理系统源代码之前先想明白业务在数据库里长什么样再谈表结构和接口。适合两类人一类是给中小工厂做信息化改造的开发另一类是工厂内部想自研的技术负责人。不建议一上来追求大而全先把订单、物料、报工这条主链走通够用就好。2. 先拆业务再碰代码生产管理系统源代码的领域模型与数据库设计2.1 把车间语言翻成表物料、BOM、工序与工作中心做生产管理系统源代码之前我习惯先问车间主任三个问题物料档案谁维护换料时流程怎么走报工是个人报还是班组报这三个问题的答案直接决定数据库表怎么设计。最常见的做法是先建十张核心表物料、物料分类、BOM、工序、工艺路线、工作中心、工单、工单工序、报工记录、库存。见过不少翻车例子上来直接写业务代码等到要算生产成本时发现没有工作中心表又回头补数据还不如一开始就规划进去。先给一张物料表的基础建表语句CREATE TABLE material ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, material_code VARCHAR(32) NOT NULL COMMENT 物料编码, material_name VARCHAR(128) NOT NULL COMMENT 物料名称, spec VARCHAR(64) DEFAULT NULL COMMENT 规格型号, uom VARCHAR(16) NOT NULL DEFAULT PCS COMMENT 单位, category_id BIGINT NULL COMMENT 物料分类ID, is_purchased TINYINT NOT NULL DEFAULT 0 COMMENT 1外购 0自制, default_warehouse VARCHAR(16) DEFAULT WH01 COMMENT 默认仓库, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_material_code (material_code), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT物料主数据;逻辑说明material_code 加唯一索引编码一旦发布不允许在系统里改这是行业惯例改编码比删表重灌还麻烦。uom 默认 PCS但对涂料、线缆这种按公斤、按米计量的物料单位不一致会让后面库存和成本聚合非常痛苦我一般宁可用两天时间统一计量单位也不要留二十种单位到报表阶段再换算。is_purchased 和 default_warehouse 是给后续采购和领料逻辑留的钩子外购物料不需要工艺路线自制件才需要展开 BOM。category_id 不要建字符串目录树最可靠的做法是单独建 category 表用 parent_id 自关联形成树查询和权限控制都方便。2.2 工单与报工定义生产管理系统源代码的业务主链生产管理系统源代码的核心主链是“销售订单 → 生产工单 → 工序报工 → 成品入库”。工单是车间调度和执行的最小单位报工是现场反馈到系统里的关键动作。工单表至少要包含工单号、物料、计划数量、计划开始结束时间、优先级、状态、来源订单号。报工表记录每道工序的实际开始时间、结束时间、合格数量、不合格数量、操作人、工作中心。工单状态流转我一般这样设计CREATE TABLE work_order ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, wo_no VARCHAR(32) NOT NULL COMMENT 工单号, material_id BIGINT NOT NULL COMMENT 物料ID, plan_qty DECIMAL(12,3) NOT NULL COMMENT 计划数量, completed_qty DECIMAL(12,3) NOT NULL DEFAULT 0 COMMENT 累计完工数量, status VARCHAR(16) NOT NULL DEFAULT CREATED COMMENT CREATED已创建 RELEASED已下达 IN_PROGRESS生产中 COMPLETED已完工 CANCELLED已取消, sales_order_no VARCHAR(32) DEFAULT NULL COMMENT 来源销售订单号, due_date DATE DEFAULT NULL COMMENT 交期, priority TINYINT NOT NULL DEFAULT 5 COMMENT 数字越大优先级越高, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_wo_no (wo_no), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT生产工单;逻辑说明工单状态用字符串比数字可读性好前后端联调时不会出现“3 到底代表什么”的歧义。uk_wo_no 唯一键必须加哪怕开发阶段用不到上线后任何外部系统对接都要靠工单号做关联重复工单号是灾难。completed_qty 保存累计值不要用计划数量减已报工数量来算剩余因为报工可能回退、质检可能判废减法容易把账算乱。priority 用 tinyint 默认 5范围 0 到 9 足够不要设计成“高/中/低”字符串排序和筛选都不好写。报工表要单独建因为一道工序可能被多次报工比如上午干 200 件、下午干 150 件不能覆盖式更新。报工记录里带上实际工时后续算工时工资和成本都有依据。最开始我没加工序字段后来统计各工序产能时只能靠报工备注反推非常痛苦。2.3 预留扩展位批次、序列号与追溯字段设计的两个原则做生产管理系统源代码第一版可能不需要批次追溯但表设计时最好留好位置。很多行业尤其是汽配和电子装配客户会要求“我这批货是哪张工单、哪个批次、用了哪一批次原材料”都能查到。虽然初版用不上但字段可以先加ALTER TABLE work_order ADD COLUMN batch_no VARCHAR(32) NULL COMMENT 批次号, ADD COLUMN serial_track_flag TINYINT NOT NULL DEFAULT 0 COMMENT 1工序级序列号追踪;两个原则必须坚持。第一编号字段预留两倍长度。比如现在工单号规则是 WO2024001觉得 20 位够了但将来可能要加工厂代码、产品线代码宁可 VARCHAR(32) 也不要 VARCHAR(16)。第二时间字段统一用 DATETIME 且全部存服务器本地时间不要一部分存 UTC、一部分存北京时间到对账时坑到怀疑人生。另外所有表都加 status 字段做软删除生产数据不能 DELETE一旦删了工单、报工、库存之间的追溯链就断了这条血泪经验后面还会提。3. 核心闭环实现从销售订单到成品入库的代码怎么写3.1 最小可运行技术栈与工程骨架第一个问题往往是“用什么写”。做中小工厂的生产管理系统源代码我常用的方案是 Flask PostgreSQL或者 Spring Boot MySQL看团队熟悉什么。第一版强烈建议单体应用不要一上来就拆微服务理由放在后面避坑章讲。下面以 Python Flask 为例工程骨架一般是这样production-mgr/ ├── app.py ├── config.py ├── models.py ├── schemas.py ├── services/ │ ├── order_service.py │ ├── bom_service.py │ ├── work_order_service.py │ └── inventory_service.py ├── api/ │ ├── work_order_api.py │ └── report_api.py ├── db.py ├── requirements.txt └── migrations/逻辑说明services 目录放业务逻辑api 目录只放 HTTP 路由和参数校验这种方式在单体阶段花不了多少时间后续要拆服务时边界已经画好了。models.py 放 SQLAlchemy 模型直接映射第 2 章设计的表。很多开发者习惯把 SQL 写在业务文件里短期快但 BOM 展开、工单状态流转这种逻辑一复杂代码很快就变成一坨。迁移脚本用 Alembic 管理改表结构不要手工在数据库里执行 ALTER团队里两个人都能对上迁移记录。3.2 创建工单与拆分工序把 BOM 和多工序跑通现在实现最关键的动作销售订单转工单。业务规则是订单下发的物料如果是自制件读取 BOM 表展开生成一张工单同时按工艺路线生成多道工单工序。请求进来先校验物料类型再锁住 BOM 行避免并发修改最后在事务里创建工单和工序。def create_work_orders_from_sales_order(db_session, sales_order_no): order get_order_or_404(db_session, sales_order_no) bom_items get_bom_flat(db_session, order.material_id) if not bom_items: raise BusinessError(该物料没有维护BOM无法下达生产) try: with db_session.begin(): wo WorkOrder( wo_nogenerate_work_order_no(), material_idorder.material_id, plan_qtyorder.quantity, statusCREATED, sales_order_nosales_order_no, due_dateorder.due_date, ) db_session.add(wo) db_session.flush() for step_no, bom in enumerate(bom_items, start1): wos WorkOrderStep( work_order_idwo.id, step_nostep_no, process_codebom.process_code, workcenter_idbom.workcenter_id, plan_qtyorder.quantity, statusPENDING ) db_session.add(wos) return wo.id except IntegrityError: db_session.rollback() raise BusinessError(工单创建失败请检查物料编码和BOM数据)参数说明db_session.begin() 开启事务事务里任何一步失败都会回滚不会出现“工单建好了但工序没生成”的脏数据。flush() 是为了拿到 wo.id 作为外键如果不 flush下面 WorkOrderStep 的 work_order_id 还是 None。get_bom_flat 的作用是把多层 BOM 递归压平成工序列表这一步是生产管理系统源代码最容易翻车的地方递归深度超过 5 层时一定要做缓存或者改成迭代展开。3.3 报工与库存联动数字不能和账面脱节报工是现场生产管理系统源代码每天使用频次最高的操作。报工不仅要更新工单工序的完成数量还要同时处理库存半成品工序完工后转入下一工序的在制品暂存库最后一道工序完工后成品入成品库。这两个动作必须在同一个数据库事务里完成否则就会出现“工单显示完工了但仓库没收到货”的经典问题。def report_completion(db_session, wo_no, step_no, qty, operator): wo db_session.query(WorkOrder).filter_by(wo_nowo_no).with_for_update().first() if not wo: raise BusinessError(工单不存在) if wo.status COMPLETED: raise BusinessError(工单已完工禁止补报工) step db_session.query(WorkOrderStep).filter_by(work_order_idwo.id, step_nostep_no) step step.with_for_update().first() try: with db_session.begin(): report WorkReport( work_order_idwo.id, step_nostep_no, qtyqty, operatoroperator, report_timedatetime.now() ) db_session.add(report) step.completed_qty qty if step.completed_qty step.plan_qty: step.status DONE wo.completed_qty qty if wo.completed_qty wo.plan_qty: wo.status COMPLETED inventory get_inventory_record(db_session, wo.material_id) inventory.available_qty qty except IntegrityError: db_session.rollback() raise BusinessError(报工失败库存更新冲突请重试)逻辑说明with_for_update() 是行级锁防止两个工人同时对同一张工单报工导致数量叠加出错。报工成功后同时增加工单累计完成量、工序完成量和成品库存三处数据在一个事务里提交逻辑上才一致。参数 qty 必须大于 0且在接口层做一次校验数据库层要不就用 CHECK 约束不然业务层漏了脏数据直接进库。这里有个细节成品入库放在报工接口里对简单工厂够用但如果有独立质检环节应该加一个“质检通过后才入可用库存”的状态否则不良品直接进可用库存发货时才发现数量不对。4. 把源代码跑起来初始化、权限与第一个测试数据4.1 数据库初始化与种子数据一张最简物料清单从哪来代码拿到手第一件事不是跑接口而是初始化数据库。生产管理系统源代码和普通 Web 系统不同没有任何主数据时连工单都建不了。最小主数据集合是三个用户管理员、计划员、操作工、两张物料一件外购件、一件自制件、一张 BOM、一台工作中心。初始化脚本这样写export DATABASE_URLpostgresql://scm_user:scm_passlocalhost:5432/production_mgr flask db upgrade python seed_demo.pydef seed(): db.session.add(Material(material_codeM-0001, material_name铝型材6063, uomKG, is_purchasedTrue)) db.session.add(Material(material_codeM-0002, material_name加工面板, uomPCS, is_purchasedFalse)) db.session.add(Process(process_codeCUT, process_name切割)) db.session.add(Process(process_codeCNC, process_nameCNC加工)) db.session.add(Workcenter(codeWC-01, name1号加工中心)) db.session.commit()参数说明种子数据的物料编码要有规则感M 开头代表物料后面是流水号不要混用中文。Process 和 Workcenter 必须建工单工序依赖它们。有人会问为什么不用 CSV 导入第一版种子数据量小代码直接写清楚比 Excel 导入多一道看不见的转码风险。初始化完成后验证一下登录系统能看到两张物料且 M-0002 能查到底层 BOM。4.2 权限模型操作工、计划员、管理员三类角色的最小实现中小工厂不需要复杂的权限体系三类角色足够。操作工只能报工和查看自己的报工记录计划员能建订单、开工单、查库存管理员有全部权限。用一个装饰器实现是最简单可靠的方式def role_required(*roles): def wrapper(fn): def decorator(*args, **kwargs): if not current_user: abort(401) if current_user.role not in roles: abort(403, description没有操作权限) return fn(*args, **kwargs) return decorator return wrapper app.route(/api/report, methods[POST]) role_required(operator, planner, admin) def report_api(): pass app.route(/api/work-order, methods[POST]) role_required(planner, admin) def create_wo(): pass逻辑说明生产管理系统源代码里权限最好不要自己造轮子但角色也不要设计得太细。每多一个角色意味着多一套菜单配置和接口校验。第一版把“谁能报工、谁能开工单”守住就行。这个装饰器写法里有个细小但实用的点abort(401) 和 abort(403) 分开处理前端才能区分“没登录”和“没权限”不然全部返回 401操作工看到报错也不知道是登录掉了还是权限不够。4.3 本地联调最小步骤要验证的五个关键动作数据库初始化完按顺序验证五个动作任何一个出问题都先停下排查不要往下走。顺序验证动作预期结果1管理员登录能看到主菜单接口返回 2002创建自制物料及 BOM物料列表出现 M-0002BOM 有两条子项3计划员创建销售订单订单号生成状态为已审核4下达工单并报工工单状态从 CREATED 变 IN_PROGRESS报工后库存增加5操作工越权访问采购菜单返回 403前端提示“没有操作权限”这五个动作覆盖生产管理系统源代码的完整主链主数据、订单、工单、报工、权限。第 4 步如果报工后库存没变化优先检查事务是否提交、库存初始化记录是否存在。很多项目数据库里没有预置库存为 0 的初始记录报工成功但 inventory 行不存在导致外键报错。排查时看两个表work_report 有没有新记录work_order.completed_qty 有没有增加。最怕的是只更新了一个表另一个没更新这就是明显的事务边界没划对。5. 生产管理系统源代码落地避坑五条血泪经验5.1 坑一物料编码没定好就写代码翻车只能从头改现象项目做到第二个月物料表里出现“螺丝002”“螺丝 3”“不锈钢螺丝”三种写法仓库人员各用各的系统里筛选物料时一屏都放不下。原因是上线前没有定编码规则开发阶段图省事直接用了 Excel 里的中文名。解决方式是重做物料编码类别前缀 流水号导入前写一次校验脚本凡是编码重复、中文名带空格的直接拒收。这个坑最伤的地方不在编码本身而在于所有工单、库存、报工都已经引用了旧的物料 ID改编码等于全表更新外键。所以一开始那两天的时间一定要花在编码规范上。5.2 坑二报工数据双写导致账面混乱事务边界没划清现象车间反馈“系统里库存明明显示 500 件实物盘点是 480 件”查报工记录发现有一条报工 40 件的数据工单数量加了但库存扣减的代码在另一个接口里那个接口当天因为参数校验失败被前端吞掉了异常。原因就是发版时把报工和库存更新拆成了两个事务中间没有做补偿机制。解决方式报工、工单累计、库存更新强制放同一个数据库事务里再在应用入口跑一次单元测试模拟提交成功后库存必须同步。这类问题在开发环境很难复现因为只有并发或者异常路径才会触发但上线第一个月就一定会出现。5.3 坑三源数据脏到跑不动Excel 的 BOM 不是真 BOM现象导入 BOM 后工单展开时发现子件数量有的写“1/2”有的写“0.5 公斤”有的干脆空着最后生产计划一算严重缺料。原因是工厂原有的 BOM 是从设计图纸导出后人工粘到 Excel 里的合并单元格和备注混在一起。生产管理系统源代码的 BOM 导入不能直接照搬 Excel 原表必须经过清洗转换。解决方式是做一个导入校验页先加载 Excel 预览标出不合格行人工修正后再正式导入同时数量字段统一用 DECIMAL 存储。千万别让用户直接粘贴到网页表格里提交中间转码很容易丢失小数点精度。5.4 坑四开发环境能跑、车间用不了浏览器和扫码枪全是坑现象系统做完了演示环境用的是 Chrome 最新版一切正常。到了车间现场发现扫码枪把二维码内容扫进输入框后自动带一个回车直接把表单提交了页面刷新资料没存上。原因是扫码枪默认配置就是在条码后发送回车键但表单没有阻止默认回车行为。解决方式是给报工输入框绑定 keydown 事件如果 event.key 是 Enter 就调用查询接口而不是触发表单提交。车间里还有一部分旧电脑用 IE 或老版本 EdgeVue 全家桶在那边会白屏需要提前定浏览器兼容目标我一般直接规定“车间终端只装 Chrome 和对应驱动版本”并写进交付文档。reportInput.addEventListener(keydown, (event) { if (event.key Enter) { event.preventDefault(); queryWorkOrderByScanCode(reportInput.value.trim()); } });5.5 坑五第一版就上微服务维护成本直接压垮现象某个开发团队拿到生产管理系统源代码需求后觉得“以后要接 MES、要对接 ERP”第一版就拆出七个服务网关、注册中心、消息队列全上了。结果正式上线后光服务部署和环境配置就花了三天现场报工出现延迟排查链路要翻三层日志最后团队里三个核心工程师都走光了。原因不是微服务方向错而是第一版的用户数和业务复杂度根本撑不起分布式成本。解决方式单体应用 模块化代码结构把 services 之间的调用约定直接定义为内部函数接口将来真的需要拆分时再按接口边界把模块提出来。只要是几十人规模的工厂单体应用处理每分钟几千次请求毫无压力完全不需要在创业阶段自找麻烦。6. 让生产管理系统源代码值得投入报表、接口与二次开发的底子生产管理系统源代码做完报工闭环只是开始真正让老板觉得值得的关键是“今天车间干了多少活、哪个工序积压了”。最直接有效的一步是做一个按工作中心和日期的产报汇总接口给老板一个能看懂的数字。一个简单的日产量看板查询SELECT wc.code AS workcenter_code, DATE(r.report_time) AS report_date, SUM(r.qty) AS total_qty, COUNT(DISTINCT r.work_order_id) AS wo_count FROM work_report r JOIN work_order_step wos ON r.work_order_id wos.work_order_id AND r.step_no wos.step_no JOIN workcenter wc ON wos.workcenter_id wc.id WHERE r.report_time %(start_date)s AND r.report_time %(end_date)s GROUP BY wc.code, DATE(r.report_time) ORDER BY report_date DESC, total_qty DESC;这段 SQL 能直接回答“每个工作中心每天的产出”。注意 JOIN 条件里同时带工单号和工序号否则多工序工单会出现重复计数。REPORT 时间和工单创建时间跨天时按报工时间统计才符合实际。报表接口返回 JSON 统一结构code、message、data 三件套前端不用为每个接口单独做异常处理。二次开发的底子要留好两个东西。一个是所有写操作接口都记录操作人和操作时间将来追溯谁改错了立刻能查到另一个是给外部系统留一个只读的 API 前缀比如 /api/v1/external/专门给 ERP 同步库存和订单状态用。我吃过一次亏第一次做系统时没有留外部接口后来要对接某进销存软件对方说要提供库存查询接口我硬补了两周才完成。现在做生产管理系统源代码我第一件事就是把 /api/v1/external/ 这个接口前缀和鉴权逻辑写进项目模板里哪怕暂时为空接口扩展点先留着。权限和报表都过了测试再把操作工的报工页面优化一下大按钮、大字体、扫码自动查询、成功后给出声音反馈。车间人员不会看密集的表格这个环节做好了系统才真正能落地。我习惯在交付时让计划员用真实工单跑满一周期间只解决现场反馈的问题不新增任何功能。希望帮到你。本文还有配套的精品资源点击获取