| | |
| | | </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> |
| | |
| | | <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" |
| | |
| | | </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> |
| | | |
| | |
| | | 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" |
| | |
| | | <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> |
| | |
| | | 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"; |
| | |
| | | id: null, |
| | | plateNumber: "", |
| | | status: "idle", |
| | | currentMileage: 0, |
| | | returnMileage: 0, |
| | | }); |
| | | const vehicleRules = { |
| | | plateNumber: [{ required: true, message: "请输入车牌号", trigger: "blur" }], |
| | |
| | | id: item.id, |
| | | plateNumber: item.plateNumber, |
| | | status: mapVehicleStatusFromApi(item.status), |
| | | currentMileage: item.mileage || 0, |
| | | returnMileage: item.mileage || 0, |
| | | })); |
| | | vehiclePage.total = res.data?.total || 0; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | try { |
| | | const apiData = { |
| | | plateNumber: vehicleForm.plateNumber, |
| | | mileage: vehicleForm.currentMileage, |
| | | mileage: vehicleForm.returnMileage, |
| | | status: mapVehicleStatusToApi(vehicleForm.status), |
| | | }; |
| | | |
| | |
| | | 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"; |
| | | } |
| | | |
| | | // 判断是否可以归还(借出中) |
| | |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | width: 210, |
| | | operation: [ |
| | | { |
| | | name: "详情", |
| | | type: "text", |
| | | clickFun: (row) => openBorrowDetail(row), |
| | | }, |
| | | { |
| | | name: "延期", |
| | | type: "text", |
| | |
| | | // 从表单数据中获取借出信息 |
| | | 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; |
| | |
| | | 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 || '', |
| | |
| | | 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(); |
| | |
| | | flowNodes: [], |
| | | storageBlobDTOs: [], |
| | | formFieldDefs: [], |
| | | formConfig: null, |
| | | templateSnapshot: null, |
| | | }); |
| | | const extendSubmitFormRules = reactive({}); |
| | | const extendSubmitFormFields = ref([]); |
| | |
| | | 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]) { |
| | |
| | | |
| | | // 延期模板绑定确认 |
| | | 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; |
| | | } |
| | |
| | | |
| | | // 提交延期申请 |
| | | 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; |
| | | } |
| | | |
| | | // ==================== 归还车辆 ==================== |
| | |
| | | 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; |
| | | } |
| | |
| | | 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 { |