| | |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | itemId?: number; |
| | | modelValue?: number; |
| | | modelValue?: number | number[]; |
| | | multiple?: boolean; |
| | | placeholder?: string; |
| | | }>(), |
| | | { |
| | |
| | | disabled: false, |
| | | itemId: undefined, |
| | | modelValue: undefined, |
| | | multiple: false, |
| | | placeholder: '请选择 BOM 物料', |
| | | }, |
| | | ); |
| | | const emit = defineEmits<{ |
| | | change: [bom: MesMdProductBomApi.ProductBom | undefined]; |
| | | 'update:modelValue': [value: number | undefined]; |
| | | change: [ |
| | | bom: MesMdProductBomApi.ProductBom[] | MesMdProductBomApi.ProductBom | undefined, |
| | | ]; |
| | | 'update:modelValue': [value: number[] | number | undefined]; |
| | | }>(); |
| | | const attrs = useAttrs(); // 透传属性 |
| | | const dialogRef = ref<InstanceType<typeof MdProductBomSelectDialog>>(); // BOM 物料选择弹窗 |
| | | const hovering = ref(false); // 是否悬停 |
| | | const selectedBom = ref<MesMdProductBomApi.ProductBom>(); // 当前选中的 BOM 物料 |
| | | const selectedBoms = ref<MesMdProductBomApi.ProductBom[]>([]); // 已选 BOM 物料(单选时最多一项) |
| | | |
| | | const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称 |
| | | const showClear = computed( |
| | | () => |
| | | props.allowClear && |
| | | !props.disabled && |
| | | hovering.value && |
| | | props.modelValue !== undefined && |
| | | props.modelValue !== null, |
| | | ); |
| | | |
| | | /** 根据 BOM 子物料编号回显选择器 */ |
| | | async function resolveBomById(bomItemId: number | undefined) { |
| | | if ( |
| | | bomItemId === undefined || |
| | | bomItemId === null || |
| | | props.itemId === undefined || |
| | | props.itemId === null |
| | | ) { |
| | | selectedBom.value = undefined; |
| | | return; |
| | | const selectedBom = computed(() => selectedBoms.value[0]); // 单选时的当前项 |
| | | const displayLabel = computed(() => { |
| | | // 多选展示「名称、名称」,单选展示单个名称 |
| | | if (props.multiple) { |
| | | return selectedBoms.value |
| | | .map((bom) => bom.bomItemName) |
| | | .filter(Boolean) |
| | | .join('、'); |
| | | } |
| | | if (selectedBom.value?.bomItemId === bomItemId) { |
| | | return selectedBom.value?.bomItemName ?? ''; |
| | | }); // 选择器展示名称 |
| | | const showClear = computed(() => { |
| | | if (!props.allowClear || props.disabled || !hovering.value) { |
| | | return false; |
| | | } |
| | | if (props.multiple) { |
| | | return Array.isArray(props.modelValue) && props.modelValue.length > 0; |
| | | } |
| | | return props.modelValue !== undefined && props.modelValue !== null; |
| | | }); |
| | | |
| | | /** 从 modelValue 解析出 BOM 物料编号列表 */ |
| | | function getModelIds() { |
| | | if (props.multiple) { |
| | | return Array.isArray(props.modelValue) |
| | | ? props.modelValue.filter((id): id is number => id != null) |
| | | : []; |
| | | } |
| | | return typeof props.modelValue === 'number' ? [props.modelValue] : []; |
| | | } |
| | | |
| | | /** 根据 BOM 物料编号回显选择器 */ |
| | | async function resolveBomsById(ids: number[]) { |
| | | if (ids.length === 0 || props.itemId === undefined || props.itemId === null) { |
| | | selectedBoms.value = []; |
| | | return; |
| | | } |
| | | const list = await getProductBomListByItemId(props.itemId as number); |
| | | selectedBom.value = list.find((item) => item.bomItemId === bomItemId); |
| | | selectedBoms.value = list.filter( |
| | | (item) => item.bomItemId != null && ids.includes(item.bomItemId), |
| | | ); |
| | | } |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (value) => { |
| | | resolveBomById(value); |
| | | () => { |
| | | resolveBomsById(getModelIds()); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | |
| | | watch( |
| | | () => props.itemId, |
| | | () => { |
| | | selectedBom.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | selectedBoms.value = []; |
| | | emit('update:modelValue', props.multiple ? [] : undefined); |
| | | emit('change', props.multiple ? [] : undefined); |
| | | }, |
| | | ); |
| | | |
| | | /** 清空已选 BOM 物料 */ |
| | | function clearSelected() { |
| | | selectedBom.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | selectedBoms.value = []; |
| | | emit('update:modelValue', props.multiple ? [] : undefined); |
| | | emit('change', props.multiple ? [] : undefined); |
| | | } |
| | | |
| | | /** 打开 BOM 物料选择弹窗 */ |
| | |
| | | clearSelected(); |
| | | return; |
| | | } |
| | | dialogRef.value?.open(props.itemId as number, props.modelValue); |
| | | const ids = getModelIds(); |
| | | dialogRef.value?.open(props.itemId as number, props.multiple ? ids : ids[0]); |
| | | } |
| | | |
| | | /** 回填选中的 BOM 物料 */ |
| | | function handleSelected(row: MesMdProductBomApi.ProductBom) { |
| | | selectedBom.value = row; |
| | | emit('update:modelValue', row.bomItemId); |
| | | emit('change', row); |
| | | function handleSelected(rows: MesMdProductBomApi.ProductBom[]) { |
| | | selectedBoms.value = rows; |
| | | emit( |
| | | 'update:modelValue', |
| | | props.multiple |
| | | ? rows |
| | | .map((row) => row.bomItemId) |
| | | .filter((id): id is number => id != null) |
| | | : rows[0]?.bomItemId, |
| | | ); |
| | | emit('change', props.multiple ? rows : rows[0]); |
| | | } |
| | | </script> |
| | | |
| | |
| | | @mouseenter="hovering = true" |
| | | @mouseleave="hovering = false" |
| | | > |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedBom ? undefined : false"> |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedBoms.length ? undefined : false"> |
| | | <template #title> |
| | | <div v-if="selectedBom" class="leading-6"> |
| | | <div v-if="multiple" class="leading-6"> |
| | | <div v-for="bom in selectedBoms" :key="bom.bomItemId"> |
| | | {{ bom.bomItemName || '-' }}{{ bom.bomItemCode ? `(${bom.bomItemCode})` : '' }} |
| | | </div> |
| | | </div> |
| | | <div v-else-if="selectedBom" class="leading-6"> |
| | | <div>编码:{{ selectedBom.bomItemCode || '-' }}</div> |
| | | <div>名称:{{ selectedBom.bomItemName || '-' }}</div> |
| | | <div>规格:{{ selectedBom.bomItemSpecification || '-' }}</div> |
| | |
| | | </Input> |
| | | </Tooltip> |
| | | </div> |
| | | <MdProductBomSelectDialog ref="dialogRef" @selected="handleSelected" /> |
| | | </template> |
| | | <MdProductBomSelectDialog |
| | | ref="dialogRef" |
| | | :multiple="multiple" |
| | | @selected="handleSelected" |
| | | /> |
| | | </template> |