# 用户绑定车辆功能实现说明 ## 概述 实现了完整的用户绑定车辆功能,包括前端绑定页面、后端API接口、数据库表结构和业务逻辑。 ## 1. 数据库表结构 ### 文件:`sql/user_vehicle_bind.sql` 创建了用户车辆绑定表 `sys_user_vehicle`: ```sql CREATE TABLE IF NOT EXISTS sys_user_vehicle ( id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', user_id BIGINT(20) NOT NULL COMMENT '用户ID', vehicle_id BIGINT(20) NOT NULL COMMENT '车辆ID', bind_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '绑定时间', bind_by VARCHAR(64) DEFAULT '' COMMENT '绑定操作人', status CHAR(1) DEFAULT '0' COMMENT '绑定状态(0正常 1解绑)', remark VARCHAR(500) DEFAULT NULL COMMENT '备注', create_by VARCHAR(64) DEFAULT '' COMMENT '创建者', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_by VARCHAR(64) DEFAULT '' COMMENT '更新者', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY idx_user_vehicle (user_id, vehicle_id), KEY idx_user_id (user_id), KEY idx_vehicle_id (vehicle_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户车辆绑定表'; ``` **业务规则**: - 一个用户同时只能绑定一辆车辆(通过业务逻辑控制) - 一辆车辆可以被多个用户绑定(如司机轮班) - status='0'表示当前绑定有效,'1'表示已解绑 - 通过 (user_id, vehicle_id) 唯一索引确保不重复绑定 ## 2. 后端接口实现 ### 2.1 Controller层 **文件**:`VehicleInfoController.java` 新增以下接口: #### (1) 绑定车辆接口 ``` POST /system/vehicle/bind ``` 请求参数: ```json { "userId": 用户ID, "vehicleId": 车辆ID } ``` #### (2) 解绑车辆接口 ``` POST /system/vehicle/unbind ``` 请求参数: ```json { "userId": 用户ID, "vehicleId": 车辆ID } ``` #### (3) 获取用户绑定车辆接口 ``` GET /system/vehicle/user/bound/{userId} ``` 返回数据: ```json { "vehicleId": 车辆ID, "vehicleNumber": "车牌号", "vehicleType": "车辆类型", "vehicleBrand": "车辆品牌", "vehicleModel": "车辆型号" } ``` ### 2.2 Service层 **文件**:`IVehicleInfoService.java` 和 `VehicleInfoServiceImpl.java` 新增方法: - `bindVehicleToUser(userId, vehicleId)` - 绑定车辆到用户 - `unbindVehicleFromUser(userId, vehicleId)` - 解绑用户车辆 - `getUserBoundVehicle(userId)` - 获取用户当前绑定的车辆 **业务逻辑**: ```java @Transactional public int bindVehicleToUser(Long userId, Long vehicleId) { // 先解绑用户的所有车辆(确保一个用户只绑定一辆车) vehicleInfoMapper.unbindAllVehiclesFromUser(userId); // 绑定新车辆 String bindBy = SecurityUtils.getUsername(); return vehicleInfoMapper.bindVehicleToUser(userId, vehicleId, bindBy); } ``` ### 2.3 Mapper层 **文件**:`VehicleInfoMapper.java` 和 `VehicleInfoMapper.xml` 新增Mapper方法: ```java // 绑定车辆到用户 public int bindVehicleToUser(@Param("userId") Long userId, @Param("vehicleId") Long vehicleId, @Param("bindBy") String bindBy); // 解绑用户车辆 public int unbindVehicleFromUser(@Param("userId") Long userId, @Param("vehicleId") Long vehicleId); // 解绑用户的所有车辆 public int unbindAllVehiclesFromUser(@Param("userId") Long userId); // 获取用户当前绑定的车辆 public VehicleInfo getUserBoundVehicle(@Param("userId") Long userId); ``` 新增SQL映射: ```xml INSERT INTO sys_user_vehicle (user_id, vehicle_id, bind_time, bind_by, status, create_by, create_time) VALUES (#{userId}, #{vehicleId}, NOW(), #{bindBy}, '0', #{bindBy}, NOW()) UPDATE sys_user_vehicle SET status = '1', update_time = NOW() WHERE user_id = #{userId} AND vehicle_id = #{vehicleId} AND status = '0' UPDATE sys_user_vehicle SET status = '1', update_time = NOW() WHERE user_id = #{userId} AND status = '0' ``` ## 3. 前端实现 ### 3.1 API调用 **文件**:`app/api/vehicle.js` 已有接口定义: ```javascript // 绑定车辆到用户 export function bindVehicleToUser(userId, vehicleId) { return request({ url: '/vehicle/bind', method: 'post', data: { userId: userId, vehicleId: vehicleId } }) } // 解绑用户车辆 export function unbindVehicleFromUser(userId, vehicleId) { return request({ url: '/vehicle/unbind', method: 'post', data: { userId: userId, vehicleId: vehicleId } }) } ``` ### 3.2 绑定车辆页面 **文件**:`app/pages/bind-vehicle.vue` 主要改进: #### (1) 从后端加载车辆列表 ```javascript loadVehicleList() { const deptId = this.currentUser.deptId || 100 listAvailableVehicles(deptId, 'GENERAL').then(response => { const vehicleList = response.data || response.rows || [] this.vehicleOptions = vehicleList.map(vehicle => ({ id: vehicle.vehicleId, name: vehicle.vehicleNo, type: vehicle.vehicleType, brand: vehicle.vehicleBrand, model: vehicle.vehicleModel })) this.vehiclePlates = this.vehicleOptions.map(v => v.name) }) } ``` #### (2) 调用绑定接口 ```javascript bindVehicle() { if (!this.selectedVehiclePlate || !this.selectedVehicleId) { this.$modal.showToast('请选择车牌号') return } this.$modal.confirm('确认绑定车辆 ' + this.selectedVehiclePlate + ' 吗?').then(() => { const userId = this.currentUser.userId bindVehicleToUser(userId, this.selectedVehicleId).then(response => { this.$modal.showToast('车辆绑定成功') // 更新Vuex中的用户信息 this.$store.dispatch('GetInfo') // 返回上一页 setTimeout(() => { this.$tab.navigateBack() }, 1500) }) }) } ``` #### (3) 扫码绑定功能 支持扫描二维码快速绑定车辆(需要在实际使用时配置二维码内容格式) ## 4. 使用流程 ### 4.1 绑定车辆 1. 用户进入"绑定车辆"页面 2. 可以选择: - 扫描车辆二维码自动绑定 - 从下拉列表选择车牌号手动绑定 3. 确认绑定后: - 系统自动解绑用户之前绑定的车辆 - 绑定新选择的车辆 - 更新用户信息 - 返回首页 ### 4.2 获取绑定车辆信息 - 首页自动加载当前用户绑定的车辆信息 - 创建任务时自动填充绑定的车辆(普通任务) - 个人中心显示绑定的车辆信息 ### 4.3 更换车辆 1. 用户点击"更换车辆"按钮 2. 进入绑定车辆页面 3. 选择新车辆并确认 4. 系统自动解绑旧车辆,绑定新车辆 ## 5. 数据流程 ``` 用户操作 ↓ 前端页面 (bind-vehicle.vue) ↓ API调用 (vehicle.js) ↓ 后端Controller (VehicleInfoController) ↓ Service层 (VehicleInfoServiceImpl) ├── 解绑所有旧绑定 (unbindAllVehiclesFromUser) └── 绑定新车辆 (bindVehicleToUser) ↓ Mapper层 (VehicleInfoMapper) ↓ 数据库操作 (sys_user_vehicle表) ↓ 返回结果 ↓ 更新用户信息 (Vuex) ``` ## 6. 注意事项 1. **权限控制**:绑定接口使用@Anonymous注解,允许匿名访问(实际部署时可根据需要调整) 2. **事务处理**:绑定操作使用@Transactional确保数据一致性 3. **唯一性约束**:通过数据库唯一索引和业务逻辑确保一个用户只绑定一辆车 4. **历史记录**:通过status字段保留绑定历史,便于追溯 5. **错误处理**:所有接口都有完善的异常捕获和错误提示 ## 7. 测试建议 ### 7.1 单元测试 - 测试绑定车辆接口 - 测试解绑车辆接口 - 测试获取绑定车辆接口 - 测试重复绑定同一车辆 ### 7.2 集成测试 - 测试完整的绑定流程 - 测试更换车辆流程 - 测试多用户绑定同一车辆 - 测试并发绑定场景 ### 7.3 UI测试 - 测试扫码绑定功能 - 测试下拉选择绑定功能 - 测试绑定成功后的页面跳转 - 测试绑定信息的正确显示 ## 8. 后续优化建议 1. **二维码生成**:为每辆车生成唯一的二维码,便于扫码绑定 2. **绑定审批**:添加绑定审批流程,防止随意绑定 3. **绑定限制**:根据用户角色限制可绑定的车辆类型 4. **通知推送**:绑定/解绑成功后发送通知给相关人员 5. **数据统计**:统计车辆绑定情况,分析车辆使用率