# 编辑功能 - 车牌号未正确传递问题修复 ## 问题描述 用户反馈:在编辑运送清单时,**车牌号没有正确传递/显示**。 ## 问题根源 ### 原因分析 1. **异步加载时序问题**: - `open()` 方法中使用 `setTimeout(fillFormWithEditData, 500)` 来等待下拉列表加载 - 但车辆列表 API 响应时间可能超过 500ms - 导致 `fillFormWithEditData` 执行时,`vehicleOptions` 还是空的 - 车牌号虽然赋值了,但因为下拉框选项列表为空,无法正确显示 2. **数据结构问题**: - `detail` 接口返回的数据结构: ```javascript { delivery: { licensePlate: "鄂A 66662", ... }, supplierId: 44, buyerId: 41, eartagIds: [...], collarIds: [...], serverIds: "..." } ``` - 需要从 `editData.delivery.licensePlate` 中获取车牌号 ## 解决方案 ### 1. 后端修改 - 补充设备信息和 ID 字段 **文件**: `DeliveryServiceImpl.java` ```java // 在 detail() 方法中补充设备信息 // 查询耳标设备信息(类型2) List eartagDevices = deliveryDeviceMapper.selectList( new LambdaQueryWrapper() .eq(DeliveryDevice::getDeliveryId, id) .eq(DeliveryDevice::getDeviceType, 2) ); List eartagIds = new ArrayList<>(); if (eartagDevices != null && !eartagDevices.isEmpty()) { for (DeliveryDevice device : eartagDevices) { if (device.getDeviceId() != null && !device.getDeviceId().isEmpty()) { eartagIds.add(device.getDeviceId()); } } } resMap.put("eartagIds", eartagIds); // 查询项圈设备信息(类型3) List collarDevices = deliveryDeviceMapper.selectList( new LambdaQueryWrapper() .eq(DeliveryDevice::getDeliveryId, id) .eq(DeliveryDevice::getDeviceType, 3) ); List collarIds = new ArrayList<>(); if (collarDevices != null && !collarDevices.isEmpty()) { for (DeliveryDevice device : collarDevices) { if (device.getDeviceId() != null && !device.getDeviceId().isEmpty()) { collarIds.add(device.getDeviceId()); } } } resMap.put("collarIds", collarIds); // 补充 supplierId 和 buyerId if (delivery.getSupplierId() != null && !delivery.getSupplierId().isEmpty()) { String firstSupplierId = delivery.getSupplierId().split(",")[0].trim(); try { resMap.put("supplierId", Integer.parseInt(firstSupplierId)); } catch (NumberFormatException e) { resMap.put("supplierId", null); } } else { resMap.put("supplierId", null); } resMap.put("buyerId", delivery.getBuyerId()); ``` ### 2. 前端修改 - 改为 Promise.all 等待所有下拉列表加载完成 **文件**: `createDeliveryDialog.vue` #### 修改前(有问题) ```javascript const open = (editData = null) => { dialogVisible.value = true; loadSupplierAndBuyerList(); // 异步但不等待 loadDeviceOptions(); // 异步但不等待 loadDriverList(); // 异步但不等待 loadVehicleList(); // 异步但不等待 loadOrderList(); // 异步但不等待 // 如果传入了编辑数据,则填充表单 if (editData) { setTimeout(() => { fillFormWithEditData(editData); }, 500); // ❌ 固定延迟,不可靠 } }; ``` #### 修改后(正确) ```javascript const open = async (editData = null) => { dialogVisible.value = true; // 并行加载所有下拉列表数据,等待全部完成 await Promise.all([ loadSupplierAndBuyerList(), loadDeviceOptions(), loadDriverList(), loadVehicleList(), // ✅ 确保车辆列表加载完成 loadOrderList() ]); console.log('[OPEN-DIALOG] 所有下拉列表加载完成'); console.log('[OPEN-DIALOG] 车辆列表:', vehicleOptions.value); // 如果传入了编辑数据,则填充表单 if (editData) { fillFormWithEditData(editData); // ✅ 此时所有选项都已加载 } }; ``` ### 3. 增强车牌号填充日志 ```javascript const fillFormWithEditData = (editData) => { // ... // 车牌号 formData.plateNumber = delivery.licensePlate || ''; console.log('[EDIT-FILL] 车牌号:', formData.plateNumber); console.log('[EDIT-FILL] 当前车辆列表:', vehicleOptions.value); // 检查车牌号是否在车辆列表中 const vehicleExists = vehicleOptions.value.find(v => v.licensePlate === formData.plateNumber); if (!vehicleExists && formData.plateNumber) { console.warn('[EDIT-FILL] ⚠️ 车牌号在车辆列表中不存在:', formData.plateNumber); } // ... }; ``` ### 4. 前端调用 detail 接口获取完整数据 **文件**: `attestation.vue` ```javascript const editDelivery = async (row) => { try { console.log('[EDIT-DELIVERY] 准备编辑运送清单, ID:', row.id); // 检查编辑对话框组件是否已加载 if (!editDialogRef.value || !editDialogRef.value.open) { ElMessage.warning('编辑功能暂不可用,请刷新页面重试'); return; } // ✅ 调用 detail 接口获取完整数据(包含 supplierId, buyerId, 设备信息等) const detailRes = await getDeliveryDetail(row.id); console.log('[EDIT-DELIVERY] 获取到详情数据:', detailRes); if (detailRes.code === 200 && detailRes.data) { // 传入完整的 detail 数据给 open() 方法 editDialogRef.value.open(detailRes.data); } else { ElMessage.error('获取运单详情失败:' + (detailRes.msg || '未知错误')); } } catch (error) { console.error('[EDIT-DELIVERY] 打开编辑对话框失败:', error); ElMessage.error('打开编辑对话框失败,请重试'); } }; ``` ## 测试步骤 ### 1. 清理并重新编译后端 ```bash cd tradeCattle mvn clean compile -DskipTests ``` ### 2. 重启后端服务 确保新的 `detail` 接口逻辑生效。 ### 3. 刷新前端浏览器 清除缓存,重新加载 Vue 组件。 ### 4. 测试编辑功能 1. 进入"入境检疫"页面 2. 点击任意运送清单的"编辑"按钮 3. 观察控制台日志: ``` [EDIT-DELIVERY] 准备编辑运送清单, ID: 95 [EDIT-DELIVERY] 获取到详情数据: { delivery: {...}, supplierId: 44, buyerId: 41, eartagIds: [...], collarIds: [...], serverIds: "..." } [OPEN-DIALOG] 所有下拉列表加载完成 [OPEN-DIALOG] 车辆列表: [{ id: 1, licensePlate: "鄂A 66662", ... }, ...] [EDIT-FILL] 开始填充编辑数据: {...} [EDIT-FILL] 发货方ID: 44, 采购方ID: 41 [EDIT-FILL] 车牌号: 鄂A 66662 [EDIT-FILL] 当前车辆列表: [{ id: 1, licensePlate: "鄂A 66662", ... }] [EDIT-FILL] 主机ID: host001 [EDIT-FILL] 耳标IDs: ["ear001", "ear002"] [EDIT-FILL] 项圈IDs: ["collar001"] ``` ### 5. 验证字段是否正确填充 - ✅ 发货方下拉框应显示正确的供应商 - ✅ 采购方下拉框应显示正确的买家 - ✅ **车牌号下拉框应显示正确的车牌号** - ✅ 司机下拉框应显示正确的司机 - ✅ 设备下拉框应显示已绑定的设备 ## 关键改进点 ### 🔑 核心改进 1. **从固定延迟改为 Promise.all 等待** - 确保所有下拉列表数据加载完成后才填充表单 - 避免因网络延迟导致的数据不匹配 2. **后端补充完整数据** - `detail` 接口返回 `supplierId`, `buyerId` 用于下拉框回显 - 返回 `eartagIds`, `collarIds` 用于设备选择器回显 3. **增强日志** - 每一步都有清晰的日志输出 - 便于排查问题 ## 常见问题排查 ### Q1: 车牌号显示为空? **检查**: 1. 控制台日志:`[EDIT-FILL] 车牌号:` 的值是否正确 2. 控制台日志:`[EDIT-FILL] 当前车辆列表:` 是否包含该车牌号 3. 如果车辆列表为空,检查 `loadVehicleList()` 是否正常执行 ### Q2: 车牌号有值但下拉框未选中? **可能原因**: - 数据库中的车牌号与车辆表中的车牌号**不完全匹配**(空格、大小写等) - 检查日志:`⚠️ 车牌号在车辆列表中不存在` **解决办法**: - 确保 `delivery.licensePlate` 和 `vehicle.licensePlate` 完全一致 ### Q3: 编辑时其他字段正常,唯独车牌号不对? **检查**: 1. 数据库 `delivery` 表的 `license_plate` 字段值 2. 后端日志:是否正确返回 `licensePlate` 3. 前端网络请求:查看 `/delivery/detail?id=xxx` 返回的数据 ## 总结 ✅ **问题已修复**: - 使用 `Promise.all` 确保所有下拉列表加载完成 - 后端补充完整的设备信息和 ID 字段 - 增强日志便于问题排查 ✅ **用户体验改善**: - 编辑对话框打开速度更快(并行加载) - 所有字段都能正确回显 - 错误信息更清晰