gaoluyang
2026-06-03 6fc42b742367a9a042104a5ef9231ba639a8752a
英泽防锈
1.审批管理页面添加逻辑修改
2.车辆管理页面开发联调
已修改5个文件
272 ■■■■■ 文件已修改
src/api/officeProcessAutomation/vehicle.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/vehicle-apply/index.vue 263 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/officeProcessAutomation/vehicle.js
@@ -56,7 +56,7 @@
export function updateVehicle(data) {
  return request({
    url: "/approve/vehicle/update",
    method: "post",
    method: "put",
    data,
  });
}
@@ -131,7 +131,7 @@
export function updateBorrow(data) {
  return request({
    url: "/approve/vehicle/borrow/update",
    method: "post",
    method: "put",
    data,
  });
}
src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js
@@ -225,6 +225,7 @@
      flowNodes: bindingForm.flowNodes,
      templateAttachments: bindingForm.templateAttachments,
      storageBlobDTOs: bindingForm.storageBlobDTOs,
      formConfig: bindingForm.formConfig,
    };
  }
src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue
@@ -401,9 +401,9 @@
      <template #footer>
        <el-button type="primary" @click="editFromDetail">编 辑</el-button>
        <el-button @click="detailDialog.visible = false">关 闭</el-button>
        <el-button type="primary" @click="editFromDetail">编 辑</el-button>
      </template>
src/views/officeProcessAutomation/ApproveManage/vehicle-apply/index.vue
@@ -19,7 +19,7 @@
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="currentMileage" label="当前公里数" width="120" align="center" />
        <el-table-column prop="returnMileage" label="当前公里数" width="120" align="center" />
        <el-table-column label="操作" width="150" align="center" fixed="right">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openVehicleDialog(scope.row)">编辑</el-button>
@@ -162,9 +162,9 @@
            <el-option label="保养中" value="maintenance" />
          </el-select>
        </el-form-item>
        <el-form-item label="当前公里数" prop="currentMileage">
        <el-form-item label="当前公里数" prop="returnMileage">
          <el-input-number
            v-model="vehicleForm.currentMileage"
            v-model="vehicleForm.returnMileage"
            :min="0"
            :precision="1"
            :step="0.1"
@@ -175,8 +175,8 @@
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="vehicleDialog.visible = false">取消</el-button>
        <el-button type="primary" :loading="vehicleSaveLoading" @click="saveVehicle">保存</el-button>
        <el-button @click="vehicleDialog.visible = false">取消</el-button>
      </template>
    </el-dialog>
@@ -245,6 +245,17 @@
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item label="公里数" prop="mileage" required>
          <el-input-number
            v-model="returnForm.mileage"
            :min="0"
            :precision="1"
            :step="0.1"
            controls-position="right"
            style="width: 100%"
            placeholder="请输入归还时公里数"
          />
        </el-form-item>
        <el-form-item label="附件">
          <AttachmentUploadImage
            v-model:fileList="returnForm.returnStorageBlobDTOs"
@@ -256,6 +267,80 @@
      <template #footer>
        <el-button type="primary" :loading="returnLoading" @click="submitReturn">确认归还</el-button>
        <el-button @click="returnDialog.visible = false">取消</el-button>
      </template>
    </el-dialog>
    <!-- 借出记录详情对话框 -->
    <el-dialog
      v-model="borrowDetailDialog.visible"
      title="借出记录详情"
      width="700px"
      :close-on-click-modal="false"
    >
      <el-descriptions :column="2" border v-loading="borrowDetailDialog.loading">
        <el-descriptions-item label="借出单号" :span="1">
          {{ borrowDetailDialog.data.borrowNo || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="车牌号" :span="1">
          {{ borrowDetailDialog.data.vehiclePlateNumber || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="申请人" :span="1">
          {{ borrowDetailDialog.data.applicantName || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="借出状态" :span="1">
          <el-tag :type="borrowStatusTagType(borrowDetailDialog.data.borrowStatus)" size="small">
            {{ borrowStatusLabel(borrowDetailDialog.data.borrowStatus) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="借出原因" :span="2">
          {{ borrowDetailDialog.data.borrowReason || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="借出时间" :span="1">
          {{ borrowDetailDialog.data.borrowStartTime || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="计划归还" :span="1">
          {{ borrowDetailDialog.data.plannedReturnTime || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="实际归还" :span="1">
          {{ borrowDetailDialog.data.actualReturnTime || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="延期状态" :span="1">
          <el-tag :type="extendStatusTagType(borrowDetailDialog.data.extendStatus)" size="small">
            {{ extendStatusLabel(borrowDetailDialog.data.extendStatus) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="创建时间" :span="1">
          {{ borrowDetailDialog.data.createTime || '—' }}
        </el-descriptions-item>
        <el-descriptions-item label="借出附件" :span="2">
          <template v-if="borrowDetailDialog.data.borrowStorageBlobVOList?.length">
            <el-tag
              v-for="(file, i) in borrowDetailDialog.data.borrowStorageBlobVOList"
              :key="'borrow-' + i"
              class="mr8 mb8"
              type="info"
            >
              {{ file.fileName || file.blobName || '附件' + (i + 1) }}
            </el-tag>
          </template>
          <span v-else>无</span>
        </el-descriptions-item>
        <el-descriptions-item label="归还附件" :span="2">
          <template v-if="borrowDetailDialog.data.returnStorageBlobVOList?.length">
            <el-tag
              v-for="(file, i) in borrowDetailDialog.data.returnStorageBlobVOList"
              :key="'return-' + i"
              class="mr8 mb8"
              type="info"
            >
              {{ file.fileName || file.blobName || '附件' + (i + 1) }}
            </el-tag>
          </template>
          <span v-else>无</span>
        </el-descriptions-item>
      </el-descriptions>
      <template #footer>
        <el-button @click="borrowDetailDialog.visible = false">关 闭</el-button>
      </template>
    </el-dialog>
  </div>
@@ -275,12 +360,15 @@
  saveBorrow,
  listBorrowPage,
  deleteBorrow,
  returnVehicle,
  delayBorrow,
} from "@/api/officeProcessAutomation/vehicle.js";
import FormPayloadFields from "../approve-list/components/FormPayloadFields.vue";
import ApprovalInstanceDetailDialog from "../approve-shared/components/ApprovalInstanceDetailDialog.vue";
import ApprovalInstanceSubmitDialog from "../approve-shared/components/ApprovalInstanceSubmitDialog.vue";
import ApprovalTemplateBindDialog from "../approve-shared/components/ApprovalTemplateBindDialog.vue";
import { buildInstanceTableColumns } from "../approve-shared/approvalInstanceFormConfigTable.js";
import { buildInstanceFormConfigJson } from "../approve-list/approveListConstants.js";
import { APPROVAL_MODULE_KEYS } from "../approve-shared/approvalModuleRegistry.js";
import { useApprovalInstanceModule } from "../approve-shared/useApprovalInstanceModule.js";
import { useFlowUserOptions } from "../approve-shared/useFlowUserOptions.js";
@@ -304,7 +392,7 @@
  id: null,
  plateNumber: "",
  status: "idle",
  currentMileage: 0,
    returnMileage: 0,
});
const vehicleRules = {
  plateNumber: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
@@ -324,7 +412,7 @@
        id: item.id,
        plateNumber: item.plateNumber,
        status: mapVehicleStatusFromApi(item.status),
        currentMileage: item.mileage || 0,
                returnMileage: item.mileage || 0,
      }));
      vehiclePage.total = res.data?.total || 0;
    }
@@ -383,12 +471,12 @@
    vehicleForm.id = row.id;
    vehicleForm.plateNumber = row.plateNumber;
    vehicleForm.status = row.status;
    vehicleForm.currentMileage = row.currentMileage;
    vehicleForm.returnMileage = row.returnMileage;
  } else {
    vehicleForm.id = null;
    vehicleForm.plateNumber = "";
    vehicleForm.status = "idle";
    vehicleForm.currentMileage = 0;
    vehicleForm.returnMileage = 0;
  }
  vehicleDialog.visible = true;
}
@@ -402,7 +490,7 @@
    try {
      const apiData = {
        plateNumber: vehicleForm.plateNumber,
        mileage: vehicleForm.currentMileage,
        mileage: vehicleForm.returnMileage,
        status: mapVehicleStatusToApi(vehicleForm.status),
      };
      
@@ -698,15 +786,9 @@
  return labelMap[status] || status;
}
// 判断是否可以延期(借出中且未申请延期或延期已驳回)
// 判断是否可以延期(借出中即可延期)
function canExtendBorrow(row) {
  if (row.borrowStatus !== "BORROWING") return false;
  if (row.extendStatus === "PENDING" || row.extendStatus === "APPROVED") return false;
  // 过了计划归还时间才能延期
  if (row.plannedReturnTime) {
    return dayjs().isAfter(dayjs(row.plannedReturnTime));
  }
  return false;
  return row.borrowStatus === "BORROWING";
}
// 判断是否可以归还(借出中)
@@ -747,8 +829,13 @@
    label: "操作",
    align: "center",
    fixed: "right",
    width: 150,
    width: 210,
    operation: [
      {
        name: "详情",
        type: "text",
        clickFun: (row) => openBorrowDetail(row),
      },
      {
        name: "延期",
        type: "text",
@@ -790,25 +877,25 @@
      // 从表单数据中获取借出信息
      const formPayload = submitForm.formPayload || {};
      const fields = submitForm.formFieldDefs || [];
      // 查找车辆选择字段(先尝试使用项目中已有的查找方式,再兼容直接取值)
      const vehicleField = findVehicleNoField(fields);
      // 车辆选择字段的值是车牌号,需要从vehicleList中根据车牌号查找对应的车辆ID
      // 优先从 formPayload.vehiclePlateNumber 获取,如果不存在则通过字段key获取
      const selectedPlateNumber = formPayload.vehiclePlateNumber ||
      const selectedPlateNumber = formPayload.vehiclePlateNumber ||
        (vehicleField?.key ? formPayload[vehicleField.key] : null);
      let vehicleId = null;
      if (selectedPlateNumber) {
        const selectedVehicle = vehicleList.value.find(v => v.plateNumber === selectedPlateNumber);
        vehicleId = selectedVehicle?.id;
      }
      // 直接使用表单中的时间字段
      const borrowStartTime = formPayload.borrowStartTime;
      const plannedReturnTime = formPayload.plannedReturnTime;
      if (!vehicleId) {
        ElMessage.warning("请选择车辆");
        return;
@@ -817,16 +904,13 @@
        ElMessage.warning("请选择车辆使用时间");
        return;
      }
      // 只调用 saveBorrow 接口,不再调用审批实例提交
      // formConfig 是模板详情接口返回的原始 JSON 字符串
      console.log('=== submitForm debug ===', {
        templateId: submitForm.templateId,
        templateKey: submitForm.templateKey,
        templateSnapshotTemplateId: submitForm.templateSnapshot?.templateId,
        formConfig: submitForm.formConfig || submitForm.templateSnapshot?.formConfig || activeTemplate.value?.formConfig,
        'formConfig type': typeof submitForm.formConfig,
      });
      // 构建 formConfig,包含模板字段定义和用户填写的表单数据
      const formConfig = buildInstanceFormConfigJson(
        submitForm.templateSnapshot || activeTemplate.value,
        formPayload
      );
      const submitData = {
        vehicleId: vehicleId,
        borrowReason: formPayload.borrowReason || formPayload.reason || '',
@@ -835,16 +919,15 @@
        borrowStatus: 'IN_APPROVAL',
        approvalTemplateId: submitForm.templateId || submitForm.templateSnapshot?.templateId || submitForm.templateKey,
        borrowStorageBlobDTOs: submitForm.storageBlobDTOs || [],
        formConfig: submitForm.formConfig,
        formConfig: formConfig,
      };
      console.log('=== saveBorrow submitData ===', JSON.parse(JSON.stringify(submitData)));
      const borrowRes = await saveBorrow(submitData);
      if (borrowRes.code !== 200) {
        ElMessage.error(borrowRes.msg || "保存借出记录失败");
        return;
      }
      ElMessage.success("提交成功");
      submitDialog.visible = false;
      fetchBorrowList();
@@ -872,6 +955,8 @@
  flowNodes: [],
  storageBlobDTOs: [],
  formFieldDefs: [],
  formConfig: null,
  templateSnapshot: null,
});
const extendSubmitFormRules = reactive({});
const extendSubmitFormFields = ref([]);
@@ -888,10 +973,8 @@
function openExtendDialog(row) {
  // 保存原审批信息
  extendSourceRow.id = row.id;
  extendSourceRow.instanceNo = row.instanceNo || "";
  // 尝试从多个可能的字段名中获取车牌号
  const payload = row.formPayload || {};
  extendSourceRow.vehiclePlateNumber = payload.vehicleNo || payload.plateNumber || payload.vehiclePlateNumber || payload.carNo || "";
  extendSourceRow.instanceNo = row.instanceNo || row.borrowNo || "";
  extendSourceRow.vehiclePlateNumber = row.vehiclePlateNumber || "";
  // 从车辆使用时间计算原到期日期
  const useTimeField = findVehicleUseTimeField(row.formFieldDefs || []);
  if (useTimeField?.key && row.formPayload?.[useTimeField.key]) {
@@ -906,17 +989,18 @@
// 延期模板绑定确认
function onExtendTemplateBound(payload) {
  const { templateId, templateName, formFieldDefs, formPayload, flowNodes, templateAttachments, storageBlobDTOs } = payload;
  const { templateId, templateName, formFieldDefs, formPayload, flowNodes, templateAttachments, storageBlobDTOs, formConfig, templateSnapshot } = payload;
  extendActiveTemplate.value = { id: templateId, name: templateName, fields: formFieldDefs };
  extendSubmitForm.templateId = templateId;
  extendSubmitForm.templateName = templateName;
  extendSubmitForm.formFieldDefs = formFieldDefs || [];
  extendSubmitFormFields.value = formFieldDefs || [];
  // 初始化表单数据
  extendSubmitForm.formPayload = formPayload || {};
  extendSubmitForm.flowNodes = flowNodes || [];
  extendSubmitForm.templateAttachments = templateAttachments || [];
  extendSubmitForm.storageBlobDTOs = storageBlobDTOs || [];
  extendSubmitForm.formConfig = formConfig || null;
  extendSubmitForm.templateSnapshot = templateSnapshot || null;
  // 打开提交对话框
  extendSubmitDialog.visible = true;
}
@@ -928,37 +1012,47 @@
// 提交延期申请
async function onExtendSubmit() {
  if (!extendSubmitFormRef.value) return;
  extendSubmitSaving.value = true;
  try {
    // 构建提交数据
    // formConfig 是模板详情接口返回的原始 JSON 字符串
    const payload = {
      ...extendSubmitForm.formPayload,
      originalInstanceNo: extendSourceRow.instanceNo,
      vehiclePlateNumber: extendSourceRow.vehiclePlateNumber,
      originalEndDate: extendSourceRow.originalEndDate,
      formConfig: extendSubmitForm.formConfig,
    };
    const formPayload = extendSubmitForm.formPayload || {};
    // 这里调用创建延期审批实例的API
    // await createVehicleDelayApproval({
    //   templateId: extendSubmitForm.templateId,
    //   formPayload: payload,
    //   flowNodes: extendSubmitForm.flowNodes,
    //   storageBlobDTOs: extendSubmitForm.storageBlobDTOs,
    //   formConfig: extendSubmitForm.formFieldDefs || [],
    // });
    // 构建 formConfig,包含模板字段定义和用户填写的表单数据
    const formConfig = buildInstanceFormConfigJson(
      extendSubmitForm.templateSnapshot,
      formPayload
    );
    ElMessage.success("延期申请已提交");
    extendSubmitDialog.visible = false;
    onSearch();
    const res = await delayBorrow({
      id: extendSourceRow.id,
      extendTargetReturnTime: formPayload.extendTargetReturnTime || formPayload.newEndDate || '',
      extendReason: formPayload.extendReason || '',
      formConfig: formConfig,
    });
    if (res.code === 200) {
      ElMessage.success("延期申请已提交");
      extendSubmitDialog.visible = false;
      onSearch();
    } else {
      ElMessage.error(res.msg || "提交失败");
    }
  } catch (error) {
    ElMessage.error(error?.message || "提交失败");
  } finally {
    extendSubmitSaving.value = false;
  }
}
// ==================== 借出记录详情 ====================
const borrowDetailDialog = reactive({
  visible: false,
  loading: false,
  data: {},
});
function openBorrowDetail(row) {
  borrowDetailDialog.data = { ...row };
  borrowDetailDialog.visible = true;
}
// ==================== 归还车辆 ====================
@@ -972,20 +1066,21 @@
  instanceNo: "",
  vehiclePlateNumber: "",
  actualReturnTime: "",
  mileage: null,
  returnStorageBlobDTOs: [],
});
const returnRules = {
  actualReturnTime: [{ required: true, message: "请选择实际归还时间", trigger: "change" }],
  mileage: [{ required: true, message: "请输入公里数", trigger: "blur" }],
};
// 打开归还车辆对话框
function openReturnDialog(row) {
  returnForm.id = row.id;
  returnForm.instanceNo = row.instanceNo || "";
  // 尝试从多个可能的字段名中获取车牌号
  const payload = row.formPayload || {};
  returnForm.vehiclePlateNumber = payload.vehicleNo || payload.plateNumber || payload.vehiclePlateNumber || payload.carNo || "";
  returnForm.instanceNo = row.borrowNo || row.instanceNo || "";
  returnForm.vehiclePlateNumber = row.vehiclePlateNumber || "";
  returnForm.actualReturnTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
  returnForm.mileage = null;
  returnForm.returnStorageBlobDTOs = [];
  returnDialog.visible = true;
}
@@ -995,23 +1090,23 @@
  if (!returnFormRef.value) return;
  await returnFormRef.value.validate(async (valid) => {
    if (!valid) return;
    returnLoading.value = true;
    try {
      // 这里调用归还车辆的API
      // 1. 更新车辆公里数
      const vehicle = vehicleList.value.find((v) => v.plateNumber === returnForm.vehiclePlateNumber);
      if (vehicle) {
        vehicle.currentMileage += returnForm.mileage;
        vehicle.status = returnForm.vehicleStatus === "good" ? "idle" : "repair";
      const res = await returnVehicle({
        id: returnForm.id,
        actualReturnTime: returnForm.actualReturnTime,
        mileage: returnForm.mileage,
        returnStorageBlobDTOs: returnForm.returnStorageBlobDTOs,
      });
      if (res.code === 200) {
        ElMessage.success("车辆归还成功");
        returnDialog.visible = false;
        fetchBorrowList();
        fetchVehicleList();
      } else {
        ElMessage.error(res.msg || "归还失败");
      }
      // 2. 创建归还审批记录(实际项目中调用API)
      // await createVehicleReturnApproval({...});
      ElMessage.success("车辆归还成功");
      returnDialog.visible = false;
      onSearch();
    } catch (error) {
      ElMessage.error(error?.message || "归还失败");
    } finally {
vite.config.js
@@ -8,7 +8,7 @@
  const { VITE_APP_ENV } = env;
  const baseUrl =
      env.VITE_APP_ENV === "development"
          ? "http://42.63.70.231:9000"
          ? "http://192.168.0.226:7005"
          : env.VITE_BASE_API;
  const javaUrl =
      env.VITE_APP_ENV === "development"