style:设备台账-关键件/备件交互优化(穿梭框)

main
黄伟杰 2 weeks ago
parent 252a3b532e
commit 410e5d644a

@ -149,34 +149,28 @@
</el-col> -->
<el-col :span="24">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.criticalComponent')" prop="componentIds">
<el-cascader
v-model="criticalComponentCascaderValue"
:options="criticalComponentPagedOptions"
:props="cascaderProps"
filterable
<el-input
:model-value="criticalComponentDisplay"
readonly
clearable
collapse-tags
:show-all-levels="false"
class="device-ledger-selection-input"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderComponentIds')"
class="!w-full"
@change="handleCriticalComponentChange"
@clear="clearCriticalComponent"
@click="openCriticalComponentDialog"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.sparePart')" prop="beijianIds">
<el-cascader
v-model="beijianCascaderValue"
:options="beijianPagedOptions"
:props="cascaderProps"
filterable
<el-input
:model-value="beijianDisplay"
readonly
clearable
collapse-tags
:show-all-levels="false"
class="device-ledger-selection-input"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderBeijianIds')"
class="!w-full"
@change="handleBeijianChange"
@clear="clearBeijian"
@click="openBeijianDialog"
/>
</el-form-item>
</el-col>
@ -199,6 +193,48 @@
</template>
</Dialog>
<el-dialog
v-model="criticalComponentDialogVisible"
title="选择关键件"
width="860px"
class="device-ledger-transfer-dialog"
append-to-body
>
<div class="device-ledger-transfer">
<el-transfer
v-model="criticalComponentDraft"
:data="criticalComponentTransferData"
filterable
:filter-placeholder="t('EquipmentManagement.EquipmentLedger.placeholderComponentIds')"
/>
</div>
<template #footer>
<el-button @click="criticalComponentDialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="confirmCriticalComponentDialog">{{ t('common.ok') }}</el-button>
</template>
</el-dialog>
<el-dialog
v-model="beijianDialogVisible"
title="选择备件"
width="860px"
class="device-ledger-transfer-dialog"
append-to-body
>
<div class="device-ledger-transfer">
<el-transfer
v-model="beijianDraft"
:data="beijianTransferData"
filterable
:filter-placeholder="t('EquipmentManagement.EquipmentLedger.placeholderBeijianIds')"
/>
</div>
<template #footer>
<el-button @click="beijianDialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="confirmBeijianDialog">{{ t('common.ok') }}</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
@ -287,31 +323,61 @@ const deviceTypeTree = ref<DeviceTypeTreeVO[]>([])
const users = ref<UserVO[]>([])
const criticalComponentOptions = ref<{ label: string; value: number }[]>([])
const beijianOptions = ref<{ label: string; value: number }[]>([])
const PAGE_SIZE = 10
const buildPagedOptions = (options: { label: string; value: number }[]) => {
const result: { label: string; value: string; children: { label: string; value: number }[] }[] = []
for (let i = 0; i < options.length; i += PAGE_SIZE) {
const pageIndex = result.length + 1
result.push({
label: String(pageIndex),
value: `page-${pageIndex}`,
children: options.slice(i, i + PAGE_SIZE).map((item) => ({
label: item.label,
value: item.value
}))
})
}
return result
const criticalComponentTransferData = computed(() =>
criticalComponentOptions.value.map((item) => ({ key: item.value, label: item.label }))
)
const beijianTransferData = computed(() =>
beijianOptions.value.map((item) => ({ key: item.value, label: item.label }))
)
const criticalComponentDialogVisible = ref(false)
const beijianDialogVisible = ref(false)
const criticalComponentDraft = ref<number[]>([])
const beijianDraft = ref<number[]>([])
const formatSelectedSummary = (ids: number[], options: { label: string; value: number }[]) => {
const optionMap = new Map<number, string>(options.map((item) => [item.value, item.label]))
const labels = ids.map((id) => optionMap.get(id)).filter((v): v is string => Boolean(v))
if (!labels.length) return ''
if (labels.length <= 3) return labels.join('、')
return `${labels.slice(0, 3).join('、')}…等${labels.length}`
}
const cascaderProps = { multiple: true, emitPath: false, checkStrictly: false }
const criticalComponentDisplay = computed(() =>
formatSelectedSummary(formData.value.componentIds ?? [], criticalComponentOptions.value)
)
const beijianDisplay = computed(() =>
formatSelectedSummary(formData.value.beijianIds ?? [], beijianOptions.value)
)
const clearCriticalComponent = () => {
formData.value.componentIds = []
}
const clearBeijian = () => {
formData.value.beijianIds = []
}
const criticalComponentCascaderValue = ref<(number | string)[]>([])
const beijianCascaderValue = ref<(number | string)[]>([])
const openCriticalComponentDialog = () => {
criticalComponentDraft.value = [...(formData.value.componentIds ?? [])]
criticalComponentDialogVisible.value = true
}
const openBeijianDialog = () => {
beijianDraft.value = [...(formData.value.beijianIds ?? [])]
beijianDialogVisible.value = true
}
const criticalComponentPagedOptions = computed(() => buildPagedOptions(criticalComponentOptions.value))
const beijianPagedOptions = computed(() => buildPagedOptions(beijianOptions.value))
const confirmCriticalComponentDialog = () => {
const validMap = new Set(criticalComponentOptions.value.map((item) => item.value))
const selected = Array.from(new Set(criticalComponentDraft.value.map((v) => Number(v)).filter((v) => validMap.has(v))))
formData.value.componentIds = selected
criticalComponentDialogVisible.value = false
}
const confirmBeijianDialog = () => {
const validMap = new Set(beijianOptions.value.map((item) => item.value))
const selected = Array.from(new Set(beijianDraft.value.map((v) => Number(v)).filter((v) => validMap.has(v))))
formData.value.beijianIds = selected
beijianDialogVisible.value = false
}
const ensureOptionsLoaded = async () => {
const [deviceTypeRes, userRes, criticalRes, beijianRes] = await Promise.all([
@ -336,48 +402,6 @@ const ensureOptionsLoaded = async () => {
})
}
watch(
() => formData.value.componentIds,
(ids) => {
criticalComponentCascaderValue.value = Array.isArray(ids) ? [...ids] : []
},
{ immediate: true }
)
watch(
() => formData.value.beijianIds,
(ids) => {
beijianCascaderValue.value = Array.isArray(ids) ? [...ids] : []
},
{ immediate: true }
)
const handleCriticalComponentChange = (values: (number | string)[]) => {
const validIds = new Set<number>()
const validMap = new Set(criticalComponentOptions.value.map((item) => item.value))
for (const v of values) {
const num = Number(v)
if (!Number.isNaN(num) && validMap.has(num)) {
validIds.add(num)
}
}
formData.value.componentIds = Array.from(validIds)
criticalComponentCascaderValue.value = Array.from(validIds)
}
const handleBeijianChange = (values: (number | string)[]) => {
const validIds = new Set<number>()
const validMap = new Set(beijianOptions.value.map((item) => item.value))
for (const v of values) {
const num = Number(v)
if (!Number.isNaN(num) && validMap.has(num)) {
validIds.add(num)
}
}
formData.value.beijianIds = Array.from(validIds)
beijianCascaderValue.value = Array.from(validIds)
}
/** 打开弹窗 */
const open = async (type: string, id?: number, defaultDeviceTypeId?: number) => {
dialogVisible.value = true
@ -468,4 +492,47 @@ const resetForm = () => {
:deep(.ellipsis-text){
max-width: 300px;
}
.device-ledger-transfer {
width: 100%;
overflow-x: auto;
}
.device-ledger-transfer :deep(.el-transfer) {
width: 100%;
min-width: 760px;
flex-wrap: nowrap;
}
.device-ledger-transfer :deep(.el-transfer-panel) {
flex: 1 0 340px;
width: 340px;
}
.device-ledger-transfer-dialog :deep(.el-dialog__body) {
padding-top: 8px;
}
.device-ledger-transfer-dialog .device-ledger-transfer :deep(.el-transfer-panel) {
height: 560px;
}
.device-ledger-transfer-dialog .device-ledger-transfer :deep(.el-transfer-panel__body) {
height: 520px;
}
.device-ledger-transfer-dialog .device-ledger-transfer :deep(.el-transfer-panel__list) {
height: 100%;
}
.device-ledger-transfer :deep(.el-transfer__buttons) {
flex: 0 0 72px;
padding: 0 12px;
}
.device-ledger-selection-input :deep(.el-input__inner) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

Loading…
Cancel
Save