sen
2026-03-31 cc41746818af3b619167947ecb4401ccdfbec2d8
ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue
@@ -155,7 +155,7 @@
        </el-tooltip>
        <el-tooltip content="查看行程" placement="top">
          <el-link size="small" type="primary" v-if="![0, 1].includes(row.status)" @click="handleLogItinerary(row)"
            v-hasPermi="['tms:tmsTrip:list']" class="link-btn" underline="never" icon="el-icon-view">
            v-hasPermi="['tms:tmsTrip:list']" class="link-btn" underline="never" icon="Finished">
            &nbsp;
          </el-link>
        </el-tooltip>
@@ -165,13 +165,13 @@
            &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">
            &nbsp;
          </el-link>
        </el-tooltip>
        </el-tooltip> -->
        <el-tooltip content="日志" placement="top">
          <el-link size="small" type="primary" @click="handleFlow(row)" class="link-btn"
@@ -214,7 +214,7 @@
            min="0"></el-input-number>
        </template>
      </avue-crud>
      <h2 v-if="optionType == 'addFinance'">实报实销费用1</h2>
      <h2 v-if="optionType == 'addFinance'">实报实销费用</h2>
      <avue-form v-if="optionType == 'addItinerary' || optionType == 'addFinance'" v-model="boxForm" ref="boxFormRef"
        :option="boxFormOption">
@@ -348,7 +348,7 @@
      </avue-crud>
      <div v-if="active === 'tab4'">
        <h2>实报实销费用</h2>
        <h2>实报实销费用3</h2>
        <!-- <avue-form v-model="boxForm" ref="boxFormRef" :option="boxFormOption">
        </avue-form> -->
@@ -357,7 +357,6 @@
            <el-input-number v-model="row.actualFeeAmount" :precision="2" :min="0" controls-position="right"
              placeholder="输入金额" style="width: 100%" />
          </template>
          <template #currency="{ row }">
            <el-radio-group v-model="row.currency">
              <el-radio v-for="item in sys_currency" :key="item.value" :label="item.value">
@@ -366,8 +365,19 @@
            </el-radio-group>
          </template>
          <template #voucherUrl="{ row }">
            <avue-upload v-model="row.voucherUrl" :action="'/common/upload2'" type="upload" accept="image/*"
              @upload-after="(res, done, loading, column) => handleUploadAfter(res, done, loading, column, row)"></avue-upload>
            <!-- <avue-upload v-model="row.voucherUrl" :action="'/common/upload2'" type="upload" accept="image/*"
              @upload-after="(res, done, loading, column) => handleUploadAfter(res, done, loading, column, row)"></avue-upload> -->
            <!-- 凭证图片 -->
            <el-upload class="upload-demo" ref="uploadRef" :limit="1" drag :action="urlApi + '/common/upload2'" multiple
              :show-file-list="true" :on-success="(res) => handleUploadAfter(res, row)"
              :on-exceed="(files) => handleExceed(files, row)">
              <el-icon class="el-icon--upload"><upload-filled /></el-icon>
              <div class="el-upload__text">
                点击或将图片拖拽到此区域上传
              </div>
            </el-upload>
          </template>
          <template #remark="{ row }">
            <el-input v-model="row.remark" placeholder="填写备注" clearable />
@@ -503,7 +513,7 @@
        <div class="dialog-footer">
          <el-button @click="print = 0" v-if="print == 1">重新填写</el-button>
          <el-button type="primary" :loading="pageF.isUploading" @click="submitForm6">
            {{ pageF.isUploading ? '提交中' : '确 定2' }}
            {{ pageF.isUploading ? '提交中' : '确 定' }}
          </el-button>
          <el-button @click="open6 = false">取 消</el-button>
@@ -611,10 +621,11 @@
  printDispatchOrder,
  importTemplateTmsDispatchOrder, ypdddjSumbit,
  tmsTmsDispatchOrderImportLog,
  saveTmsFinanceDetail2
  saveTmsFinanceDetail2,
  getLastLicensePlate
} from "@/api/tms/tmsDispatchOrder";
import useCurrentInstance from "@/utils/useCurrentInstance";
import { computed, onMounted, reactive, ref, toRefs, watch, getCurrentInstance, nextTick } from "vue";
import { computed, onMounted, onBeforeUnmount, reactive, ref, toRefs, watch, getCurrentInstance, nextTick } from "vue";
import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface";
import { usePagePlus } from "@/hooks/usePagePlus";
import { hasPermission } from "@/utils/permissionUtils";
@@ -743,7 +754,7 @@
  labelWidth: 130,
  searchSpan: 6,
  searchLabelWidth: 150,
  menuWidth: 300,
  menuWidth: 350,
  height: 530,
  group: [
    {
@@ -1152,7 +1163,6 @@
            }
          ],
          change: ({ value }: any) => {
            console.log(value)
            option.value.group.forEach((item: any) => {
              if (item.prop == 'pcxx') {
                item.column.commissionModel.display = value != 1;
@@ -1275,24 +1285,64 @@
            }
          ],
          change: (val: any) => {
            // 防止重复执行
            if (data.isChanging) return;
            data.isChanging = true;
            const table = crudRef.value?.getPropRef?.('mainDriverId')?.$refs?.temp;
            if (!table) return;
            if (!table) {
              data.isChanging = false;
              return;
            }
            let active = table.active;
            if (Array.isArray(active)) active = active[0];
            if (active) {
              Object.assign(form.value, {
                mainDriverId: active.id,
                mainDriverName: active.driverName,
              });
              // 获取车牌号并赋值
              getLastLicensePlate(active.driverName).then(res => {
                if (res.code == 200) {
                  form.value.licensePlate = res.data.licensePlate;
                    form.value.vehicleId = res.data.vehicleId
                }
              }).finally(() => {
                data.isChanging = false;
              });
            } else {
              data.isChanging = false;
            }
          },
          // change: (val: any) => {
          //   const table = crudRef.value?.getPropRef?.('mainDriverId')?.$refs?.temp;
          //   if (!table) return;
          //   let active = table.active;
          //   if (Array.isArray(active)) active = active[0];
          //   console.log(active,'888');
          //   if (active) {
          //     Object.assign(form.value, {
          //       mainDriverId: active.id,
          //       mainDriverName: active.driverName,
          //     });
          //     console.log(active.driverName,'44');
          //     getLastLicensePlate(active.driverName).then(res => {
          //       console.log(res);
          //     })
          //   }
          // },
          type: 'table', suffixIcon: 'search',
          children: {
            border: true,
            searchMenuSpan: 5,
            column: {
              vehicleProviderName: {
                label: '车辆服务商', minWidth: 130,
                label: '车辆服务商1', minWidth: 130,
                search: true,
              },
              driverName: {
@@ -1403,7 +1453,7 @@
        },
        vehicleId: {
          label: '车牌号', dataType: 'string',
          label: '车牌号1', dataType: 'string',
          display: true,
          rules: [
            {
@@ -2182,7 +2232,7 @@
    },
  }
})
const urlApi = ref(import.meta.env.VITE_APP_BASE_API)
const itineraryTableOption = ref({
  menu: false,
  addBtn: false,
@@ -2261,19 +2311,19 @@
      ],
    },
    currency: {
      label: '币种',
      label: '币制',
      display: true,
      type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_currency',
      rules: [
        {
          required: true,
          message: "币种不能为空", trigger: "change"
          message: "币制不能为空", trigger: "change"
        }
      ],
    },
    voucherUrl: {
      label: '费用凭证',
      label: '费用凭证1',
      display: true,
      accept: 'string', dataType: 'string',
      type: 'upload',
@@ -2324,7 +2374,7 @@
      display: true,
    },
    currency: {
      label: '币种',
      label: '币制',
      display: true,
      type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_currency',
    },
@@ -3114,48 +3164,46 @@
  getBeginListFunc: (params = {}) => {
    // 1. 日期转换
    let newParams = <any>{ ...params };
    console.log(newParams, '2');
   if (newParams) {
  // 1. 定义日期字段映射 (数组名 : 接口需要的前缀)
  // 这样写的好处是:如果你有多个日期,直接在这里添加一行即可
  const dateMap = {
    confirmTimeRangeArray: 'confirmTimeRange',
    createTimeRangeArray: 'createTime',
    updateTimeRangeArray: 'updateTimeRange',
    okTimeRangeArray: 'okTime',
    orderTimeRangeArray: 'orderTime'
  };
    if (newParams) {
      // 1. 定义日期字段映射 (数组名 : 接口需要的前缀)
      // 这样写的好处是:如果你有多个日期,直接在这里添加一行即可
      const dateMap = {
        confirmTimeRangeArray: 'confirmTimeRange',
        createTimeRangeArray: 'createTime',
        updateTimeRangeArray: 'updateTimeRange',
        okTimeRangeArray: 'okTime',
        orderTimeRangeArray: 'orderTime'
      };
  // 2. 遍历处理日期
  Object.keys(dateMap).forEach(arrayKey => {
    const prefix = dateMap[arrayKey];
    const range = newParams[arrayKey];
      // 2. 遍历处理日期
      Object.keys(dateMap).forEach(arrayKey => {
        const prefix = dateMap[arrayKey];
        const range = newParams[arrayKey];
    if (Array.isArray(range) && range.length > 0) {
      // 赋值 Begin 和 End
      newParams[`${prefix}Begin`] = range[0];
      newParams[`${prefix}End`] = range[1];
        if (Array.isArray(range) && range.length > 0) {
          // 赋值 Begin 和 End
          newParams[`${prefix}Begin`] = range[0];
          newParams[`${prefix}End`] = range[1];
        }
        // 【核心改动】:无论是否有值,处理完后都把原始的 Array 字段删掉
        // 这样请求里就不会出现 confirmTimeRangeArray: [...]
        delete newParams[arrayKey];
      });
      // 3. 通用清洗:删除所有空字符串、null 或 undefined 的其他字段
      Object.keys(newParams).forEach(key => {
        const val = newParams[key];
        if (val === '' || val === null || val === undefined) {
          delete newParams[key];
        }
      });
    } else {
      newParams = {};
    }
    // 【核心改动】:无论是否有值,处理完后都把原始的 Array 字段删掉
    // 这样请求里就不会出现 confirmTimeRangeArray: [...]
    delete newParams[arrayKey];
  });
  // 3. 通用清洗:删除所有空字符串、null 或 undefined 的其他字段
  Object.keys(newParams).forEach(key => {
    const val = newParams[key];
    if (val === '' || val === null || val === undefined) {
      delete newParams[key];
    }
  });
} else {
  newParams = {};
}
console.log('最终发送给接口的参数:', newParams);
return newParams;
    return newParams;
    // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.createTimeRangeArray, 'createTime');
    // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.updateTimeRangeArray, 'updateTime');
    // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.confirmTimeRangeArray, 'confirmTime');
@@ -3240,7 +3288,6 @@
const handleUploadItinerary = (row: any) => {
  optionType.value = 'addItinerary';
  boxFormOption.value = itineraryOption.value;
  console.log(itineraryOption.value);
  boxTableOption.value = itineraryTableOption.value;
  listTmsTrip({ dispatchOrderId: row.id, pageNum: 1, pageSize: 999 }).then(res => {
@@ -3256,7 +3303,6 @@
      vehicleNumber: row.licensePlate,
      vehicleId: row.vehicleId,
    }
    console.log(boxForm.value);
  })
}
@@ -3900,7 +3946,6 @@
                  form2.value.districtId = districtCode;
                  form2.value.streetId = townshipCode;
                  form2.value.dispatchTransportArea = params.regeocode.formatted_address || params.regeocode.formattedAddress;
                  console.log(form2.value, "form2")
                }
              });
            }
@@ -4109,7 +4154,6 @@
getQuotationItems();
const getTabData = (val: string) => {
  console.log(val)
  let filter = quotationItems.value.filter((item: any) => {
    return item.remark == val;
  });
@@ -4127,9 +4171,7 @@
    dispatchOrderId: form.value.id, financeType: 2,
    pageNum: 1, pageSize: 999
  }).then(async res => {
    boxTableData.value = res.rows || [];
    boxForm.value = {
      dispatchOrderId: form.value.id,
      dataSource: 0,
@@ -4173,8 +4215,12 @@
    // 3. 处理凭证 URL (如果有单张或多张上传的逻辑)
    // 假设后端需要的是逗号分隔的字符串
    const submitData = validDetails.map(item => {
    const submitData = validDetails.map((item: any) => {
      let url = item.voucherUrl;
      item.dispatchOrderId = form.value.id;
      item.financeType = 2;
      item.status = 0;
      item.dataSource = 1;
      if (Array.isArray(url)) {
        url = url.join(',');
      }
@@ -4735,13 +4781,12 @@
    },
    {
      label: '费用凭证',
      label: '费用凭证2',
      display: true,
      span: 24,
      accept: 'string', dataType: 'object',
      type: 'upload',
      // action: '/common/upload2',
      prop: 'voucherUrl', // 这里改成 prop 属性
      slot: true,        // 开启插槽
      width: 200
@@ -4755,6 +4800,7 @@
});
// 3. 回显初始化
const initExpenditureData = () => {
  tmsFinanceDetails.value = []
  if (fee_type.value && fee_type.value.length > 0 && tmsFinanceDetails.value.length === 0) {
    tmsFinanceDetails.value = fee_type.value.map(item => ({
      feeType: item.value,
@@ -4772,19 +4818,25 @@
    initExpenditureData();
  }
});
const handleUploadAfter = (res, done, loading, column, row) => {
const handleUploadAfter = (res: any, row: any) => {
  // res 是接口返回的完整数据
  if (res && res.url) {
  if (res.code === 200) {
    // 手动给这一行的数据赋值
    row.voucherUrl = res.url;
    console.log('上传成功,当前行数据:', row);
    row.voucherUrl = res.data.url;
  } else if (res.data && res.data.url) {
    // 如果返回的数据包裹在 data 里
    row.voucherUrl = res.data.url;
  }
  done(); // 必须调用 done 结束上传状态
};
/** 当文件超出限制时(实现自动替换逻辑) */
const handleExceed = (files: any, row: any) => {
  // 1. 清除当前显示的文件列表
  uploadRef.value.clearFiles();
  // 2. 手动把新选择的文件添加进去重新上传
  const file = files[0];
  uploadRef.value.handleStart(file);
  uploadRef.value.submit();
};
const flowLogIshow = ref()
const flowParams = ref([])
@@ -4874,4 +4926,74 @@
.link-btn {
  font-size: 18px;
}
/*  */
/* 现有的样式保持不变... */
.specific-drag-area {
  width: 100%;
  :deep(.full-width-drag) {
    // 1. 核心:隐藏 Avue 默认在 dragger 下方生成的那个“点击上传”按钮
    // 在 3.x 版本中,它是 el-upload 后的一个兄弟节点或者是内部节点
    .el-button--primary {
      display: none !important;
    }
    .el-upload {
      width: 100%;
      display: block; // 确保块级显示
      .el-upload-dragger {
        width: 100%;
        height: 120px;
        background-color: #fcfdfe;
        border: 2px dashed #dcdfe6;
        border-radius: 8px;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 0 !important;
        // 覆盖 Element Plus 默认的内部文字排版,防止冲突
        .el-upload__text {
          display: none !important;
        }
        &:hover {
          border-color: #409eff;
          background-color: #f5f7fa;
        }
      }
    }
  }
  // 3. 自定义内容的样式(确保它不被 display:none 影响)
  .drag-zone-inner {
    pointer-events: none;
    text-align: center;
    .upload-icon {
      font-size: 32px !important;
      color: #909399;
      margin-bottom: 8px;
    }
    .drag-text {
      .main-title {
        font-size: 14px;
        color: #606266;
        font-weight: bold;
        line-height: 1.5;
      }
      .sub-title {
        font-size: 12px;
        color: #a8abb2;
        margin-top: 4px;
      }
    }
  }
}
</style>