UniappVue3/src/pages/WorkOrderEdit/compoents/GatePassInfo.vue

705 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 出入证申请 -->
<template>
<view class="MainBox">
<view class="FormBox">
<view class="FormItem">
<view class="FormLableBox">项目名称</view>
<view class="FormValueBox">
<u-input v-model="allData.BasicsInfo.ProjectName" placeholder="请输入项目名称" readonly></u-input>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox">作业地点</view>
<view class="FormValueBox">
<u-input v-model="allData.BasicsInfo.SpecificAddress" placeholder="请输入作业地点" readonly></u-input>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox">作业班成员</view>
<view class="FormValueBox">
<view class="MemberBox">
<u-tag v-for="(member, index) in memberList" :key="member.id" shape="circle">
{{ member.name }}
</u-tag>
<view v-if="!memberList || memberList.length === 0" class="empty-tip">暂无作业班成员</view>
</view>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox mustBox">出入证有效日期</view>
<view class="FormValueBox">
<view class="date-range-box">
<view class="date-item">
<u-input v-model="startValidTimeText" placeholder="开始日期" readonly>
<template #suffix>
<u-button type="primary" size="small"
@click="showStartValidTimePicker = true">选择日期</u-button>
</template>
</u-input>
<up-datetime-picker :show="showStartValidTimePicker" v-model="startValidTime" mode="date"
:minDate="minTimestamp" @confirm="HandleStartValidTimeConfirm"
@cancel="showStartValidTimePicker = false" format="YYYY-MM-DD"></up-datetime-picker>
</view>
<view class="date-separator">至</view>
<view class="date-item">
<u-input v-model="endValidTimeText" placeholder="结束日期" readonly>
<template #suffix>
<u-button type="primary" size="small"
@click="showEndValidTimePicker = true">选择日期</u-button>
</template>
</u-input>
<up-datetime-picker :show="showEndValidTimePicker" v-model="endValidTime" mode="date"
:minDate="endValidTimeMinTimestamp" @confirm="HandleEndValidTimeConfirm"
@cancel="showEndValidTimePicker = false" format="YYYY-MM-DD"></up-datetime-picker>
</view>
</view>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox FlexBox">
<view class="mustBox">随行车辆信息</view>
<view class="addBtn" @click="showCarInputPopup = true">添加</view>
</view>
<view class="FormValueBox">
<view class="CarListBox">
<view v-for="item in formData.CarList" :key="item.id" class="CarItem">
<view class="CarInfoBox">
<view class="CarTitleBox">{{ item.code }}</view>
<view class="CartypeBox">{{ item.type }}</view>
</view>
<view>
<u-button text="删除" type="primary" size="small"
@click="HandleDeleteCar(item.id)"></u-button>
</view>
</view>
</view>
</view>
<!-- 车辆信息输入弹窗 -->
<u-popup :show="showCarInputPopup" mode="center" :round="10" @close="showCarInputPopup = false">
<view class="car-input-popup">
<view class="popup-title">添加车辆信息</view>
<view class="popup-form">
<view class="form-item">
<view class="form-label">车辆类型</view>
<u-input v-model="carInputForm.type" placeholder="请输入车辆类型" :maxlength="50"></u-input>
</view>
<view class="form-item">
<view class="form-label">车牌号</view>
<u-input v-model="carInputForm.code" placeholder="请输入车牌号" :maxlength="20"></u-input>
</view>
</view>
<view class="popup-buttons">
<u-button text="取消" type="info" @click="showCarInputPopup = false"></u-button>
<u-button text="确定" type="primary" @click="HandleCarInputConfirm"></u-button>
</view>
</view>
</u-popup>
</view>
<view class="FormItem">
<view class="FormLableBox">附件上传</view>
<view class="FormValueBox">
<up-upload width="100%" @afterRead="afterRead" multiple accept="image/*,application/pdf">
<view class="UploadBox">
<view class="UpIcon">
<img src="@/static/icon/upload-icon.png" alt="">
</view>
<view class="UpTitle">点击上传</view>
<view class="UpDesc">支持JPG,PNG,PDF格式上传单个文件大小不超过10MB</view>
</view>
</up-upload>
</view>
<view class="UpFileListBox">
<view v-for="item in fileList1" :key="item.fid || item.url" class="UpFileItem">
<view>
<view class="UpFileName">{{ item.name }}</view>
<view class="UpFileSize">{{ item.size }}</view>
<view v-if="item.uploading" class="UpFileStatus">上传中...</view>
</view>
<u-button text="删除" type="primary" size="small" :disabled="item.uploading"
@click="deletePic(item.fid)">
</u-button>
</view>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox">备注</view>
<view class="FormValueBox">
<u-input v-model="formData.remark" type="textarea" :maxlength="500" placeholder="请输入备注信息"
:autoHeight="true"></u-input>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { generateGuid } from '@/utils/index.js';
import dayjs from "dayjs";
import { ref, computed, onMounted, watch, defineExpose } from "vue";
import { uploadFileApi } from '@/api/modules/workTicket';
const props = defineProps({
allData: {
type: Object,
default: () => { },
}
})
const showStartValidTimePicker = ref(false); // 出入证开始有效日期选择器是否显示
const showEndValidTimePicker = ref(false); // 出入证结束有效日期选择器是否显示
const startValidTime = ref(null); // 开始有效日期时间戳
const endValidTime = ref(null); // 结束有效日期时间戳
const startValidTimeText = ref(''); // 开始有效日期显示文本
const endValidTimeText = ref(''); // 结束有效日期显示文本
const minTimestamp = ref(dayjs('2020-01-01').valueOf()); // 最小可选日期时间戳
const showCarInputPopup = ref(false); // 车辆信息输入弹窗是否显示
// 结束有效日期的最小时间戳(不能小于开始日期)
const endValidTimeMinTimestamp = computed(() => {
if (startValidTime.value) {
return startValidTime.value;
}
return minTimestamp.value;
});
// 车辆信息输入表单
const carInputForm = ref({
type: '', // 车辆类型
code: '', // 车牌号
});
// 组件数据
const formData = ref({
validTime: '', // 出入证有效日期格式YYYY-MM-DD 或 YYYY-MM-DD 至 YYYY-MM-DD
CarList: [], // 随行车辆数组
remark: '', // 备注
})
const fileList1 = ref([]); // 上传的文件列表
// 从基础信息中获取作业班成员列表
const memberList = computed(() => {
return props.allData?.BasicsInfo?.MemberList || [];
});
// 处理上传文件事件
const afterRead = async (e) => {
console.log('上传的文件:', e);
let fileInfo = e.file[0];
// 判断文件大小
if (fileInfo.size > 10 * 1024 * 1024) {
uni.showToast({
title: '文件大小不能超过10MB',
icon: 'none'
});
return;
}
// 判断文件类型
if (!fileInfo.name.match(/\.(jpg|png|pdf)$/i)) {
uni.showToast({
title: '请上传JPG,PNG,PDF格式的文件',
icon: 'none'
});
return;
}
// 生成临时文件ID用于标识上传中的文件
const tempFid = generateGuid();
const tempFile = {
fid: tempFid,
name: fileInfo.name,
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
url: fileInfo.url,
uploading: true // 标记为上传中
};
// 先添加到列表,显示上传状态
fileList1.value.push(tempFile);
try {
// 调用上传接口
const uploadResult = await uploadFileApi(
fileInfo.url, // 文件路径
'file', // 文件字段名
{}, // 额外的表单数据
{ loading: true, loadingText: '上传中...' }
);
// 上传成功,更新文件信息
// 接口返回的数据结构: { name: "文件名", url: "文件URL" }
const serverUrl = uploadResult?.url || fileInfo.url;
const serverFileName = uploadResult?.name || fileInfo.name;
// 使用服务器返回的文件名作为唯一标识如果没有则使用临时ID
const fileId = uploadResult?.name || tempFid;
// 更新文件列表中的对应项
const fileIndex = fileList1.value.findIndex(item => item.fid === tempFid);
if (fileIndex !== -1) {
fileList1.value[fileIndex] = {
fid: fileId,
name: serverFileName, // 使用服务器返回的文件名
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
url: serverUrl, // 使用服务器返回的URL
uploading: false
};
}
uni.showToast({
title: '上传成功',
icon: 'success',
duration: 1500
});
} catch (error) {
console.error('文件上传失败:', error);
// 上传失败,从列表中移除
fileList1.value = fileList1.value.filter(item => item.fid !== tempFid);
uni.showToast({
title: '上传失败,请重试',
icon: 'none',
duration: 2000
});
}
}
// 删除上传的文件
const deletePic = (fid) => {
console.log('删除文件:', fid);
let arr = [...fileList1.value];
arr = arr.filter(item => item.fid !== fid);
fileList1.value = arr;
}
// 从 allData 中恢复之前填写的数据
const restoreFormData = (data) => {
if (!data || Object.keys(data).length === 0) return;
if (data.validTime) {
formData.value.validTime = data.validTime;
// 解析有效日期,恢复开始和结束日期
const timeStr = data.validTime.trim();
if (timeStr.includes('至')) {
const parts = timeStr.split('至').map(s => s.trim());
if (parts[0]) {
startValidTimeText.value = parts[0];
startValidTime.value = dayjs(parts[0]).valueOf();
}
if (parts[1]) {
endValidTimeText.value = parts[1];
endValidTime.value = dayjs(parts[1]).valueOf();
}
} else {
startValidTimeText.value = timeStr;
startValidTime.value = dayjs(timeStr).valueOf();
}
}
if (data.CarList && Array.isArray(data.CarList)) {
formData.value.CarList = [...data.CarList];
}
if (data.remark) formData.value.remark = data.remark;
// 恢复文件列表(如果需要的话,可以从 data 中恢复)
// if (data.fileList && Array.isArray(data.fileList)) {
// fileList1.value = [...data.fileList];
// }
};
// 监听 allData.GatePassInfo 的变化,恢复表单数据
watch(() => props.allData?.GatePassInfo, (newData) => {
if (newData && Object.keys(newData).length > 0) {
restoreFormData(newData);
}
}, { immediate: true, deep: true });
// 组件暴露方法
defineExpose({
getFormData() {
// 解析有效日期,支持 "YYYY-MM-DD" 或 "YYYY-MM-DD 至 YYYY-MM-DD" 格式
let validityStartTime = '';
let validityEndTime = '';
if (formData.value.validTime) {
const timeStr = formData.value.validTime.trim();
if (timeStr.includes('至')) {
// 包含"至"的情况,拆分开始和结束日期
const parts = timeStr.split('至').map(s => s.trim());
validityStartTime = parts[0] ? `${parts[0]} 08:00:00` : '';
validityEndTime = parts[1] ? `${parts[1]} 18:00:00` : '';
} else {
// 单个日期,作为开始日期,结束日期设为同一天
validityStartTime = `${timeStr} 08:00:00`;
validityEndTime = `${timeStr} 18:00:00`;
}
}
// 转换车辆列表格式
const vehicleList = formData.value.CarList.map(car => ({
licensePlate: car.code || '',
vehicleType: car.type || ''
}));
// 提取附件URL列表只返回已上传成功的文件排除上传中的文件
const attachmentList = fileList1.value
.filter(file => !file.uploading && file.url) // 过滤掉上传中的文件和没有URL的文件
.map(file => file.url || '')
.filter(url => url);
// 从基础信息中获取项目ID和作业地点
const projectId = props.allData?.BasicsInfo?.projectId || null;
const workLocation = props.allData?.BasicsInfo?.SpecificAddress || '';
// 调试信息:打印 projectId 的值
console.log('GatePassInfo getFormData - projectId:', projectId);
console.log('GatePassInfo getFormData - allData.BasicsInfo:', props.allData?.BasicsInfo);
// 从基础信息中获取成员ID列表
const memberList = props.allData?.BasicsInfo?.MemberList || [];
const sysUserIds = memberList.map(member => {
// 如果成员ID是字符串尝试转换为数字
const id = member.id;
return typeof id === 'string' ? parseInt(id) || id : id;
});
return {
projectId,
workLocation,
sysUserIds,
validityStartTime,
validityEndTime,
vehicleList,
attachmentList,
remark: formData.value.remark || ''
};
}
})
// 生命周期钩子函数
onMounted(() => {
// 组件挂载后,从 allData 中恢复数据
if (props.allData?.GatePassInfo && Object.keys(props.allData.GatePassInfo).length > 0) {
restoreFormData(props.allData.GatePassInfo);
}
});
// 处理出入证开始有效日期选择器确认事件
const HandleStartValidTimeConfirm = (e) => {
const selectedDate = (e.value && dayjs(e.value).isValid()) ? e.value : minTimestamp.value;
startValidTimeText.value = dayjs(selectedDate).format('YYYY-MM-DD');
startValidTime.value = selectedDate;
endValidTimeText.value = '';
endValidTime.value = null;
showStartValidTimePicker.value = false;
updateValidTime();
}
// 处理出入证结束有效日期选择器确认事件
const HandleEndValidTimeConfirm = (e) => {
const selectedDate = (e.value && dayjs(e.value).isValid()) ? e.value : minTimestamp.value;
// 检查是否选择了开始日期
if (startValidTime.value && dayjs(selectedDate).isBefore(dayjs(startValidTime.value))) {
uni.showToast({
title: '结束日期不能小于开始日期',
icon: 'none',
duration: 2000
});
return;
}
endValidTimeText.value = dayjs(selectedDate).format('YYYY-MM-DD');
endValidTime.value = selectedDate;
showEndValidTimePicker.value = false;
updateValidTime();
}
// 更新出入证有效日期
const updateValidTime = () => {
if (startValidTimeText.value && endValidTimeText.value) {
formData.value.validTime = `${startValidTimeText.value}${endValidTimeText.value}`;
} else if (startValidTimeText.value) {
formData.value.validTime = startValidTimeText.value;
} else {
formData.value.validTime = '';
}
}
// 处理车辆信息输入确认事件
const HandleCarInputConfirm = () => {
// 验证输入
if (!carInputForm.value.type || carInputForm.value.type.trim() === '') {
uni.showToast({
title: '请输入车辆类型',
icon: 'none',
duration: 2000
});
return;
}
if (!carInputForm.value.code || carInputForm.value.code.trim() === '') {
uni.showToast({
title: '请输入车牌号',
icon: 'none',
duration: 2000
});
return;
}
// 检查车牌号是否已存在
const isExist = formData.value.CarList.some(item => item.code === carInputForm.value.code.trim());
if (isExist) {
uni.showToast({
title: '该车牌号已存在',
icon: 'none',
duration: 2000
});
return;
}
// 添加车辆信息
const newCar = {
id: generateGuid(), // 使用生成唯一ID
type: carInputForm.value.type.trim(),
code: carInputForm.value.code.trim()
};
formData.value.CarList.push(newCar);
console.log('添加车辆成功:', newCar);
// 清空表单并关闭弹窗
carInputForm.value.type = '';
carInputForm.value.code = '';
showCarInputPopup.value = false;
uni.showToast({
title: '添加成功',
icon: 'success',
duration: 1500
});
};
// 删除车辆
const HandleDeleteCar = (carId) => {
const index = formData.value.CarList.findIndex(item => item.id === carId);
if (index !== -1) {
formData.value.CarList.splice(index, 1);
console.log('删除车辆成功');
}
};
</script>
<style lang="scss" scoped>
.UploadBox {
width: 100%;
height: 300rpx;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20rpx;
padding: 20rpx;
border: 1rpx dashed #e4e7ed;
border-radius: 10rpx;
.UpTitle {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.UpDesc {
font-size: 24rpx;
color: #666;
}
}
.UpFileListBox {
margin-top: 20rpx;
height: auto;
.UpFileItem {
border: 1rpx solid #e4e7ed;
padding: 20rpx;
border-radius: 10rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
.UpFileName {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.UpFileSize {
font-size: 24rpx;
color: #666;
}
.UpFileStatus {
font-size: 24rpx;
color: #2979ff;
margin-top: 10rpx;
}
}
}
.FlexBox {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
.addBtn {
font-size: 30rpx;
color: #2979ff;
font-weight: bold;
}
.MainBox {
padding: 20rpx;
background-color: #fff;
height: 100%;
overflow: auto;
}
.mustBox::after {
content: "*";
color: red;
font-size: 30rpx;
margin-left: 10rpx;
}
.CarListBox {
border: 1rpx solid #e4e7ed;
padding: 20rpx;
border-radius: 10rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
.CarItem {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
flex-wrap: wrap;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
padding: 20rpx;
border-radius: 10rpx;
.CarInfoBox {
.CarTitleBox {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.CartypeBox {
font-size: 24rpx;
color: #666;
}
}
}
}
.FormBox {
// background-color: #f5f5f5;
height: 100%;
.FormItem {
padding: 20rpx;
background-color: #fff;
.FormLableBox {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.FormValueBox {
font-size: 30rpx;
margin-top: 20rpx;
.MemberBox {
min-height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 20rpx;
flex-wrap: wrap;
border: 1rpx solid #e4e7ed;
padding: 20rpx;
border-radius: 10rpx;
.empty-tip {
color: #999;
font-size: 28rpx;
}
}
.date-range-box {
display: flex;
align-items: center;
gap: 20rpx;
flex: 1;
.date-item {
flex: 1;
}
.date-separator {
color: #999;
font-size: 28rpx;
}
}
}
}
}
// 车辆信息输入弹窗样式
.car-input-popup {
width: 600rpx;
padding: 40rpx;
background-color: #fff;
border-radius: 20rpx;
.popup-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-bottom: 40rpx;
}
.popup-form {
display: flex;
flex-direction: column;
gap: 30rpx;
margin-bottom: 40rpx;
.form-item {
display: flex;
flex-direction: column;
gap: 20rpx;
.form-label {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
.popup-buttons {
display: flex;
gap: 20rpx;
justify-content: space-between;
}
}
</style>