<el-button @click="changeLanguage('en_US')">English</el-button>
<el-button @click="changeLanguage('zh_CN')">中文</el-button>
<el-button @click="changeLanguage('es_MX')">Español</el-button>
<CustomerInfo ref="customerInfo" :customer="formData.customer" :is-not-check="isNotCheck" />
<InspectionItems ref="inspectionItems" :items="formData.inspectionItems" :is-not-check="isNotCheck" />
<PdiImageUpload ref="imageUpload" v-model:image-map="formData.imageMap" :initial-data="formData.imageMap"
:is-not-check="isNotCheck" :code="route.query.code"/>
<el-checkbox
v-model="checkedCarrier"
:disabled="!isNotCheck"
v-show="signatureConfig.carrierOptional">
{{ $t('inspectionManagement.carrierSignature') }}
</el-checkbox>
<template v-if="photo.warehouseKeeperSignatureImg">
{{ $t('inspectionManagement.warehouseKeeperSignature') }}
<el-image width="95%" style="height: 200px;" :src="photo.warehouseKeeperSignatureImg" />
</template>
<template v-else>
<CustomerSignature ref="warehouseSignature" :title="$t('inspectionManagement.warehouseKeeperSignature')"
:initial-image="formData.signatures.warehouse" @upload-success="handleWarehouseSignature"
@clear-success="handleClearWarehouse" @touchstart="handleSignatureTouchStart" :code="route.query.code"/>
</template>
<template v-if="photo.inspectedSignatureImg">
{{ $t('inspectionManagement.inspectorSignature') }}
<el-image width="95%" style="height: 200px;" :src="photo.inspectedSignatureImg" />
</template>
<template v-else>
<CustomerSignature ref="inspectedSignature" :title="$t('inspectionManagement.inspectorSignature')"
:initial-image="formData.signatures.inspector" @upload-success="handleInspectorSignature"
@clear-success="handleClearInspector" @touchstart="handleSignatureTouchStart" :code="route.query.code"/>
</template>
<template v-if="photo.carrierSignatureImg">
{{ $t('inspectionManagement.carrierSignature') }}
<el-image width="95%" style="height: 200px;" :src="photo.carrierSignatureImg" />
</template>
<template v-else>
<CustomerSignature ref="carrierSignature" :title="$t('inspectionManagement.carrierSignature')"
:initial-image="formData.signatures.carrier" @upload-success="handleCarrierSignature"
@clear-success="handleClearCarrier" @touchstart="handleSignatureTouchStart" :code="route.query.code"/>
</template>
<template v-if="photo.customerSignatureImg">
{{ $t('inspectionManagement.customerSignature') }}
<el-image width="95%" style="height: 200px;" :src="photo.customerSignatureImg" />
</template>
<template v-else>
<CustomerSignature ref="customerSignature" :title="$t('inspectionManagement.customerSignature')"
:initial-image="formData.signatures.customer" @upload-success="handleCustomerSignature"
@clear-success="handleClearCustomer" :code="route.query.code" @touchstart="handleSignatureTouchStart" />
</template>
<el-button type="primary" @click="handleSubmit" v-show="submitButton" :loading="buttonLoading">{{ $t('systemOperations.submitDocument') }}</el-button>
<el-dialog v-model="pdiDialogVisible" :title="$t('inspectionManagement.customerSignature')" width="500px">
<el-form>
<el-form-item :title="$t('inspectionManagement.customerSignature')">
<el-input v-model="pdiUrl" readonly class="copy-input">
<template #append>
<el-button icon="DocumentCopy" @click="copyPDIUrl" :title="$t('systemOperations.copy')" />
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="pdiDialogVisible = false">{{ $t('systemOperations.close') }}</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, onMounted, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import { getPdiCheck, updatePdiCheck, completePdiCheck, customerSignAuthPdiCheck, getPdiCheckByCode, getNoNeedLoginCode } from '@/api/lease/pdiCheck';
import {getCheckList} from '@/api/lease/pdi';
import CustomerInfo from './components/CustomerInfo.vue'
import InspectionItems from './components/InspectionItems.vue'
import PdiImageUpload from './components/pdiImageUpload.vue'
import CustomerSignature from './components/CustomerSignature.vue'
import { LanguageDefaultValues } from '@/enums/LanguageDefaultValues'
import copy from '@/utils/copy'
import { fa, tr } from 'element-plus/es/locale/index.mjs';
import { useI18n } from 'vue-i18n';
import { useAppStore } from '@/store/modules/app';
const buttonLoading = ref(false)
const appStore = useAppStore();
const { t,locale } = useI18n();
const route = useRoute()
const router = useRouter();
const devicePdiId = route.query.devicePdiId
// 获取子组件引用
const customerInfo = ref(null);
// 触摸处理函数
const handleSignatureTouchStart = () => {
// 让小时表输入框失去焦点
customerInfo.value?.hoursInputRef?.blur();
};
// 根据allocateBillStatus配置签名显示逻辑
const signatureConfig = computed(() => {
const status = formData.customer.allocateBillStatus;
console.log('allocateBillStatus',status);
switch(status) {
case '11': // 待出库检查 - 仓管(固定)+ 检查人(固定)
return {
showWarehouse: true, // 显示仓管(固定)
showInspector: true, // 显示检查人(固定)
showCarrier: false, // 不显示承运人
showCustomer: false, // 不显示客户
carrierRequired: false, // 承运人不是必需的
carrierOptional: false // 承运人不可选
};
case '12': // 待入场检查 - 检查人(固定)+ 承运人(固定)+ 客户(固定)
return {
showWarehouse: false, // 不显示仓管
showInspector: true, // 显示检查人(固定)
showCarrier: true, // 显示承运人(固定)
showCustomer: true, // 显示客户(固定)
carrierRequired: true, // 承运人是必需的
carrierOptional: false // 承运人不可选(固定显示)
};
case '13': // 待退场检查 - 检查人(固定)+ 承运人(可选)+ 客户(固定)
return {
showWarehouse: false, // 不显示仓管
showInspector: true, // 显示检查人(固定)
showCarrier: true, // 显示承运人(可选)
showCustomer: true, // 显示客户(固定)
carrierRequired: false, // 承运人不是必需的
carrierOptional: true // 承运人可选
};
case '14': // 待整备检查 - 仓管(固定)+ 检查人(固定)
return {
showWarehouse: true, // 显示仓管(固定)
showInspector: true, // 显示检查人(固定)
showCarrier: false, // 不显示承运人
showCustomer: false, // 不显示客户
carrierRequired: false, // 承运人不是必需的
carrierOptional: false // 承运人不可选
};
default:
// 默认配置
return {
showWarehouse: false,
showInspector: true,
showCarrier: false,
showCustomer: false,
carrierRequired: false,
carrierOptional: false
};
}
});
const photo = reactive({
warehouseKeeperSignatureImg: '',
carrierSignatureImg: '',
customerSignatureImg: '',
inspectedSignatureImg: ''
});
const billStatus = ref(null)
const isNotCheck = ref(false);
const submitButton = ref(true)
const checkedCarrier = ref(false) // 只用于可选的承运人
const checkedPopLink = ref(false)
const showPopLinkFlag = ref(true)
const pdiUrl = ref('')
const pdiDialogVisible = ref(false);
// 表单数据结构
const formData = reactive({
sourceBillType: '',
billType: '',
vehicleId: '',
customer: {
license: '',
vin: '',
vehicleSelfCode: '',
hours: '',
coordinate: '',
billNo: '',
allocateBillStatus: '', // 关键字段:分配单状态
sourceBillNo: '',
allocateBillStatusNameL: [],
billType:'',
billTypeL:[],
billDate: new Date().toISOString().split('T')[0],
},
inspectionItems: [],
imageMap: {
front: [],
back: [],
left: [],
right: [],
pipeline: [],
oil: [],
battery: [],
other: []
},
signatures: {
carrier: '',
customer: '',
warehouse: '',
inspector: '',
}
})
// 添加响应式的字段映射
const fieldMapping = ref({});
// 加载配置项映射
const loadFieldMapping = async () => {
try {
const res = await getCheckList();
if (res.code === 200 && res.data) {
fieldMapping.value = res.data;
} else {
// 如果接口失败,使用默认映射
fieldMapping.value = {
'inspectionManagement.vehicleKeys': { field: 'vehicleKey', remark: 'vehicleKeyRemark' },
};
console.warn('使用默认字段映射');
}
} catch (error) {
console.error('加载配置项映射失败:', error);
// 使用默认映射作为后备
fieldMapping.value = {
'inspectionManagement.vehicleKeys': { field: 'vehicleKey', remark: 'vehicleKeyRemark' },
};
}
};
// 字段映射表
const FIELD_MAPPING = {
'inspectionManagement.vehicleKeys': { field: 'vehicleKey', remark: 'vehicleKeyRemark' },
'inspectionManagement.hydraulicOilLevel': { field: 'hydraulicOilLevel', remark: 'hydraulicOilLevelRemark' },
'inspectionManagement.lampCover': { field: 'lampshade', remark: 'lampshadeRemark' },
'inspectionManagement.horn': { field: 'horn', remark: 'hornRemark' },
'inspectionManagement.batteryLiquidPosition': { field: 'batteryElectricFluid', remark: 'batteryElectricFluidRemark' },
'inspectionManagement.gantry': { field: 'gantry', remark: 'gantryRemark' },
'inspectionManagement.headlight': { field: 'headlight', remark: 'headlightRemark' },
'inspectionManagement.brakeOilLevel': { field: 'brakeOilLevel', remark: 'brakeOilLevelRemark' },
'inspectionManagement.rearviewMirror': { field: 'rearviewMirror', remark: 'rearviewMirrorRemark' },
'inspectionManagement.fireExtinguisher': { field: 'fireExtinguisher', remark: 'fireExtinguisherRemark' },
'inspectionManagement.battery': { field: 'battery', remark: 'batteryRemark' },
'inspectionManagement.batteryConnection': { field: 'batteryConnection', remark: 'batteryConnectionRemark' },
'inspectionManagement.machineCircuitConnection': { field: 'wholeMachineCircuitConnection', remark: 'wholeMachineCircuitConnectionRemark' },
'inspectionManagement.reverseAlarm': { field: 'reverseAlarm', remark: 'reverseAlarmRemark' },
'inspectionManagement.hydraulicSteering': { field: 'hydraulicSteering', remark: 'hydraulicSteeringRemark' },
'inspectionManagement.brakePedal': { field: 'brakePedal', remark: 'brakePedalRemark' },
'inspectionManagement.handBrakeLever': { field: 'handBrakeLever', remark: 'handBrakeLeverRemark' },
'inspectionManagement.controlHandleCheck': { field: 'controlHandleCheck', remark: 'controlHandleCheckRemark' },
'inspectionManagement.forkTiltCheck': { field: 'forkTiltCheck', remark: 'forkTiltCheckRemark' },
'inspectionManagement.forkLiftCheck': { field: 'forkLiftCheck', remark: 'forkLiftCheckRemark' },
'inspectionManagement.lubricantInspection': { field: 'lubricantInspection', remark: 'lubricantInspectionRemark' },
'inspectionManagement.tires': { field: 'tires', remark: 'tiresRemark' },
'inspectionManagement.workLights': { field: 'workLights', remark: 'workLightsRemark' },
'inspectionManagement.rearTurnSignal': { field: 'rearTurnSignal', remark: 'rearTurnSignalRemark' },
'inspectionManagement.frontTurnSignal': { field: 'frontTurnSignal', remark: 'frontTurnSignalRemark' },
'inspectionManagement.seatBelt': { field: 'seatBelt', remark: 'seatBeltRemark' },
'inspectionManagement.bodyDamage': { field: 'bodyDamage', remark: 'bodyDamageRemark' },
'inspectionManagement.hoses': { field: 'hoses', remark: 'hosesRemark' },
'inspectionManagement.batteryAspect': { field: 'batteryAspect', remark: 'batteryAspectRemark' },
'inspectionManagement.seat': { field: 'seat', remark: 'seatRemark' },
'inspectionManagement.forks': { field: 'forks', remark: 'forksRemark' },
'inspectionManagement.stickers': { field: 'stickers', remark: 'stickersRemark' },
'inspectionManagement.steeringWheel': { field: 'steeringWheel', remark: 'steeringWheelRemark' },
'inspectionManagement.engineCleaning': { field: 'engineCleaning', remark: 'engineCleaningRemark' },
'inspectionManagement.generalCleaning': { field: 'generalCleaning', remark: 'generalCleaningRemark' },
'inspectionManagement.fuel': { field: 'fuel', remark: 'fuelRemark' },
}
// 处理签名上传
const handleCarrierSignature = (data) => {
formData.signatures.carrier = data.ossId
}
const handleCustomerSignature = (data) => {
formData.signatures.customer = data.ossId
}
const handleWarehouseSignature = (data) => {
formData.signatures.warehouse = data.ossId
}
const handleInspectorSignature = (data) => {
formData.signatures.inspector = data.ossId
}
// 处理签名清空
const handleClearWarehouse = () => {
formData.signatures.warehouse = ''
}
const handleClearInspector = () => {
formData.signatures.inspector = ''
}
const handleClearCarrier = () => {
formData.signatures.carrier = ''
}
const handleClearCustomer = () => {
formData.signatures.customer = ''
}
const copyPDIUrl = async () => {
copy(pdiUrl.value)
}
// 图片字段映射表
const IMAGE_FIELD_MAPPING = {
front: 'frontImg',
back: 'backImg',
left: 'leftImg',
right: 'rightImg',
pipeline: 'conduitImg',
oil: 'fluidImg',
battery: 'electricityImg',
fuel: 'fuelImg',
other: 'otherImg'
}
// 提交处理
const handleSubmit = async () => {
buttonLoading.value = true
try {
if(!formData.customer.hours){
ElMessage.error(`${t('equipmentManagement.currentHourMeterReading')}`)
buttonLoading.value = false
return
}
// 根据配置校验签名
const config = signatureConfig.value;
// 校验固定显示的签名
if (config.showWarehouse && !formData.signatures.warehouse) {
ElMessage.error(`${t('inspectionManagement.warehouseKeeperSignature')}`)
buttonLoading.value = false
return
}
if (config.showInspector && !formData.signatures.inspector) {
ElMessage.error(`${t('inspectionManagement.inspectorSignature')}`)
buttonLoading.value = false
return
}
if (config.showCustomer && !formData.signatures.customer) {
ElMessage.error(`${t('inspectionManagement.customerSignature')}`)
buttonLoading.value = false
return
}
// 校验承运人签名(固定必需或可选已勾选的情况)
if (config.showCarrier && config.carrierRequired && !formData.signatures.carrier) {
ElMessage.error(`${t('inspectionManagement.carrierSignature')}`)
buttonLoading.value = false
return
}
if (config.showCarrier && config.carrierOptional && checkedCarrier.value && !formData.signatures.carrier) {
ElMessage.error(`${t('inspectionManagement.carrierSignature')}`)
buttonLoading.value = false
return
}
// 构造请求数据
const postData = {
billId: devicePdiId,
billNo: formData.customer.billNo,
vehicleId: formData.vehicleId,
hmrNow: formData.customer.hours,
coordinate: formData.customer.coordinate,
sourceBillType: formData.sourceBillType,
billType: formData.billType,
billDate: `${formData.customer.billDate} 00:00:00`,
remark: LanguageDefaultValues,
// 检测项数据
...formData.inspectionItems.reduce((acc, item) => {
const mapping = handleSubmit[item.name]
acc[mapping.field] = item.selected
acc[mapping.remark] = item.comment
return acc
}, {}),
// 图片数据
...Object.entries(formData.imageMap).reduce((acc, [key, images]) => {
const fieldName = IMAGE_FIELD_MAPPING[key];
if (!fieldName) return acc;
if (typeof images === 'string' && images) {
acc[fieldName] = images;
} else if (Array.isArray(images) && images.length > 0) {
const ids = images.map(img => img.id || '').filter(Boolean);
if (ids.length > 0) {
acc[fieldName] = ids.join(',');
}
}
return acc;
}, {}),
// 签名数据 - 根据配置决定是否提交
warehouseKeeperSignatureImg: config.showWarehouse ? formData.signatures.warehouse : '',
inspectedSignatureImg: config.showInspector ? formData.signatures.inspector : '',
customerSignatureImg: config.showCustomer ? formData.signatures.customer : '',
carrierSignatureImg: (config.showCarrier && (config.carrierRequired || checkedCarrier.value)) ? formData.signatures.carrier : ''
}
if (billStatus.value === '0') {
const res1 = await completePdiCheck(postData)
if (res1.code === 200) {
ElMessage.success(t('systemOperations.operationSuccessful'))
buttonLoading.value = false
submitButton.value = false
showPopLinkFlag.value = false
const code = res1.data
if (code) {
pdiUrl.value = `${window.location.origin}${router.resolve({
name: 'editPDICheck',
query: { devicePdiId, code }
}).href}`
if(!config.showCustomer && checkedPopLink.value){
pdiDialogVisible.value = true
}
}
}
} else if (billStatus.value === '1') {
const code1 = route.query.code
const res2 = await customerSignAuthPdiCheck(postData, code1)
if (res2.code === 200) {
ElMessage.success(t('systemOperations.operationSuccessful'))
buttonLoading.value = false
submitButton.value = false
showPopLinkFlag.value = false
}
}
buttonLoading.value = false
} catch (error) {
console.error('提交失败:', error)
buttonLoading.value = false
ElMessage.error(t('systemOperations.operationFailed'))//操作失败
}
}
// 初始化可选签名复选框状态
const initOptionalSignatures = () => {
const config = signatureConfig.value;
// 只初始化可选的承运人复选框,默认勾选
if (config.carrierOptional) {
checkedCarrier.value = true;
// 如果已有签名数据,根据实际情况设置
if (billStatus.value === '1' || billStatus.value === '2') {
checkedCarrier.value = !!formData.signatures.carrier;
}
}
}
// 初始化数据
const loadData = async () => {
proxy?.$modal.loading('');
try {
await loadFieldMapping();// 先加载字段映射
let res = {};
if (route.query.code) {
res = await getPdiCheckByCode(devicePdiId, route.query.code);
} else {
res = await getPdiCheck(devicePdiId)
}
const { code, data } = { ...res };
if (code !== 200) return
billStatus.value = data.billStatus
isNotCheck.value = data.billStatus === '0'
if (data.billStatus == '1'|| data.billStatus == '2') {
submitButton.value = false
}
formData.sourceBillType = data.sourceBillType
formData.billType = data.billType
formData.vehicleId = data.vehicleVo?.vehicleId
// 签名图片URL
photo.warehouseKeeperSignatureImg = data.warehouseKeeperSignatureImgUrl;
photo.carrierSignatureImg = data.carrierSignatureImgUrl;
photo.customerSignatureImg = data.customerSignatureImgUrl;
photo.inspectedSignatureImg = data.inspectedSignatureImgUrl;
// 客户信息 - 重要:设置allocateBillStatus
formData.customer = {
license: data.vehicleVo?.vehiclePlate || '',
vin: data.vehicleVo?.vinNumber || '',
vehicleSelfCode: data.vehicleVo?.vehicleSelfCode || '',
billDate: data.billDate || new Date().toISOString().split('T')[0],
hours: data.hmrNow || '',
coordinate: data.coordinate || '',
billNo: data.billNo,
allocateBillStatus: data.allocateBillStatus, // 关键字段
allocateBillStatusNameL: data.allocateBillStatusNameL,
sourceBillNo: data.sourceBillNo||'',
billType: data.billType||'',
billTypeL: data.billTypeL||[],
}
console.log('formData.customer', formData.customer);
// 初始化检测项
formData.inspectionItems = Object.keys(fieldMapping.value).map(name => {
const mapping = fieldMapping.value[name]
return {
name,
selected: data[mapping.field] || '0',
comment: data[mapping.remark] || ''
}
})
// 初始化图片数据
const initImageMap = (key, urls) => {
return urls?.split(',').filter(Boolean).map(url => ({ url })) || []
}
formData.imageMap = {
front: initImageMap('front', data.frontImgUrl),
back: initImageMap('back', data.backImgUrl),
left: initImageMap('left', data.leftImgUrl),
right: initImageMap('right', data.rightImgUrl),
pipeline: initImageMap('pipeline', data.conduitImgUrl),
oil: initImageMap('oil', data.fluidImgUrl),
battery: initImageMap('battery', data.electricityImgUrl),
fuel: initImageMap('fuel', data.fuelImgUrl),
other: initImageMap('other', data.otherImgUrl)
}
// 签名数据
formData.signatures = {
carrier: data.carrierSignatureImgUrl || '',
customer: data.customerSignatureImgUrl || '',
warehouse: data.warehouseKeeperSignatureImgUrl || '',
inspector: data.inspectedSignatureImgUrl || ''
}
// 数据加载完成后初始化可选签名
initOptionalSignatures();
} catch (error) {
console.error('数据加载失败:', error)
}
proxy?.$modal.closeLoading();
}
const changeLanguage = (lang) => {
localStorage.setItem('language', lang)
locale.value = lang
}
// 监听allocateBillStatus变化,重新初始化可选签名
watch(() => formData.customer.allocateBillStatus, () => {
initOptionalSignatures();
}, { immediate: false })
// 生命周期
onMounted(async () => {
await loadData()
})
const { proxy } = getCurrentInstance();
const closeSelectedTag = () => {
proxy?.$tab.closePage(route);
};
</script>
<style scoped>
.pdi-edit-container {
max-width: 1200px;
margin: 20px auto;
padding: 20px;
}
.submit-btn {
margin-top: 30px;
text-align: center;
}
</style>
提交时提示:
editPdiCustomer.vue:473 提交失败: TypeError: Cannot read properties of undefined (reading ‘field’)
at editPdiCustomer.vue:415:21
at Proxy.reduce ()
at handleSubmit (editPdiCustomer.vue:413:35)
handleSubmit @ editPdiCustomer.vue:473