puzhibing
2026-04-10 ed838e62602c0a63a64ff4bd144a0d16cc9a7cf8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.xiaopeng.operation.service.impl;
 
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.operation.config.UidVinBindingConfig;
import com.xiaopeng.operation.dto.PriorityMatchResult;
import com.xiaopeng.operation.dto.PriorityMatchResult.FailReason;
import com.xiaopeng.operation.service.IXpElectronicFenceAreaService;
import com.xiaopeng.operation.service.UidVinPriorityMatcher;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.util.Objects;
 
/**
 * UID-VIN 优先匹配执行器实现
 * <p>
 * 匹配流程:查绑定配置 → 查询车辆状态 → 校验可用条件 → 返回结果
 * </p>
 */
@Slf4j
@Service
public class UidVinPriorityMatcherImpl implements UidVinPriorityMatcher {
 
    @Resource
    private UidVinBindingConfig uidVinBindingConfig;
 
    @Resource
    private XpVehicleClient xpVehicleClient;
 
    @Resource
    private IXpElectronicFenceAreaService xpElectronicFenceAreaService;
 
    @Override
    public PriorityMatchResult tryPriorityMatch(String uid, String orderNo, String electronicAreaId) {
        log.info("[人车订单绑定测试] ===== 开始优先匹配, uid={}, orderNo={}, electronicAreaId={} =====", uid, orderNo, electronicAreaId);
 
        // 1. 查询绑定配置
        log.info("[人车订单绑定测试] 步骤1: 查询UID绑定配置, uid={}", uid);
        String vin = uidVinBindingConfig.getBoundVin(uid);
        if (vin == null) {
            log.info("[人车订单绑定测试] 步骤1结果: 该UID无绑定VIN, uid={}, orderNo={}", uid, orderNo);
            return PriorityMatchResult.fail(FailReason.NO_BINDING);
        }
        log.info("[人车订单绑定测试] 步骤1结果: 找到绑定关系, uid={}, vin={}", uid, vin);
 
        // 2. 查询车辆状态
        log.info("[人车订单绑定测试] 步骤2: 调用车队服务查询车辆状态, vin={}", vin);
        R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(vin);
        log.info("[人车订单绑定测试] 步骤2: 车队服务返回, code={}, data={}", vehicleR.getCode(), vehicleR.getData() != null ? "有数据" : "null");
        if (vehicleR.getCode() != R.SUCCESS || vehicleR.getData() == null) {
            log.info("[人车订单绑定测试] 步骤2结果: 车辆不存在或查询失败, uid={}, vin={}, orderNo={}, responseCode={}", uid, vin, orderNo, vehicleR.getCode());
            return PriorityMatchResult.fail(FailReason.VEHICLE_NOT_FOUND);
        }
 
        XpVehicle vehicle = vehicleR.getData();
        log.info("[人车订单绑定测试] 步骤2结果: 车辆信息获取成功, vin={}, plateNumber={}, operatingStatus={}, state={}, vehicleType={}, electronicId={}",
                vin, vehicle.getPlateNumber(), vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType(), vehicle.getElectronicId());
 
        // 3. 校验车辆可用条件:operatingStatus=1, state=0, vehicleType!=1
        log.info("[人车订单绑定测试] 步骤3: 校验车辆可用条件 (operatingStatus==1 && state==0 && vehicleType!=1)");
        if (!isVehicleAvailable(vehicle)) {
            if (!Objects.equals(vehicle.getState(), 0)) {
                log.info("[人车订单绑定测试] 步骤3结果: 车辆已接单(state={}), 当前有未完成订单, 无法指派, uid={}, vin={}, plateNumber={}, orderNo={}",
                        vehicle.getState(), uid, vin, vehicle.getPlateNumber(), orderNo);
            } else {
                log.info("[人车订单绑定测试] 步骤3结果: 车辆不可用, uid={}, vin={}, orderNo={}, operatingStatus={}, state={}, vehicleType={}",
                        uid, vin, orderNo, vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType());
            }
            return PriorityMatchResult.fail(FailReason.VEHICLE_UNAVAILABLE);
        }
        log.info("[人车订单绑定测试] 步骤3结果: 车辆可用条件校验通过");
 
        // 4. 校验电子围栏一致性:将 areaId 转换为 fenceId,与车辆的 electronicId 比较
        log.info("[人车订单绑定测试] 步骤4: 校验电子围栏一致性, 订单围栏区域ID={}, 车辆围栏ID={}", electronicAreaId, vehicle.getElectronicId());
        if (!isSameElectronicFence(vehicle, electronicAreaId)) {
            log.info("[人车订单绑定测试] 步骤4结果: 围栏不一致, uid={}, vin={}, orderNo={}, vehicleElectronicId={}, electronicAreaId={}",
                    uid, vin, orderNo, vehicle.getElectronicId(), electronicAreaId);
            return PriorityMatchResult.fail(FailReason.WRONG_AREA);
        }
        log.info("[人车订单绑定测试] 步骤4结果: 围栏校验通过");
 
        // 5. 所有校验通过
        log.info("[人车订单绑定测试] ===== 匹配成功, uid={}, vin={}, orderNo={} =====", uid, vin, orderNo);
        return PriorityMatchResult.success(vin);
    }
 
    /**
     * 校验车辆是否可用:运营中(1)、空闲(0)、非测试车(!=1)
     */
    private boolean isVehicleAvailable(XpVehicle vehicle) {
        return Objects.equals(vehicle.getOperatingStatus(), 1)
                && Objects.equals(vehicle.getState(), 0)
                && !Objects.equals(vehicle.getVehicleType(), 1);
    }
 
    /**
     * 校验车辆是否在同一电子围栏内
     * <p>
     * electronicAreaId 是围栏区域ID,需要通过 IXpElectronicFenceAreaService 查询
     * 对应的围栏ID(electronicId),再与车辆的 electronicId 比较。
     */
    private boolean isSameElectronicFence(XpVehicle vehicle, String electronicAreaId) {
        if (electronicAreaId == null || vehicle.getElectronicId() == null) {
            log.info("[人车订单绑定测试] 围栏校验: 参数为空, electronicAreaId={}, vehicleElectronicId={}", electronicAreaId, vehicle.getElectronicId());
            return false;
        }
        try {
            XpElectronicFenceArea area = xpElectronicFenceAreaService.getById(Long.parseLong(electronicAreaId));
            if (area == null || area.getElectronicId() == null) {
                log.info("[人车订单绑定测试] 围栏校验: 围栏区域不存在或无关联围栏, electronicAreaId={}", electronicAreaId);
                return false;
            }
            boolean same = Objects.equals(vehicle.getElectronicId(), area.getElectronicId());
            log.info("[人车订单绑定测试] 围栏校验: 车辆围栏ID={}, 区域关联围栏ID={}, 是否一致={}", vehicle.getElectronicId(), area.getElectronicId(), same);
            return same;
        } catch (NumberFormatException e) {
            log.info("[人车订单绑定测试] 围栏校验: electronicAreaId格式异常, electronicAreaId={}", electronicAreaId);
            return false;
        }
    }
}