ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SpringBoot+Vue3车辆管理系统:从数据库设计到权限控制实战

SpringBoot+Vue3车辆管理系统:从数据库设计到权限控制实战 前阵子帮一个做企业车队管理的朋友搭了一套车辆管理系统用的就是Java SpringBootVue3MyBatis这套前后端分离方案数据库用的MySQL。折腾了小两周从数据库设计到权限控制从动态查询到报表统计踩了不少坑也沉淀出一些比较通用的做法。今天把整套系统从设计思路到核心代码完整拆一遍打算做毕业设计、公司内部工具或者自己练手项目的朋友可以直接照着这套思路和代码走。这套系统解决的核心问题很明确传统车辆管理靠Excel和纸质台账车辆档案散、用车审批慢、维修加油记录对不上账。系统化之后就是一套标准流程——车辆信息统一建档用车人在线提交申请管理员审批司机接单出车归还登记维修和加油记录可查月底还能按部门、按费用类型出统计报表。如果你需要的就是这类场景那么这篇文章从表结构到前后端代码基本是能直接拿来改的。1. 项目整体设计与技术选型思路1.1 为什么选择前后端分离架构前后端分离这套架构放到今天已经不是选择题而是默认项。所谓前后端分离简单说就是后端只管提供数据接口返回JSON前端只管页面渲染和交互通过HTTP请求拿数据。两边用接口文档约定好格式各干各的互不干扰。这个项目选前后端分离主要出于三个层面的考虑。第一是团队协作层面。前后端分离以后后端同学可以专注写接口、调SQL前端同学专注撸页面两边并行开发不需要等对方完成才能动工。就算你是一个人做整套系统分开写的好处也很明显——改页面样式不会碰坏业务逻辑换一套前端界面也不会动后端代码维护成本低很多。第二是部署层面。Vue3打包后是一堆纯静态文件扔到Nginx里就能跑SpringBoot打包成Jar包扔到服务器上java -jar就能启动。两者各自独立部署、独立扩容互不拖累。开发环境下用Vite做代理转发生产环境用Nginx反代API链路很清晰。第三是技术演进层面。前端Vue3组合式API加Element Plus组件库做后台管理系统的效率比传统JSP加jQuery那套高几个量级。后端SpringBoot简化了Spring的XML配置内嵌Tomcat不用额外部署容器MyBatis控制SQL又比JPA那种全自动ORM更灵活特别适合报表查询这类复杂SQL场景。1.2 技术栈选型背后的取舍整套系统的技术栈是SpringBoot 2.7 MyBatis MySQL 8.0 Vue3 Element Plus Pinia Vue Router。SpringBoot选2.7而不是更高版本是为了兼容性。SpringBoot 3.x强制要求JDK 17而很多生产环境的JDK还停在8或者112.7版本用JDK 8就能跑部署成本最低。如果你是新项目且JDK版本没问题直接用3.x也可以但要注意javax包名换成jakarta的坑。MyBatis相比JPA优势在SQL可控性。车辆管理系统的查询条件非常碎按车牌号查、按司机查、按时间范围查、按状态查还有各种组合条件。MyBatis动态SQL可以用if标签灵活拼条件写起来直观、调试方便SQL性能也好优化。JPA那种根据方法名推导SQL的方式碰到多表联查和复杂统计就很别扭。MySQL 8.0没啥可说的开源免费、稳定成熟、资料多。8.0相比5.7主要多了窗口函数和通用表表达式做排名和分组统计方便不少后面报表模块会用到。前端Vue3加Element Plus是国内后台管理系统的事实标准。Vue3的组合式API写起来比Options API逻辑更聚合一个功能相关的数据和方法可以放在一起不用像以前那样散在data、methods、computed各个块里。Element Plus组件库全覆盖表格、表单、弹窗、日期选择器、树形控件开箱即用。2. 数据库表结构设计与核心功能拆解2.1 车辆信息与司机档案表设计车辆管理系统最核心的实体就是车辆和司机。车辆表我把字段拆成基础信息、状态信息、运营信息三个维度。基础信息包括车牌号、品牌型号、车辆类型轿车/SUV/货车/客车、座位数、购买日期、车辆识别代号VIN码、发动机号。车牌号是业务上的天然唯一标识直接建唯一索引。状态信息包括当前状态可用/出车中/维修中/已报废、当前里程、所属部门、停放位置。这里有个设计细节当前状态不要只存一个状态字段而是存状态码比如1可用、2出车中、3维修中、4报废。这样相当于用整型做枚举查询快程序里可以维护映射关系显示中文名。运营信息包括年检到期日、保险到期日、保养周期等。这些字段是给到期提醒功能用的虽然不复杂但很实用——车辆年检和保险到期前30天自动提醒比人工记Excel靠谱得多。司机表相对简单字段包括姓名、手机号、驾照编号、驾照类型、入职日期、状态。车主和司机可能不是同一个人所以车辆表和司机表是单独的通过外键关联一个司机可以绑定多辆车也可以是一辆车对应多个司机看具体业务。我做的是多对多关系中间表存绑定关系和绑定时间。不过大部分中小型车队都是一车一司机做成车辆表带driver_id字段也没问题这个按实际业务灵活调整。2.2 业务流转表设计用车申请、维修、加油、违章车辆管理系统真正复杂的是业务流转表。我最开始只做了车辆表和司机表朋友看完说没用他要的是能完整走完用车-审批-出车-归还-费用全流程的系统。于是又补了四张核心业务表。用车申请表是整套系统的主业务表。字段包括申请单号、申请部门、申请人、联系方式、用车事由、目的地、预计出发时间、预计归还时间、乘客人数、申请状态待审批/已通过/已驳回/已取消/已完成、审批人和审批时间。这张表是整个系统状态流转的核心审批通过后生成出车单出车单关联到具体车辆和司机。维修记录表记录车辆维修保养明细。字段包括维修车辆、维修日期、维修类型保养/小修/大修/轮胎更换等、维修项目描述、维修金额、维修厂名称、当前里程。这张表有两个作用一是费用核算月底统计每辆车花了多少钱二是车辆档案买二手车或者评估车况时维修记录是最真实的证据。加油记录表字段包括加油车辆、加油日期、加油量升、加油金额、油品类型、加油站、当前里程、上次加油里程。通过当前里程和上次加油里程的差值结合加油量就能算出百公里油耗。这个数据对车队成本控制非常有价值一辆车油耗突然升高往往意味着车况有问题或者驾驶习惯不好。违章记录表字段包括违章车辆、违章日期、违章地点、违章行为、罚款金额、扣分、处理状态、处理日期。违章数据多了以后可以做统计哪些路段违章高发、哪些司机违章率高等不过这是进阶功能先不说。2.3 表关系设计与索引规划这六张表的关系并不复杂核心逻辑线是部门拥有一辆车车辆关联司机用于产生用车申请用车申请关联维修、加油、违章等记录。MySQL是关系型数据库这些关系靠外键体现。外键有一个需要注意的设计考量。严格模式下外键会保证数据完整性比如你不能给一辆不存在的车添加加油记录。但实际开发中很多团队会刻意不建物理外键只建立索引在应用层保证数据一致。原因有两点一是物理外键在删除或更新时容易触发级联操作业务复杂的场景下级联可能产生不可控的连带影响二是高频读写的系统里外键约束会有额外的检查开销。我的习惯是保留逻辑外键关系但通过索引约束实现。唯一索引保证数据唯一性普通索引加速查询。以用车申请表为例申请单号建唯一索引车辆ID、司机ID、申请部门ID建普通索引状态字段建普通索引。查询条件里最常用的就是状态加时间范围这条索引能撑起绝大部分查询场景。MySQL建索引也有讲究。状态这种低基数取值少字段单独建索引收益不大但和申请时间组合起来做联合索引就有意义了。比如status, apply_time联合索引既支持单独按状态查也支持按状态加时间范围查。创建索引的SQL如下CREATE INDEX idx_status_apply_time ON vehicle_apply(status, apply_time); CREATE INDEX idx_vehicle_id ON vehicle_apply(vehicle_id); CREATE INDEX idx_applicant ON vehicle_apply(applicant);索引不是越多越好。每建一个索引插入和更新数据时就要多维护一棵B树写性能会受影响。索引设计的原则是——针对实际查询场景建索引不要对着字段列表挨个建。3. 后端核心实现SpringBootMyBatis落地3.1 项目初始化与统一响应封装后端工程我用Spring Initializr初始化依赖选了Spring Web、MyBatis、MySQL Driver、Lombok。选择SpringBoot 2.7.18JDK用8到最后都不会有兼容性问题。工程目录分层我按Controller、Service、Mapper、Entity的经典四层来做。Entity对应数据库表Mapper负责SQL操作Service写业务逻辑Controller暴露接口。四层结构看起来多但每层职责单一项目变大以后不会乱。一套系统里所有Controller返回的数据结构强烈建议统一。我封装了一个Result类结构包含code、message、data三个字段。code为200时表示成功其他值表示业务异常message给前端提示信息data放实际数据可以是对象、列表或者分页结果。前端Axios封装里统一判断code等于200才走成功逻辑否则弹出message提示。这样定义一次前后端都轻松。Lombok可以在编译期自动生成getter/setter、toString、构造方法等模板代码实体类看起来清爽很多。不过我建议在实体类上还是手动指定一下字段映射防止MyBatis因为驼峰命名和下划线命名不一致导致查询结果字段为null。全局配置map-underscore-to-camel-case设为true后数据库字段user_name能自动映射成userName两个地方配合好就不会出问题。3.2 JWT登录认证与权限控制车辆管理系统有管理员、审批人和普通用户司机/申请人三个角色登录认证用JWT做无状态Token方案。JWT的本质含义是用户登录成功后后端签发一个加密串给前端前端每次请求都带上它后端验签通过就认为是可信用户。具体流程是前端把用户名密码发给后端登录接口后端校验成功后生成JWT返回前端把Token存到localStorage或Pinia里Axios请求拦截器在每个请求头上带上Authorization后端写一个拦截器拦截除登录接口以外所有接口校验Token过期和签名。密码存储绝对不能明文用BCrypt加密同一密码每次加密得到的密文都不一样安全性好很多。JWT生成逻辑我用的jjwt库核心代码如下public String generateToken(String username, Integer roleId) { // 设置签发时间与过期时间这里配置为8小时 Date now new Date(); Date expireDate new Date(now.getTime() 8 * 60 * 60 * 1000); return Jwts.builder() .setSubject(username) .claim(roleId, roleId) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, secretKey.getBytes(StandardCharsets.UTF_8)) .compact(); }角色权限控制我用的最简单的一种方式自定义注解RequireRole标注在Controller方法上拦截器里解析注解里的角色值然后和Token里的角色比对不匹配就返回无权限。这种方案够用、代码量小、逻辑直观。如果你要更细粒度的权限控制比如按钮级权限就需要引入Spring Security或者Sa-Token这类框架了但对于车辆管理这种内部系统角色级别的控制已经足够。3.3 MyBatis动态SQL与多条件分页查询车辆管理列表页的筛选条件往往五花八门——按车牌模糊搜索、按下拉列表选状态、按日期范围。后端如果每个场景都写一条SQL代码会膨胀到没法维护。MyBatis的 和 标签就是为这种场景准备的。以车辆列表查询为例查询条件是车牌号、车辆类型、状态这三项且每一项都可以为空。使用动态SQL后只需写一条查询语句MyBatis会在运行时根据传入条件自动拼SQL。它的写法是select idselectVehicleList resultTypecom.example.entity.Vehicle SELECT * FROM vehicle where if testplateNo ! null and plateNo ! AND plate_no LIKE CONCAT(%, #{plateNo}, %) /if if testvehicleType ! null and vehicleType ! AND vehicle_type #{vehicleType} /if if teststatus ! null AND status #{status} /if /where ORDER BY create_time DESC /select标签会自动处理AND前缀问题——如果第一个条件不成立后续条件里的AND会自动被去掉不会生成WHERE AND这种病句。这个设计非常方便但也隐藏了一个常见问题就是status为0时if判断不到注意后面踩坑章节细说。分页查询是我强烈建议的知识点。车辆列表动辄几百条数据一次全查出来前端渲染会卡传输也慢。传统做法是limit #{offset}, #{pageSize}同时先count一遍总数。用PageHelper插件可以省掉手写count的麻烦用法简单先PageHelper.startPage(pageNum, pageSize)紧接着执行查询插件自动拦截SQL并生成count。但要注意startPage必须紧跟查询中间不要穿插其他SQL操作否则分页会串到错误的查询上。3.4 核心业务接口实现以用车申请审批为例用车申请审批是整个系统里状态流转最复杂的业务我把流程拆成四步提交申请、审批通过、开始出车、完成归还。提交申请接口接收前端传来的表单数据包括申请部门、申请人、事由、目的地、用车时间范围、乘客人数。先校验时间合法性归还时间必须晚于出发时间然后生成一个申请单号单号规则是YYYYMMDD加四位序列号比如202503140001。这一步用存储过程或者Java代码生成序列都可以我图省事直接在Java里做了加上synchronized锁保证并发下不重复。审批通过接口核心逻辑是把申请状态从待审批改为已通过同时写入审批人、审批时间和审批意见。审批时要做两个额外检查一是车辆是否可用二是时间是否有冲突。时间冲突检查的SQL需要花点心思判断两段时间是否有交集条件就是新申请的出发时间小于已有申请的归还时间且新申请的归还时间大于已有申请的出发时间。这条SQL写不好最容易漏我在第四章节里的坑里详细讲。开始出车接口把申请状态改成出车中同时把车辆状态改成出车中并把申请记录关联到具体车牌号。完成归还接口把申请状态改成已完成把车辆状态改回可用更新当前里程同时计算本次用车时长为后续统计做准备。整个审批链路的核心逻辑都存在Service层事务注解直接打在方法上。只要方法内部抛了异常所有写操作全部回滚不会出现申请状态改了但车辆状态没改这种数据不一致的脏数据。事务是这里不能省的底线保障省了后面一定会出事。4. 前端Vue3Element Plus页面实现4.1 环境搭建与工程初始化前端这一块的坑往往不在代码本身而是环境问题。Vue3需要Node.js 16.0及以上版本建议直接用18或20 LTS版本。装Node的时候顺手把npm一起装好然后设置npm镜像源不然下载依赖包等到怀疑人生。工程初始化用官方脚手架npm create vitelatest vehicle-web -- --template vue cd vehicle-web npm install npm install vue-router4 pinia element-plus axios npm run devVite创建的项目默认端口是5173开发环境下前端跑在5173后端跑在8080跨域问题需要处理。我的做法是在vite.config.js里配置代理把接口请求代理到后端地址避免开发环境的跨域麻烦export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })Element Plus引入方式我建议全量引入。虽然按需引入能减少打包体积但对于管理系统这种场景组件用得多而且杂全量引入省心不少。按需引入需要额外配置插件并且每个用到的组件都要手动在代码里引入开发效率被拖累体积优化那点收益对内部系统意义不大。4.2 Axios请求封装与路由守卫Axios封装是所有前端项目的标配。我在utils/request.js里统一创建axios实例设置baseURL为/api同时配置了请求拦截器和响应拦截器。请求拦截器负责把Token塞进请求头响应拦截器负责统一处理业务状态码和HTTP状态码。响应拦截的核心逻辑如下service.interceptors.response.use( (response) { const res response.data if (res.code 200) { return res } // 业务状态码非200要么Token过期要么业务异常 if (res.code 401) { localStorage.removeItem(token) router.push(/login) } ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) }, (error) { ElMessage.error(error.message || 网络异常) return Promise.reject(error) } )前端路由守卫控制页面访问权限。车辆管理系统的路由分成两块需要登录的页面和不需要登录的页面。登录之后没权限的页面通过路由meta里的roles字段控制不属于当前角色的路由直接跳转403页面。router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login) { next() } else if (!token) { next(/login) } else { next() } })4.3 车辆管理列表页与表单页实现车辆管理页面是典型的管理后台页面布局就是左侧栏加顶部栏加主体区域。主体区域一个筛选表单、一个操作按钮区、一张数据表格、一个分页器。这是管理系统最经典的页面范式几乎所有模块都复用这个结构。表格用Element Plus的el-table组件。字段栏位对应后端返回的车辆数据状态字段用el-tag标签展示不同颜色可用是绿色、出车中是蓝色、维修中是橙色一眼就能看出车辆状态。操作栏放编辑、详情、删除三个按钮按钮上绑定对应方法。分页用el-pagination组件配置total、current-page、page-size切换页码时重新调列表接口。表单页用el-form组件字段包括车牌号、车辆类型、品牌型号、座位数、购买日期等。表单校验用Element Plus自带的rules机制车牌号必填、车辆类型必填、购买日期必填。提交时校验通过的再调新增或修改接口校验不通过的阻止提交并弹出第一个错误位置。这里有个细节编辑场景要在打开弹窗时用nextTick把表单数据回填到组件上因为弹窗打开瞬间DOM还没有渲染完。车牌号查询这种场景前端可以加一个防抖用户输入完300毫秒之后再请求接口。不然用户每敲一个字就触发一次请求后端接口会被打爆。4.4 数据可视化与统计报表实现统计报表模块是这套系统的加分项也是让管理员最直观看到系统价值的模块。车辆使用率、部门用车次数、费用分类统计这三块数据用ECharts图表展示。车辆使用率以饼图展示按状态分组统计可用、出车中、维修中、报废的车辆数。后端提供统计接口前端用ECharts的pie类型渲染。部门用车次数以柱状图展示按月统计各个部门的用车申请次数。费用统计需要按类型拆分维修费、加油费、罚款分别汇总用堆叠柱状图最直观。ECharts在Vue3里的用法是先安装echarts依赖然后在组件里通过ref挂载DOM节点在onMounted生命周期里初始化实例。一个容易踩的坑是图表数据没有响应式更新——ECharts实例初始化时拿到的数据如果是空后续数据请求回来以后需要调用setOption更新配置项光改数据源没用。统计接口的SQL是整套系统里最复杂的涉及多表和聚合。以月度部门用车次数统计为例SQL大概是SELECT dept_name, DATE_FORMAT(apply_time, %Y-%m) AS month, COUNT(*) AS cnt FROM vehicle_apply va JOIN sys_dept sd ON va.dept_id sd.id WHERE apply_time #{startDate} AND apply_time #{endDate} GROUP BY dept_id, DATE_FORMAT(apply_time, %Y-%m) ORDER BY month, cnt DESC5. 我在实际开发中踩过的坑与排查技巧5.1 MySQL时区与SQL模式问题这个坑几乎每个SpringBoot连接MySQL 8的人都会遇到。开发环境连数据库时启动项目报错说连接超时或者时区不对原因是MySQL 8.0后默认时区是UTC和本地时间对不上。解决办法是在数据库连接URL上带时区参数jdbc:mysql://localhost:3306/vehicle_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai另一个常见问题是MySQL 8默认开启了ONLY_FULL_GROUP_BY。这个模式下SELECT列表里出现的非聚合字段必须全部出现在GROUP BY子句里。我前面写的部门统计SQL如果GROUP BY里漏了dept_name就报错。这个模式其实是好事能防止SQL语义歧义但如果你接手老项目碰到报错可以考虑去掉这个模式不过我不建议这么做。5.2 MyBatis中0和字符串比较的坑这个问题我在动态SQL那节提到过很经典也很隐蔽。场景是这样的车辆类型的下拉选择默认选项的值是0表示全部类型。传入的查询条件是Integer类型值为0。动态SQL里写的是if testvehicleType ! null and vehicleType ! AND vehicle_type #{vehicleType} /if问题来了——当vehicleType为Integer 0时vehicleType ! 这个条件是false还是true答案是false。因为MyBatis的OGNL表达式会自动把两个不同类型做转换比较Integer 0会被转成字符串0然后和空字符串比较不相等。看似没问题但实际在OGNL里Integer 0和空字符串比较会触发类型转换的坑结果是表达式被判定为false整个if块被跳过。排查这个问题花了我大半天时间最后是打印SQL日志才发现条件被静默移除了。解决办法很简单Integer判断只用null判断就行去掉空字符串判断String类型才需要同时判断null和空字符串。痛过一次之后我总结出的规范是实体类里所有Integer和Long类型字段动态SQL判断只写 ! nullString类型字段才写 ! null and ! 。5.3 跨域与Token失效问题开发环境下往往会遇到跨域问题。前端跑的5173端口请求8080端口的后端接口被浏览器拦截最常见的报错是Access-Control-Allow-Origin相关。解决办法有两个开发环境用Vite代理前面已配置生产环境用Nginx反向代理。如果要在后端配置CORS那就加一个配置类允许跨域来源和请求头。但我还是推荐用代理方案原因是最接近生产环境排查问题更方便。Token失效是我在系统上线前发现的问题。管理端和用户端并发访问时Token因为过期被拦截页面突然跳到登录页用户体验很差。我的优化方案是Token过期时间设为8小时前端在响应拦截器里判断401时弹出友好提示而不是直接跳转同时在后端加入Token续期逻辑——当Token剩余有效期不足2小时时响应头里带上新Token前端检测到后更新存储。这样用户连续使用时不会突然被踢下线只有真正长时间不操作才需要重新登录。5.4 Vue3响应式丢失问题从Vue2转Vue3的朋友最容易踩这个坑。Vue3使用Proxy实现响应式但有一个限制直接给响应式对象新增属性不会触发视图更新。比如const form ref({}) form.value.plateNo 京A123455.5 时间范围查询的边界问题车辆管理系统的列表页几乎都有查询某个时间段内的记录这个需求。前端el-date-picker选择的是一个时间范围数组传给后端的是startDate和endDate两个字符串。问题通常出在endDate上。用户选择的是2025-03-14期望是这一天内所有记录。但如果你直接用endDate去和数据库时间字段比较往往会丢掉当天最后几秒数据因为endDate默认是2025-03-14 00:00:00。被记录的条件是走了截断处理直接用DATE()函数包字段。踩过这个坑后我的规范写法是传startDate时用当天零点传endDate时在前端或者后端把日期追加到23:59:59即2025-03-14 23:59:59。或者更稳妥一点后端统一把endDate加一天查询条件写成小于下一天的零点即 2025-03-15。这样无论是秒级精度还是毫秒级精度都不会漏数据。说到分页查询还有一个常见的连表问题。车辆列表带司机信息的SQL需要join司机表。一开始写的SQL没有注意分页的count语句导致PageHelper生成的count语句跟着join一起执行查出来的总数翻了好几倍。排查后发现是join产生了一对多关联一辆车关联多个司机记录时每行都会计入总数。解决办法是用子查询去重或者先分页再关联这个坑不遇到很难想到。5.4 再说一个前端接口的坑Axios请求POST数据时默认会序列化成JSON请求头是Content-Type: application/json。SpringBoot的RequestBody可以正常接收。但如果你用POST方式提交表单数据且请求头变成了application/x-www-form-urlencoded后端RequestBody就收不到数据对象里全是null。这个问题的排查信号就是——控制台打印参数都是null但数据库连接正常也没报错。5.5 MyBatis嵌套结果映射车辆详情页需要同时展示绑定的司机和最近几条维修记录。如果用单表查询然后代码里拼装效率低不说代码也难看。用MyBatis的嵌套查询可以优雅解决。在Vehicle实体里加一个List 字段Mapper里用collection标签映射resultMap idVehicleDetailMap typecom.example.entity.Vehicle id columnid propertyid/ result columnplate_no propertyplateNo/ ... collection propertyrepairRecords ofTypecom.example.entity.RepairRecord id columnrepair_id propertyid/ result columnrepair_date propertyrepairDate/ ... /collection /resultMap但这里有一个N1查询风险。使用嵌套查询时如果外层查出10辆车每辆车又要查一次关联记录就会产生11条SQL。数据量小的时候无所谓但车辆到几百台维修记录几千条时响应时间会明显变慢。解决方式是改为join查询一次查出所有数据MyBatis根据resultMap自动完成映射。join查询的缺点是如果关联数据太多会产生数据冗余因为多行记录里的车辆信息会重复返回。实际项目里可以根据数据量和场景权衡我一般推荐join因为数据库最怕的不是查询次数多而是每次查询都要全表扫描。join一次搞定比多次次次全表扫描强。6. 这套系统的后续扩展方向系统做到这个程度核心业务已经闭环。但如果要真正投入到生产环境使用我建议再补以下几个方向。推送提醒模块。用车申请审批通过或驳回需要通知申请人年检和保险到期需要提前预警违章记录录入后需要通知司机。这些场景都可以接入邮件或者企业微信/钉钉机器人推送。实现上不难写一个独立的消息推送服务在业务代码的关键节点调用即可。移动端适配。管理员经常在外面跑不方便开电脑审批。可以考虑做一套H5页面复用后端接口或者直接用低代码工具套壳。审批功能在移动端上体验好一点这套系统的使用率会高很多。数据备份与审计日志。车辆管理涉及费用和车辆资产审计日志非常必要。谁在什么时间改了什么车辆的什么信息都应该有记录。MySQL本身有binlog可以做数据恢复但业务层面的操作日志有助于追踪责任。实现方案可以在MyBatis拦截器里统一记录写操作配合一个日志表存储。仪表盘首页优化。目前统计报表是单独页面可以再加一个看板首页把车辆总数、今日出车次数、本月油耗、待审批申请数等关键指标直接呈现在首页管理员打开系统第一眼就能掌握全局。这个用ECharts加几个统计接口就能完成前端布局花点心思即可。如果你打算在这个项目基础上做毕业设计建议把第2章的数据库设计文档和第4章的报表页面做深一点这两个部分最容易体现工作量和技术深度。如果只是公司内部工具用先把第3章的业务流程打通第5章的坑提前避开整体开发周期能控制在两周左右。最后分享一个我在这套系统中坚持的习惯——所有写操作接口都在Service层打了日志记录操作人、操作类型、操作结果和耗时。前期开发时这看起来多余但系统一上线遇到问题这些日志就是排查的命根子。没有日志线上出了问题就像闭着眼在黑屋子里找东西有了日志很多问题一眼就能定位到具体方法和参数。
返回列表