You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
18 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1200px" @closed="handleDialogClosed">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-row>
<el-col :span="8">
<el-form-item label="维修单编号" prop="repairCode">
<el-input v-model="formData.repairCode" placeholder="请输入维修单编号" :disabled="isRepairMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="维修单" prop="repairName">
<el-input v-model="formData.repairName" placeholder="请输入维修单名称" :disabled="isRepairMode" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="设备类型" prop="machineryTypeId">
<el-radio-group v-model="formData.machineryTypeId" :disabled="isRepairMode">
<el-radio :label="1">设备</el-radio>
<el-radio :label="2">关键件</el-radio>
</el-radio-group>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item label="设备" prop="deviceId">
<el-select
v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
:disabled="isRepairMode" placeholder="请选择设备" class="!w-full">
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="showComponentSelect" label="关键件" prop="componentId">
<el-select
v-model="formData.componentId" clearable :loading="componentLoading" :disabled="isRepairMode"
placeholder="请选择关键件" class="!w-full">
<el-option
v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="machineryName" :required="false">
<el-input v-model="formData.machineryName" placeholder="自动带出" disabled />
</el-form-item>
<el-form-item label="设备编码" prop="machineryCode" :required="false">
<el-input v-model="formData.machineryCode" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="规格型号" prop="machinerySpec" :required="false">
<el-input v-model="formData.machinerySpec" placeholder="自动带出" disabled />
</el-form-item>
<el-form-item label="品牌" prop="machineryBrand" :required="false">
<el-input v-model="formData.machineryBrand" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="维修人员" prop="acceptedBy">
<el-select
v-model="formData.acceptedBy" filterable clearable placeholder="请选择维修人员" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收人员" prop="confirmBy">
<el-select
v-model="formData.confirmBy" filterable clearable placeholder="请选择验收人员" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<template v-if="showRepairFields">
<el-row>
<el-col :span="8">
<el-form-item label="报修日期" prop="requireDate">
<el-date-picker v-model="formData.requireDate" type="date" value-format="x" placeholder="选择报修日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="完成日期" prop="finishDate">
<el-date-picker v-model="formData.finishDate" type="date" value-format="x" placeholder="选择完成日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="confirmDate">
<el-date-picker v-model="formData.confirmDate" type="date" value-format="x" placeholder="选择验收日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="维修结果" prop="repairResult">
<Editor v-model="formData.repairResult" height="150px" :readonly="repairFieldsDisabled" />
</el-form-item>
</template>
</el-form>
<!-- 子表的表单 -->
<el-tabs v-model="subTabsName">
<el-tab-pane label="设备维修项目行" name="dvRepairLine">
<DvRepairLineForm ref="dvRepairLineFormRef" :repair-id="formData.id" :is-repair-mode="formType === 'repair'" />
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DvRepairApi, DvRepairVO } from '@/api/mes/dvrepair'
import DvRepairLineForm from './components/DvRepairLineForm.vue'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { RepairItemsApi } from '@/api/mes/repairItems'
import { getSimpleUserList, UserVO } from '@/api/system/user'
/** 设备维修记录 表单 */
defineOptions({ name: 'DvRepairForm' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const isRepairMode = computed(() => formType.value === 'update' || formType.value === 'repair')
const showRepairFields = computed(() => formType.value === 'update' || formType.value === 'repair')
const repairFieldsDisabled = computed(() => formType.value !== 'repair')
const isHydrating = ref(false)
const emit = defineEmits(['success', 'closed']) // 定义 success 事件,用于操作成功后的回调
const formData = ref({
id: undefined,
repairCode: undefined,
repairName: undefined,
deviceId: undefined as number | undefined,
componentId: undefined as number | undefined,
machineryId: undefined,
machineryCode: undefined,
machineryName: undefined,
machineryBrand: undefined,
machinerySpec: undefined,
machineryTypeId: undefined,
requireDate: undefined,
finishDate: undefined,
confirmDate: undefined,
repairResult: undefined,
acceptedBy: undefined,
confirmBy: undefined,
status: undefined,
remark: undefined,
})
const showComponentSelect = computed(() => formData.value.machineryTypeId === 2)
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number; raw?: DeviceLedgerVO }[]>([])
const deviceOptionsLoaded = ref(false)
const componentLoading = ref(false)
const componentOptions = ref<{ label: string; value: number }[]>([])
const users = ref<UserVO[]>([])
const ensureUsersLoaded = async () => {
if (users.value.length) return
users.value = (await getSimpleUserList()) ?? []
}
const normalizeUserId = (value: any) => {
if (value === undefined || value === null || value === '') return undefined
const str = String(value)
if (/^\d+$/.test(str)) return str
const matched = users.value.find((u) => u.nickname === str)
return matched ? String(matched.id) : str
}
const upsertDeviceOption = (
options: { label: string; value: number; raw?: DeviceLedgerVO }[],
option: { label: string; value: number; raw?: DeviceLedgerVO }
) => {
const existed = options.some((o) => o.value === option.value)
return existed ? options : [option, ...options]
}
const toComponentOption = (item: any) => {
const id = typeof item?.id === 'number' ? item.id : Number(item?.id)
if (Number.isNaN(id)) return undefined
const code = item?.code ?? item?.componentCode ?? item?.subjectCode
const name = item?.name ?? item?.componentName ?? item?.subjectName
const label = `${code ?? ''} ${name ?? ''}`.trim() || String(id)
return { label, value: id }
}
const loadComponentOptionsByDeviceId = async (deviceId: number) => {
componentLoading.value = true
try {
const data = await RepairItemsApi.getComponentList(deviceId)
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as any[]
componentOptions.value = rows.map(toComponentOption).filter(Boolean) as { label: string; value: number }[]
} finally {
componentLoading.value = false
}
}
const ensureDeviceOptionsLoaded = async () => {
if (deviceOptionsLoaded.value) return
deviceLoading.value = true
try {
const data = await DeviceLedgerApi.getDeviceLedgerList({})
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as DeviceLedgerVO[]
deviceOptions.value = rows
.filter((r) => typeof r?.id === 'number')
.map((r) => ({ label: `${r.deviceCode ?? ''} ${r.deviceName ?? ''}`.trim(), value: r.id, raw: r }))
deviceOptionsLoaded.value = true
} finally {
deviceLoading.value = false
}
}
watch(
() => formData.value.machineryTypeId,
(val) => {
if (isHydrating.value) return
formData.value.deviceId = undefined
formData.value.componentId = undefined
formData.value.machineryId = undefined
formData.value.machineryCode = undefined
formData.value.machineryName = undefined
formData.value.machineryBrand = undefined
formData.value.machinerySpec = undefined
componentOptions.value = []
setLineRows([])
}
)
watch(
() => formData.value.deviceId,
async (deviceId) => {
if (isHydrating.value) return
formData.value.componentId = undefined
componentOptions.value = []
if (typeof deviceId !== 'number') {
setLineRows([])
}
const option = deviceOptions.value.find((o) => o.value === deviceId)
if (option?.raw) {
formData.value.machineryCode = option.raw.deviceCode
formData.value.machineryName = option.raw.deviceName
formData.value.machinerySpec = option.raw.deviceSpec
formData.value.machineryBrand = option.raw.deviceBrand
}
if (formData.value.machineryTypeId === 2 && typeof deviceId === 'number') {
await loadComponentOptionsByDeviceId(deviceId)
}
if (formData.value.machineryTypeId === 1 && typeof deviceId === 'number') {
await prefillLinesByDeviceOrComponent({ deviceId, deviceType: 1 })
}
}
)
watch(
() => formData.value.componentId,
async (componentId) => {
if (isHydrating.value) return
if (formData.value.machineryTypeId !== 2) return
const deviceId = formData.value.deviceId
if (typeof deviceId !== 'number' || typeof componentId !== 'number') {
setLineRows([])
return
}
await prefillLinesByDeviceOrComponent({ deviceId, componentId, deviceType: 2 })
}
)
const formRules = reactive({
repairCode: [{ required: true, message: '维修单编号不能为空', trigger: 'blur' }],
machineryId: [{ required: true, message: '设备ID不能为空', trigger: 'blur' }],
machineryCode: [{ required: true, message: '设备编码不能为空', trigger: 'blur' }],
machineryName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
machineryTypeId: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
})
const formRef = ref() // 表单 Ref
/** 子表的表单 */
const subTabsName = ref('dvRepairLine')
const dvRepairLineFormRef = ref()
const normalizeDeviceOrComponentList = (data: any) => {
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as any[]
return rows
}
const toDvRepairLineRow = (item: any) => {
const subjectId = item?.subjectId ?? item?.id
return {
id: undefined,
repairId: formData.value.id,
subjectId,
subjectCode: item?.subjectCode ?? item?.subject_code ?? item?.code,
subjectName: item?.subjectName ?? item?.subject_name ?? item?.name,
subjectType: item?.subjectType ?? item?.subject_type ?? item?.type,
subjectContent: item?.subjectContent ?? item?.projectContent ?? item?.subject_content,
subjectStandard: item?.subjectStandard ?? item?.judgmentCriteria ?? item?.subject_standard,
malfunction: undefined,
malfunctionUrl: undefined,
repairDes: undefined,
remark: undefined
}
}
const setLineRows = (rows: any[]) => {
dvRepairLineFormRef.value?.setData(rows)
}
const prefillLinesByDeviceOrComponent = async (params: { deviceId: number; componentId?: number; deviceType: number }) => {
if (formType.value !== 'create') return
const data = await RepairItemsApi.getDeviceOrComponentList(params)
const list = normalizeDeviceOrComponentList(data)
setLineRows(list.map(toDvRepairLineRow))
}
let openRequestId = 0
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
const currentOpenId = ++openRequestId
dialogVisible.value = true
dialogTitle.value = type === 'repair' ? '维修' : t('action.' + type)
formType.value = type
resetForm()
await ensureUsersLoaded()
await ensureDeviceOptionsLoaded()
if (currentOpenId !== openRequestId) return
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
isHydrating.value = true
formData.value = await DvRepairApi.getDvRepair(id)
if (currentOpenId !== openRequestId) return
;(formData.value as any).requireDate = (formData.value as any).requireDate ?? undefined
;(formData.value as any).finishDate = (formData.value as any).finishDate ?? undefined
;(formData.value as any).confirmDate = (formData.value as any).confirmDate ?? undefined
;(formData.value as any).repairResult = (formData.value as any).repairResult ?? ''
;(formData.value as any).acceptedBy = normalizeUserId((formData.value as any).acceptedBy)
;(formData.value as any).confirmBy = normalizeUserId((formData.value as any).confirmBy)
const typeId = typeof formData.value.machineryTypeId === 'number' ? formData.value.machineryTypeId : Number(formData.value.machineryTypeId)
formData.value.machineryTypeId = Number.isNaN(typeId) ? formData.value.machineryTypeId : typeId
const deviceId = (formData.value as any).deviceId
const resolvedDeviceId = typeof deviceId === 'number' ? deviceId : formData.value.machineryId
if (typeof resolvedDeviceId === 'number') {
formData.value.deviceId = resolvedDeviceId
const label = `${formData.value.machineryCode ?? ''} ${formData.value.machineryName ?? ''}`.trim() || `ID:${resolvedDeviceId}`
deviceOptions.value = upsertDeviceOption(deviceOptions.value, { label, value: resolvedDeviceId })
}
if (formData.value.machineryTypeId === 2 && typeof formData.value.deviceId === 'number') {
await loadComponentOptionsByDeviceId(formData.value.deviceId)
const componentId = (formData.value as any).componentId
const resolvedComponentId = typeof componentId === 'number' ? componentId : Number(componentId)
if (!Number.isNaN(resolvedComponentId)) {
formData.value.componentId = resolvedComponentId
}
}
} finally {
isHydrating.value = false
formLoading.value = false
}
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const handleDialogClosed = () => {
openRequestId++
emit('closed')
}
onBeforeUnmount(() => {
openRequestId++
})
/** 提交表单 */
const submitForm = async () => {
// 校验表单
await formRef.value.validate()
// 校验子表单
try {
await dvRepairLineFormRef.value.validate()
} catch (e) {
subTabsName.value = 'dvRepairLine'
return
}
// 提交请求
formLoading.value = true
try {
const data = { ...(formData.value as any) } as DvRepairVO & { deviceId?: number; componentId?: number }
;(data as any).acceptedBy = normalizeUserId((data as any).acceptedBy)
;(data as any).confirmBy = normalizeUserId((data as any).confirmBy)
if (formType.value === 'repair') {
;(data as any).status = 1
}
if (typeof formData.value.deviceId === 'number') {
data.machineryId = formData.value.deviceId as any
}
;(data as any).deviceId = formData.value.deviceId
;(data as any).componentId = formData.value.machineryTypeId === 2 ? formData.value.componentId : undefined
const lineList = dvRepairLineFormRef.value.getData() || []
if (formType.value === 'repair') {
const requireDate = data.requireDate
const finishDate = data.finishDate
const confirmDate = data.confirmDate
const repairResult = data.repairResult
const updateReqVOList = lineList
await DvRepairApi.updateDvRepairStatus({
id: data.id,
requireDate,
finishDate,
confirmDate,
repairResult,
updateReqVOList,
})
message.success(t('common.updateSuccess'))
} else {
;(data as any).dvRepairLines = lineList
if (formType.value === 'create') {
await DvRepairApi.createDvRepair(data)
message.success(t('common.createSuccess'))
} else {
await DvRepairApi.updateDvRepair(data)
message.success(t('common.updateSuccess'))
}
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
repairCode: undefined,
repairName: undefined,
deviceId: undefined,
componentId: undefined,
machineryId: undefined,
machineryCode: undefined,
machineryName: undefined,
machineryBrand: undefined,
machinerySpec: undefined,
machineryTypeId: 1,
requireDate: undefined,
finishDate: undefined,
confirmDate: undefined,
repairResult: '',
acceptedBy: undefined,
confirmBy: undefined,
status: undefined,
remark: undefined,
}
deviceOptionsLoaded.value = false
componentOptions.value = []
formRef.value?.resetFields()
}
</script>