首页 / 资讯中心 / 文章详情

汽车修理管理系统实战:Spring Boot+Vue全栈开发与业务闭环解析

汽车修理管理系统实战:Spring Boot+Vue全栈开发与业务闭环解析 ★ FEATURED ARTICLE
简介这是一套面向汽车修理厂日常运营场景的数字化管理软件源码适合计算机专业学生、中小型汽修企业管理者及希望学习桌面端信息管理系统的开发者参考。系统围绕客户档案、预约排程、维修订单、配件库存、财务收支、员工绩效与统计报表等模块展开并配有数据备份与权限控制思路可帮助读者理解汽修业务从接车到结算的完整数据流转。资源包共53个文件约2.66MB以h头文件与cpp源文件为主体辅以obj编译产物、tlh/tli类型库文件、mdb数据库、rc资源脚本及exe可执行程序构成一套可编译运行的VC工程骨架。目前已有678人学习下载。通过阅读源码读者可掌握各功能对话框与业务逻辑的对应关系借鉴数据库表结构设计与模块划分方式并在此基础上进行二次开发或课程设计改造。1. 汽修厂老板的Excel该换了一个能跑起来的修理管理系统长什么样如果你去问一个开汽修厂的老板店里最头疼的事是什么十有八九不是修不好车而是“账对不上、件找不到、人管不住”。接车靠手写单子配件靠脑子记库存月底算工时全靠Excel拉公式一旦师傅离职或者客户扯皮连三个月前换过什么件都查不出来。这套“汽车修理管理系统”就是冲着这个场景来的——它把接车登记、维修派工、配件出入库、结算对账这几件事串成一条线让前台、仓库、财务看到的是同一份数据。技术栈上它走的是典型的Java Web路线Spring Boot做后端MyBatis-Plus管数据MySQL存业务前端用Vue加Element UI搭管理台。适合谁一是中小型修理厂想摆脱纸质单据的二是计算机专业做毕设或课程设计需要完整业务闭环的三是想拿一个真实业务系统练手二次开发的。下面我按“能干什么、怎么跑、怎么改”的顺序把这份源码拆开讲。2. 系统骨架与业务闭环从接车到结算的数据怎么流转2.1 技术选型与分层结构这套系统没有走微服务那套重装备而是标准的单体分层架构对中小项目来说这是最务实的选择——部署简单调试直观一个人也能维护。后端按Controller、Service、Mapper三层切分实体类用MyBatis-Plus的注解直接映射表字段省掉大量XML。前端是独立的前后端分离项目通过Axios调REST接口登录态用JWT令牌维持。常见做法是后端端口跑8080前端devServer跑8081并配置代理转发这样本地开发不用处理跨域。数据库连接池用HikariCPSpring Boot 2.x默认自带配置里改改url和账号密码就能连上自己的库。# application.yml 关键配置片段 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/repair_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true这段配置里有两个参数值得注意serverTimezone必须写对否则插入时间会差8小时这是MySQL 8.x的经典坑map-underscore-to-camel-case开启后数据库的create_time会自动映射到Java的createTime不用手写ResultMap。2.2 核心业务表与状态流转系统的业务闭环围绕四张主表展开车辆表vehicle、维修工单表repair_order、配件表parts、结算表settlement。工单表里有个status字段是整条链路的灵魂它控制着一条维修记录能走到哪一步。状态值含义可执行操作0待派工前台可修改可指派师傅1维修中师傅可登记用料不可删除2待结算仓库已出库财务可生成账单3已结算只读仅可查看和打印4已取消只读保留记录用于追溯这个状态机是防止业务混乱的关键。我见过不少毕设项目把状态做成自由编辑结果出现“已结算的工单又被改了配件”这种数据打架的情况。这里用状态值卡住操作入口前端根据status渲染不同按钮后端在Service层再做一次校验双保险。2.3 一个工单从进厂到出厂的完整链路假设一辆车进厂前台先查车辆表——如果是老客户直接带出历史记录新客户则先建档。然后创建工单选维修项目比如换机油、补漆系统自动带出项目工时费和预估配件。派工给师傅后状态从0变1。师傅在移动端或后台登记实际用料仓库那边同步扣减库存。修完后状态变2财务拉出结算单算上工时、配件、折扣生成应收金额。收款后状态变3整个链路闭合。// RepairOrderServiceImpl.java 状态流转核心方法 Transactional(rollbackFor Exception.class) public void updateStatus(Long orderId, Integer targetStatus) { RepairOrder order this.getById(orderId); // 校验状态跃迁是否合法防止跳步 if (!isValidTransition(order.getStatus(), targetStatus)) { throw new BusinessException(当前状态不允许此操作); } // 进入结算前必须确认配件已全部出库 if (targetStatus 2 hasUnfinishedParts(orderId)) { throw new BusinessException(存在未出库配件无法结算); } order.setStatus(targetStatus); order.setUpdateTime(new Date()); this.updateById(order); }这段代码的Transactional注解保证了状态变更和后续操作的原子性isValidTransition是个私有方法内部用Map定义了允许的跃迁路径。参数targetStatus由前端传入但后端不信任前端必须重新校验。hasUnfinishedParts会去查配件出库记录表这是很多简化版系统漏掉的环节导致结算金额和实际用料对不上。3. 本地跑起来环境准备、建库与启动排错3.1 环境清单与版本要求在动手之前先把环境对齐版本不匹配是新手翻车最多的地方。这套系统对版本不算挑剔但有几个底线JDK 1.8或11别用17以上MyBatis-Plus老版本在模块化下有反射问题MySQL 5.7或8.08.0要改驱动类为com.mysql.cj.jdbc.DriverMaven 3.6用来拉依赖和打包Node.js 14或16前端Vue 2项目对高版本Node兼容性一般IDE用IDEA或Eclipse都行IDEA对Spring Boot支持更顺提示如果你机器上已经装了多个JDK记得在IDEA的Project Structure里把SDK和Language Level都设成8只改环境变量有时候不生效。3.2 建库与初始化数据源码包里一般会带一个sql目录里面是建表脚本和初始数据。操作顺序是先建库再导表# 登录MySQL后执行 CREATE DATABASE repair_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE repair_db; SOURCE /你的路径/repair_db.sql;字符集一定用utf8mb4不然客户姓名里的生僻字或者备注里的特殊符号会变问号。导入完成后用SHOW TABLES;确认表都建出来了通常会有十几张表除了前面说的四张主表还有用户表、角色表、菜单表这些权限相关的。初始数据里一般会预置一个管理员账号密码是加密存的。如果你不知道密码可以看sql文件里的insert语句或者直接用工具生成一个MD5或BCrypt密文替换进去。常见做法是密码用BCrypt加密登录时用BCryptPasswordEncoder.matches()比对。3.3 后端启动与接口验证后端启动就是标准的Spring Boot流程但有几个地方容易卡住# 在项目根目录执行 mvn clean package -DskipTests java -jar target/repair-system-1.0.0.jar # 或者直接在IDEA里运行Application主类启动日志里看到Started Application in x.x seconds就算成功了。然后打开浏览器或Postman访问http://localhost:8080/api/login用POST方式传JSON{ username: admin, password: 123456 }如果返回的JSON里带token字段说明后端和数据库通了。如果报Access denied for user检查application.yml里的账号密码如果报Unknown database说明库没建对如果报Table doesnt exist说明sql没导全。这三个错误覆盖了90%的启动失败。3.4 前端启动与联调前端目录通常叫repair-web或frontend进去先装依赖再跑npm install npm run servenpm install如果卡住换成淘宝镜像npm config set registry https://registry.npmmirror.com再试。启动成功后控制台会打印本地访问地址一般是http://localhost:8081。这时候如果登录报404或跨域检查vue.config.js里的proxy配置// vue.config.js 代理配置 module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, pathRewrite: { ^/api: } // 去掉前缀再转发 } } } }changeOrigin设为true是为了让后端收到的Host头是目标地址有些安全校验会检查这个。pathRewrite看后端接口有没有统一前缀有就去掉没有就删掉这行。联调通了之后登录进首页应该能看到左侧菜单和顶部的用户信息。4. 核心模块拆解工单、库存、结算三块怎么写的4.1 工单模块分页查询与多条件筛选工单列表是使用频率最高的页面前台要根据车牌、状态、时间段来查。后端用MyBatis-Plus的QueryWrapper拼条件比手写XML灵活。// RepairOrderController.java 分页查询接口 GetMapping(/page) public ResultIPageRepairOrder page( RequestParam(defaultValue 1) Integer current, RequestParam(defaultValue 10) Integer size, String plateNo, Integer status, String startDate, String endDate) { QueryWrapperRepairOrder wrapper new QueryWrapper(); // 车牌模糊匹配用户可能只记得部分 wrapper.like(StringUtils.isNotBlank(plateNo), plate_no, plateNo); // 状态精确匹配 wrapper.eq(status ! null, status, status); // 时间范围前端传的是字符串直接比较 wrapper.ge(StringUtils.isNotBlank(startDate), create_time, startDate); wrapper.le(StringUtils.isNotBlank(endDate), create_time, endDate); wrapper.orderByDesc(create_time); return Result.success(repairOrderService.page(new Page(current, size), wrapper)); }like和eq的第一个参数是条件布尔值只有为true时才拼进SQL这样避免了写一堆if判断。orderByDesc保证最新的工单排最前面。参数current和size由前端分页组件传入默认第一页每页10条。返回的IPage对象里包含总记录数和当前页数据前端Element UI的table直接绑定就行。4.2 配件库存出库扣减与并发控制库存模块最怕的是超卖——两个工单同时领同一个配件库存只剩1个结果都扣成功了。这里用乐观锁或者数据库行锁来解决。// PartsServiceImpl.java 出库扣减 Transactional(rollbackFor Exception.class) public void outbound(Long partsId, Integer quantity, Long orderId) { // 先查当前库存 Parts parts this.getById(partsId); if (parts.getStock() quantity) { throw new BusinessException(库存不足当前剩余 parts.getStock()); } // 用update语句带条件扣减防止并发 boolean success this.update() .setSql(stock stock - quantity) .eq(id, partsId) .ge(stock, quantity) // 关键库存足够才更新 .update(); if (!success) { throw new BusinessException(库存扣减失败请重试); } // 记录出库流水用于追溯 PartsRecord record new PartsRecord(); record.setPartsId(partsId); record.setQuantity(quantity); record.setOrderId(orderId); record.setType(1); // 1表示出库 partsRecordMapper.insert(record); }关键在.ge(stock, quantity)这个条件它让UPDATE语句变成UPDATE parts SET stock stock - N WHERE id ? AND stock N数据库层面保证不会扣成负数。如果更新影响行数为0说明并发时被别人抢先扣了直接抛异常让前端重试。出库流水表一定要记不然月底盘点时对不上账你连查都没处查。4.3 结算模块工时费与配件费的合并计算结算单的金额由三部分组成工时费、配件费、其他费用比如外加工再减去折扣。工时费按维修项目的标准工时乘以费率配件费按实际出库数量和售价算。// SettlementServiceImpl.java 生成结算单 public Settlement generate(Long orderId) { RepairOrder order repairOrderService.getById(orderId); // 汇总工时费 BigDecimal laborFee orderItemMapper.sumLaborFee(orderId); // 汇总配件费从出库流水里算 BigDecimal partsFee partsRecordMapper.sumPartsFee(orderId); // 其他费用从工单附加项取 BigDecimal otherFee order.getOtherFee() null ? BigDecimal.ZERO : order.getOtherFee(); BigDecimal total laborFee.add(partsFee).add(otherFee); // 折扣按百分比比如打九折传90 if (order.getDiscount() ! null order.getDiscount() 100) { total total.multiply(new BigDecimal(order.getDiscount())) .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); } Settlement settlement new Settlement(); settlement.setOrderId(orderId); settlement.setLaborFee(laborFee); settlement.setPartsFee(partsFee); settlement.setOtherFee(otherFee); settlement.setTotalAmount(total); settlement.setCreateTime(new Date()); this.save(settlement); return settlement; }金额计算全部用BigDecimal别用double浮点误差在财务场景是致命的。divide的时候指定保留两位小数和舍入模式HALF_UP是四舍五入符合日常习惯。折扣字段存的是整数百分比比如九折存90这样前端传参简单后端算的时候除以100。5. 避坑与排查启动、数据、权限的常见翻车现场5.1 启动报错“找不到符号”或“程序包不存在”现象IDEA里一片红Maven依赖下载了但编译不过。 原因多半是Lombok插件没装或没启用。实体类上用了Data注解编译期需要Lombok生成getter/setter。 解决IDEA里装Lombok插件并重启同时在Settings里开启Annotation Processors。如果还不行检查pom.xml里Lombok的scope是不是provided是的话打包时不会带进去但编译期需要。5.2 登录成功但刷新页面就退出现象登录后能进首页按F5刷新一下又跳回登录页。 原因token存在了Vuex里刷新后Vuex状态丢失但没从localStorage或cookie里恢复。 解决在路由守卫里加判断如果Vuex没token但localStorage有就重新拉用户信息并放行。常见做法是把token同时存localStorageVuex只做内存缓存。5.3 工单列表查不到刚建的数据现象明明保存成功了列表里却没有。 原因查询条件里带了默认的时间范围比如默认查当月而测试数据的时间是上个月。 解决检查前端查询表单的默认值把时间范围清空再查。或者在后端把时间条件的ge和le改成只有传了值才拼。5.4 配件出库后库存没变现象出库操作提示成功但配件表里的stock字段没减。 原因事务没生效可能是Transactional加在了private方法上或者同类内部调用绕过了代理。 解决确保注解加在public方法上且调用方是通过Spring注入的Bean调用的不是new出来的。另外检查数据库引擎是不是InnoDBMyISAM不支持事务。5.5 结算金额和手工算的对不上现象系统算出来的总额比财务手算的少几块钱。 原因配件费汇总时漏掉了某些出库记录比如退料后重新出库的或者折扣计算时舍入方式不一致。 解决把出库流水全部拉出来逐条核对确认sumPartsFee的SQL有没有过滤条件。折扣计算统一用HALF_UP别一处四舍五入一处直接截断。6. 二次开发怎么改从加字段到换架构的实操建议拿到这套源码最常做的改造是加字段和加模块。比如老板说“我要记录每辆车的保险到期日”这就涉及车辆表加字段、实体类加属性、前端表单加输入框、列表加列一条线改下来。我的习惯是先改数据库再改实体再改Mapper最后改前端顺序反了容易编译报错找不到字段。-- 车辆表加保险到期日 ALTER TABLE vehicle ADD COLUMN insurance_expire DATE COMMENT 保险到期日 AFTER plate_no;加完字段后Vehicle实体类加private Date insuranceExpire;MyBatis-Plus会自动映射。前端在车辆表单里加一个日期选择器列表里加一列显示。如果要做“保险到期提醒”可以在Service里加个定时任务每天扫一遍快到期且没提醒过的车往消息表插一条记录。另一个常见改造是换权限模型。原系统如果是简单的角色判断想改成细粒度的按钮级权限可以引入Spring Security或Shiro。但我的血泪经验是别一上来就重构先把现有登录逻辑摸透在原有User表基础上加角色和权限表逐步替换。直接换框架容易把登录态搞崩到时候连后台都进不去。验证改造是否成功我一般走三步先单元测试Service层的新方法再用Postman调接口确认返回结构没变最后前端点一遍完整流程。特别是涉及金额和库存的改动必须手工对一遍账。从那以后我每次改结算相关的代码都强制走一遍“建单-派工-出库-结算-收款”的全链路不敢跳步。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站