| | |
| | | defineProps<{ |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | modelValue?: number | number[]; |
| | | multiple?: boolean; |
| | | placeholder?: string; |
| | | productIds?: number[]; |
| | | }>(), |
| | |
| | | allowClear: true, |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | multiple: false, |
| | | placeholder: '请选择产品物料', |
| | | productIds: () => [], |
| | | }, |
| | | ); |
| | | const emit = defineEmits<{ |
| | | change: [item: MesMdItemApi.Item | undefined]; |
| | | 'update:modelValue': [value: number | undefined]; |
| | | change: [items: MesMdItemApi.Item | MesMdItemApi.Item[] | undefined]; |
| | | 'update:modelValue': [value: number | number[] | undefined]; |
| | | }>(); |
| | | const attrs = useAttrs(); // 透传属性 |
| | | const dialogRef = ref<InstanceType<typeof MdItemSelectDialog>>(); // 物料选择弹窗 |
| | | const hovering = ref(false); // 是否悬停 |
| | | const selectedItem = ref<MesMdItemApi.Item>(); // 当前选中物料 |
| | | const attrs = useAttrs(); |
| | | const dialogRef = ref<InstanceType<typeof MdItemSelectDialog>>(); |
| | | const hovering = ref(false); |
| | | const selectedItems = ref<MesMdItemApi.Item[]>([]); |
| | | |
| | | const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称 |
| | | const displayLabel = computed(() => { |
| | | if (selectedItems.value.length === 0) return ''; |
| | | return selectedItems.value.map(item => item.name ?? '').join('、'); |
| | | }); |
| | | const showClear = computed( |
| | | () => |
| | | props.allowClear && |
| | | !props.disabled && |
| | | hovering.value && |
| | | props.modelValue !== null, |
| | | (props.multiple |
| | | ? Array.isArray(props.modelValue) && props.modelValue.length > 0 |
| | | : props.modelValue != null), |
| | | ); |
| | | |
| | | /** 根据物料编号回显选择器 */ |
| | | async function resolveItemById(id: number | undefined) { |
| | | if (!id) { |
| | | selectedItem.value = undefined; |
| | | async function resolveItemsById(values: number | number[] | undefined) { |
| | | if (values == null || (Array.isArray(values) && values.length === 0)) { |
| | | selectedItems.value = []; |
| | | return; |
| | | } |
| | | if (selectedItem.value?.id === id) { |
| | | const ids = Array.isArray(values) ? values : [values]; |
| | | // 已全部回显则跳过 |
| | | if ( |
| | | ids.length === selectedItems.value.length && |
| | | ids.every((id, i) => selectedItems.value[i]?.id === id) |
| | | ) { |
| | | return; |
| | | } |
| | | selectedItem.value = await getItem(id); |
| | | const items = await Promise.all(ids.map(id => getItem(id))); |
| | | selectedItems.value = items.filter(Boolean) as MesMdItemApi.Item[]; |
| | | } |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (value) => { |
| | | resolveItemById(value); |
| | | resolveItemsById(value); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | /** 清空已选物料 */ |
| | | function clearSelected() { |
| | | selectedItem.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | selectedItems.value = []; |
| | | if (props.multiple) { |
| | | emit('update:modelValue', []); |
| | | emit('change', []); |
| | | } else { |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | } |
| | | } |
| | | |
| | | /** 打开物料选择弹窗 */ |
| | |
| | | clearSelected(); |
| | | return; |
| | | } |
| | | const selectedIds = ( |
| | | props.modelValue === null ? [] : [props.modelValue] |
| | | ) as number[]; |
| | | const selectedIds: number[] = props.multiple |
| | | ? (props.modelValue as number[] | undefined) ?? [] |
| | | : props.modelValue != null |
| | | ? [props.modelValue as number] |
| | | : []; |
| | | dialogRef.value?.open(selectedIds, { |
| | | multiple: false, |
| | | multiple: props.multiple, |
| | | productIds: props.productIds, |
| | | }); |
| | | } |
| | | |
| | | /** 回填选中的物料 */ |
| | | function handleSelected(rows: MesMdItemApi.Item[]) { |
| | | const item = rows[0]; |
| | | if (!item) { |
| | | return; |
| | | if (props.multiple) { |
| | | selectedItems.value = rows; |
| | | const ids = rows.map(r => r.id).filter(Boolean) as number[]; |
| | | emit('update:modelValue', ids); |
| | | emit('change', rows); |
| | | } else { |
| | | const item = rows[0]; |
| | | if (!item) { |
| | | return; |
| | | } |
| | | selectedItems.value = [item]; |
| | | emit('update:modelValue', item.id); |
| | | emit('change', item); |
| | | } |
| | | selectedItem.value = item; |
| | | emit('update:modelValue', item.id); |
| | | emit('change', item); |
| | | } |
| | | </script> |
| | | |
| | |
| | | @mouseenter="hovering = true" |
| | | @mouseleave="hovering = false" |
| | | > |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false"> |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedItems.length > 0 ? undefined : false"> |
| | | <template #title> |
| | | <div v-if="selectedItem" class="leading-6"> |
| | | <div>编码:{{ selectedItem.code || '-' }}</div> |
| | | <div>名称:{{ selectedItem.name || '-' }}</div> |
| | | <div>规格:{{ selectedItem.specification || '-' }}</div> |
| | | <div>单位:{{ selectedItem.unitMeasureName || '-' }}</div> |
| | | <div v-if="selectedItems.length === 1" class="leading-6"> |
| | | <div>编码:{{ selectedItems[0].code || '-' }}</div> |
| | | <div>名称:{{ selectedItems[0].name || '-' }}</div> |
| | | <div>规格:{{ selectedItems[0].specification || '-' }}</div> |
| | | <div>单位:{{ selectedItems[0].unitMeasureName || '-' }}</div> |
| | | </div> |
| | | <div v-else-if="selectedItems.length > 1" class="leading-6"> |
| | | <div v-for="item in selectedItems" :key="item.id" class="mb-2 border-b border-gray-100 pb-1 last:border-b-0 last:pb-0"> |
| | | <div>编码:{{ item.code || '-' }}</div> |
| | | <div>名称:{{ item.name || '-' }}</div> |
| | | <div>规格:{{ item.specification || '-' }}</div> |
| | | <div>单位:{{ item.unitMeasureName || '-' }}</div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <Input |