简介:这是一套面向汽车修理厂日常运营场景的数字化管理软件源码,适合计算机专业学生、课程设计开发者以及中小型汽修门店的信息化建设者参考。系统围绕客户档案、预约排程、维修订单、配件库存、财务收支、员工绩效与统计报表等模块展开,帮助解决手工记账混乱、库存预警滞后、经营数据难以汇总等实际问题。资源包共53个文件,约2.66MB,以C++源码(cpp、h)为核心,配合MFC工程文件(dsp、dsw、clw)、编译中间产物(obj、pch、idb)以及Access数据库Car.mdb,另含图标、音效与资源脚本,构成一套可直接编译运行的完整工程。已有678人学习下载。通过阅读源码,读者可掌握基于MFC与ADO数据库访问的桌面管理程序结构,理解各功能对话框与数据表的映射关系,并借鉴其模块划分与权限控制思路,用于二次开发或毕业设计参考。
1. 汽修厂老板的账本困局:这套管理系统到底能解决什么
我见过一个开了八年修理厂的老板,接车用粉笔写在白板上,配件进出靠微信语音,月底对账时发现三辆车修完了没收钱。这不是段子,是很多中小汽修门店的真实状态。这套「汽车修理厂汽车修理管理系统」就是冲着这个场景来的——它把接车登记、维修派工、配件领用、结算收款串成一条线,让每一辆进厂的车都有迹可循。适合谁用?单店或两三个工位的社区修理厂、快修快保店,以及想拿一套完整业务系统做二次开发练手的开发者。技术栈上,这类系统常见做法是后端用 Spring Boot 或 Python Flask 提供 REST 接口,前端用 Vue 或原生 HTML 加模板渲染,数据库选 MySQL,部署在一台普通云主机或门店内网机器上就能跑。下面我按「能干什么、怎么跑起来、怎么改」的顺序,把这份源码拆开讲。
2. 系统架构与目录结构:从一张工单看数据怎么流转
2.1 业务闭环:一辆车从进厂到结算经过哪些表
先别急着看代码,把业务跑通比什么都重要。一辆车进厂,前台登记车牌、车型、车主电话、故障描述,系统生成一张维修工单,状态是「待派工」。车间主管把工单指派给某个技师,状态变「维修中」。技师在维修过程中领用配件,系统扣减库存并记录领料明细。维修完成后工单转「待结算」,前台按工时费加配件费生成结算单,收款后状态变「已结算」,同时这辆车的维修历史归档,下次再来能直接调出。
这条链路对应到数据库,核心是四张表:vehicle(车辆档案)、repair_order(维修工单)、part(配件库存)、order_part(工单领料明细)。工单表通过vehicle_id关联车辆,领料明细表通过order_id和part_id把工单和配件连起来。搞清这个关系,后面看任何一段代码都不会迷路。
-- 维修工单核心表结构(简化版) CREATE TABLE repair_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '工单号,如 RO20240501001', vehicle_id BIGINT NOT NULL COMMENT '关联车辆', fault_desc VARCHAR(500) COMMENT '故障描述', status TINYINT DEFAULT 0 COMMENT '0待派工 1维修中 2待结算 3已结算', technician_id BIGINT COMMENT '指派技师', labor_fee DECIMAL(10,2) DEFAULT 0 COMMENT '工时费', part_fee DECIMAL(10,2) DEFAULT 0 COMMENT '配件费合计', created_at DATETIME DEFAULT CURRENT_TIMESTAMP );字段说明里最关键的是status,它驱动了整个系统的页面流转和权限控制。order_no用日期加流水号生成,方便前台口头报单号查进度。labor_fee和part_fee分开存,是因为结算时经常要按项目打折,分开算比混在一起灵活。
2.2 目录结构:前后端怎么分,配置文件在哪
拿到源码包,先看根目录。这类管理系统常见做法是前后端分离,目录大致长这样:
repair-system/ ├── backend/ # 后端服务 │ ├── src/main/java/... # 控制器、服务、数据访问层 │ ├── src/main/resources/ │ │ ├── application.yml # 数据库连接、端口配置 │ │ └── mapper/ # MyBatis 的 SQL 映射文件 │ └── pom.xml # Maven 依赖 ├── frontend/ # 前端页面 │ ├── src/views/ # 各业务页面:接车、派工、结算 │ ├── src/api/ # 接口请求封装 │ └── package.json └── sql/ └── init.sql # 建库建表加初始数据后端如果用的是 Spring Boot,application.yml里改数据库地址和密码就能连自己的库;前端src/api目录下通常有一个request.js,里面配了后端接口的基础地址,部署时改成实际 IP 或域名。sql/init.sql是救命文件,第一次跑必须先执行它,否则表都没有,登录都进不去。
2.3 权限与角色:为什么前台看不到成本价
系统一般内置三种角色:管理员、前台、技师。管理员能看所有数据和报表;前台能接车、派工、结算,但看不到配件的进价;技师只能看指派给自己的工单和领料。这个权限控制在代码里通常靠一个拦截器加角色字段判断实现。
// 简化的权限拦截逻辑 public boolean checkPermission(String role, String apiPath) { if ("ADMIN".equals(role)) return true; // 管理员放行 if ("FRONT".equals(role) && apiPath.startsWith("/order")) return true; if ("TECH".equals(role) && apiPath.startsWith("/task")) return true; return false; // 其余一律拒绝 }这段逻辑看着简单,但它是整个系统安全感的来源。参数role从登录后写入 session 或 token 里取,apiPath是当前请求路径。实际项目里会做得更细,比如前台能改工单但不能删工单,这些差异都落在checkPermission的分支里。改权限就是改这里的分支条件,比满项目找if靠谱得多。
3. 本地跑起来:数据库、后端、前端三步走
3.1 建库导数据:init.sql 里有什么坑
第一步永远是数据库。打开sql/init.sql,里面通常包含建库语句、建表语句和几条初始数据(比如默认管理员账号)。执行方式有两种:命令行mysql -u root -p < init.sql,或者用图形化工具打开文件直接运行。
# 登录数据库并执行初始化脚本 mysql -u root -p CREATE DATABASE repair_db DEFAULT CHARSET utf8mb4; USE repair_db; SOURCE /path/to/sql/init.sql;这里有个血泪经验:字符集一定要用utf8mb4,别用utf8。汽修系统里车主姓名、故障描述经常出现生僻字,utf8存进去会变问号,结算单打出来车主名字是乱码,客户当场就不信任你了。另外init.sql里的初始密码通常是明文或简单加密,第一次登录后立刻改掉,别留着默认账号跑在公网上。
3.2 后端启动:改配置、装依赖、看日志
数据库通了之后进backend目录。如果是 Maven 项目,先改application.yml:
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/repair_db?useUnicode=true&characterEncoding=utf8mb4 username: root password: 你的密码 server: port: 8080url里的characterEncoding=utf8mb4和数据库字符集对应,别漏。然后执行mvn clean package打包,或者直接在 IDE 里跑主启动类。启动成功的标志是日志最后出现Started Application in x seconds,并且没有Communications link failure这类数据库连接报错。
# 打包并运行 mvn clean package -DskipTests java -jar target/repair-system-1.0.jar-DskipTests是跳过测试加快打包,第一次跑建议加上,等系统跑通了再回头跑测试。如果启动报端口占用,改server.port就行,别去杀进程,容易误伤别的服务。
3.3 前端启动:接口地址别写死
前端进frontend目录,先npm install装依赖,再npm run dev起开发服务器。关键动作是找到接口基础地址的配置,通常在.env.development或src/api/request.js里。
// src/api/request.js 里的基础地址配置 const baseURL = process.env.VUE_APP_BASE_API || 'http://127.0.0.1:8080'; // 开发环境指向本地后端,生产环境改成实际服务器地址很多人本地跑不通就是卡在这:后端在 8080,前端请求却发到了别的端口,浏览器控制台一片 404。改完地址重启前端,用初始管理员账号登录,能看到接车页面就说明整条链路通了。这时候别急着录入真实数据,先随便建一辆测试车走一遍完整流程,确认工单状态能正常流转。
4. 核心模块拆解:接车、派工、结算三段代码
4.1 接车登记:工单号怎么生成才不重复
接车是整个系统的入口,代码质量直接影响后面所有环节。核心是生成一个唯一工单号并落库。
// 工单号生成:日期 + 4位当日流水 public String generateOrderNo() { String datePart = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 查询当天已有多少工单,加一作为流水号 int todayCount = orderMapper.countByDate(datePart); return "RO" + datePart + String.format("%04d", todayCount + 1); }逻辑说明:datePart取当天日期,countByDate查当天工单数量,加一后补零成四位。参数上,%04d保证流水号至少四位,当天超过 9999 单才会溢出,中小修理厂根本到不了。这里有个并发隐患:两个人同时接车可能拿到同一个流水号。常见做法是给order_no加唯一索引,插入失败就重试一次,或者直接用数据库自增 ID 拼日期,更省心。
4.2 派工与领料:库存扣减必须和工单绑定
派工是把工单指派给技师,领料是技师从仓库拿配件。这两步必须在一个事务里完成,否则会出现「配件领走了但工单没记录」的糊涂账。
@Transactional // 事务注解,保证扣库存和写明细同时成功或同时失败 public void assignAndPickParts(Long orderId, Long technicianId, List<PickItem> items) { // 1. 更新工单状态和技师 orderMapper.updateStatusAndTech(orderId, 1, technicianId); // 2. 逐项扣减库存并写领料明细 for (PickItem item : items) { int affected = partMapper.reduceStock(item.getPartId(), item.getQty()); if (affected == 0) { throw new RuntimeException("配件库存不足:" + item.getPartId()); } orderPartMapper.insert(orderId, item.getPartId(), item.getQty()); } }@Transactional是这段代码的灵魂。reduceStock的 SQL 里带WHERE stock >= #{qty}条件,库存不够时返回影响行数 0,直接抛异常回滚整个操作。参数items是技师勾选的配件列表,每项含配件 ID 和数量。这样即使中途某个配件不够,前面扣掉的库存也会回滚,不会出现半截账。
4.3 结算收款:工时费和配件费怎么算准
结算要把工时费和配件费汇总,生成最终金额。配件费从领料明细里按当时售价累加,工时费按工单上记录的金额取。
-- 汇总某工单的配件费 SELECT IFNULL(SUM(op.qty * p.sale_price), 0) AS part_fee FROM order_part op JOIN part p ON op.part_id = p.id WHERE op.order_id = #{orderId};IFNULL是防止没有领料时返回 null,导致前端显示空白。sale_price取的是配件表里的当前售价,这里有个细节:如果配件调过价,历史工单的配件费会跟着变。严谨做法是在order_part表里冗余一个unit_price字段,领料时把当时售价存进去,结算就按这个存下来的价格算,不受后续调价影响。这是很多新手会翻车的地方,改起来不难,加个字段的事。
5. 避坑与常见问题:跑不起来先看这几条
5.1 启动报数据库连接失败
现象:后端启动日志里出现Communications link failure或Access denied for user。原因通常是application.yml里的地址、端口、账号密码和实际数据库对不上,或者数据库服务根本没启动。解决:先用命令行mysql -u root -p确认能连上,再核对配置文件里的每一项,特别注意密码里有没有特殊字符需要转义。
5.2 页面能打开但接口全 404
现象:前端登录页面正常显示,点登录没反应,浏览器控制台一堆 404。原因基本是前端接口基础地址配错了,或者后端没起在预期端口。解决:打开浏览器开发者工具的 Network 面板,看请求实际发到了哪个地址,和request.js里的baseURL对比,改成一致即可。
5.3 中文乱码
现象:录入的车主姓名、故障描述存进数据库变成问号,或者页面显示乱码。原因有三处可能:数据库字符集不是utf8mb4、连接串没加characterEncoding、前端页面没声明 UTF-8。解决:按数据库、连接串、页面三层逐一排查,建库时就用utf8mb4最省事。
5.4 工单状态卡住不流转
现象:派工后工单还是显示「待派工」,或者结算后状态没变。原因多半是状态更新的 SQL 条件写死了旧状态,比如WHERE status = 0,但实际状态已经不是 0 了。解决:检查更新语句的WHERE条件,确认它和当前实际状态匹配,或者干脆只按id更新,状态值由业务代码控制。
5.5 配件库存扣成负数
现象:库存表里出现负库存。原因是扣减时没加库存充足判断,或者并发下两个请求同时扣。解决:扣减 SQL 必须带WHERE stock >= #{qty},并在业务层判断影响行数,为 0 就抛异常回滚。高并发场景再加数据库行锁或乐观锁版本号。
6. 二次开发:从改一个字段到加一张报表
拿到这套源码,最值钱的不是原样跑起来,而是按自己门店的规矩改。我一般从三个方向下手,按难度递增。
第一层:改字段和文案。比如工单表想加一个「预计交车时间」字段,改动路径是:init.sql加列、实体类加属性、Mapper 的 insert 和 update 语句加参数、前端表单加输入框。四步缺一不可,漏了哪步都会出现「填了不保存」或「保存了不显示」。这类改动最安全,适合先练手熟悉代码结构。
第二层:加业务规则。比如「结算时必须先确认所有领料都已归还或核销」。做法是在结算接口里加一段校验,查order_part表里有没有未核销的记录,有就返回错误提示。这类改动要动 Service 层,改完务必用测试数据走一遍完整流程,别只测单个接口。
第三层:加报表和统计。修理厂老板最想看的是「这个月修了多少车、哪个技师产值最高、哪些配件周转最快」。加报表的思路是新建一个统计接口,用 SQL 聚合查询出数据,前端加一个图表页面。下面是一个技师产值的统计示例:
-- 按月统计各技师完成的工单数和工时费合计 SELECT t.name AS technician, COUNT(o.id) AS order_count, IFNULL(SUM(o.labor_fee), 0) AS total_labor FROM repair_order o JOIN technician t ON o.technician_id = t.id WHERE o.status = 3 -- 只统计已结算工单 AND DATE_FORMAT(o.created_at, '%Y-%m') = #{month} GROUP BY t.id, t.name ORDER BY total_labor DESC;status = 3是关键过滤条件,只算已结算的才算真实产值,维修中的工单不能计入。DATE_FORMAT按月份分组,前端传2024-05这样的参数就能查指定月份。这个查询在数据量大的时候会慢,常见做法是给created_at和status加联合索引。
改造时有个习惯我一直保持:每次改完数据库结构,先手动执行一遍建表语句确认无误,再重启后端,最后清浏览器缓存刷新前端。这三步走完再测功能,能省掉大量「明明改了却没生效」的玄学时间。有次我改了个字段类型没同步改实体类,排查了半小时才发现是类型不匹配导致插入静默失败,从那以后我每次动表结构都强制走一遍「SQL、实体、Mapper、前端」四件套核对。希望这套拆解能帮你少走点弯路,把这份源码真正变成自己门店能用的系统。
本文还有配套的精品资源,点击获取