| | |
| | | <template> |
| | | <view class="upkeep-add"> |
| | | <!-- 使用通用页面头部组件 --> |
| | | <PageHeader title="新增保养" @back="goBack" /> |
| | | <PageHeader :title="operationType === 'edit' ? '编辑保养计划' : '新增保养计划'" @back="goBack" /> |
| | | |
| | | <!-- 表单内容 --> |
| | | <u-form @submit="sendForm" ref="formRef" label-width="110" input-align="right" error-message-align="right"> |
| | | <u-form ref="formRef" :model="form" :rules="formRules" label-width="110px"> |
| | | <!-- 基本信息 --> |
| | | <u-cell-group title="基本信息"> |
| | | <u-form-item label="设备名称" prop="deviceName" required border-bottom> |
| | | <u-input |
| | | v-model="deviceNameText" |
| | | placeholder="请选择设备名称" |
| | | readonly |
| | | @click="showDevicePicker" |
| | | clearable |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="scan" @click.stop="startScan" class="scan-icon" /> |
| | | </template> |
| | | </u-input> |
| | | </u-form-item> |
| | | <u-form-item label="规格型号" border-bottom> |
| | | <u-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请输入规格型号" |
| | | readonly |
| | | clearable |
| | | /> |
| | | </u-form-item> |
| | | <u-form-item label="保养日期" prop="upkeepDate" required border-bottom> |
| | | <u-input |
| | | v-model="form.upkeepDate" |
| | | placeholder="请选择保养日期" |
| | | readonly |
| | | @click="showDatePicker" |
| | | clearable |
| | | /> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <u-form-item label="设备名称" prop="deviceNameText" required border-bottom> |
| | | <u-input |
| | | v-model="form.deviceNameText" |
| | | placeholder="请选择设备名称" |
| | | readonly |
| | | @click="showDevicePicker" |
| | | clearable |
| | | /> |
| | | <template #right> |
| | | <u-icon name="scan" @click="startScan" class="scan-icon" /> |
| | | </template> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="规格型号" prop="deviceModel" border-bottom> |
| | | <u-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请输入规格型号" |
| | | readonly |
| | | clearable |
| | | /> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="计划保养日期" prop="maintenancePlanTime" required border-bottom> |
| | | <u-input |
| | | v-model="form.maintenancePlanTime" |
| | | placeholder="请选择计划保养日期" |
| | | readonly |
| | | @click="showDatePicker" |
| | | clearable |
| | | /> |
| | | <template #right> |
| | | <u-icon name="arrow-right" @click="showDatePicker" /> |
| | | </template> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="保养人" prop="maintenancePerson" required border-bottom> |
| | | <u-input |
| | | v-model="form.maintenancePerson" |
| | | placeholder="请选择保养人" |
| | | readonly |
| | | @click="showPersonPicker" |
| | | clearable |
| | | /> |
| | | <template #right> |
| | | <u-icon name="arrow-right" @click="showPersonPicker" /> |
| | | </template> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="保养部位" prop="maintenanceLocation" required border-bottom> |
| | | <u-input |
| | | v-model="form.maintenanceLocation" |
| | | placeholder="请输入保养部位" |
| | | clearable |
| | | /> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="保养内容" prop="maintenanceItems" required border-bottom> |
| | | <u-input |
| | | v-model="form.maintenanceItems" |
| | | placeholder="请输入保养内容" |
| | | clearable |
| | | /> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="附件" border-bottom> |
| | | <view class="attachment-upload"> |
| | | <view class="upload-buttons"> |
| | | <u-button |
| | | type="primary" |
| | | @click="chooseAttachment('camera')" |
| | | :loading="uploading" |
| | | :disabled="uploading" |
| | | :customStyle="{ marginRight: '10px', flex: 1 }" |
| | | > |
| | | <u-icon name="camera" size="18" color="#fff" style="margin-right: 5px;"></u-icon> |
| | | {{ uploading ? '上传中...' : '拍照' }} |
| | | </u-button> |
| | | <u-button |
| | | type="success" |
| | | @click="chooseAttachment('album')" |
| | | :loading="uploading" |
| | | :disabled="uploading" |
| | | :customStyle="{ flex: 1 }" |
| | | > |
| | | <u-icon name="photo" size="18" color="#fff" style="margin-right: 5px;"></u-icon> |
| | | {{ uploading ? '上传中...' : '相册' }} |
| | | </u-button> |
| | | </view> |
| | | <view v-if="attachmentList.length" class="attachment-list"> |
| | | <view |
| | | v-for="(file, index) in attachmentList" |
| | | :key="file.id || index" |
| | | class="attachment-item" |
| | | > |
| | | <image |
| | | :src="getFileAccessUrl(file)" |
| | | mode="aspectFill" |
| | | class="attachment-preview" |
| | | @click="previewAttachment(index)" |
| | | /> |
| | | <view class="attachment-delete" @click="removeAttachment(file, index)"> |
| | | <u-icon name="close" size="12" color="#fff" /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="attachment-empty">暂无附件,可拍照或从相册选择</view> |
| | | </view> |
| | | </u-form-item> |
| | | |
| | | <!-- 提交按钮 --> |
| | | <view class="footer-btns"> |
| | | <u-button class="cancel-btn" @click="goBack">取消</u-button> |
| | | <u-button class="save-btn" type="primary" @click="sendForm" :loading="loading">保存</u-button> |
| | | <u-button class="save-btn" @click="sendForm" :loading="loading">保存</u-button> |
| | | </view> |
| | | </u-form> |
| | | |
| | | <!-- 设备选择器 --> |
| | | <u-popup v-model="showDevice" mode="bottom"> |
| | | <u-picker |
| | | v-model="devicePickerValue" |
| | | :columns="deviceColumns" |
| | | @confirm="onDeviceConfirm" |
| | | @cancel="showDevice = false" |
| | | /> |
| | | </u-popup> |
| | | |
| | | <!-- 日期选择器 --> |
| | | <u-popup v-model="showDate" mode="bottom"> |
| | | <u-datetime-picker |
| | | v-model="currentDate" |
| | | title="选择日期" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDate = false" |
| | | /> |
| | | </u-popup> |
| | | <up-action-sheet |
| | | :show="showDevice" |
| | | :actions="deviceActions" |
| | | title="选择设备" |
| | | @select="onDeviceConfirm" |
| | | @close="showDevice = false" |
| | | /> |
| | | <!-- 保养人选择器 --> |
| | | <up-action-sheet |
| | | :show="showPerson" |
| | | :actions="personActions" |
| | | title="选择保养人" |
| | | @select="onPersonConfirm" |
| | | @close="showPerson = false" |
| | | /> |
| | | <up-datetime-picker |
| | | :show="showDate" |
| | | v-model="pickerDateValue" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDate = false" |
| | | mode="date" |
| | | /> |
| | | |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | // 替换 Vant 的 toast |
| | | // import { showToast } from 'vant'; |
| | | import { ref, computed, onMounted, onUnmounted } from 'vue'; |
| | | import { onShow, onUnload } from '@dcloudio/uni-app'; |
| | | import PageHeader from '@/components/PageHeader.vue'; |
| | | import config from '@/config'; |
| | | import { getToken } from '@/utils/auth'; |
| | | import { getDeviceLedger } from '@/api/equipmentManagement/ledger'; |
| | | import { |
| | | addUpkeep, |
| | | editUpkeep, |
| | | getUpkeepById, |
| | | listMaintenanceTaskFiles, |
| | | delMaintenanceTaskFile, |
| | | } from '@/api/equipmentManagement/upkeep'; |
| | | import { userListNoPageByTenantId } from '@/api/system/user'; |
| | | import useUserStore from '@/store/modules/user'; |
| | | import dayjs from "dayjs"; |
| | | import { formatDateToYMD } from '@/utils/ruoyi'; |
| | | |
| | | // 替换 toast 方法 |
| | | const userStore = useUserStore(); |
| | | |
| | | defineOptions({ |
| | | name: "设备保养计划表单", |
| | | }); |
| | | const showToast = (message) => { |
| | | uni.showToast({ |
| | | title: message, |
| | |
| | | }) |
| | | } |
| | | |
| | | import { ref, computed, onMounted, onUnmounted } from 'vue'; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import PageHeader from '@/components/PageHeader.vue'; |
| | | import { getDeviceLedger } from '@/api/equipmentManagement/ledger'; |
| | | import { addUpkeep, editUpkeep, getUpkeepById } from '@/api/equipmentManagement/upkeep'; |
| | | import dayjs from "dayjs"; |
| | | import { showToast } from 'vant'; |
| | | |
| | | defineOptions({ |
| | | name: "设备保养计划表单", |
| | | }); |
| | | const normalizeId = (raw) => { |
| | | if (raw === null || raw === undefined) return undefined; |
| | | const val = String(raw).trim(); |
| | | if (!val || val === 'undefined' || val === 'null') return undefined; |
| | | return val; |
| | | }; |
| | | |
| | | // 表单引用 |
| | | const formRef = ref(null); |
| | | const operationType = ref('add'); |
| | | const loading = ref(false); |
| | | const uploading = ref(false); |
| | | const attachmentList = ref([]); |
| | | const showDevice = ref(false); |
| | | const devicePickerValue = ref([]); |
| | | const showPerson = ref(false); |
| | | const showDate = ref(false); |
| | | const pickerDateValue = ref(Date.now()); |
| | | const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]); |
| | | |
| | | // 设备选项 |
| | | const deviceOptions = ref([]); |
| | | const deviceNameText = ref(''); |
| | | // 保养人选项 |
| | | const userOptions = ref([]); |
| | | // 转换为 action-sheet 需要的格式 |
| | | const deviceActions = computed(() => { |
| | | return deviceOptions.value.map(item => ({ |
| | | text: item.deviceName, |
| | | value: item.id, |
| | | data: item |
| | | })); |
| | | }); |
| | | const personActions = computed(() => { |
| | | return userOptions.value.map(item => ({ |
| | | name: item.nickName, |
| | | value: item.userId, |
| | | })); |
| | | }); |
| | | |
| | | // 扫码相关状态 |
| | | const isScanning = ref(false); |
| | |
| | | const formRules = { |
| | | deviceLedgerId: [{ required: true, trigger: "change", message: "请选择设备名称" }], |
| | | maintenancePlanTime: [{ required: true, trigger: "change", message: "请选择计划保养日期" }], |
| | | maintenancePerson: [{ required: true, trigger: "change", message: "请选择保养人" }], |
| | | maintenanceLocation: [{ required: true, trigger: "blur", message: "请输入保养部位" }], |
| | | maintenanceItems: [{ required: true, trigger: "blur", message: "请输入保养内容" }], |
| | | }; |
| | | |
| | | // 使用 ref 声明表单数据 |
| | |
| | | deviceLedgerId: undefined, // 设备ID |
| | | deviceModel: undefined, // 规格型号 |
| | | maintenancePlanTime: dayjs().format("YYYY-MM-DD"), // 计划保养日期 |
| | | }); |
| | | |
| | | // 设备选择器列 |
| | | const deviceColumns = computed(() => { |
| | | return deviceOptions.value.map(item => ({ |
| | | text: item.deviceName, |
| | | value: item.id |
| | | })); |
| | | maintenancePerson: userStore.nickName || undefined, // 保养人 |
| | | maintenanceLocation: undefined, // 保养部位 |
| | | maintenanceItems: undefined, // 保养内容 |
| | | tempFileIds: [], // 本次上传附件的临时文件ID,保存时提交 |
| | | }); |
| | | |
| | | // 加载设备列表 |
| | |
| | | } |
| | | }; |
| | | |
| | | // 设置设备规格型号 |
| | | const setDeviceModel = (id) => { |
| | | const option = deviceOptions.value.find((item) => item.id === id); |
| | | if (option) { |
| | | form.value.deviceModel = option.deviceModel; |
| | | deviceNameText.value = option.deviceName; |
| | | // 加载保养人列表 |
| | | const loadUserOptions = async () => { |
| | | try { |
| | | const { data } = await userListNoPageByTenantId(); |
| | | userOptions.value = data || []; |
| | | } catch (e) { |
| | | showToast('获取保养人列表失败'); |
| | | } |
| | | }; |
| | | |
| | | // 附件相关 |
| | | const extractTempFileId = (uploadedFile) => { |
| | | if (!uploadedFile) return undefined; |
| | | const data = Array.isArray(uploadedFile) ? uploadedFile[0] : uploadedFile; |
| | | return data?.tempId ?? data?.tempFileId ?? data?.id; |
| | | }; |
| | | |
| | | const syncTempFileIds = () => { |
| | | form.value.tempFileIds = attachmentList.value |
| | | .filter((item) => item.isTempFile) |
| | | .map((item) => item.tempId ?? item.tempFileId) |
| | | .filter((v) => v !== undefined && v !== null && v !== ''); |
| | | }; |
| | | |
| | | const getFileAccessUrl = (file = {}) => { |
| | | if (file?._localPreviewUrl) return file._localPreviewUrl; |
| | | const url = file.url || file.tempPath || file.tempFilePath || file.path || ''; |
| | | if (!url) return ''; |
| | | if (String(url).startsWith('http') || String(url).startsWith('blob:') || String(url).startsWith('file:') || String(url).startsWith('wxfile:')) { |
| | | return url; |
| | | } |
| | | const path = String(url).startsWith('/') ? url : `/${url}`; |
| | | return `${config.fileUrl}${path}`; |
| | | }; |
| | | |
| | | const fetchAttachmentList = async (id) => { |
| | | if (!id) { |
| | | attachmentList.value = []; |
| | | form.value.tempFileIds = []; |
| | | return; |
| | | } |
| | | try { |
| | | const { code, data } = await listMaintenanceTaskFiles({ |
| | | current: 1, |
| | | size: 100, |
| | | deviceMaintenanceId: id, |
| | | }); |
| | | if (code === 200) { |
| | | const records = data?.records || []; |
| | | attachmentList.value = records.map((file) => ({ |
| | | ...file, |
| | | isTempFile: false, |
| | | })); |
| | | } else { |
| | | attachmentList.value = []; |
| | | } |
| | | } catch (e) { |
| | | attachmentList.value = []; |
| | | } |
| | | syncTempFileIds(); |
| | | }; |
| | | |
| | | const chooseAttachment = (sourceType) => { |
| | | const source = sourceType === 'camera' ? ['camera'] : ['album']; |
| | | const remaining = 9 - attachmentList.value.length; |
| | | if (remaining <= 0) { |
| | | showToast('最多上传9张附件'); |
| | | return; |
| | | } |
| | | uni.chooseImage({ |
| | | count: Math.min(remaining, 9), |
| | | sizeType: ['original', 'compressed'], |
| | | sourceType: source, |
| | | success: (res) => { |
| | | const files = res.tempFiles || []; |
| | | if (!files.length) return; |
| | | uploadAttachments(files, res.tempFilePaths); |
| | | }, |
| | | fail: () => { |
| | | showToast('选择图片失败'); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleUploadSuccess = (response, file) => { |
| | | let uploadedFile = response?.data; |
| | | if (Array.isArray(uploadedFile)) { |
| | | uploadedFile = uploadedFile[0]; |
| | | } |
| | | const tempId = extractTempFileId(uploadedFile); |
| | | if (!tempId) { |
| | | showToast('未获取到文件ID'); |
| | | return; |
| | | } |
| | | attachmentList.value.push({ |
| | | tempId, |
| | | tempFileId: tempId, |
| | | isTempFile: true, |
| | | url: uploadedFile?.tempPath || uploadedFile?.url || uploadedFile?.downloadUrl || file.tempFilePath || file.path, |
| | | tempPath: uploadedFile?.tempPath || '', |
| | | name: uploadedFile?.originalName || uploadedFile?.originalFilename || file.name, |
| | | _localPreviewUrl: file.tempFilePath || file.path || '', |
| | | }); |
| | | syncTempFileIds(); |
| | | }; |
| | | |
| | | const uploadAttachments = async (files, tempFilePaths = []) => { |
| | | const token = getToken(); |
| | | if (!token) { |
| | | showToast('登录已失效,请重新登录'); |
| | | return; |
| | | } |
| | | uploading.value = true; |
| | | try { |
| | | for (let i = 0; i < files.length; i++) { |
| | | const file = files[i]; |
| | | const filePath = file.path || file.tempFilePath || tempFilePaths[i]; |
| | | if (!filePath) continue; |
| | | await new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: `${config.baseUrl}/file/upload`, |
| | | filePath, |
| | | name: 'file', |
| | | header: { |
| | | Authorization: `Bearer ${token}`, |
| | | }, |
| | | success: (uploadRes) => { |
| | | try { |
| | | const parsed = JSON.parse(uploadRes.data || '{}'); |
| | | if (uploadRes.statusCode === 200 && parsed.code === 200) { |
| | | handleUploadSuccess(parsed, { |
| | | ...file, |
| | | tempFilePath: filePath, |
| | | path: filePath, |
| | | name: file.name || `附件_${Date.now()}_${i}.jpg`, |
| | | }); |
| | | resolve(parsed); |
| | | } else { |
| | | reject(new Error(parsed.msg || '上传失败')); |
| | | } |
| | | } catch (err) { |
| | | reject(new Error('上传响应解析失败')); |
| | | } |
| | | }, |
| | | fail: () => reject(new Error('上传失败')), |
| | | }); |
| | | }); |
| | | } |
| | | showToast('上传成功'); |
| | | } catch (e) { |
| | | showToast(e?.message || '上传失败'); |
| | | } finally { |
| | | uploading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const previewAttachment = (index) => { |
| | | const urls = attachmentList.value |
| | | .map((item) => getFileAccessUrl(item)) |
| | | .filter(Boolean); |
| | | if (!urls.length) return; |
| | | uni.previewImage({ |
| | | urls, |
| | | current: urls[index] || urls[0], |
| | | }); |
| | | }; |
| | | |
| | | const removeAttachment = (file, index) => { |
| | | if (file?.isTempFile) { |
| | | attachmentList.value.splice(index, 1); |
| | | syncTempFileIds(); |
| | | return; |
| | | } |
| | | if (!file?.id) { |
| | | attachmentList.value.splice(index, 1); |
| | | syncTempFileIds(); |
| | | return; |
| | | } |
| | | uni.showModal({ |
| | | title: '提示', |
| | | content: '确认删除该附件吗?', |
| | | success: async (res) => { |
| | | if (!res.confirm) return; |
| | | try { |
| | | const { code } = await delMaintenanceTaskFile(file.id); |
| | | if (code === 200) { |
| | | attachmentList.value.splice(index, 1); |
| | | showToast('删除成功'); |
| | | } else { |
| | | showToast('删除失败'); |
| | | } |
| | | } catch (e) { |
| | | showToast('删除失败'); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // 加载表单数据(编辑模式) |
| | |
| | | form.value.deviceLedgerId = data.deviceLedgerId; |
| | | form.value.deviceModel = data.deviceModel; |
| | | form.value.maintenancePlanTime = dayjs(data.maintenancePlanTime).format("YYYY-MM-DD"); |
| | | form.value.maintenancePerson = data.maintenancePerson; |
| | | form.value.maintenanceLocation = data.maintenanceLocation; |
| | | form.value.maintenanceItems = data.maintenanceItems; |
| | | // 设置设备名称显示 |
| | | const device = deviceOptions.value.find(item => item.id === data.deviceLedgerId); |
| | | if (device) { |
| | | deviceNameText.value = device.deviceName; |
| | | form.value.deviceNameText = device.deviceName; |
| | | } |
| | | await fetchAttachmentList(id); |
| | | } |
| | | } catch (e) { |
| | | showToast('获取详情失败'); |
| | |
| | | } else { |
| | | // 新增模式 |
| | | operationType.value = 'add'; |
| | | attachmentList.value = []; |
| | | form.value.tempFileIds = []; |
| | | } |
| | | }; |
| | | |
| | | // 清除表单校验状态 |
| | | const clearValidate = () => { |
| | | formRef.value?.clearValidate(); |
| | | }; |
| | | |
| | | // 重置表单数据和校验状态 |
| | | const resetForm = () => { |
| | | form.value = { |
| | | deviceLedgerId: undefined, |
| | | deviceModel: undefined, |
| | | maintenancePlanTime: dayjs().format("YYYY-MM-DD"), |
| | | }; |
| | | deviceNameText.value = ''; |
| | | }; |
| | | |
| | | const resetFormAndValidate = () => { |
| | | resetForm(); |
| | | clearValidate(); |
| | | }; |
| | | |
| | | // 扫描二维码功能 |
| | |
| | | } |
| | | |
| | | isScanning.value = true; |
| | | showToast('扫码成功,3秒后自动填充设备信息'); |
| | | showToast('扫码成功'); |
| | | |
| | | // 3秒后处理扫码结果 |
| | | scanTimer.value = setTimeout(() => { |
| | | processScanResult(scanResult); |
| | | isScanning.value = false; |
| | | }, 3000); |
| | | }, 1000); |
| | | }; |
| | | |
| | | function getDeviceIdByRegExp(url) { |
| | | // 匹配deviceId=后面的数字 |
| | | const reg = /deviceId=(\d+)/; |
| | | const match = url.match(reg); |
| | | // 如果匹配到结果,返回数字类型,否则返回null |
| | | return match ? Number(match[1]) : null; |
| | | } |
| | | // 处理扫码结果并匹配设备 |
| | | const processScanResult = (scanResult) => { |
| | | // 在设备列表中查找匹配的设备 |
| | | // 假设二维码内容是设备名称或设备编号 |
| | | const matchedDevice = deviceOptions.value.find(device => |
| | | device.deviceName === scanResult || |
| | | device.deviceCode === scanResult || |
| | | device.id.toString() === scanResult |
| | | ); |
| | | const deviceId = getDeviceIdByRegExp(scanResult); |
| | | const matchedDevice = deviceOptions.value.find(item => item.id == deviceId); |
| | | |
| | | if (matchedDevice) { |
| | | // 找到匹配的设备,自动填充 |
| | | form.value.deviceLedgerId = matchedDevice.id; |
| | | deviceNameText.value = matchedDevice.deviceName; |
| | | form.value.deviceNameText = matchedDevice.deviceName; |
| | | form.value.deviceModel = matchedDevice.deviceModel; |
| | | showToast('设备信息已自动填充'); |
| | | } else { |
| | |
| | | showDevice.value = true; |
| | | }; |
| | | |
| | | // 显示保养人选择器 |
| | | const showPersonPicker = () => { |
| | | if (!userOptions.value.length) { |
| | | showToast('暂无可选保养人'); |
| | | return; |
| | | } |
| | | showPerson.value = true; |
| | | }; |
| | | |
| | | // 确认保养人选择 |
| | | const onPersonConfirm = (selected) => { |
| | | const user = userOptions.value.find(item => item.userId === selected.value); |
| | | form.value.maintenancePerson = user?.nickName || selected.name || ''; |
| | | showPerson.value = false; |
| | | }; |
| | | |
| | | // 确认设备选择 |
| | | const onDeviceConfirm = ({ selectedValues, selectedOptions }) => { |
| | | form.value.deviceLedgerId = selectedOptions[0].value; |
| | | devicePickerValue.value = selectedValues; |
| | | const onDeviceConfirm = (selected) => { |
| | | // selected 返回的是选中项 |
| | | form.value.deviceLedgerId = selected.value; |
| | | form.value.deviceNameText = selected.name; |
| | | const selectedDevice = deviceOptions.value.find(item => item.id === selected.value); |
| | | if (selectedDevice) { |
| | | form.value.deviceModel = selectedDevice.deviceModel; |
| | | } |
| | | showDevice.value = false; |
| | | setDeviceModel(selectedOptions[0].value); |
| | | }; |
| | | |
| | | // 显示日期选择器 |
| | |
| | | }; |
| | | |
| | | // 确认日期选择 |
| | | const onDateConfirm = ({ selectedValues }) => { |
| | | form.value.maintenancePlanTime = selectedValues.join('-'); |
| | | currentDate.value = selectedValues; |
| | | const onDateConfirm = (e) => { |
| | | form.value.maintenancePlanTime = formatDateToYMD(e.value); |
| | | showDate.value = false; |
| | | }; |
| | | |
| | |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | // 页面加载时获取设备列表和参数 |
| | | // 页面加载时获取设备列表、保养人列表和参数 |
| | | loadDeviceName(); |
| | | loadUserOptions(); |
| | | getPageParams(); |
| | | }); |
| | | |
| | |
| | | const sendForm = async () => { |
| | | try { |
| | | // 手动验证表单 |
| | | await formRef.value?.validate(); |
| | | const valid = await formRef.value.validate(); |
| | | if (!valid) return; |
| | | |
| | | loading.value = true; |
| | | const id = getPageId(); |
| | | |
| | | syncTempFileIds(); |
| | | // 准备提交数据 |
| | | const submitData = { ...form.value }; |
| | | submitData.tempFileIds = form.value.tempFileIds || []; |
| | | // 确保日期格式正确 |
| | | if (submitData.maintenancePlanTime && !submitData.maintenancePlanTime.includes(':')) { |
| | | submitData.maintenancePlanTime = submitData.maintenancePlanTime + ' 00:00:00'; |
| | | } |
| | | |
| | | const { code } = id |
| | | const result = id |
| | | ? await editUpkeep({ id: id, ...submitData }) |
| | | : await addUpkeep(submitData); |
| | | const { code } = result || {}; |
| | | |
| | | if (code == 200) { |
| | | showToast(`${id ? "编辑" : "新增"}计划成功`); |
| | | setTimeout(() => { |
| | | uni.removeStorageSync('repairId'); |
| | | uni.navigateBack(); |
| | | }, 1500); |
| | | } else { |
| | |
| | | |
| | | // 返回上一页 |
| | | const goBack = () => { |
| | | // 清除存储的id |
| | | uni.removeStorageSync('repairId'); |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // 获取页面参数 |
| | | const getPageParams = () => { |
| | | const pages = getCurrentPages(); |
| | | const currentPage = pages[pages.length - 1]; |
| | | const options = currentPage.options; |
| | | |
| | | // 根据是否有id参数来判断是新增还是编辑 |
| | | if (options.id) { |
| | | // 编辑模式,获取详情 |
| | | loadForm(options.id); |
| | | } else { |
| | | // 新增模式 |
| | | loadForm(); |
| | | } |
| | | }; |
| | | |
| | | // 获取页面ID |
| | | const getPageId = () => { |
| | | const pages = getCurrentPages(); |
| | | const currentPage = pages[pages.length - 1]; |
| | | const options = currentPage.options; |
| | | return options.id; |
| | | return normalizeId(uni.getStorageSync('repairId')); |
| | | }; |
| | | |
| | | // 获取页面参数 |
| | | const getPageParams = () => { |
| | | const id = getPageId(); |
| | | if (id) { |
| | | loadForm(id); |
| | | } else { |
| | | operationType.value = 'add'; |
| | | attachmentList.value = []; |
| | | form.value.tempFileIds = []; |
| | | loadForm(); |
| | | } |
| | | }; |
| | | |
| | | onUnload(() => { |
| | | uni.removeStorageSync('repairId'); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import '@/static/scss/form-common.scss'; |
| | | .upkeep-add { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | |
| | | margin-left: 8px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .attachment-upload { |
| | | width: 100%; |
| | | } |
| | | |
| | | .upload-buttons { |
| | | display: flex; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .attachment-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .attachment-item { |
| | | position: relative; |
| | | width: 80px; |
| | | height: 80px; |
| | | } |
| | | |
| | | .attachment-preview { |
| | | width: 80px; |
| | | height: 80px; |
| | | border-radius: 6px; |
| | | background: #f5f5f5; |
| | | } |
| | | |
| | | .attachment-delete { |
| | | position: absolute; |
| | | top: -6px; |
| | | right: -6px; |
| | | width: 18px; |
| | | height: 18px; |
| | | border-radius: 50%; |
| | | background: rgba(0, 0, 0, 0.65); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .attachment-empty { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | </style> |