简介这是一套专为小型工厂定制的轻量级ERP系统源码面向Java初/中级开发者及中小型制造企业IT人员解决传统工厂在销售、采购、生产、库存等环节数据割裂、流程低效的问题。资源包仅5KB含3个核心文件index.html为前端入口页.gitignore规范版本控制行为.inscode可能包含IDE配置或代码检查规则整体结构简洁便于快速部署与二次开发。目前已有145人学习下载适合希望掌握SpringBootVue全栈ERP开发范式的学习者。读者可直接获取完整技术架构实现后端SpringBootMySQL、前端VueElementUIUniAPP、四大业务模块CRM/OA/进销存/财务的集成逻辑以及标准化接口设计与跨端适配思路是理解制造业数字化管理落地的典型教学级项目参考。1. 小型工厂ERP系统源码不是“拿来即用”的玩具而是要亲手拧紧每颗螺丝的生产指挥台你搜到“小型工厂ERP系统源码”大概率正被三件事压着喘不过气车间报工靠微信截图、采购入库靠Excel手填、老板突然要查上月某型号产品的总工时和毛利——而你翻遍表格发现BOM版本对不上、工单状态没闭环、仓库库存数和财务应付账款差了两万八。这不是管理问题是信息断点在吃掉利润。这套源码不是给你装个软件就完事的“开箱即用”产品它是一套可拆解、可焊接、可校准的轻量级制造执行中枢专为50人以内、产线不超过3条、SKU在2000以内的中小型离散制造场景设计。它不追求SAP式的全模块覆盖但把订单→BOM→工单→报工→入库→成本归集这条主干链做成了可追溯、可回滚、可审计的闭环。适合两类人一是懂点Python/PHPMySQL的产线IT支持工程师能自己调参数、改字段、接扫码枪二是有制造业经验的创业者愿意花两周时间带着班组长一起跑通首单全流程。别指望它自动解决人员执行力但它会把“谁、在什么时间、干了什么事、用了什么料、耗了多少工时”全部钉死在数据库里——这才是小型工厂真正需要的“确定性”。2. 搭建前必做的三件事环境裁剪、数据结构校准、权限沙盘推演2.1 环境部署为什么必须用PHP 7.4 MySQL 5.7而非最新版这套源码的底层逻辑建立在MySQL的ENUM类型强约束和PHP 7.4的mysqli_real_escape_string安全过滤机制上。我曾试过直接升到PHP 8.2结果所有BOM展开页面报Fatal error: Uncaught TypeError: mysqli::real_escape_string(): Argument #1 ($string) must be of type string, null given——因为PHP 8.1起废弃了该函数对null的隐式转换而源码中某处工单状态判断未做空值兜底。正确做法是# Ubuntu 20.04 LTS环境下推荐避免兼容性黑匣子 sudo apt update sudo apt install -y php7.4 php7.4-mysql php7.4-curl php7.4-gd php7.4-mbstring php7.4-xml php7.4-zip mysql-server-5.7 # 启动后立即修改MySQL配置关键否则中文乱码日期函数报错 sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf # 在[mysqld]段落末尾添加 character-set-server utf8mb4 collation-server utf8mb4_unicode_ci default-time-zone 08:00 # 重启服务 sudo systemctl restart mysql提示不要用Docker一键拉取“最新版LAMP镜像”。源码中/app/config/database.php硬编码了charset utf8若MySQL实际用utf8mb4而PHP连接层仍发utf8指令会导致BOM表中带emoji的物料描述存入时截断后续展开BOM直接报错。必须手动确认SHOW VARIABLES LIKE character_set%;返回全为utf8mb4。2.2 数据结构校准从“标准字段”到“你的车间语言”的翻译表源码自带的m_product产品表有unit单位字段但默认只预置了PCS件、SET套。而你的冲压车间实际用TON吨计原材料线束车间用ROLL卷计线材。强行改代码会破坏升级路径正确做法是扩展枚举值并同步更新前端下拉-- 进入MySQL执行假设数据库名erp_dev USE erp_dev; ALTER TABLE m_product MODIFY COLUMN unit ENUM(PCS,SET,TON,ROLL,METER,KG) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 刷新缓存部分版本需 FLUSH PRIVILEGES;接着修改前端模板文件/public/views/product/create.blade.phpLaravel风格或/templates/product_form.html原生PHP中对应下拉框!-- 找到原下拉框替换为 -- select nameunit classform-control option valuePCS件/option option valueSET套/option option valueTON吨/option option valueROLL卷/option option valueMETER米/option option valueKG千克/option /select参数说明ENUM类型在此处不是偷懒而是用数据库级约束防止脏数据。比如采购员误选BOX箱单位但系统里根本没有这个枚举值插入直接失败——这比让错误数据进库再花三天排查溯源强十倍。别怕改表结构小型工厂数据量小ALTER TABLE秒级完成。2.3 权限沙盘推演用一张表定义谁能看到什么、能改什么源码权限模型基于RBAC角色-权限-资源但默认角色只有admin和user。你需要按真实组织切分计划员不能删工单仓管员不能改BOM质检员只能看到自己班组的报工记录。核心是修改m_role_permission表权限映射表和m_user_role表用户-角色绑定角色ID角色名可访问模块可操作动作数据范围限制101计划员工单管理、BOM管理创建/编辑工单、查看BOM仅限statusplanning的工单102仓管员入库管理、库存查询创建入库单、调整库存仅限warehouse_id3北仓103质检员报工管理、检验记录提交检验结果、驳回报工仅限team_id IN (5,6)A/B线班组执行SQL初始化角色示例-- 插入新角色 INSERT INTO m_role (id, name, description) VALUES (101, 计划员, 负责工单排程与BOM维护), (102, 仓管员, 负责北仓物料收发), (103, 质检员, 负责A/B线产品检验); -- 绑定权限假设工单列表页路由为/workorder/index编辑为/workorder/edit INSERT INTO m_role_permission (role_id, route, action) VALUES (101, /workorder/index, view), (101, /workorder/edit, edit), (101, /bom/index, view), (102, /inventory/inbound, create), (102, /inventory/stock, view), (103, /reporting/submit, create);血泪经验千万别跳过这步直接给所有人admin权限某次上线后仓管员误点了“删除历史工单”因无数据范围限制连带清空了三个月的报工记录。后来我们加了硬规则所有DELETE操作必须携带WHERE created_at DATE_SUB(NOW(), INTERVAL 7 DAY)且前端按钮需二次弹窗输入当日生产编号才放行。3. 核心流程跑通从接单到入库的最小闭环实操3.1 创建客户与产品用两条SQL搞定基础数据筑基很多新手卡在第一步——系统提示“客户不存在”或“物料编码重复”。根源在于源码强制要求客户、产品、仓库三者先存在才能创建销售订单。最简路径是绕过前端表单直连数据库注入-- 1. 创建客户注意customer_code必须唯一建议用公司简称年份 INSERT INTO m_customer (customer_code, customer_name, contact_person, phone, address) VALUES (CUST2024A, XX机电设备有限公司, 张经理, 13800138000, XX市XX区工业路88号); -- 2. 创建产品product_code即ERP内部编码务必与车间看板一致 INSERT INTO m_product (product_code, product_name, unit, spec, category) VALUES (P-001-MOTOR, Y系列三相异步电机, PCS, 0.75KW/380V/50Hz, 电机);逻辑说明m_customer表的customer_code是销售订单主键so_no的前缀来源如SO-CUST2024A-2024001m_product的product_code则直接用于BOM子项关联。这两张表是整个业务流的“根节点”必须先于任何单据存在。别信前端“快速录入”按钮——它常因JS校验缺失导致空字段插入失败而SQL命令一次到位。3.2 录入销售订单避开“税率自动填充”陷阱的三步法销售订单SO创建界面看似简单但有个隐藏坑当选择客户后系统会根据m_customer.tax_rate字段自动填充订单税率。而源码默认所有客户tax_rate0导致财务导出销项税为0。正确操作先更新客户税率进入MySQLUPDATE m_customer SET tax_rate 13.0 WHERE customer_code CUST2024A;创建订单时手动覆盖在SO表单中即使税率已显示13%仍需点击税率输入框再按回车——触发JavaScript重算含税价逻辑源码中calculateTotal()函数依赖blur事件。检查BOM关联订单保存后立即访问/so/bom?so_id123假设刚建的订单ID为123确认系统是否自动展开BOM。若为空说明m_product中该产品is_bom_parent0非父项需执行UPDATE m_product SET is_bom_parent 1 WHERE product_code P-001-MOTOR;参数说明is_bom_parent是布尔开关1表示此产品可作为BOM顶层成品0表示仅为子项如螺丝、轴承。源码逻辑是只有is_bom_parent1的产品才能被选入销售订单且其BOM树才会被自动加载。漏设此项订单看似创建成功实则无法驱动后续工单生成。3.3 生成工单与报工让车间扫码枪真正“听懂人话”工单WO是连接计划与执行的关键。源码提供两种生成方式手动创建适合试产单和自动展开适合批量单。重点说自动展开# 假设销售订单ID为123执行后台命令Linux服务器 php artisan wo:generate --so_id123 --plan_date2024-06-15 # 或Windows下 php artisan.bat wo:generate --so_id123 --plan_date2024-06-15该命令会读取SO中产品P-001-MOTOR的BOM查m_bom_headerm_bom_item表按需求数量反算子项用量如1台电机需2个端盖创建工单主表m_work_order及明细m_wo_item自动分配至line_id2假设BOM中指定产线为2号装配线报工环节车间用扫码枪扫工单号如WO-20240615-001调用APIcurl -X POST http://your-erp.local/api/reporting/scan \ -H Content-Type: application/json \ -d {wo_code:WO-20240615-001,operator_id:105,qty_good:5,qty_ng:0}避坑关键扫码报工必须传operator_id操作员工号而非姓名。源码用此ID关联m_employee表获取班组、技能等级用于后续产能分析。若传姓名API返回{error:operator not found}——因为数据库查的是数字ID字段。4. 避坑指南上线前必须验证的5个致命断点4.1 现象BOM展开后子项数量为0但数据库m_bom_item里明明有数据原因m_bom_header表中status字段值为draft草稿源码逻辑只读取statusactive的BOM版本。解决执行UPDATE m_bom_header SET statusactive WHERE product_codeP-001-MOTOR;并确认valid_from日期早于当前日期。4.2 现象采购入库单保存后库存查询页面数量不变原因入库单状态未设为confirmed已确认。源码中库存变动仅在m_purchase_inbound.statusconfirmed时触发update_stock()事务。解决在入库单列表页找到刚建的单据点击“确认”按钮非“保存”或直接SQLUPDATE m_purchase_inbound SET statusconfirmed WHERE id456;4.3 现象导出Excel报表时中文全变成问号????原因PHPfputcsv()函数未指定BOM头Excel默认用ANSI编码打开UTF-8文件。解决修改导出函数如/app/Exports/StockExport.php在__construct()中添加$this-headers [\xEF\xBB\xBF . 物料编码, 物料名称, 库存数量]; // UTF-8 BOM头4.4 现象修改密码后无法登录提示“密码错误”原因源码密码加密使用password_hash($pwd, PASSWORD_DEFAULT)但部分旧版PHP 7.4环境PASSWORD_DEFAULT指向bcrypt而数据库里存的是argon2i哈希因之前升级过PHP。解决统一降级为bcrypt修改登录验证逻辑// 在AuthController.php的login方法中 if (password_verify($request-password, $user-password)) { // 原逻辑 } else { // 兼容旧哈希尝试用bcrypt重新hash比对 if (password_needs_rehash($user-password, PASSWORD_BCRYPT)) { $rehash password_hash($request-password, PASSWORD_BCRYPT); if (hash_equals($user-password, $rehash)) { // 更新数据库密码为bcrypt格式 $user-password $rehash; $user-save(); } } }4.5 现象手机浏览器访问报工页扫码后页面白屏原因前端JS调用navigator.mediaDevices.getUserMedia()请求摄像头权限但HTTP协议下Chrome禁用此API必须HTTPS。解决开发阶段用http://localhost可绕过生产环境必须配Nginx反向代理Lets Encrypt证书。临时方案在/public/js/reporting.js中注释掉扫码逻辑改用手工输入工单号。5. 成本核算与数据看板用三条SQL榨干源码里的利润线索5.1 动态计算单台产品实际成本不依赖财务模块的硬核公式源码未内置成本模块但所有数据都在库里。以电机P-001-MOTOR为例单台实际成本材料费人工费制造费用。材料费可直接聚合BOM人工和制造费需关联报工-- 执行此SQL替换日期范围 SELECT p.product_code, p.product_name, ROUND(SUM(bi.qty * pm.price),2) AS material_cost, ROUND(SUM(r.qty_good * e.hourly_rate * 0.5),2) AS labor_cost, -- 假设每台耗0.5工时 ROUND(SUM(r.qty_good * 12.8),2) AS overhead_cost -- 制造费用按12.8元/台摊销 FROM m_product p JOIN m_bom_header bh ON p.id bh.product_id JOIN m_bom_item bi ON bh.id bi.bom_header_id JOIN m_product pm ON bi.component_id pm.id JOIN m_work_order wo ON p.id wo.product_id JOIN m_reporting r ON wo.id r.wo_id JOIN m_employee e ON r.operator_id e.id WHERE p.product_code P-001-MOTOR AND wo.plan_date BETWEEN 2024-06-01 AND 2024-06-30 GROUP BY p.product_code, p.product_name;参数说明e.hourly_rate需提前在m_employee表中维护12.8是示例制造费率实际应按月度总制造费用/当月总合格产量计算。此SQL可嵌入自定义报表页让班组长实时看到“干一台赚多少”。5.2 构建产线OEE看板用视图固化关键指标OEE设备综合效率 时间开动率 × 性能开动率 × 合格品率。源码无现成看板但可用MySQL视图聚合CREATE VIEW v_oee_daily AS SELECT DATE(r.created_at) as report_date, l.line_name, ROUND(AVG(CASE WHEN r.statuscompleted THEN 1 ELSE 0 END),3) as time_availability, ROUND(AVG(r.speed_ratio),3) as performance_rate, ROUND(AVG(r.yield_rate),3) as quality_rate, ROUND(AVG(CASE WHEN r.statuscompleted THEN 1 ELSE 0 END) * AVG(r.speed_ratio) * AVG(r.yield_rate),3) as oee_score FROM m_reporting r JOIN m_work_order wo ON r.wo_id wo.id JOIN m_line l ON wo.line_id l.id GROUP BY DATE(r.created_at), l.line_name;然后在前端页面调用SELECT * FROM v_oee_daily WHERE report_date CURDATE();即可展示今日各线OEE。技巧speed_ratio速度比率和yield_rate合格率字段需在报工时由班组长手动填写这是倒逼数据质量的关键设计——不填满这两个数报工单无法提交。5.3 防止数据污染给关键表加“后悔药”触发器曾因误操作清空m_wo_item工单子项表导致300个工单BOM丢失。现在所有核心表都加了BEFORE DELETE触发器自动备份到历史表-- 创建备份表 CREATE TABLE m_wo_item_history LIKE m_wo_item; ALTER TABLE m_wo_item_history ADD COLUMN deleted_at DATETIME; -- 创建触发器 DELIMITER $$ CREATE TRIGGER wo_item_before_delete BEFORE DELETE ON m_wo_item FOR EACH ROW BEGIN INSERT INTO m_wo_item_history SELECT OLD.*, NOW(); END$$ DELIMITER ;教训上线前我花了整整一天给m_work_order、m_bom_item、m_reporting三张表加了同类触发器。不是信不过自己是信不过那个凌晨三点改完代码、脑子发懵的自己。现在每次DELETE前触发器会默默存一份快照SELECT * FROM m_wo_item_history ORDER BY deleted_at DESC LIMIT 10;就能找回刚删的数据。希望帮到你。本文还有配套的精品资源点击获取