package com.ruoyi.system.service.impl; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.system.domain.VehicleInfo; import com.ruoyi.system.domain.VehicleDept; import com.ruoyi.system.domain.VehicleSyncDTO; import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.VehicleInfoMapper; import com.ruoyi.system.service.IVehicleInfoService; import com.ruoyi.system.service.IVehicleSyncDataService; import com.ruoyi.system.service.IVehicleSyncService; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 车辆同步服务实现 * * 职责:将从 SQL Server 查询到的车辆数据同步到 MySQL * * 数据流向:接收 DTO → 同步到 MySQL * * @author ruoyi * @date 2025-10-20 */ @Service public class VehicleSyncServiceImpl implements IVehicleSyncService { private static final Logger log = LoggerFactory.getLogger(VehicleSyncServiceImpl.class); @Autowired private IVehicleInfoService vehicleInfoService; @Autowired private SysDeptMapper sysDeptMapper; @Autowired private VehicleInfoMapper vehicleInfoMapper; /** * 同步车辆数据到MySQL * * @param vehicles 从SQL Server查询的车辆列表 * @return 同步结果 */ @Override @Transactional public AjaxResult syncVehicles(List vehicles) { if (vehicles == null || vehicles.isEmpty()) { return AjaxResult.error("车辆数据为空,无法同步"); } try { log.info("开始同步 {} 条车辆数据到 MySQL...", vehicles.size()); int insertCount = 0; int updateCount = 0; int skipCount = 0; Map errorMessages = new HashMap<>(); for (VehicleSyncDTO vehicleDTO : vehicles) { try { // 提取车牌号(去除括号中的内容) String plateNumber = extractPlateNumber(vehicleDTO.getCarLicense()); if (StringUtils.isBlank(plateNumber)) { log.warn("车辆 CarID={} 车牌号为空,跳过同步", vehicleDTO.getCarId()); skipCount++; continue; } // 查询车辆是否存在 VehicleInfo existingVehicle = findVehicleByPlateNumber(plateNumber); // 解析所有分公司ID(CarOrdClass可能包含多个编码,如:HB,TI) List vehicleDepts = parseVehicleDepts(vehicleDTO.getCarOrdClass()); // 设置默认的主部门ID(第一个分公司) Long primaryDeptId = null; if (!vehicleDepts.isEmpty()) { primaryDeptId = vehicleDepts.get(0).getDeptId(); } if (existingVehicle != null) { // 更新车辆信息 existingVehicle.setCarId(vehicleDTO.getCarId()); existingVehicle.setDeptId(primaryDeptId); // 设置主部门 vehicleInfoService.updateVehicleInfo(existingVehicle); // 更新车辆-分公司关联 syncVehicleDepts(existingVehicle.getVehicleId(), vehicleDepts); updateCount++; log.debug("更新车辆: {} (CarID={}), 关联分公司数: {}", plateNumber, vehicleDTO.getCarId(), vehicleDepts.size()); } else { // 新增车辆信息 VehicleInfo newVehicle = new VehicleInfo(); newVehicle.setVehicleNo(plateNumber); newVehicle.setCarId(vehicleDTO.getCarId()); newVehicle.setDeptId(primaryDeptId); // 设置主部门 newVehicle.setStatus("0"); newVehicle.setPlatformCode("LEGACY"); // 标记为旧系统同步 newVehicle.setRemark("从旧系统同步,CarID: " + vehicleDTO.getCarId()); vehicleInfoService.insertVehicleInfo(newVehicle); // 新增车辆-分公司关联 syncVehicleDepts(newVehicle.getVehicleId(), vehicleDepts); insertCount++; log.debug("新增车辆: {} (CarID={}), 关联分公司数: {}", plateNumber, vehicleDTO.getCarId(), vehicleDepts.size()); } } catch (Exception e) { String errorMsg = String.format("同步车辆 CarID=%d 失败: %s", vehicleDTO.getCarId(), e.getMessage()); log.error(errorMsg, e); errorMessages.put("CarID_" + vehicleDTO.getCarId(), errorMsg); } } String resultMsg = String.format( "车辆同步完成 - 新增: %d, 更新: %d, 跳过: %d, 失败: %d", insertCount, updateCount, skipCount, errorMessages.size()); log.info(resultMsg); Map result = new HashMap<>(); result.put("insertCount", insertCount); result.put("updateCount", updateCount); result.put("skipCount", skipCount); result.put("errorCount", errorMessages.size()); result.put("errors", errorMessages); if (errorMessages.isEmpty()) { return AjaxResult.success(resultMsg, result); } else { return AjaxResult.warn(resultMsg, result); } } catch (Exception e) { log.error("同步车辆数据到 MySQL 失败", e); return AjaxResult.error("同步失败: " + e.getMessage()); } } /** * 提取车牌号(去除括号中的内容) * 例如:浙A12345(奔驰) -> 浙A12345 * * @param carLicense 原始车牌号 * @return 提取后的车牌号 */ private String extractPlateNumber(String carLicense) { if (StringUtils.isBlank(carLicense)) { return null; } // 去除空格 String license = carLicense.trim(); // 查找左括号位置(支持中文和英文括号) int leftBracketIndex = license.indexOf('('); int leftBracketIndexCn = license.indexOf('('); // 取最小的有效括号位置 int bracketIndex = -1; if (leftBracketIndex >= 0 && leftBracketIndexCn >= 0) { bracketIndex = Math.min(leftBracketIndex, leftBracketIndexCn); } else if (leftBracketIndex >= 0) { bracketIndex = leftBracketIndex; } else if (leftBracketIndexCn >= 0) { bracketIndex = leftBracketIndexCn; } // 如果找到括号,截取括号前的部分;否则返回原字符串 if (bracketIndex > 0) { return license.substring(0, bracketIndex).trim(); } return license; } /** * 根据车牌号查找车辆(模糊匹配) * * @param plateNumber 车牌号 * @return 车辆信息 */ private VehicleInfo findVehicleByPlateNumber(String plateNumber) { // 先尝试精确匹配 VehicleInfo vehicle = vehicleInfoService.selectVehicleInfoByPlateNumber(plateNumber); if (vehicle != null) { return vehicle; } // 如果精确匹配失败,尝试模糊匹配(查询所有车辆,找到包含该车牌号的) VehicleInfo query = new VehicleInfo(); List allVehicles = vehicleInfoService.selectVehicleInfoList(query); for (VehicleInfo v : allVehicles) { if (StringUtils.isNotBlank(v.getVehicleNo())) { // 如果数据库中的车牌号包含查询的车牌号,或查询的车牌号包含数据库中的车牌号 String dbPlateNumber = extractPlateNumber(v.getVehicleNo()); if (plateNumber.contains(dbPlateNumber) || dbPlateNumber.contains(plateNumber)) { return v; } } } return null; } /** * 从 CarOrdClass 解析多个分公司关联 * CarOrdClass格式可能是:HB、HB,TI、HB.TI等 * * @param carOrdClass 车辆单据类型编码 * @return 车辆-分公司关联列表 */ private List parseVehicleDepts(String carOrdClass) { List vehicleDepts = new ArrayList<>(); if (StringUtils.isBlank(carOrdClass)) { log.debug("CarOrdClass为空,无法解析分公司"); return vehicleDepts; } // 拆分CarOrdClass,可能的分隔符:, . 空格 String[] codes = carOrdClass.split("[.,\\s]+"); for (String code : codes) { if (StringUtils.isBlank(code)) { continue; } code = code.trim(); // 查询匹配dispatch_order_class或service_order_class的部门 SysDept dept = findDeptByOrderClass(code); if (dept != null && dept.getParentId() != null && dept.getParentId() == 100L) { // 只处理分公司(parent_id=100) VehicleDept vehicleDept = new VehicleDept(); vehicleDept.setDeptId(dept.getDeptId()); vehicleDept.setOrderClass(code); vehicleDept.setCreateBy("system"); vehicleDepts.add(vehicleDept); log.debug("通过order_class='{}' 找到分公司: {} (ID={})", code, dept.getDeptName(), dept.getDeptId()); } else { log.debug("未找到匹配order_class='{}' 的分公司", code); } } return vehicleDepts; } /** * 同步车辆-分公司关联 * * @param vehicleId 车辆ID * @param vehicleDepts 分公司关联列表 */ private void syncVehicleDepts(Long vehicleId, List vehicleDepts) { if (vehicleId == null || vehicleDepts == null) { return; } // 先删除旧的关联 vehicleInfoMapper.deleteVehicleDeptByVehicleId(vehicleId); // 再插入新的关联 if (!vehicleDepts.isEmpty()) { for (VehicleDept vd : vehicleDepts) { vd.setVehicleId(vehicleId); } vehicleInfoMapper.batchInsertVehicleDept(vehicleDepts); log.debug("同步车辆ID={} 的分公司关联,数量: {}", vehicleId, vehicleDepts.size()); } } /** * 根据order_class查询部门(同时匹配dispatch_order_class和service_order_class) * * @param orderClass 编码 * @return 部门信息 */ private SysDept findDeptByOrderClass(String orderClass) { if (StringUtils.isBlank(orderClass)) { return null; } try { // 先尝试匹配dispatch_order_class SysDept query = new SysDept(); query.setDispatchOrderClass(orderClass); List depts = sysDeptMapper.selectDeptList(query); if (depts != null && !depts.isEmpty()) { return depts.get(0); } // 如果没有找到,尝试匹配service_order_class query = new SysDept(); query.setServiceOrderClass(orderClass); depts = sysDeptMapper.selectDeptList(query); if (depts != null && !depts.isEmpty()) { return depts.get(0); } } catch (Exception e) { log.error("查询order_class='{}' 的部门失败", orderClass, e); } return null; } }