feat:排产弹框-新增设备名称列/关联设备按钮

pull/1/head
黄伟杰 1 month ago
parent 972bf17c56
commit 663b99800c

@ -134,6 +134,7 @@
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTaskCodeColumn')" align="center" prop="taskCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductCodeColumn')" align="center" prop="barCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductNameColumn')" align="center" prop="productName" sortable />
<el-table-column label="设备名称" align="center" prop="deviceDisplayName" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTotalNumberColumn')" align="center" prop="number" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTablePlanNumberColumn')" align="center" prop="planNumber" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableUnplanNumberColumn')" align="center">
@ -143,11 +144,14 @@
</span>
</template>
</el-table-column>
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableOperateColumn')" align="center" width="100px">
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableOperateColumn')" align="center" width="180px">
<template #default="scope">
<el-button link type="info" @click="openProductItemNeed(scope.row)">
{{ t('ProductionPlan.TaskSummary.detailActionMaterialLabel') }}
</el-button>
<el-button link type="primary" @click="openDeviceRelationDialog(scope.row)">
关联设备
</el-button>
</template>
</el-table-column>
</el-table>
@ -165,12 +169,41 @@
@saved="handlePreviewSaved"
/>
<Dialog v-model="deviceRelationDialogVisible" title="关联设备" width="520px">
<el-form :model="deviceRelationForm" label-width="90px" v-loading="deviceRelationLoading">
<el-form-item label="关联设备">
<el-input
:model-value="deviceRelationDisplayText"
placeholder="点击选择设备"
readonly
@click="openDeviceSelectDialog"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" :loading="deviceRelationSaving" @click="submitDeviceRelation"></el-button>
<el-button @click="deviceRelationDialogVisible = false">取消</el-button>
</template>
</Dialog>
<TableSelectDialog
ref="deviceSelectDialogRef"
title="选择设备"
:columns="deviceColumns"
:fetch-api="fetchDeviceLedgerPage"
row-key="id"
@confirm="handleDeviceSelectConfirm"
/>
<ItemNeedIndex ref="itemNeedRef" />
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { TaskApi } from '@/api/mes/task'
import { ProductApi } from '@/api/erp/product/product'
import { DeviceLedgerApi } from '@/api/mes/deviceledger'
import TableSelectDialog from '@/components/TableSelectDialog/TableSelectDialog.vue'
import ItemNeedIndex from '@/views/mes/bom/ItemNeedIndex.vue'
import { dateFormatter2 } from '@/utils/formatTime'
import TaskSchedulePreviewDialog from './TaskSchedulePreviewDialog.vue'
@ -191,6 +224,29 @@ const itemNeedRef = ref()
const taskTableRef = ref()
const detailTableRef = ref()
const previewScheduleList = ref<any[]>([])
const deviceSelectDialogRef = ref()
const deviceRelationDialogVisible = ref(false)
const deviceRelationLoading = ref(false)
const deviceRelationSaving = ref(false)
const currentDeviceRelationRow = ref<any>()
const currentProductData = ref<any>()
const selectedDeviceRows = ref<any[]>([])
const deviceRelationForm = reactive({
productId: undefined as number | undefined,
devices: [] as { id: number; name: string }[]
})
const deviceColumns = [
{ label: '设备编号', prop: 'deviceCode', minWidth: 140 },
{ label: '设备名称', prop: 'deviceName', minWidth: 160 },
{ label: '设备型号', prop: 'deviceModel', minWidth: 140 },
{ label: '所属车间', prop: 'workshop', minWidth: 140 }
]
const deviceRelationDisplayText = computed(() => {
if (!deviceRelationForm.devices.length) return ''
if (!selectedDeviceRows.value.length) return deviceRelationForm.devices.map((item) => item.name).join('、')
return selectedDeviceRows.value.map((item) => item.deviceName || item.name || item.code || `ID:${item.id}`).join('、')
})
const scheduleRuleOptions = [
{ label: '订单优先级', value: 2 },
@ -227,6 +283,77 @@ const taskDetailRequestMap = new Map<number, Promise<any[]>>()
const currentDetailRequestId = ref(0)
const taskTableBusy = computed(() => taskLoading.value || taskSelectionLoading.value)
const getRelationName = (item: Record<string, any>, nameKeys: string[], fallbackPrefix: string, id: number) => {
for (const key of nameKeys) {
const value = item[key]
if (value !== undefined && value !== null && String(value).trim() !== '') {
return String(value)
}
}
return `${fallbackPrefix}ID:${id}`
}
const normalizeRelationList = (
value: unknown,
fallbackRows: any[] | undefined,
nameKeys: string[],
fallbackPrefix: string
): { id: number; name: string }[] => {
const fallbackMap = new Map<number, string>()
;(fallbackRows || []).forEach((row) => {
const id = Number(row?.id)
if (!Number.isFinite(id)) return
fallbackMap.set(id, getRelationName(row, nameKeys, fallbackPrefix, id))
})
const parseArray = (source: unknown): any[] => {
if (Array.isArray(source)) return source
if (typeof source === 'string') {
const content = source.trim()
if (!content) return []
try {
const parsed = JSON.parse(content.startsWith('[') ? content : `[${content}]`)
return Array.isArray(parsed) ? parsed : []
} catch {
return content.split(',').map((item) => item.trim()).filter(Boolean)
}
}
return []
}
return parseArray(value)
.map((item) => {
if (typeof item === 'object' && item !== null) {
const id = Number((item as any).id)
if (!Number.isFinite(id)) return undefined
return {
id,
name: getRelationName(item as any, nameKeys, fallbackPrefix, id)
}
}
const id = Number(item)
if (!Number.isFinite(id)) return undefined
return {
id,
name: fallbackMap.get(id) || `${fallbackPrefix}ID:${id}`
}
})
.filter((item): item is { id: number; name: string } => Boolean(item))
}
const toDeviceRows = (devices: { id: number; name: string }[]) => {
return devices.map((item) => ({
id: item.id,
deviceName: item.name,
name: item.name
}))
}
const buildRelationIdList = (list: { id: number; name: string }[]) => {
return list.map((item) => Number(item.id)).filter((id) => Number.isFinite(id))
}
const fetchDeviceLedgerPage = (params: Record<string, any>) => {
return DeviceLedgerApi.getDeviceLedgerPage({
...params,
isScheduled: 1
})
}
const loadTaskList = async () => {
taskLoading.value = true
try {
@ -276,7 +403,8 @@ const getTaskDetailList = async (taskRow?: any) => {
const list = (data?.list ?? []).map((item: any) => ({
...item,
_parentTaskOrderPriority: taskRow?.isUrgent,
_parentTaskDeliveryDate: taskRow?.deliveryDate
_parentTaskDeliveryDate: taskRow?.deliveryDate,
deviceDisplayName: item.deviceDisplayName || item.deviceName || item.feedingPipelineName || ''
}))
allDetailsMap.value[taskId] = list
return list
@ -445,6 +573,90 @@ const openProductItemNeed = (row: any) => {
const number = row.number - row.planNumber > 0 ? row.number - row.planNumber : 0
itemNeedRef.value.open('product', row.productName, row.productId, number)
}
const openDeviceRelationDialog = async (row: any) => {
if (!row?.productId) {
message.warning('当前明细没有关联产品,无法设置设备')
return
}
currentDeviceRelationRow.value = row
deviceRelationDialogVisible.value = true
deviceRelationLoading.value = true
selectedDeviceRows.value = []
try {
const productData = await ProductApi.getProduct(Number(row.productId))
currentProductData.value = productData
const devices = normalizeRelationList(
(productData as any).devices ?? (productData as any).deviceIds,
(productData as any).deviceList,
['name', 'deviceName', 'code'],
'设备'
)
deviceRelationForm.productId = Number(row.productId)
deviceRelationForm.devices = devices
selectedDeviceRows.value = toDeviceRows(devices)
} finally {
deviceRelationLoading.value = false
}
}
const openDeviceSelectDialog = () => {
const rows = selectedDeviceRows.value.length
? selectedDeviceRows.value.map((item) => ({ ...item, id: Number(item.id) }))
: toDeviceRows(deviceRelationForm.devices)
deviceSelectDialogRef.value?.open(rows)
}
const handleDeviceSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
deviceRelationForm.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
}
const submitDeviceRelation = async () => {
if (!currentProductData.value || !deviceRelationForm.productId) return
deviceRelationSaving.value = true
try {
const currentData = currentProductData.value as any
const moldIds = normalizeRelationList(
currentData.molds ?? currentData.moldIds,
currentData.moldList,
['name', 'code'],
'模具'
)
const payload: any = {
...currentData,
deviceIds: buildRelationIdList(deviceRelationForm.devices),
moldIds: buildRelationIdList(moldIds)
}
delete payload.devices
delete payload.molds
await ProductApi.updateProduct(payload)
const displayText = deviceRelationForm.devices.map((item) => item.name).join('、')
const rowId = currentDeviceRelationRow.value?.id
if (rowId !== undefined) {
Object.values(allDetailsMap.value).forEach((rows) => {
rows.forEach((item: any) => {
if (item.id === rowId) {
item.deviceDisplayName = displayText
}
})
})
const target = detailList.value.find((item: any) => item.id === rowId)
if (target) {
target.deviceDisplayName = displayText
}
}
message.success('关联设备已保存')
deviceRelationDialogVisible.value = false
} finally {
deviceRelationSaving.value = false
}
}
const handlePreviewSaved = async () => {
dialogVisible.value = false

Loading…
Cancel
Save