package com.ruoyi.unattended.access.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.unattended.access.dto.AccessVerifyRequest; import com.ruoyi.unattended.access.mapper.AccessGateMapper; import com.ruoyi.unattended.access.mapper.AccessRecordMapper; import com.ruoyi.unattended.access.mapper.AccessVehicleMapper; import com.ruoyi.unattended.access.pojo.AccessGate; import com.ruoyi.unattended.access.pojo.AccessRecord; import com.ruoyi.unattended.access.pojo.AccessVehicle; import com.ruoyi.unattended.access.service.AccessService; import com.ruoyi.unattended.pojo.UnattendedOperation; import com.ruoyi.unattended.service.UnattendedOperationService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Slf4j @Service public class AccessServiceImpl implements AccessService { @Resource private AccessGateMapper accessGateMapper; @Resource private AccessRecordMapper accessRecordMapper; @Resource private AccessVehicleMapper accessVehicleMapper; @Resource private UnattendedOperationService unattendedOperationService; @Override public IPage gatePage(Page page, AccessGate query) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .like(StringUtils.hasText(query.getGateName()), AccessGate::getGateName, query.getGateName()) .like(StringUtils.hasText(query.getArea()), AccessGate::getArea, query.getArea()) .orderByDesc(AccessGate::getCreateTime); return accessGateMapper.selectPage(page, wrapper); } @Override public boolean gateSave(AccessGate gate) { if (!StringUtils.hasText(gate.getDeviceStatus())) { gate.setDeviceStatus("online"); } if (!StringUtils.hasText(gate.getGateType())) { gate.setGateType("all"); } return accessGateMapper.insert(gate) > 0; } @Override public boolean gateUpdate(AccessGate gate) { return accessGateMapper.updateById(gate) > 0; } @Override public boolean gateRemove(List ids) { if (CollectionUtils.isEmpty(ids)) { return false; } return accessGateMapper.deleteBatchIds(ids) > 0; } /* ---------- 车辆通行授权 ---------- */ @Override public IPage vehiclePage(Page page, AccessVehicle query) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .like(StringUtils.hasText(query.getPlateNumber()), AccessVehicle::getPlateNumber, query.getPlateNumber()) .like(StringUtils.hasText(query.getRfidTag()), AccessVehicle::getRfidTag, query.getRfidTag()) .like(StringUtils.hasText(query.getCarrierName()), AccessVehicle::getCarrierName, query.getCarrierName()) .eq(StringUtils.hasText(query.getStatus()), AccessVehicle::getStatus, query.getStatus()) .orderByDesc(AccessVehicle::getId); return accessVehicleMapper.selectPage(page, wrapper); } @Override public boolean vehicleSave(AccessVehicle vehicle) { if (!StringUtils.hasText(vehicle.getStatus())) { vehicle.setStatus("valid"); } return accessVehicleMapper.insert(vehicle) > 0; } @Override public boolean vehicleUpdate(AccessVehicle vehicle) { return accessVehicleMapper.updateById(vehicle) > 0; } @Override public boolean vehicleRemove(List ids) { if (CollectionUtils.isEmpty(ids)) { return false; } return accessVehicleMapper.deleteBatchIds(ids) > 0; } private AccessVehicle matchVehicle(String plateNumber, String rfidTag) { AccessVehicle byPlate = null; if (StringUtils.hasText(plateNumber)) { byPlate = accessVehicleMapper.selectOne(Wrappers.lambdaQuery() .eq(AccessVehicle::getPlateNumber, plateNumber).last("limit 1")); } if (byPlate != null) { return byPlate; } if (StringUtils.hasText(rfidTag)) { return accessVehicleMapper.selectOne(Wrappers.lambdaQuery() .eq(AccessVehicle::getRfidTag, rfidTag).last("limit 1")); } return null; } /** * 识别核验 + 放行判定 + 记录。 * * 车辆:车牌识别 + RFID 双要素,识别到即放行;在车辆档案中的车辆补充承运商信息; * 人员:人脸识别 + 工卡刷卡 双要素; * 地磅联动:指定 weighbridgeRecordId 时,校验该地磅记录存在且红外检测无异常。 */ @Override @Transactional(rollbackFor = Exception.class) public AccessRecord verify(AccessVerifyRequest request) { AccessRecord record = new AccessRecord(); record.setAccessTime(LocalDateTime.now()); record.setGateId(request.getGateId()); record.setDirection(StringUtils.hasText(request.getDirection()) ? request.getDirection() : "in"); record.setCarrierName(request.getCarrierName()); record.setWeighbridgeRecordId(request.getWeighbridgeRecordId()); record.setWeighbridgeLinked(Boolean.TRUE.equals(request.getWeighbridgeLinked()) ? 1 : 0); AccessGate gate = request.getGateId() == null ? null : accessGateMapper.selectById(request.getGateId()); if (gate != null) { record.setGateName(gate.getGateName()); } List methods = new ArrayList<>(); List rejects = new ArrayList<>(); boolean verified = false; if ("person".equalsIgnoreCase(request.getAccessType())) { record.setAccessType("person"); record.setPersonName(request.getPersonName()); record.setWorkCardNo(request.getWorkCardNo()); record.setIdCardFace(request.getIdCardFace()); if ("matched".equalsIgnoreCase(request.getIdCardFace())) { methods.add("人脸识别"); } if (StringUtils.hasText(request.getWorkCardNo())) { methods.add("工卡"); } // 双要素:人脸 + 工卡 if (!StringUtils.hasText(request.getPersonName()) || !"matched".equalsIgnoreCase(request.getIdCardFace())) { rejects.add("人脸识别未通过"); } if (!StringUtils.hasText(request.getWorkCardNo())) { rejects.add("未刷工卡"); } verified = rejects.isEmpty(); } else { record.setAccessType("vehicle"); record.setPlateNumber(request.getPlateNumber()); record.setRfidTag(request.getRfidTag()); // 车牌识别 + RFID 双因子,识别到即视为通过;未登记车辆不拦截 if (StringUtils.hasText(request.getPlateNumber())) { methods.add("车牌识别"); } else { rejects.add("车牌识别失败"); } if (StringUtils.hasText(request.getRfidTag())) { methods.add("RFID"); } else { rejects.add("RFID标签未识别"); } if (rejects.isEmpty()) { AccessVehicle vehicle = matchVehicle(request.getPlateNumber(), request.getRfidTag()); if (vehicle != null) { if (!StringUtils.hasText(record.getCarrierName()) && StringUtils.hasText(vehicle.getCarrierName())) { record.setCarrierName(vehicle.getCarrierName()); } if ("disabled".equalsIgnoreCase(vehicle.getStatus())) { rejects.add("该车辆通行授权已停用"); } } } verified = rejects.isEmpty(); } // 地磅联动校验 if (Boolean.TRUE.equals(request.getWeighbridgeLinked())) { if (request.getWeighbridgeRecordId() == null) { rejects.add("缺少关联地磅记录"); verified = false; } else { UnattendedOperation op = unattendedOperationService.getById(request.getWeighbridgeRecordId()); if (op == null) { rejects.add("关联地磅记录不存在"); verified = false; } else { if (StringUtils.hasText(op.getCarrierName())) { record.setCarrierName(op.getCarrierName()); } if (op.getCheatFlag() != null && op.getCheatFlag() == 1) { rejects.add("地磅检测异常:" + (op.getCheatReason() == null ? "车辆位置偏移" : op.getCheatReason())); verified = false; } if ("alarm".equalsIgnoreCase(op.getInfraredStatus())) { rejects.add("红外检测报警"); verified = false; } } } } record.setVerifyMethod(methods.isEmpty() ? null : String.join("+", methods)); if (verified && rejects.isEmpty()) { record.setVerifyResult("pass"); record.setReleaseStatus("released"); record.setRejectReason(null); } else { record.setVerifyResult("reject"); record.setReleaseStatus("blocked"); record.setRejectReason(String.join(";", rejects)); } accessRecordMapper.insert(record); if ("vehicle".equals(record.getAccessType()) && "released".equals(record.getReleaseStatus())) { log.info("[门禁放行] 车牌={} 门禁={} 方式={}", record.getPlateNumber(), record.getGateName(), record.getVerifyMethod()); } return record; } @Override public IPage recordPage(Page page, AccessRecord query) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .like(StringUtils.hasText(query.getPlateNumber()), AccessRecord::getPlateNumber, query.getPlateNumber()) .like(StringUtils.hasText(query.getPersonName()), AccessRecord::getPersonName, query.getPersonName()) .eq(StringUtils.hasText(query.getAccessType()), AccessRecord::getAccessType, query.getAccessType()) .eq(StringUtils.hasText(query.getGateId() == null ? null : String.valueOf(query.getGateId())), AccessRecord::getGateId, query.getGateId()) .orderByDesc(AccessRecord::getAccessTime); return accessRecordMapper.selectPage(page, wrapper); } }