<script lang="ts" setup>
|
import type { MesMdItemApi } from '#/api/mes/md/item';
|
|
import { computed, ref, useAttrs, watch } from 'vue';
|
|
import { IconifyIcon } from '@vben/icons';
|
|
import { Input, Tooltip } from 'ant-design-vue';
|
|
import { getItem } from '#/api/mes/md/item';
|
|
import MdItemSelectDialog from './select-dialog.vue';
|
|
defineOptions({ name: 'MdItemSelect', inheritAttrs: false });
|
|
const props = withDefaults(
|
defineProps<{
|
allowClear?: boolean;
|
disabled?: boolean;
|
modelValue?: number | number[];
|
multiple?: boolean;
|
placeholder?: string;
|
productIds?: number[];
|
}>(),
|
{
|
allowClear: true,
|
disabled: false,
|
modelValue: undefined,
|
multiple: false,
|
placeholder: '请选择产品品种',
|
productIds: () => [],
|
},
|
);
|
const emit = defineEmits<{
|
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 selectedItems = ref<MesMdItemApi.Item[]>([]);
|
|
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.multiple
|
? Array.isArray(props.modelValue) && props.modelValue.length > 0
|
: props.modelValue != null),
|
);
|
|
/** 根据品种编号回显选择器 */
|
async function resolveItemsById(values: number | number[] | undefined) {
|
if (values == null || (Array.isArray(values) && values.length === 0)) {
|
selectedItems.value = [];
|
return;
|
}
|
const ids = Array.isArray(values) ? values : [values];
|
// 已全部回显则跳过
|
if (
|
ids.length === selectedItems.value.length &&
|
ids.every((id, i) => selectedItems.value[i]?.id === id)
|
) {
|
return;
|
}
|
const items = await Promise.all(ids.map(id => getItem(id)));
|
selectedItems.value = items.filter(Boolean) as MesMdItemApi.Item[];
|
}
|
|
watch(
|
() => props.modelValue,
|
(value) => {
|
resolveItemsById(value);
|
},
|
{ immediate: true },
|
);
|
|
/** 清空已选品种 */
|
function clearSelected() {
|
selectedItems.value = [];
|
if (props.multiple) {
|
emit('update:modelValue', []);
|
emit('change', []);
|
} else {
|
emit('update:modelValue', undefined);
|
emit('change', undefined);
|
}
|
}
|
|
/** 打开品种选择弹窗 */
|
function handleClick(event: MouseEvent) {
|
if (props.disabled) {
|
return;
|
}
|
const target = event.target as HTMLElement;
|
if (showClear.value && target.closest('.ant-input-suffix')) {
|
event.stopPropagation();
|
clearSelected();
|
return;
|
}
|
const selectedIds: number[] = props.multiple
|
? (props.modelValue as number[] | undefined) ?? []
|
: props.modelValue != null
|
? [props.modelValue as number]
|
: [];
|
dialogRef.value?.open(selectedIds, {
|
multiple: props.multiple,
|
productIds: props.productIds,
|
});
|
}
|
|
/** 回填选中的品种 */
|
function handleSelected(rows: MesMdItemApi.Item[]) {
|
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);
|
}
|
}
|
</script>
|
|
<template>
|
<div
|
v-bind="attrs"
|
class="w-full"
|
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
@click="handleClick"
|
@mouseenter="hovering = true"
|
@mouseleave="hovering = false"
|
>
|
<Tooltip :mouse-enter-delay="0.5" :open="selectedItems.length > 0 ? undefined : false">
|
<template #title>
|
<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
|
:disabled="disabled"
|
:placeholder="placeholder"
|
:value="displayLabel"
|
readonly
|
>
|
<template #suffix>
|
<IconifyIcon
|
class="size-4"
|
:icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
|
/>
|
</template>
|
</Input>
|
</Tooltip>
|
</div>
|
<MdItemSelectDialog ref="dialogRef" @selected="handleSelected" />
|
</template>
|