3个文件已修改
150 ■■■■ 已修改文件
tms/src/main/java/com/ruoyi/tms/service/impl/TmsArBillServiceImpl.java 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tms/src/main/java/com/ruoyi/tms/service/impl/TmsDispatchOrderServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tms/src/main/java/com/ruoyi/tms/service/impl/TmsArBillServiceImpl.java
@@ -21,6 +21,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@@ -570,8 +571,8 @@
            String rateStr = sysConfigService.selectConfigByKey("sys.hk.rmb.rate");
            BigDecimal exchangeRate = new BigDecimal(rateStr);
            
            // 收集所有费用名称,用于动态生成列
            Set<String> feeNames = new HashSet<>();
            // 收集所有费用名称和对应的货币,用于动态生成列
            Map<String, String> feeCurrencyMap = new HashMap<>();
                for (TmsArBillItem item : bill.getItems()) {
                    // 应收费用ID
@@ -580,15 +581,33 @@
                    List<TmsReceivableFeeItem> tmsReceivableFeeItems = tmsReceivableFeeItemMapper.selectTmsReceivableFeeItemList(new TmsReceivableFeeItem() {{
                        setHeadId(arFeeId);
                    }});
                    // 从应收费用明细中收集费用名称
                    // 从应收费用明细中收集费用名称和货币
                    for (TmsReceivableFeeItem feeItem : tmsReceivableFeeItems) {
                        feeNames.add(feeItem.getFeeName());
                        feeCurrencyMap.put(feeItem.getFeeName(), feeItem.getCurrency());
                    }
                }
            
            // 将费用名称转换为列表,保持顺序
            List<String> feeNameList = new ArrayList<>(feeNames);
            // 将费用名称转换为列表,并按要求排序:运费放在最前面,杂费放在最后面
            List<String> feeNameList = new ArrayList<>();
            List<String> otherFees = new ArrayList<>();
            for (String feeName : feeCurrencyMap.keySet()) {
                if ("运费".equals(feeName)) {
                    feeNameList.add(feeName);
                } else if ("杂费".equals(feeName)) {
                    otherFees.add(feeName);
                } else {
                    otherFees.add(feeName);
                }
            }
            // 添加其他费用
            feeNameList.addAll(otherFees.stream().filter(fee -> !"杂费".equals(fee)).collect(Collectors.toList()));
            // 添加杂费到最后
            if (feeCurrencyMap.containsKey("杂费")) {
                feeNameList.add("杂费");
            }
            
            // 基础列数(序号、装货日期、装货点、卸货点、车牌、型号)
            int baseColumns = 6;
@@ -614,7 +633,7 @@
            createTitleArea(sheet, styles,bill);
            
            // 表头
            createDynamicTableHeader(sheet, styles, feeNameList, baseColumns, remarkColumn);
            createDynamicTableHeader(sheet, styles, feeNameList, feeCurrencyMap, baseColumns, remarkColumn);
            
            // 数据区域
            int startRow = 5;
@@ -687,12 +706,8 @@
                        }});
                        // 处理应收费用明细
                        for (TmsReceivableFeeItem feeItem : tmsReceivableFeeItems) {
                            BigDecimal amount = feeItem.getRegisterAmount();
                            // 如果是港币,转换为人民币
                            if ("HKD".equals(feeItem.getCurrency()) || "港币".equals(feeItem.getCurrency())) {
                                amount = amount.multiply(exchangeRate).setScale(2, RoundingMode.HALF_UP);
                            }
                            feeMap.put(feeItem.getFeeName(), amount);
                            // 保持原始金额,不进行币种转换
                            feeMap.put(feeItem.getFeeName(), feeItem.getRegisterAmount());
                        }
                        
                        // 填充费用列
@@ -707,9 +722,9 @@
                            feeTotals.put(feeName, feeTotals.get(feeName).add(feeAmount));
                        }
                        
                        // 备注
                        // 备注 - 为空
                        Cell remarkCell = row.createCell(remarkColumn);
                        remarkCell.setCellValue("" + (fee.getDispatchNo() != null ? fee.getDispatchNo() : ""));
                        remarkCell.setCellValue("");
                        remarkCell.setCellStyle(styles.get("data"));
                        
                        rowIndex++;
@@ -746,13 +761,24 @@
                if (i == 0) {
                    cell.setCellValue("合计(RMB)");
                }
                // 合计行的备注设置汇率
                if (i == remarkColumn) {
                    cell.setCellValue("汇率: " + exchangeRate);
                }
                cell.setCellStyle(styles.get("total"));
            }
            sheet.addMergedRegion(new CellRangeAddress(totalRow, totalRow, 0, 5));
            // 计算所有费用的合计
            // 计算所有费用的合计(转换为人民币)
            BigDecimal grandTotal = BigDecimal.ZERO;
            for (BigDecimal amount : feeTotals.values()) {
            for (String feeName : feeTotals.keySet()) {
                BigDecimal amount = feeTotals.get(feeName);
                // 获取该费用的币种
                String currency = feeCurrencyMap.get(feeName);
                // 如果是港币,转换为人民币
                if ("HKD".equals(currency) || "港币".equals(currency)) {
                    amount = amount.multiply(exchangeRate).setScale(2, RoundingMode.HALF_UP);
                }
                grandTotal = grandTotal.add(amount);
            }
            
@@ -898,7 +924,6 @@
     *
     * @param sheet 工作表
     * @param styles 样式映射
     * @param tmsReceivableFee 应收费用查询条件
     */
    private void createTitleArea(SXSSFSheet sheet, Map<String, CellStyle> styles, TmsArBill tmsArBill) {
        // 标题行(无边框,居中)
@@ -964,10 +989,11 @@
     * @param sheet 工作表
     * @param styles 样式映射
     * @param feeNameList 费用名称列表
     * @param feeCurrencyMap 费用名称到货币的映射
     * @param baseColumns 基础列数
     * @param remarkColumn 备注列位置
     */
    private void createDynamicTableHeader(SXSSFSheet sheet, Map<String, CellStyle> styles, List<String> feeNameList, int baseColumns, int remarkColumn) {
    private void createDynamicTableHeader(SXSSFSheet sheet, Map<String, CellStyle> styles, List<String> feeNameList, Map<String, String> feeCurrencyMap, int baseColumns, int remarkColumn) {
        Row headerRow = sheet.createRow(4);
        headerRow.setHeightInPoints(25);
        
@@ -982,7 +1008,10 @@
        // 费用列
        for (int i = 0; i < feeNameList.size(); i++) {
            Cell cell = headerRow.createCell(baseColumns + i);
            cell.setCellValue(feeNameList.get(i) + "(人民币)");
            String feeName = feeNameList.get(i);
            String currency = feeCurrencyMap.get(feeName);
            cell.setCellValue(feeName + "(" + currency + ")");
            cell.setCellStyle(styles.get("header"));
        }
        
tms/src/main/java/com/ruoyi/tms/service/impl/TmsDispatchOrderServiceImpl.java
@@ -1207,6 +1207,7 @@
                // 2、 获取实报实销费用
                List<TmsFinanceDetail> tmsFinanceDetails = tmsFinanceDetailService.selectTmsFinanceDetailList(new TmsFinanceDetail() {{
                    setDispatchOrderId(tmsDispatchOrder.getId());
                    setStatus(0);
                }});
                if (tmsFinanceDetails != null && !tmsFinanceDetails.isEmpty()){
@@ -1326,6 +1327,7 @@
                // 2、 获取实报实销费用
                List<TmsFinanceDetail> tmsFinanceDetails = tmsFinanceDetailService.selectTmsFinanceDetailList(new TmsFinanceDetail() {{
                    setDispatchOrderId(tmsDispatchOrder.getId());
                    setStatus(0);
                    setIsYF(1);
                }});
ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue
@@ -202,7 +202,7 @@
            &nbsp;
          </el-link>
        </el-tooltip>
        <!--
        <!--
        <el-tooltip content="完成行程" placement="top">
          <el-link size="small" type="primary" v-if="[2].includes(row.status)" @click="handleOk(row)" class="link-btn"
            v-hasPermi="['tms:tmsDispatchOrder:okOrder']" underline="never" icon="el-icon-circle-check">
@@ -319,7 +319,7 @@
      </div>
      <div v-if="optionType == 'loading'">
            <el-descriptions v-if="optionNum == 'radio'" style="margin-bottom: 20px" :column="2" border>
        <el-descriptions v-if="optionNum == 'radio'" style="margin-bottom: 20px" :column="2" border>
          <el-descriptions-item label="调度单号">{{ form.dispatchNo }}</el-descriptions-item>
          <el-descriptions-item label="客户">{{ form.customerName }}</el-descriptions-item>
          <el-descriptions-item label="项目名称">{{ form.projectName }}</el-descriptions-item>
@@ -728,6 +728,7 @@
const boxFormRef = ref();
const goodsCrudRef = ref();
const actualFormRef = ref();
const isAutoSettingVehicle = ref(false);
/**
 * 字典公共转换函数
 */
@@ -1356,38 +1357,52 @@
              message: "主驾驶员不能为空", trigger: "change"
            }
          ],
          change: (val: any) => {
            // 防止重复执行
          // 在 mainDriverId 的 change 事件中
          change: async (val: any) => {
            if (data.isChanging) return;
            data.isChanging = true;
            isAutoSettingVehicle.value = true;
            const table = crudRef.value?.getPropRef?.('mainDriverId')?.$refs?.temp;
            if (!table) {
              data.isChanging = false;
              isAutoSettingVehicle.value = false;
              return;
            }
            let active = table.active;
            if (Array.isArray(active)) active = active[0];
               console.log('自动填充成功:', active);
            if (active && active.driverName) {
              try {
            if (active) {
              Object.assign(form.value, {
                mainDriverId: active.id,
                mainDriverName: active.driverName,
              });
                await nextTick(); // 等待清空生效
                const res = await getLastLicensePlate(active.driverName);
              // 获取车牌号并赋值
              getLastLicensePlate(active.driverName).then(res => {
                if (res.code == 200) {
                  form.value.licensePlate = res.data.licensePlate;
                  form.value.vehicleId = res.data.vehicleId
                  form.value.actualVehicleType = res.data.vehicleType;
                if (res.code === 200 && res.data) {
                  const vehicleData = res.data;
                  nextTick(() => {
                    Object.assign(form.value, {
                      licensePlate: vehicleData.licensePlate,
                      vehicleId: vehicleData.vehicleId,
                      actualVehicleType: vehicleData.actualVehicleType,
                      driverName: vehicleData.driverName,
                    });
                  })
                  await nextTick();
                  console.log('自动填充成功:', form.value);
                }
              }).finally(() => {
              } catch (e) {
                console.error("自动获取车牌失败", e);
              } finally {
                data.isChanging = false;
              });
                setTimeout(() => {
                  // isAutoSettingVehicle.value = false;
                }, 500); // 稍微延长一点时间,防止 vehicleId 的 change 事件误触
              }
            } else {
              data.isChanging = false;
              // isAutoSettingVehicle.value = false;
            }
          },
          // change: (val: any) => {
@@ -1403,7 +1418,7 @@
          //       mainDriverName: active.driverName,
          //     });
          //     console.log(active.driverName,'44');
          //     getLastLicensePlate(active.driverName).then(res => {
          //     getLastLicensePlate(active.driverName).then(res => {
          //       console.log(res);
          //     })
@@ -1415,7 +1430,7 @@
            searchMenuSpan: 5,
            column: {
              vehicleProviderName: {
                label: '车辆服务商1', minWidth: 130,
                label: '车辆服务商', minWidth: 130,
                search: true,
              },
              driverName: {
@@ -1506,6 +1521,8 @@
              if (Array.isArray(value)) {
                id = value[0]
              }
              console.log(98521);
              getTmsDriver(id).then(res => {
                return callback(res.data || {})
              })
@@ -1534,11 +1551,19 @@
              message: "车牌号不能为空", trigger: "change"
            }
          ],
          // vehicleId 配置中的 change
          change: (val: any) => {
            // 如果是自动填充触发的,直接返回,不执行后续逻辑
            if (isAutoSettingVehicle.value) {
              return;
            }
            const table = crudRef.value?.getPropRef?.('vehicleId')?.$refs?.temp;
            if (!table) return;
            let active = table.active;
            if (Array.isArray(active)) active = active[0];
            console.log(9852);
            if (active) {
              Object.assign(form.value, {
                vehicleId: active.id,
@@ -1592,10 +1617,14 @@
              if (Array.isArray(value)) {
                id = value[0]
              }
              console.log(555, 'xq1');
              getTmsVehicle(id).then(res => {
                return callback(res.data || {})
              })
            } else {
              console.log(444, 'xq1');
              listTmsVehicle({
                pageSize: page.pageSize,
                pageNum: page.currentPage, ...data,
@@ -2615,10 +2644,14 @@
          if (Array.isArray(value)) {
            id = value[0]
          }
          console.log(998, 'xq1');
          getTmsVehicle(id).then(res => {
            return callback(res.data || {})
          })
        } else {
          console.log(669, 'xq2');
          listTmsVehicle({ pageSize: page.pageSize, pageNum: page.currentPage, ...data }).then(res => {
            return callback({
              total: res.total,
@@ -3563,7 +3596,7 @@
          customsServiceProviderName: form.value.customsServiceProviderName
        };
      });
    }else if (optionNum.value == 'radio') {
    } else if (optionNum.value == 'radio') {
      result = [{
        id: form.value.id,
        customsServiceProviderId: form.value.customsServiceProviderId,
@@ -3583,7 +3616,7 @@
    })
  } else if (optionType.value === 'loading') {
       let result = <any>[];
    let result = <any>[];
    if (optionNum.value == 'checkbox') {
      result = clearanceList.value.map(item => {
        return {
@@ -3592,7 +3625,7 @@
          loadingServiceProviderName: form.value.loadingServiceProviderName
        };
      });
    }else if (optionNum.value == 'radio') {
    } else if (optionNum.value == 'radio') {
      result = [{
        id: form.value.id,
        loadingServiceProviderId: form.value.loadingServiceProviderId,
@@ -4247,7 +4280,7 @@
const handleCustomsAdd = (row) => {
  title.value = '补充委托装卸信息';
   clearanceList.value = [];
  clearanceList.value = [];
  // 2. 清除表格视觉上的选中状态
  if (crudRef.value) {
    crudRef.value.clearSelection();