| | |
| | | |
| | | defineOptions({ name: 'MdProductBomSelectDialog' }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | multiple?: boolean; |
| | | }>(), |
| | | { |
| | | multiple: false, |
| | | }, |
| | | ); |
| | | |
| | | const emit = defineEmits<{ |
| | | selected: [row: MesMdProductBomApi.ProductBom]; |
| | | selected: [rows: MesMdProductBomApi.ProductBom[]]; |
| | | }>(); |
| | | |
| | | const open = ref(false); // 弹窗是否打开 |
| | | const list = ref<MesMdProductBomApi.ProductBom[]>([]); // BOM 子物料列表 |
| | | const selectedRow = ref<MesMdProductBomApi.ProductBom>(); // 当前选中的 BOM 行 |
| | | const selectedRows = ref<MesMdProductBomApi.ProductBom[]>([]); // 已选 BOM 行(单选时最多一行) |
| | | const preSelectedIds = ref<number[]>([]); // 预选 BOM 物料编号 |
| | | |
| | | /** 获取多选记录,包含 VXE reserve 记录 */ |
| | | function getMultipleSelectedRows() { |
| | | const selectedMap = new Map<number, MesMdProductBomApi.ProductBom>(); |
| | | const records = [ |
| | | ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []), |
| | | ...(gridApi.grid.getCheckboxRecords?.() ?? []), |
| | | ] as MesMdProductBomApi.ProductBom[]; |
| | | records.forEach((row) => { |
| | | if (row.bomItemId != null) { |
| | | selectedMap.set(row.bomItemId, row); |
| | | } |
| | | }); |
| | | return [...selectedMap.values()]; |
| | | } |
| | | |
| | | /** 处理勾选变化 */ |
| | | function handleCheckboxSelectChange() { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | |
| | | /** 上周单击行痕迹,用于吞掉双击触发的第二次 click */ |
| | | let lastClick = { bomItemId: undefined as number | undefined, time: 0 }; |
| | | |
| | | /** 单击行:多选切换勾选;单选由 radioConfig.trigger='row' 处理 */ |
| | | async function handleCellClick({ |
| | | row, |
| | | column, |
| | | }: { |
| | | row: MesMdProductBomApi.ProductBom; |
| | | column?: { type?: string }; |
| | | }) { |
| | | // 点击勾选/单选列自身由控件处理,避免二次切换 |
| | | if (column?.type === 'checkbox' || column?.type === 'radio') { |
| | | return; |
| | | } |
| | | if (!props.multiple) { |
| | | return; |
| | | } |
| | | const now = Date.now(); |
| | | if (lastClick.bomItemId === row.bomItemId && now - lastClick.time < 300) { |
| | | lastClick.time = 0; |
| | | return; |
| | | } |
| | | lastClick = { bomItemId: row.bomItemId, time: now }; |
| | | const selected = gridApi.grid.isCheckedByCheckboxRow(row); |
| | | await gridApi.grid.setCheckboxRow(row, !selected); |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | |
| | | /** 处理行双击 */ |
| | | async function handleCellDblclick({ |
| | | row, |
| | | }: { |
| | | row: MesMdProductBomApi.ProductBom; |
| | | }) { |
| | | if (props.multiple) { |
| | | return; // 多选由单击 cellClick 切换,双击不再重复处理 |
| | | } |
| | | selectedRows.value = [row]; |
| | | gridApi.grid.setRadioRow(row); |
| | | handleConfirm(); |
| | | } |
| | | |
| | | /** 处理单选变化 */ |
| | | function handleRadioChange(row: MesMdProductBomApi.ProductBom) { |
| | | selectedRows.value = [row]; |
| | | } |
| | | |
| | | /** 当前选择列类型 */ |
| | | function getSelectColumn() { |
| | | return { |
| | | type: props.multiple ? 'checkbox' : 'radio', |
| | | width: 55, |
| | | align: 'center', |
| | | } as const; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | border: true, |
| | | columns: [ |
| | | { type: 'radio', width: 55, align: 'center' }, |
| | | ...(useProductBomGridColumns(true) || []), |
| | | ], |
| | | columns: [getSelectColumn(), ...(useProductBomGridColumns(true) || [])], |
| | | data: list.value, |
| | | height: 500, |
| | | keepSource: true, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | checkboxConfig: { |
| | | highlight: true, |
| | | range: true, |
| | | reserve: true, |
| | | }, |
| | | radioConfig: { |
| | | highlight: true, |
| | |
| | | }, |
| | | } as VxeTableGridOptions<MesMdProductBomApi.ProductBom>, |
| | | gridEvents: { |
| | | cellDblclick: ({ row }: { row: MesMdProductBomApi.ProductBom }) => { |
| | | selectedRow.value = row; |
| | | gridApi.grid.setRadioRow(row); |
| | | handleConfirm(); |
| | | }, |
| | | cellClick: handleCellClick, |
| | | cellDblclick: handleCellDblclick, |
| | | checkboxChange: handleCheckboxSelectChange, |
| | | checkboxAll: handleCheckboxSelectChange, |
| | | radioChange: ({ row }: { row: MesMdProductBomApi.ProductBom }) => { |
| | | selectedRow.value = row; |
| | | handleRadioChange(row); |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | /** 打开 BOM 物料选择弹窗 */ |
| | | async function openModal(itemId: number, selectedBomItemId?: number) { |
| | | /** 回显预选 BOM 物料(数据一次性加载,无分页,直接勾选即可) */ |
| | | async function applyPreSelection() { |
| | | if (preSelectedIds.value.length === 0) { |
| | | return; |
| | | } |
| | | for (const row of list.value) { |
| | | if ( |
| | | row.bomItemId === undefined || |
| | | row.bomItemId === null || |
| | | !preSelectedIds.value.includes(row.bomItemId) |
| | | ) { |
| | | continue; |
| | | } |
| | | if (props.multiple) { |
| | | await gridApi.grid.setCheckboxRow(row, true); |
| | | } else { |
| | | await gridApi.grid.setRadioRow(row); |
| | | selectedRows.value = [row]; |
| | | return; |
| | | } |
| | | } |
| | | if (props.multiple) { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | } |
| | | |
| | | /** 打开 BOM 物料选择弹窗(selectedBomItemIds 单选传单个编号,多选传编号数组) */ |
| | | async function openModal(itemId: number, selectedBomItemIds?: number | number[]) { |
| | | open.value = true; |
| | | selectedRow.value = undefined; |
| | | preSelectedIds.value = ( |
| | | Array.isArray(selectedBomItemIds) |
| | | ? selectedBomItemIds |
| | | : selectedBomItemIds === undefined || selectedBomItemIds === null |
| | | ? [] |
| | | : [selectedBomItemIds] |
| | | ).filter((id): id is number => id != null); |
| | | selectedRows.value = []; |
| | | gridApi.setLoading(true); |
| | | try { |
| | | list.value = await getProductBomListByItemId(itemId); |
| | | gridApi.setGridOptions({ data: list.value }); |
| | | gridApi.setGridOptions({ |
| | | data: list.value, |
| | | columns: [getSelectColumn(), ...(useProductBomGridColumns(true) || [])], |
| | | }); |
| | | await nextTick(); |
| | | if (selectedBomItemId !== null) { |
| | | const match = list.value.find( |
| | | (row) => row.bomItemId === selectedBomItemId, |
| | | ); |
| | | if (match) { |
| | | selectedRow.value = match; |
| | | gridApi.grid.setRadioRow(match); |
| | | } |
| | | } |
| | | await applyPreSelection(); |
| | | } finally { |
| | | gridApi.setLoading(false); |
| | | } |
| | |
| | | /** 关闭 BOM 物料选择弹窗 */ |
| | | async function closeModal() { |
| | | open.value = false; |
| | | selectedRow.value = undefined; |
| | | selectedRows.value = []; |
| | | preSelectedIds.value = []; |
| | | await gridApi.grid.clearCheckboxRow(); |
| | | await gridApi.grid.clearCheckboxReserve(); |
| | | await gridApi.grid.clearRadioRow(); |
| | | } |
| | | |
| | | /** 确认选择 BOM 物料 */ |
| | | function handleConfirm() { |
| | | if (!selectedRow.value) { |
| | | message.warning('请选择一条数据'); |
| | | const rows = props.multiple |
| | | ? getMultipleSelectedRows() |
| | | : selectedRows.value.slice(0, 1); |
| | | if (rows.length === 0) { |
| | | message.warning(props.multiple ? '请至少选择一条数据' : '请选择一条数据'); |
| | | return; |
| | | } |
| | | emit('selected', selectedRow.value); |
| | | emit('selected', rows); |
| | | open.value = false; |
| | | } |
| | | |
| | |
| | | > |
| | | <Grid table-title="BOM 子物料列表" /> |
| | | </Modal> |
| | | </template> |
| | | </template> |