| | |
| | | <!-- |
| | | * @Author : yuan |
| | | * @Date : 2026-01-20 14:04:02 |
| | | * @LastEditors : yuan |
| | | * @LastEditTime : 2026-01-20 16:38:55 |
| | | * @FilePath : \applications\drone-command\src\views\basicManage\maintainRecord\FormDiaLog.vue |
| | | * @Description : |
| | | * Copyright 2026 OBKoro1, All Rights Reserved. |
| | | * 2026-01-20 14:04:02 |
| | | --> |
| | | <template> |
| | | <el-dialog class="command-page-view-dialog" v-model="visible" :title="titleEnum[dialogMode]" @closed="handleClosed" |
| | | destroy-on-close :close-on-click-modal="false"> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">维护时间</div> |
| | | <div class="val">{{ list?.[0]?.maintainTime }}</div> |
| | | <div class="val">{{ dayjs(list?.[0]?.maintainTime).format('YYYY-MM-DD') }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">维护内容</div> |
| | |
| | | <div class="command-table-content"> |
| | | <el-table class="command-table" :data="list"> |
| | | <el-table-column type="index" width="60" label="序号" /> |
| | | <el-table-column prop="maintainTime" label="维护时间" /> |
| | | <el-table-column prop="maintainTime" show-overflow-tooltip label="维护时间"> |
| | | <template v-slot="{ row }"> |
| | | {{ dayjs(row.maintainTime).format('YYYY-MM-DD') }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="maintainContent" label="维护内容" /> |
| | | <el-table-column prop="replacePart" label="跟换部件" /> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="command-table-pagination"> |
| | | <el-pagination popper-class="command-select-popper" |
| | | v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> |
| | | <el-pagination popper-class="command-select-popper" v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" layout="total, prev, pager, next, sizes" :total="total" |
| | | @change="getList" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <el-form-item label="维护计划周期" prop="planCycleType"> |
| | | <el-select class="command-select" popper-class="command-select-popper" |
| | | v-model="formData.planCycleType" placeholder="请选择" clearable |
| | | @change="formData.planCycleValue = []"> |
| | | @change="formData.planCycleValue = ''"> |
| | | <el-option v-for="item in planCycleOptions" :key="item.value" :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护计划时间" prop="planCycleValue"> |
| | | <el-select class="command-select" popper-class="command-select-popper" |
| | | v-model="formData.planCycleValue" placeholder="请选择" clearable multiple |
| | | :disabled="!formData.planCycleType"> |
| | | <el-option v-for="item in planCycleValueOptions" :key="item.value" :label="item.value" |
| | | :value="item.value" /> |
| | | <el-form-item label="维护计划时间" prop="planCycleValue" > |
| | | <el-date-picker |
| | | v-if="formData.planCycleType === '1'" |
| | | :disabled="!formData.planCycleType" |
| | | class="command-date-picker" |
| | | popper-class="command-date-picker-popper" |
| | | v-model="formData.planCycleValue" |
| | | type="date" |
| | | placeholder="请选择" |
| | | clearable |
| | | value-format="YYYY-MM-DD" |
| | | :format="planCycleDateFormat" |
| | | :disabled-date="getPlanCycleDisabledDate" |
| | | :editable="false" /> |
| | | <el-select |
| | | v-else |
| | | :disabled="!formData.planCycleType" |
| | | class="command-select" |
| | | popper-class="command-select-popper" |
| | | v-model="formData.planCycleValue" |
| | | placeholder="请选择" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in planCycleValueOptions" |
| | | :key="item.value" |
| | | :label="item.value" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button color="#284FE3" v-if="!dialogReadonly" type="primary" :loading="submitting" |
| | | :disabled="submitting" @click="handleSubmit"> |
| | | 保存 |
| | |
| | | |
| | | <script setup> |
| | | import { computed, ref } from 'vue' |
| | | import dayjs from 'dayjs' |
| | | import 'dayjs/locale/zh-cn' |
| | | import { ElMessage } from 'element-plus' |
| | | import { fieldRules, getDictLabel } from '@ztzf/utils' |
| | | import { fwDeviceMaintainRecordPageApi } from '@/views/basicManage/maintainRecord/fwDeviceMaintainRecord' |
| | | import { saveOperationLog } from '@ztzf/apis' |
| | | import { useRoute } from 'vue-router' |
| | | import { |
| | | fwDeviceMaintainPlanDetailApi, |
| | | fwDeviceMaintainPlanSubmitApi, |
| | |
| | | const initForm = () => ({ |
| | | deviceId: '', |
| | | planCycleType: '', |
| | | planCycleValue: [], |
| | | planCycleValue: '', |
| | | }) |
| | | |
| | | dayjs.locale('zh-cn') |
| | | |
| | | const planCycleOptions = inject('planCycleOptions') |
| | | const planCycleValueOptions = ref([]) |
| | |
| | | const deviceList = ref([]) // 设备列表 |
| | | const getPlanCycleLabel = inject('getPlanCycleLabel') |
| | | const dictObj = inject('dictObj') |
| | | const route = useRoute() |
| | | const dialogReadonly = computed(() => dialogMode.value === 'view') |
| | | const titleEnum = ref({ edit: '编辑', view: '查看', add: '维护计划' }) |
| | | |
| | | const planCycleLabel = computed(() => { |
| | | const item = planCycleOptions.find(option => option.value === formData.value.planCycleType) |
| | | return item?.label || formData.value.planCycleType || '-' |
| | | const planCycleDateFormat = computed(() => { |
| | | const type = formData.value.planCycleType |
| | | if (type === '1') return 'M\u6708D\u53f7' |
| | | if (type === '2') return 'D\u53f7' |
| | | if (type === '3') return 'dddd' |
| | | return 'YYYY-MM-DD' |
| | | }) |
| | | |
| | | |
| | | const rules = { |
| | | deviceId: fieldRules(true), |
| | |
| | | } |
| | | |
| | | // 获取设备列表 |
| | | function getDeviceList() { |
| | | function getDeviceList () { |
| | | return fwDevicePageApi({ current: 1, size: 999 }).then(res => { |
| | | deviceList.value = res?.data?.data?.records ?? [] |
| | | }) |
| | | } |
| | | |
| | | // 关闭弹框 |
| | | function handleCancel() { |
| | | function handleCancel () { |
| | | visible.value = false |
| | | } |
| | | |
| | | // 提交新增/编辑 |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | await fwDeviceMaintainPlanSubmitApi(formData.value) |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | // 加载详情 |
| | | async function loadDetail() { |
| | | if (!formData.value.id) return |
| | | const res = await fwDeviceMaintainPlanDetailApi({ id: formData.value.id }) |
| | | formData.value = res?.data?.data ?? {} |
| | | console.log(formData.value, 66) |
| | | } |
| | | |
| | | // 关闭后重置 |
| | | function handleClosed() { |
| | | formData.value = initForm() |
| | | } |
| | | |
| | | const initSearchParams = () => ({ |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | | const searchParams = ref(initSearchParams()) |
| | | const total = ref(0) // 总条数 |
| | | const loading = ref(true) // 列表加载中 |
| | | const list = ref([]) // 列表数据 |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const params = { ...searchParams.value, planId: formData.value.id } |
| | | const res = await fwDeviceMaintainRecordPageApi(params) |
| | | list.value = res?.data?.data?.records ?? [] |
| | | total.value = res?.data?.data?.total ?? 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | | visible.value = true |
| | | await getDeviceList() |
| | | if (dialogMode.value === 'add') { |
| | | formData.value = initForm() |
| | | } else { |
| | | formData.value = row |
| | | await loadDetail() |
| | | getList() |
| | | } |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | |
| | | watch( |
| | | () => formData.value?.planCycleType, |
| | |
| | | planCycleValueOptions.value.push({ value: `${index + 1}号` }) |
| | | }) |
| | | } else if (type === '3') { |
| | | ;[...Array(7)].forEach((item, index) => { |
| | | planCycleValueOptions.value.push({ value: `星期${index + 1}` }) |
| | | ;['一', '二', '三', '四', '五', '六', '日'].forEach((item, index) => { |
| | | planCycleValueOptions.value.push({ value: `星期${item}` }) |
| | | }) |
| | | } |
| | | } |
| | | ) |
| | | |
| | | // 提交新增/编辑 |
| | | async function handleSubmit () { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | const payload = { |
| | | ...formData.value, |
| | | planCycleValue: [formatPlanCycleValue( |
| | | formData.value.planCycleValue, |
| | | formData.value.planCycleType |
| | | )], |
| | | } |
| | | await fwDeviceMaintainPlanSubmitApi(payload) |
| | | const actionText = dialogMode.value === 'add' ? '维护计划-新增' : '维护计划-编辑' |
| | | saveOperationLog({ |
| | | requestUri: route.path, |
| | | title: `${route.name || '维护记录管理'}-${actionText}`, |
| | | type: 1 |
| | | }) |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | // 加载详情 |
| | | async function loadDetail () { |
| | | if (!formData.value.id) return |
| | | const res = await fwDeviceMaintainPlanDetailApi({ id: formData.value.id }) |
| | | const data = res?.data?.data ?? {} |
| | | if (dialogMode.value !== 'view' && data?.planCycleType && data.planCycleValue) { |
| | | data.planCycleValue = normalizePlanCycleValue(data.planCycleValue, data.planCycleType) |
| | | } |
| | | formData.value = data |
| | | console.log(formData.value, 66) |
| | | } |
| | | |
| | | // 关闭后重置 |
| | | function handleClosed () { |
| | | formData.value = initForm() |
| | | } |
| | | |
| | | const initSearchParams = () => ({ |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | | const searchParams = ref(initSearchParams()) |
| | | const total = ref(0) // 总条数 |
| | | const loading = ref(true) // 列表加载中 |
| | | const list = ref([]) // 列表数据 |
| | | async function getList () { |
| | | loading.value = true |
| | | try { |
| | | const params = { ...searchParams.value, planId: formData.value.id } |
| | | const res = await fwDeviceMaintainRecordPageApi(params) |
| | | list.value = res?.data?.data?.records ?? [] |
| | | total.value = res?.data?.data?.total ?? 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open ({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | | visible.value = true |
| | | await getDeviceList() |
| | | if (dialogMode.value === 'add') { |
| | | formData.value = initForm() |
| | | } else { |
| | | formData.value = row |
| | | await loadDetail() |
| | | getList() |
| | | } |
| | | } |
| | | |
| | | function toDateString (date) { |
| | | const year = date.getFullYear() |
| | | const month = String(date.getMonth() + 1).padStart(2, '0') |
| | | const day = String(date.getDate()).padStart(2, '0') |
| | | return `${year}-${month}-${day}` |
| | | } |
| | | |
| | | function formatPlanCycleValue (value, type) { |
| | | if (typeof value !== 'string') return value |
| | | if (!value.includes('-')) return value |
| | | const date = new Date(value) |
| | | if (Number.isNaN(date.getTime())) return value |
| | | if (type === '1') return `${date.getMonth() + 1}\u6708${date.getDate()}\u53f7` |
| | | if (type === '2') return `${date.getDate()}\u53f7` |
| | | if (type === '3') { |
| | | const day = date.getDay() |
| | | const week = day === 0 ? 7 : day |
| | | return `\u661f\u671f${week}` |
| | | } |
| | | return value |
| | | } |
| | | |
| | | function normalizePlanCycleValue (value, type) { |
| | | if (!value) return '' |
| | | const now = new Date() |
| | | if (typeof value !== 'string') return '' |
| | | if (value.includes('-')) return value |
| | | if (type === '1') { |
| | | const match = value.match(/(\d{1,2})\u6708(\d{1,2})\u53f7/) |
| | | if (!match) return '' |
| | | const month = Number.parseInt(match[1], 10) - 1 |
| | | const day = Number.parseInt(match[2], 10) |
| | | return toDateString(new Date(now.getFullYear(), month, day)) |
| | | } |
| | | if (type === '2') { |
| | | const match = value.match(/(\d{1,2})\u53f7/) |
| | | if (!match) return '' |
| | | const day = Number.parseInt(match[1], 10) |
| | | return toDateString(new Date(now.getFullYear(), now.getMonth(), day)) |
| | | } |
| | | if (type === '3') { |
| | | const match = value.match(/\u661f\u671f(\d)/) |
| | | if (!match) return '' |
| | | const week = Number.parseInt(match[1], 10) |
| | | const { start } = getWeekRange(now) |
| | | const date = new Date(start) |
| | | date.setDate(start.getDate() + Math.min(Math.max(week, 1), 7) - 1) |
| | | return toDateString(date) |
| | | } |
| | | return value |
| | | } |
| | | |
| | | function getWeekRange (date) { |
| | | const base = new Date(date.getFullYear(), date.getMonth(), date.getDate()) |
| | | const day = base.getDay() |
| | | const diff = day === 0 ? -6 : 1 - day |
| | | const start = new Date(base) |
| | | start.setDate(base.getDate() + diff) |
| | | start.setHours(0, 0, 0, 0) |
| | | const end = new Date(start) |
| | | end.setDate(start.getDate() + 6) |
| | | end.setHours(23, 59, 59, 999) |
| | | return { start, end } |
| | | } |
| | | |
| | | function getPlanCycleDisabledDate (date) { |
| | | const type = formData.value.planCycleType |
| | | if (!type) return false |
| | | const now = new Date() |
| | | if (type === '1') { |
| | | return date.getFullYear() !== now.getFullYear() |
| | | } |
| | | if (type === '2') { |
| | | return date.getFullYear() !== now.getFullYear() || date.getMonth() !== now.getMonth() |
| | | } |
| | | if (type === '3') { |
| | | const { start, end } = getWeekRange(now) |
| | | return date < start || date > end |
| | | } |
| | | return false |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | |
| | | </script> |