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.
besure_web/src/views/mes/moldoperate/MoldOperateForm.vue

569 lines
19 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">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="120px"
v-loading="formLoading"
>
<el-form-item :label="t('MoldManagement.MoldOperate.operateType')" prop="operateType">
<el-radio-group v-model="formData.operateType">
<el-radio :label="1">{{ t('MoldManagement.MoldOperate.operateTypeUp') }}</el-radio>
<el-radio :label="2">{{ t('MoldManagement.MoldOperate.operateTypeDown') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.device')" prop="deviceId" v-if="formData.operateType != null">
<!-- <el-select
v-model="formData.deviceId"
filterable
clearable
:loading="deviceLoading"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')"
class="!w-full"
@change="deviceChange(formData.deviceId)"
>
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>-->
<el-input :model-value="displayItemDevice" readonly clearable class="device-ledger-selection-input"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')"
@click="openCriticalComponentDialog" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.mold')" prop="moldId" v-if="formData.operateType == '1'">
<!-- <el-select
v-model="formData.moldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderMold')"
class="!w-full"
>
<el-option
v-for="item in moldList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>-->
<el-input
:model-value="moldDisplayText"
:placeholder="t('MoldManagement.MoldOperate.placeholderMold')"
readonly
@click="openMoldSelectDialog"
/>
</el-form-item>
<el-form-item
v-if="formData.operateType == '2' && formData.deviceId"
:label="t('MoldManagement.MoldOperate.lowerMold')"
prop="lowerMoldId"
>
<el-select
v-model="formData.lowerMoldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderLowerMold')"
class="!w-full"
>
<el-option
v-for="item in lowerMoldList"
:key="item.id"
:label="item.name || item.moldName || `ID:${item.id}`"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('MoldManagement.MoldOperate.placeholderRemark')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
<TableSelectDialog
ref="deviceSelectDialogRef"
title="选择设备"
:columns="deviceColumns"
:fetch-api="fetchDeviceLedgerPage"
row-key="id"
@confirm="handleDeviceSelectConfirm"
:query-params="mergedQueryParams"
>
<!-- 使用 header 插槽插入查询表单 -->
<template #header>
<el-form ref="searchFormRef" :model="searchParams" :inline="true" >
<el-form-item label="设备编号" prop="deviceCode">
<el-input v-model="searchParams.deviceCode" placeholder="请输入编号" clearable />
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="searchParams.deviceName" placeholder="请输入名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">{{ t('FactoryModeling.ProductInformation.searchButtonText') }}</el-button>
<el-button @click="resetSearch">{{ t('FactoryModeling.ProductInformation.resetButtonText') }}</el-button>
</el-form-item>
</el-form>
</template>
</TableSelectDialog>
<TableSelectDialog
ref="moldSelectDialogRef"
title="选择模具"
:columns="moldColumns"
:fetch-api="MoldBrandApi.getMoldPage"
row-key="id"
@confirm="handleMoldSelectConfirm"
:query-params="mergedMoldQueryParams"
>
<!-- 使用 header 插槽插入查询表单 -->
<template #header>
<el-form ref="searchMoldFormRef" :model="searchMoldParams" :inline="true" >
<el-form-item label="模具编号" prop="code">
<el-input v-model="searchMoldParams.code" placeholder="请输入编号" clearable />
</el-form-item>
<el-form-item label="模具名称" prop="name">
<el-input v-model="searchMoldParams.name" placeholder="请输入名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleMoldSearch">{{ t('FactoryModeling.ProductInformation.searchButtonText') }}</el-button>
<el-button @click="resetMoldSearch">{{ t('FactoryModeling.ProductInformation.resetButtonText') }}</el-button>
</el-form-item>
</el-form>
</template>
</TableSelectDialog>
</template>
<script setup lang="ts">
import { MoldOperateApi, MoldOperateVO } from '@/api/mes/moldoperate'
import { MoldBrandApi, MoldVO } from '@/api/erp/mold'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import TableSelectDialog from '@/components/TableSelectDialog/TableSelectDialog.vue'
/** */
defineOptions({ name: 'MoldOperateForm' })
const { t } = useI18n() //
const message = useMessage() //
const moldList = ref<MoldVO[]>([]) // 上模可选模具列表(在途)
const lowerMoldList = ref<any[]>([]) // 下模可选模具列表
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number; raw?: DeviceLedgerVO }[]>([])
const deviceOptionsLoaded = ref(false)
const initializingOperateType = ref(false)
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
id: undefined,
operateType: undefined,
moldId: undefined,
deviceId: undefined,
remark: undefined,
lowerMoldId: undefined,
})
const validateMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '1') {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorMoldRequired')))
} else {
callback()
}
}
const validateLowerMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '2') {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorLowerMoldRequired')))
} else {
callback()
}
}
const formRules = reactive({
operateType: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperateTypeRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorDeviceRequired'), trigger: 'blur' }],
moldId: [{ required: true, validator: validateMoldId, trigger: 'change' }],
lowerMoldId: [{ required: true, validator: validateLowerMoldId, trigger: 'change' }],
})
const formRef = ref() // 表单 Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
initSelectedItems()
await ensureDeviceOptionsLoaded()
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
initializingOperateType.value = true
const data = await MoldOperateApi.getMoldOperate(id)
formData.value = {
...formData.value,
...data,
lowerMoldId: (data as any).lowerMoldId,
}
// 编辑时根据类型格式化模具字段
if (String(formData.value.operateType) === '1') {
if (typeof formData.value.moldId === 'string') {
const parts = formData.value.moldId.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
formData.value.moldId = parts as any
}
await loadUpMoldList()
} else if (String(formData.value.operateType) === '2') {
const rawLower = (formData.value as any).lowerMoldId
if (typeof rawLower === 'string') {
const parts = rawLower.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
;(formData.value as any).lowerMoldId = parts
}
await loadLowerMoldList()
}
} finally {
initializingOperateType.value = false
formLoading.value = false
}
}else{
ids.value=[]
moldIds.value=[]
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
// const submitForm = async () => {
// // 校验表单
// await formRef.value.validate()
// // 检验
// if (formData.value.operateType === '1') {
// const data = await someApiToCheck(formData.value.deviceId)
// if (data === true) {
// message.alert('请先将该设备上的模具换下!')
// return;
// }
// }
// // 提交请求
// formLoading.value = true
// try {
// const data = formData.value as unknown as MoldOperateVO
// if (formType.value === 'create') {
// await MoldOperateApi.createMoldOperate(data)
// message.success(t('common.createSuccess'))
// } else {
// await MoldOperateApi.updateMoldOperate(data)
// message.success(t('common.updateSuccess'))
// }
// dialogVisible.value = false
// // 发送操作成功的事件
// emit('success')
// } finally {
// formLoading.value = false
// }
// }
const submitForm = async () => {
// 立即开始 loading
formLoading.value = true
try {
// 1. 表单校验
await formRef.value.validate()
// 2. 组装提交数据
const raw = formData.value as any
const submitData: any = {
id: raw.id,
operateType: raw.operateType,
deviceId: raw.deviceId,
remark: raw.remark,
}
if (String(raw.operateType) === '1') {
const ids = Array.isArray(raw.moldId) ? raw.moldId : raw.moldId != null ? [raw.moldId] : []
submitData.moldId = ids.map((v: any) => v).join(',')
} else if (String(raw.operateType) === '2') {
const allIds = lowerMoldList.value
.map((item: any) => item?.id)
.filter((id: any) => id !== undefined && id !== null)
const lowerIds = Array.isArray(raw.lowerMoldId)
? raw.lowerMoldId
: raw.lowerMoldId != null
? [raw.lowerMoldId]
: []
submitData.lowerMoldId = lowerIds.map((v: any) => v).join(',')
const lowerIdSet = new Set(lowerIds.map((v: any) => String(v)))
const remainIds = allIds.filter((id: any) => !lowerIdSet.has(String(id)))
submitData.moldId = remainIds.join(',')
}
// 3. 提交数据
if (formType.value === 'create') {
await MoldOperateApi.createMoldOperate(submitData)
message.success(t('common.createSuccess'))
} else {
await MoldOperateApi.updateMoldOperate(submitData)
message.success(t('common.updateSuccess'))
}
// 4. 成功处理
dialogVisible.value = false
emit('success')
} catch (error) {
} finally {
// 确保 loading 状态被清除
formLoading.value = false
}
}
const ensureDeviceOptionsLoaded = async () => {
if (deviceOptionsLoaded.value) return
deviceLoading.value = true
try {
const data = await DeviceLedgerApi.getDeviceLedgerPage({})
const rows = (data?.list ?? []) 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
}
}
// 设备更改
const deviceChange = async (deviceId:number) => {
if (String(formData.value.operateType) === '2' && deviceId) {
await loadLowerMoldList()
formData.value.lowerMoldId = undefined as any
}
}
const loadUpMoldList = async () => {
moldList.value = await MoldBrandApi.getInTransitMoldAllList()
}
const loadLowerMoldList = async () => {
if (!formData.value.deviceId) {
lowerMoldList.value = []
return
}
const list = await MoldOperateApi.getLowerMoldList(formData.value.deviceId)
lowerMoldList.value = Array.isArray(list) ? list : []
}
watch(
() => formData.value.operateType,
async (val) => {
if (initializingOperateType.value) {
return
}
formData.value.deviceId = undefined as any
formData.value.moldId = undefined as any
formData.value.lowerMoldId = undefined as any
moldList.value = []
lowerMoldList.value = []
if (!val) {
return
}
if (String(val) === '1') {
await loadUpMoldList()
} else if (String(val) === '2') {
await loadLowerMoldList()
}
}
)
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
operateType: undefined,
moldId: undefined,
deviceId: undefined,
remark: undefined,
lowerMoldId: undefined,
}
formRef.value?.resetFields()
}
const deviceColumns = [
{ label: '设备编号', prop: 'deviceCode', minWidth: 140 },
{ label: '设备名称', prop: 'deviceName', minWidth: 160 },
{ label: '设备型号', prop: 'deviceModel', minWidth: 140 },
{ label: '所属车间', prop: 'workshop', minWidth: 140 }
]
const moldColumns = [
{ label: '模具编码', prop: 'code', minWidth: 140 },
{ label: '模具名称', prop: 'name', minWidth: 160 },
{ label: '模具型号', prop: 'brandName', minWidth: 140 },
{ label: '状态', prop: 'status', minWidth: 100 }
]
const fetchDeviceLedgerPage = (params: Record<string, any>) => {
return DeviceLedgerApi.getDeviceLedgerPage({
...params,
isScheduled: 1
})
}
const selectedDeviceRows = ref<any[]>([])
const selectedMoldRows = ref<any[]>([])
const handleDeviceSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
formData.value.devices = payload.rows
.map((item) => {
const id = Number(item.id)
if (!Number.isFinite(id)) return undefined
return {
id,
name: item.deviceName || item.name || item.code || `设备ID:${id}`
}
})
.filter((item): item is { id: number; name: string } => Boolean(item))
selectedDeviceRows.value = payload.rows
formData.value.deviceId = payload.ids.join(',')
ids.value = payload.ids.map((id) => Number(id))
}
const handleMoldSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
formData.value.molds = payload.rows
.map((item) => {
const id = Number(item.id)
if (!Number.isFinite(id)) return undefined
return {
id,
name: item.name || item.code || `模具ID:${id}`
}
})
.filter((item): item is { id: number; name: string } => Boolean(item))
selectedMoldRows.value = payload.rows
formData.value.moldId = payload.ids.join(',')
moldIds.value = payload.ids.map((id) => Number(id))
}
// 1. 自定义表单的查询参数
const searchParams = reactive({
deviceCode: undefined,
deviceName: undefined,
})
const searchFormRef = ref()
const handleSearch = () => {
// 触发弹窗内部重新加载数据
deviceSelectDialogRef.value?.reload?.()
}
const resetSearch = () => {
searchFormRef.value?.resetFields()
handleSearch()
}
// 1. 自定义表单的查询参数
const searchMoldParams = reactive({
code: undefined,
name: undefined,
})
const searchMoldFormRef = ref()
const handleMoldSearch = () => {
// 触发弹窗内部重新加载数据
moldSelectDialogRef.value?.reload?.()
}
const resetMoldSearch = () => {
searchMoldFormRef.value?.resetFields()
handleSearch()
}
const moldSelectDialogRef = ref()
// 2. 合并参数:将表单参数与组件内部的分页参数合并
const mergedQueryParams = computed(() => ({ ...searchParams }))
const mergedMoldQueryParams = computed(() => ({ ...searchMoldParams }))
const ids = ref([])
const moldIds= ref([])
const itemList = ref<DeviceLedgerVO[]>([])
const moldItemList = ref<MoldVO[]>([])
const deviceSelectDialogRef = ref(false)
const deviceList = ref<DeviceLedgerVO[]>([])
const selectedRows = ref<any[]>([])
const total = ref(0)
const queryFormRef = ref()
const loading = ref(true)
const displayItemDevice = computed( () => {
if (!ids.value.length)return ''
if (!itemList.value.length) {
return formData.value.deviceId ? String(formData.value.deviceId) : ''
}
const map = new Map(itemList.value.map((item) => [item.id, item.deviceName]))
const names = ids.value
.map((id) => map.get(id))
.filter((name) => name)
return names.join(',')
})
const moldDisplayText = computed(() => {
if (!moldIds.value.length)return ''
if (!moldItemList.value.length) {
return formData.value.moldId ? String(formData.value.moldId) : ''
}
const map = new Map(moldItemList.value.map((item) => [item.id, item.name]))
const names = moldIds.value
.map((id) => map.get(id))
.filter((name) => name)
return names.join(',')
})
const openCriticalComponentDialog = async () => {
searchParams.deviceCode=''
searchParams.deviceName=''
searchMoldParams.code=''
searchMoldParams.name=''
const rows = selectedDeviceRows.value.map((item) => ({ ...item, id: Number(item.id) }))
deviceSelectDialogRef.value?.open(rows)
let initIds= formData.value.deviceId!=undefined?formData.value.deviceId.toString().split(","):[]
ids.value=initIds.map((id) => Number(id))
}
const openMoldSelectDialog = () => {
const rows = selectedMoldRows.value.map((item) => ({ ...item, id: Number(item.id) }))
moldSelectDialogRef.value?.open(rows)
}
const toDeviceRows = (split: any) => {
return split.map((item: any) => ({
id: item,
deviceName: item
}))
}
const initSelectedItems = async () => {
if (!itemList.value.length) {
loading.value = true
try {
itemList.value = await DeviceLedgerApi.getDeviceLedgerList()
} finally {
loading.value = false
}
}
if (!moldItemList.value.length) {
loading.value = true
try {
moldItemList.value = await MoldBrandApi.getMoldAllList()
} finally {
loading.value = false
}
}
}
</script>