refactor(mes): 统一 antd 和 ele 选择组件代码风格
- 规范 select 空值判断和回显逻辑 - 统一物料、供应商、客户选择弹窗的单选/多选行为 - 清理 components 内 TODO 并修复相关 DICT_TYPE 导入pull/351/MERGE
parent
b3154ef87a
commit
22e9081a45
|
|
@ -9,6 +9,8 @@ import { Select } from 'ant-design-vue';
|
||||||
|
|
||||||
import { getCheckPlanPage } from '#/api/mes/dv/checkplan';
|
import { getCheckPlanPage } from '#/api/mes/dv/checkplan';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvCheckPlanSelect' });
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
|
|
@ -48,15 +50,11 @@ async function getList() {
|
||||||
function handleChange(value: SelectValue) {
|
function handleChange(value: SelectValue) {
|
||||||
const planId = typeof value === 'number' ? value : undefined;
|
const planId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', planId);
|
emit('update:modelValue', planId);
|
||||||
// TODO @AI:可以简化,不换行么?
|
emit('change', list.value.find((item) => item.id === planId));
|
||||||
emit(
|
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === planId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @AI:下面,2 个,需要有空行么?
|
|
||||||
watch(() => [props.status, props.type], getList);
|
watch(() => [props.status, props.type], getList);
|
||||||
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { Select } from 'ant-design-vue';
|
||||||
|
|
||||||
import { getMachinerySimpleList } from '#/api/mes/dv/machinery';
|
import { getMachinerySimpleList } from '#/api/mes/dv/machinery';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvMachinerySelect' });
|
||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
|
|
@ -16,7 +18,12 @@ withDefaults(
|
||||||
modelValue?: number;
|
modelValue?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{ allowClear: true, disabled: false, modelValue: undefined, placeholder: '请选择设备' },
|
{
|
||||||
|
allowClear: true,
|
||||||
|
disabled: false,
|
||||||
|
modelValue: undefined,
|
||||||
|
placeholder: '请选择设备',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [row?: MesDvMachineryApi.Machinery];
|
change: [row?: MesDvMachineryApi.Machinery];
|
||||||
|
|
@ -33,13 +40,9 @@ async function getList() {
|
||||||
function handleChange(value: SelectValue) {
|
function handleChange(value: SelectValue) {
|
||||||
const machineryId = typeof value === 'number' ? value : undefined;
|
const machineryId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', machineryId);
|
emit('update:modelValue', machineryId);
|
||||||
emit(
|
emit('change', list.value.find((item) => item.id === machineryId));
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === machineryId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @AI:按照目前项目的规则,会希望 /** 初始化么 */ ?如果喜欢,是不是加到 style.vue 里?
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesDvMachineryTypeApi } from '#/api/mes/dv/machinery/type';
|
import type { MesDvMachineryTypeApi } from '#/api/mes/dv/machinery/type';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { Select } from 'ant-design-vue';
|
||||||
|
|
||||||
import { getSubjectSimpleList } from '#/api/mes/dv/subject';
|
import { getSubjectSimpleList } from '#/api/mes/dv/subject';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvSubjectSelect' });
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
|
|
@ -30,7 +32,7 @@ const emit = defineEmits<{
|
||||||
'update:modelValue': [value?: number];
|
'update:modelValue': [value?: number];
|
||||||
}>();
|
}>();
|
||||||
const list = ref<MesDvSubjectApi.Subject[]>([]); // 项目列表
|
const list = ref<MesDvSubjectApi.Subject[]>([]); // 项目列表
|
||||||
const filteredList = computed( // 筛选后的项目列表
|
const filteredList = computed(
|
||||||
() => list.value.filter((item) => !props.type || item.type === props.type),
|
() => list.value.filter((item) => !props.type || item.type === props.type),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -43,10 +45,7 @@ async function getList() {
|
||||||
function handleChange(value: SelectValue) {
|
function handleChange(value: SelectValue) {
|
||||||
const subjectId = typeof value === 'number' ? value : undefined;
|
const subjectId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', subjectId);
|
emit('update:modelValue', subjectId);
|
||||||
emit(
|
emit('change', list.value.find((item) => item.id === subjectId));
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === subjectId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,14 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesDvSubjectApi } from '#/api/mes/dv/subject';
|
import type { MesDvSubjectApi } from '#/api/mes/dv/subject';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode, MesDvSubjectTypeEnum } from '@vben/constants';
|
import {
|
||||||
|
CommonStatusEnum,
|
||||||
|
DICT_TYPE,
|
||||||
|
MesAutoCodeRuleCode,
|
||||||
|
MesDvSubjectTypeEnum,
|
||||||
|
} from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import {
|
||||||
useClientSelectGridFormSchema,
|
useClientSelectGridFormSchema,
|
||||||
} from '../data';
|
} from '../data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MdClientSelectDialog' });
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
selected: [rows: MesMdClientApi.Client[]];
|
selected: [rows: MesMdClientApi.Client[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
@ -24,44 +26,12 @@ const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const selectedRows = ref<MesMdClientApi.Client[]>([]); // 已选客户列表
|
const selectedRows = ref<MesMdClientApi.Client[]>([]); // 已选客户列表
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选客户编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选客户编号列表
|
||||||
const latestQueryRows = ref<MesMdClientApi.Client[]>([]); // 最近一次查询返回的客户列表
|
|
||||||
const queryFinished = ref(false); // 最近一次查询是否完成
|
|
||||||
|
|
||||||
// TODO @芋艿:是否有必要搞的这么复杂???后续测试看看。
|
|
||||||
// TODO @AI:需要简化下么?好像只有它这里有。。。
|
|
||||||
const MAX_TABLE_READY_FRAMES = 60;
|
|
||||||
|
|
||||||
/** 等待下一帧 */
|
|
||||||
function waitNextFrame(): Promise<void> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
requestAnimationFrame(() => resolve());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前表格数据 */
|
/** 获取当前表格数据 */
|
||||||
function getTableRows() {
|
function getTableRows() {
|
||||||
return gridApi.grid.getTableData().fullData as MesMdClientApi.Client[];
|
return gridApi.grid.getTableData().fullData as MesMdClientApi.Client[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 等待 VXE 将当前查询结果写入表格数据后再回显选中 */
|
|
||||||
async function waitTableReady(): Promise<void> {
|
|
||||||
if (preSelectedIds.value.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let index = 0; index < MAX_TABLE_READY_FRAMES; index += 1) {
|
|
||||||
if (queryFinished.value) {
|
|
||||||
const rows = getTableRows();
|
|
||||||
if (latestQueryRows.value.length === 0 && rows.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (latestQueryRows.value.length > 0 && rows.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await waitNextFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
function getMultipleSelectedRows() {
|
function getMultipleSelectedRows() {
|
||||||
const selectedMap = new Map<number, MesMdClientApi.Client>();
|
const selectedMap = new Map<number, MesMdClientApi.Client>();
|
||||||
|
|
@ -71,7 +41,7 @@ function getMultipleSelectedRows() {
|
||||||
] as MesMdClientApi.Client[];
|
] as MesMdClientApi.Client[];
|
||||||
records.forEach((row) => {
|
records.forEach((row) => {
|
||||||
const rowId = row.id;
|
const rowId = row.id;
|
||||||
if (rowId !== null && rowId !== undefined) {
|
if (rowId != null) {
|
||||||
selectedMap.set(rowId, row);
|
selectedMap.set(rowId, row);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -111,10 +81,9 @@ async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// proxy 表格回显选中时要读取 fullData,否则首次打开可能读不到刚查询出的数据。
|
|
||||||
const rows = getTableRows();
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id === null || !preSelectedIds.value.includes(row.id as number)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (multiple.value) {
|
if (multiple.value) {
|
||||||
|
|
@ -150,15 +119,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
const data = await getClientPage({
|
return await getClientPage({
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
...formValues,
|
...formValues,
|
||||||
status: CommonStatusEnum.ENABLE,
|
status: CommonStatusEnum.ENABLE,
|
||||||
});
|
});
|
||||||
latestQueryRows.value = data.list || [];
|
|
||||||
queryFinished.value = true;
|
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -198,8 +164,6 @@ async function openModal(
|
||||||
open.value = true;
|
open.value = true;
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
latestQueryRows.value = [];
|
|
||||||
queryFinished.value = false;
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
gridApi.setGridOptions({
|
gridApi.setGridOptions({
|
||||||
columns: useClientSelectGridColumns(multiple.value),
|
columns: useClientSelectGridColumns(multiple.value),
|
||||||
|
|
@ -207,13 +171,13 @@ async function openModal(
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
await waitTableReady();
|
|
||||||
await applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭客户选择弹窗 */
|
/** 关闭客户选择弹窗 */
|
||||||
function closeModal() {
|
async function closeModal() {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
|
await resetQueryState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 确认选择客户 */
|
/** 确认选择客户 */
|
||||||
|
|
|
||||||
|
|
@ -38,18 +38,16 @@ const selectedItem = ref<MesMdClientApi.Client>(); // 当前选中客户
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// TODO @AI:这种,是不是应该放到 // computed( 后面?
|
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.allowClear &&
|
props.allowClear &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据客户编号回显选择器 */
|
/** 根据客户编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getClient(id as number);
|
selectedItem.value = await getClient(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdClientSelect] resolveItemById failed:', error);
|
console.error('[MdClientSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -89,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的客户 */
|
/** 回填选中的客户 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdClientApi } from '#/api/mes/md/client';
|
import type { MesMdClientApi } from '#/api/mes/md/client';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ async function openModal(itemId: number, selectedBomItemId?: number) {
|
||||||
list.value = await getProductBomListByItemId(itemId);
|
list.value = await getProductBomListByItemId(itemId);
|
||||||
gridApi.setGridOptions({ data: list.value });
|
gridApi.setGridOptions({ data: list.value });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (selectedBomItemId !== null) {
|
if (selectedBomItemId != null) {
|
||||||
const match = list.value.find(
|
const match = list.value.find(
|
||||||
(row) => row.bomItemId === selectedBomItemId,
|
(row) => row.bomItemId === selectedBomItemId,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -40,17 +40,16 @@ const selectedBom = ref<MesMdProductBomApi.ProductBom>(); // 当前选中的 BOM
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.allowClear &&
|
props.allowClear &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据 BOM 子物料编号回显选择器 */
|
/** 根据 BOM 子物料编号回显选择器 */
|
||||||
async function resolveBomById(bomItemId: number | undefined) {
|
async function resolveBomById(bomItemId: number | undefined) {
|
||||||
if (bomItemId === null || props.itemId === null) {
|
if (bomItemId == null || props.itemId == null) {
|
||||||
selectedBom.value = undefined;
|
selectedBom.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +57,7 @@ async function resolveBomById(bomItemId: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const list = await getProductBomListByItemId(props.itemId as number);
|
const list = await getProductBomListByItemId(props.itemId);
|
||||||
selectedBom.value = list.find((item) => item.bomItemId === bomItemId);
|
selectedBom.value = list.find((item) => item.bomItemId === bomItemId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdProductBomSelect] resolveBomById failed:', error);
|
console.error('[MdProductBomSelect] resolveBomById failed:', error);
|
||||||
|
|
@ -91,7 +90,7 @@ function clearSelected() {
|
||||||
|
|
||||||
/** 打开 BOM 物料选择弹窗 */
|
/** 打开 BOM 物料选择弹窗 */
|
||||||
function handleClick(event: MouseEvent) {
|
function handleClick(event: MouseEvent) {
|
||||||
if (props.disabled || props.itemId === null) {
|
if (props.disabled || props.itemId == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
|
|
@ -100,7 +99,7 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dialogRef.value?.open(props.itemId as number, props.modelValue);
|
dialogRef.value?.open(props.itemId, props.modelValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的 BOM 物料 */
|
/** 回填选中的 BOM 物料 */
|
||||||
|
|
|
||||||
|
|
@ -23,52 +23,58 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const open = ref(false); // 弹窗是否打开
|
const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const syncingSingleSelection = ref(false); // 是否同步单选勾选状态
|
|
||||||
const selectedRows = ref<MesMdItemApi.Item[]>([]); // 已选物料列表
|
const selectedRows = ref<MesMdItemApi.Item[]>([]); // 已选物料列表
|
||||||
const selectedItemTypeId = ref<number>(); // 当前筛选分类编号
|
const selectedItemTypeId = ref<number>(); // 当前筛选分类编号
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选物料编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选物料编号列表
|
||||||
const typeTreeRef = ref<InstanceType<typeof MdItemTypeTree>>(); // 物料分类树
|
const typeTreeRef = ref<InstanceType<typeof MdItemTypeTree>>(); // 物料分类树
|
||||||
|
|
||||||
/** 单选模式下同步 VXE 勾选状态,避免跨页残留多选 */
|
/** 获取当前表格数据 */
|
||||||
async function syncSingleSelection(row?: MesMdItemApi.Item) {
|
function getTableRows() {
|
||||||
syncingSingleSelection.value = true;
|
return gridApi.grid.getTableData().fullData as MesMdItemApi.Item[];
|
||||||
await nextTick();
|
|
||||||
await gridApi.grid.clearCheckboxRow();
|
|
||||||
if (row) {
|
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
|
||||||
}
|
|
||||||
await nextTick();
|
|
||||||
syncingSingleSelection.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化,单选模式只保留最后一条 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function handleCheckboxChange({
|
function getMultipleSelectedRows() {
|
||||||
checked,
|
const selectedMap = new Map<number, MesMdItemApi.Item>();
|
||||||
records,
|
const records = [
|
||||||
row,
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
}: {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
checked: boolean;
|
] as MesMdItemApi.Item[];
|
||||||
records: MesMdItemApi.Item[];
|
records.forEach((row) => {
|
||||||
row?: MesMdItemApi.Item;
|
const rowId = row.id;
|
||||||
}) {
|
if (rowId != null) {
|
||||||
if (syncingSingleSelection.value) {
|
selectedMap.set(rowId, row);
|
||||||
return;
|
}
|
||||||
}
|
});
|
||||||
if (!multiple.value) {
|
return [...selectedMap.values()];
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理勾选变化 */
|
||||||
function handleCheckboxAll({ records }: { records: MesMdItemApi.Item[] }) {
|
function handleCheckboxSelectChange() {
|
||||||
if (syncingSingleSelection.value) {
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理单选变化 */
|
||||||
|
function handleRadioChange(row: MesMdItemApi.Item) {
|
||||||
|
selectedRows.value = [row];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选模式下切换行勾选 */
|
||||||
|
async function toggleMultipleRow(row: MesMdItemApi.Item) {
|
||||||
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理行双击 */
|
||||||
|
async function handleCellDblclick({ row }: { row: MesMdItemApi.Item }) {
|
||||||
|
if (multiple.value) {
|
||||||
|
await toggleMultipleRow(row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = records;
|
selectedRows.value = [row];
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 按分类筛选物料 */
|
/** 按分类筛选物料 */
|
||||||
|
|
@ -78,18 +84,25 @@ function handleItemTypeNodeClick(row: MesMdItemTypeApi.ItemType | undefined) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选物料 */
|
/** 回显预选物料 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesMdItemApi.Item[];
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +111,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useItemSelectGridFormSchema(),
|
schema: useItemSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useItemSelectGridColumns(),
|
columns: useItemSelectGridColumns(true),
|
||||||
height: 560,
|
height: 560,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
|
|
@ -106,6 +119,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
range: true,
|
range: true,
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
radioConfig: {
|
||||||
|
highlight: true,
|
||||||
|
trigger: 'row',
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -129,8 +146,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<MesMdItemApi.Item>,
|
} as VxeTableGridOptions<MesMdItemApi.Item>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
checkboxAll: handleCheckboxAll,
|
cellDblclick: handleCellDblclick,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesMdItemApi.Item }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -140,6 +161,8 @@ async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
typeTreeRef.value?.reset();
|
typeTreeRef.value?.reset();
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,10 +175,13 @@ async function openModal(
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useItemSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭物料选择弹窗 */
|
/** 关闭物料选择弹窗 */
|
||||||
|
|
@ -166,14 +192,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择物料 */
|
/** 确认选择物料 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,16 @@ const selectedItem = ref<MesMdItemApi.Item>(); // 当前选中物料
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.allowClear &&
|
props.allowClear &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据物料编号回显选择器 */
|
/** 根据物料编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getItem(id as number);
|
selectedItem.value = await getItem(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdItemSelect] resolveItemById failed:', error);
|
console.error('[MdItemSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的物料 */
|
/** 回填选中的物料 */
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdItemApi } from '#/api/mes/md/item';
|
import type { MesMdItemApi } from '#/api/mes/md/item';
|
||||||
import type { MesMdProductBomApi } from '#/api/mes/md/item/productBom';
|
import type { MesMdProductBomApi } from '#/api/mes/md/item/productBom';
|
||||||
|
|
||||||
import { DICT_TYPE, h, markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
@ -356,9 +356,11 @@ export function useItemSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 物料选择弹窗列表字段 */
|
/** 物料选择弹窗列表字段 */
|
||||||
export function useItemSelectGridColumns(): VxeTableGridOptions<MesMdItemApi.Item>['columns'] {
|
export function useItemSelectGridColumns(
|
||||||
|
multiple = true,
|
||||||
|
): VxeTableGridOptions<MesMdItemApi.Item>['columns'] {
|
||||||
return [
|
return [
|
||||||
{ type: 'checkbox', width: 50 },
|
{ type: multiple ? 'checkbox' : 'radio', width: 50 },
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
title: '物料编码',
|
title: '物料编码',
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,14 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdItemTypeApi } from '#/api/mes/md/item/type';
|
import type { MesMdItemTypeApi } from '#/api/mes/md/item/type';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode, MesItemOrProductEnum } from '@vben/constants';
|
import {
|
||||||
|
CommonStatusEnum,
|
||||||
|
DICT_TYPE,
|
||||||
|
MesAutoCodeRuleCode,
|
||||||
|
MesItemOrProductEnum,
|
||||||
|
} from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,71 +16,86 @@ import {
|
||||||
useVendorSelectGridFormSchema,
|
useVendorSelectGridFormSchema,
|
||||||
} from '../data';
|
} from '../data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MdVendorSelectDialog' });
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
selected: [rows: MesMdVendorApi.Vendor[]];
|
selected: [rows: MesMdVendorApi.Vendor[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const open = ref(false); // 弹窗是否打开
|
const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const syncingSingleSelection = ref(false); // 是否同步单选勾选状态
|
|
||||||
const selectedRows = ref<MesMdVendorApi.Vendor[]>([]); // 已选供应商列表
|
const selectedRows = ref<MesMdVendorApi.Vendor[]>([]); // 已选供应商列表
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选供应商编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选供应商编号列表
|
||||||
|
|
||||||
/** 单选模式下同步 VXE 勾选状态,避免跨页残留多选 */
|
/** 获取当前表格数据 */
|
||||||
async function syncSingleSelection(row?: MesMdVendorApi.Vendor) {
|
function getTableRows() {
|
||||||
syncingSingleSelection.value = true;
|
return gridApi.grid.getTableData().fullData as MesMdVendorApi.Vendor[];
|
||||||
await nextTick();
|
|
||||||
await gridApi.grid.clearCheckboxRow();
|
|
||||||
if (row) {
|
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
|
||||||
}
|
|
||||||
await nextTick();
|
|
||||||
syncingSingleSelection.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化,单选模式只保留最后一条 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function handleCheckboxChange({
|
function getMultipleSelectedRows() {
|
||||||
checked,
|
const selectedMap = new Map<number, MesMdVendorApi.Vendor>();
|
||||||
records,
|
const records = [
|
||||||
row,
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
}: {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
checked: boolean;
|
] as MesMdVendorApi.Vendor[];
|
||||||
records: MesMdVendorApi.Vendor[];
|
records.forEach((row) => {
|
||||||
row?: MesMdVendorApi.Vendor;
|
const rowId = row.id;
|
||||||
}) {
|
if (rowId != null) {
|
||||||
if (syncingSingleSelection.value) {
|
selectedMap.set(rowId, row);
|
||||||
return;
|
}
|
||||||
}
|
});
|
||||||
if (!multiple.value) {
|
return [...selectedMap.values()];
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理勾选变化 */
|
||||||
function handleCheckboxAll({ records }: { records: MesMdVendorApi.Vendor[] }) {
|
function handleCheckboxSelectChange() {
|
||||||
if (syncingSingleSelection.value) {
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理单选变化 */
|
||||||
|
function handleRadioChange(row: MesMdVendorApi.Vendor) {
|
||||||
|
selectedRows.value = [row];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选模式下切换行勾选 */
|
||||||
|
async function toggleMultipleRow(row: MesMdVendorApi.Vendor) {
|
||||||
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理行双击 */
|
||||||
|
async function handleCellDblclick({ row }: { row: MesMdVendorApi.Vendor }) {
|
||||||
|
if (multiple.value) {
|
||||||
|
await toggleMultipleRow(row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = records;
|
selectedRows.value = [row];
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选供应商 */
|
/** 回显预选供应商 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesMdVendorApi.Vendor[];
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +104,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useVendorSelectGridFormSchema(),
|
schema: useVendorSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useVendorSelectGridColumns(),
|
columns: useVendorSelectGridColumns(true),
|
||||||
height: 520,
|
height: 520,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
|
|
@ -97,6 +112,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
range: true,
|
range: true,
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
radioConfig: {
|
||||||
|
highlight: true,
|
||||||
|
trigger: 'row',
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -119,8 +138,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<MesMdVendorApi.Vendor>,
|
} as VxeTableGridOptions<MesMdVendorApi.Vendor>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
checkboxAll: handleCheckboxAll,
|
cellDblclick: handleCellDblclick,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesMdVendorApi.Vendor }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -128,6 +151,8 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
async function resetQueryState() {
|
async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,10 +165,13 @@ async function openModal(
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useVendorSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭供应商选择弹窗 */
|
/** 关闭供应商选择弹窗 */
|
||||||
|
|
@ -154,14 +182,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择供应商 */
|
/** 确认选择供应商 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,16 @@ const selectedItem = ref<MesMdVendorApi.Vendor>(); // 当前选中供应商
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.allowClear &&
|
props.allowClear &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据供应商编号回显选择器 */
|
/** 根据供应商编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getVendor(id as number);
|
selectedItem.value = await getVendor(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdVendorSelect] resolveItemById failed:', error);
|
console.error('[MdVendorSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的供应商 */
|
/** 回填选中的供应商 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdVendorApi } from '#/api/mes/md/vendor';
|
import type { MesMdVendorApi } from '#/api/mes/md/vendor';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
@ -416,9 +416,11 @@ export function useVendorSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 供应商选择弹窗的字段 */
|
/** 供应商选择弹窗的字段 */
|
||||||
export function useVendorSelectGridColumns(): VxeTableGridOptions<MesMdVendorApi.Vendor>['columns'] {
|
export function useVendorSelectGridColumns(
|
||||||
|
multiple = true,
|
||||||
|
): VxeTableGridOptions<MesMdVendorApi.Vendor>['columns'] {
|
||||||
return [
|
return [
|
||||||
{ type: 'checkbox', width: 50 },
|
{ type: multiple ? 'checkbox' : 'radio', width: 50 },
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
title: '供应商编码',
|
title: '供应商编码',
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,11 @@ const selectedItem = ref<MesMdWorkstationApi.Workstation>(); // 选中的工作
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.allowClear &&
|
props.allowClear &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据工作站编号回显选择器 */
|
/** 根据工作站编号回显选择器 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdWorkstationApi } from '#/api/mes/md/workstation';
|
import type { MesMdWorkstationApi } from '#/api/mes/md/workstation';
|
||||||
|
|
||||||
import { DICT_TYPE, h, markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdWorkshopApi } from '#/api/mes/md/workstation/workshop';
|
import type { MesMdWorkshopApi } from '#/api/mes/md/workstation/workshop';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { ElOption, ElSelect } from 'element-plus';
|
||||||
|
|
||||||
import { getCheckPlanPage } from '#/api/mes/dv/checkplan';
|
import { getCheckPlanPage } from '#/api/mes/dv/checkplan';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvCheckPlanSelect' });
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
clearable?: boolean;
|
clearable?: boolean;
|
||||||
|
|
@ -46,13 +48,11 @@ async function getList() {
|
||||||
function handleChange(value: number | string | undefined) {
|
function handleChange(value: number | string | undefined) {
|
||||||
const planId = typeof value === 'number' ? value : undefined;
|
const planId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', planId);
|
emit('update:modelValue', planId);
|
||||||
emit(
|
emit('change', list.value.find((item) => item.id === planId));
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === planId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => [props.status, props.type], getList);
|
watch(() => [props.status, props.type], getList);
|
||||||
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -66,6 +66,11 @@ onMounted(getList);
|
||||||
filterable
|
filterable
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<ElOption v-for="item in list" :key="item.id" :label="item.name" :value="item.id!" />
|
<ElOption
|
||||||
|
v-for="item in list"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id!"
|
||||||
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { ElOption, ElSelect } from 'element-plus';
|
||||||
|
|
||||||
import { getMachinerySimpleList } from '#/api/mes/dv/machinery';
|
import { getMachinerySimpleList } from '#/api/mes/dv/machinery';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvMachinerySelect' });
|
||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
clearable?: boolean;
|
clearable?: boolean;
|
||||||
|
|
@ -14,7 +16,12 @@ withDefaults(
|
||||||
modelValue?: number;
|
modelValue?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{ clearable: true, disabled: false, modelValue: undefined, placeholder: '请选择设备' },
|
{
|
||||||
|
clearable: true,
|
||||||
|
disabled: false,
|
||||||
|
modelValue: undefined,
|
||||||
|
placeholder: '请选择设备',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [row?: MesDvMachineryApi.Machinery];
|
change: [row?: MesDvMachineryApi.Machinery];
|
||||||
|
|
@ -31,10 +38,7 @@ async function getList() {
|
||||||
function handleChange(value: number | string | undefined) {
|
function handleChange(value: number | string | undefined) {
|
||||||
const machineryId = typeof value === 'number' ? value : undefined;
|
const machineryId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', machineryId);
|
emit('update:modelValue', machineryId);
|
||||||
emit(
|
emit('change', list.value.find((item) => item.id === machineryId));
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === machineryId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
|
|
@ -50,6 +54,11 @@ onMounted(getList);
|
||||||
filterable
|
filterable
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<ElOption v-for="item in list" :key="item.id" :label="item.name" :value="item.id!" />
|
<ElOption
|
||||||
|
v-for="item in list"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id!"
|
||||||
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesDvMachineryTypeApi } from '#/api/mes/dv/machinery/type';
|
import type { MesDvMachineryTypeApi } from '#/api/mes/dv/machinery/type';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { ElOption, ElSelect } from 'element-plus';
|
||||||
|
|
||||||
import { getSubjectSimpleList } from '#/api/mes/dv/subject';
|
import { getSubjectSimpleList } from '#/api/mes/dv/subject';
|
||||||
|
|
||||||
|
defineOptions({ name: 'DvSubjectSelect' });
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
clearable?: boolean;
|
clearable?: boolean;
|
||||||
|
|
@ -28,7 +30,7 @@ const emit = defineEmits<{
|
||||||
'update:modelValue': [value?: number];
|
'update:modelValue': [value?: number];
|
||||||
}>();
|
}>();
|
||||||
const list = ref<MesDvSubjectApi.Subject[]>([]); // 项目列表
|
const list = ref<MesDvSubjectApi.Subject[]>([]); // 项目列表
|
||||||
const filteredList = computed( // 筛选后的项目列表
|
const filteredList = computed(
|
||||||
() => list.value.filter((item) => !props.type || item.type === props.type),
|
() => list.value.filter((item) => !props.type || item.type === props.type),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -41,10 +43,7 @@ async function getList() {
|
||||||
function handleChange(value: number | string | undefined) {
|
function handleChange(value: number | string | undefined) {
|
||||||
const subjectId = typeof value === 'number' ? value : undefined;
|
const subjectId = typeof value === 'number' ? value : undefined;
|
||||||
emit('update:modelValue', subjectId);
|
emit('update:modelValue', subjectId);
|
||||||
emit(
|
emit('change', list.value.find((item) => item.id === subjectId));
|
||||||
'change',
|
|
||||||
list.value.find((item) => item.id === subjectId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(getList);
|
onMounted(getList);
|
||||||
|
|
@ -60,6 +59,11 @@ onMounted(getList);
|
||||||
filterable
|
filterable
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<ElOption v-for="item in filteredList" :key="item.id" :label="item.name" :value="item.id!" />
|
<ElOption
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id!"
|
||||||
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,14 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesDvSubjectApi } from '#/api/mes/dv/subject';
|
import type { MesDvSubjectApi } from '#/api/mes/dv/subject';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode, MesDvSubjectTypeEnum } from '@vben/constants';
|
import {
|
||||||
|
CommonStatusEnum,
|
||||||
|
DICT_TYPE,
|
||||||
|
MesAutoCodeRuleCode,
|
||||||
|
MesDvSubjectTypeEnum,
|
||||||
|
} from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import {
|
||||||
useClientSelectGridFormSchema,
|
useClientSelectGridFormSchema,
|
||||||
} from '../data';
|
} from '../data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MdClientSelectDialog' });
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
selected: [rows: MesMdClientApi.Client[]];
|
selected: [rows: MesMdClientApi.Client[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
@ -24,43 +26,12 @@ const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const selectedRows = ref<MesMdClientApi.Client[]>([]); // 已选客户列表
|
const selectedRows = ref<MesMdClientApi.Client[]>([]); // 已选客户列表
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选客户编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选客户编号列表
|
||||||
const latestQueryRows = ref<MesMdClientApi.Client[]>([]); // 最近一次查询返回的客户列表
|
|
||||||
const queryFinished = ref(false); // 最近一次查询是否完成
|
|
||||||
|
|
||||||
// TODO @芋艿:是否有必要搞的这么复杂???后续测试看看。
|
|
||||||
const MAX_TABLE_READY_FRAMES = 60;
|
|
||||||
|
|
||||||
/** 等待下一帧 */
|
|
||||||
function waitNextFrame(): Promise<void> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
requestAnimationFrame(() => resolve());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前表格数据 */
|
/** 获取当前表格数据 */
|
||||||
function getTableRows() {
|
function getTableRows() {
|
||||||
return gridApi.grid.getTableData().fullData as MesMdClientApi.Client[];
|
return gridApi.grid.getTableData().fullData as MesMdClientApi.Client[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 等待 VXE 将当前查询结果写入表格数据后再回显选中 */
|
|
||||||
async function waitTableReady(): Promise<void> {
|
|
||||||
if (preSelectedIds.value.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let index = 0; index < MAX_TABLE_READY_FRAMES; index += 1) {
|
|
||||||
if (queryFinished.value) {
|
|
||||||
const rows = getTableRows();
|
|
||||||
if (latestQueryRows.value.length === 0 && rows.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (latestQueryRows.value.length > 0 && rows.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await waitNextFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
function getMultipleSelectedRows() {
|
function getMultipleSelectedRows() {
|
||||||
const selectedMap = new Map<number, MesMdClientApi.Client>();
|
const selectedMap = new Map<number, MesMdClientApi.Client>();
|
||||||
|
|
@ -69,8 +40,9 @@ function getMultipleSelectedRows() {
|
||||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
] as MesMdClientApi.Client[];
|
] as MesMdClientApi.Client[];
|
||||||
records.forEach((row) => {
|
records.forEach((row) => {
|
||||||
if (row.id !== null) {
|
const rowId = row.id;
|
||||||
selectedMap.set(row.id as number, row);
|
if (rowId != null) {
|
||||||
|
selectedMap.set(rowId, row);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return [...selectedMap.values()];
|
return [...selectedMap.values()];
|
||||||
|
|
@ -109,10 +81,9 @@ async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// proxy 表格回显选中时要读取 fullData,否则首次打开可能读不到刚查询出的数据。
|
|
||||||
const rows = getTableRows();
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id === null || !preSelectedIds.value.includes(row.id as number)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (multiple.value) {
|
if (multiple.value) {
|
||||||
|
|
@ -148,15 +119,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
const data = await getClientPage({
|
return await getClientPage({
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
...formValues,
|
...formValues,
|
||||||
status: CommonStatusEnum.ENABLE,
|
status: CommonStatusEnum.ENABLE,
|
||||||
});
|
});
|
||||||
latestQueryRows.value = data.list || [];
|
|
||||||
queryFinished.value = true;
|
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -196,8 +164,6 @@ async function openModal(
|
||||||
open.value = true;
|
open.value = true;
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
latestQueryRows.value = [];
|
|
||||||
queryFinished.value = false;
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
gridApi.setGridOptions({
|
gridApi.setGridOptions({
|
||||||
columns: useClientSelectGridColumns(multiple.value),
|
columns: useClientSelectGridColumns(multiple.value),
|
||||||
|
|
@ -205,13 +171,13 @@ async function openModal(
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
await waitTableReady();
|
|
||||||
await applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭客户选择弹窗 */
|
/** 关闭客户选择弹窗 */
|
||||||
function closeModal() {
|
async function closeModal() {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
|
await resetQueryState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 确认选择客户 */
|
/** 确认选择客户 */
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,16 @@ const selectedItem = ref<MesMdClientApi.Client>(); // 当前选中客户
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.clearable &&
|
props.clearable &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据客户编号回显选择器 */
|
/** 根据客户编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getClient(id as number);
|
selectedItem.value = await getClient(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdClientSelect] resolveItemById failed:', error);
|
console.error('[MdClientSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的客户 */
|
/** 回填选中的客户 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdClientApi } from '#/api/mes/md/client';
|
import type { MesMdClientApi } from '#/api/mes/md/client';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ async function openModal(itemId: number, selectedBomItemId?: number) {
|
||||||
list.value = await getProductBomListByItemId(itemId);
|
list.value = await getProductBomListByItemId(itemId);
|
||||||
gridApi.setGridOptions({ data: list.value });
|
gridApi.setGridOptions({ data: list.value });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (selectedBomItemId !== null) {
|
if (selectedBomItemId != null) {
|
||||||
const match = list.value.find(
|
const match = list.value.find(
|
||||||
(row) => row.bomItemId === selectedBomItemId,
|
(row) => row.bomItemId === selectedBomItemId,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -40,17 +40,16 @@ const selectedBom = ref<MesMdProductBomApi.ProductBom>(); // 当前选中的 BOM
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.clearable &&
|
props.clearable &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据 BOM 子物料编号回显选择器 */
|
/** 根据 BOM 子物料编号回显选择器 */
|
||||||
async function resolveBomById(bomItemId: number | undefined) {
|
async function resolveBomById(bomItemId: number | undefined) {
|
||||||
if (bomItemId === null || props.itemId === null) {
|
if (bomItemId == null || props.itemId == null) {
|
||||||
selectedBom.value = undefined;
|
selectedBom.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +57,7 @@ async function resolveBomById(bomItemId: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const list = await getProductBomListByItemId(props.itemId as number);
|
const list = await getProductBomListByItemId(props.itemId);
|
||||||
selectedBom.value = list.find((item) => item.bomItemId === bomItemId);
|
selectedBom.value = list.find((item) => item.bomItemId === bomItemId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdProductBomSelect] resolveBomById failed:', error);
|
console.error('[MdProductBomSelect] resolveBomById failed:', error);
|
||||||
|
|
@ -91,7 +90,7 @@ function clearSelected() {
|
||||||
|
|
||||||
/** 打开 BOM 物料选择弹窗 */
|
/** 打开 BOM 物料选择弹窗 */
|
||||||
function handleClick(event: MouseEvent) {
|
function handleClick(event: MouseEvent) {
|
||||||
if (props.disabled || props.itemId === null) {
|
if (props.disabled || props.itemId == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
|
|
@ -100,7 +99,7 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dialogRef.value?.open(props.itemId as number, props.modelValue);
|
dialogRef.value?.open(props.itemId, props.modelValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的 BOM 物料 */
|
/** 回填选中的 BOM 物料 */
|
||||||
|
|
|
||||||
|
|
@ -23,52 +23,58 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const open = ref(false); // 弹窗是否打开
|
const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const syncingSingleSelection = ref(false); // 是否同步单选勾选状态
|
|
||||||
const selectedRows = ref<MesMdItemApi.Item[]>([]); // 已选物料列表
|
const selectedRows = ref<MesMdItemApi.Item[]>([]); // 已选物料列表
|
||||||
const selectedItemTypeId = ref<number>(); // 当前筛选分类编号
|
const selectedItemTypeId = ref<number>(); // 当前筛选分类编号
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选物料编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选物料编号列表
|
||||||
const typeTreeRef = ref<InstanceType<typeof MdItemTypeTree>>(); // 物料分类树
|
const typeTreeRef = ref<InstanceType<typeof MdItemTypeTree>>(); // 物料分类树
|
||||||
|
|
||||||
/** 单选模式下同步 VXE 勾选状态,避免跨页残留多选 */
|
/** 获取当前表格数据 */
|
||||||
async function syncSingleSelection(row?: MesMdItemApi.Item) {
|
function getTableRows() {
|
||||||
syncingSingleSelection.value = true;
|
return gridApi.grid.getTableData().fullData as MesMdItemApi.Item[];
|
||||||
await nextTick();
|
|
||||||
await gridApi.grid.clearCheckboxRow();
|
|
||||||
if (row) {
|
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
|
||||||
}
|
|
||||||
await nextTick();
|
|
||||||
syncingSingleSelection.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化,单选模式只保留最后一条 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function handleCheckboxChange({
|
function getMultipleSelectedRows() {
|
||||||
checked,
|
const selectedMap = new Map<number, MesMdItemApi.Item>();
|
||||||
records,
|
const records = [
|
||||||
row,
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
}: {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
checked: boolean;
|
] as MesMdItemApi.Item[];
|
||||||
records: MesMdItemApi.Item[];
|
records.forEach((row) => {
|
||||||
row?: MesMdItemApi.Item;
|
const rowId = row.id;
|
||||||
}) {
|
if (rowId != null) {
|
||||||
if (syncingSingleSelection.value) {
|
selectedMap.set(rowId, row);
|
||||||
return;
|
}
|
||||||
}
|
});
|
||||||
if (!multiple.value) {
|
return [...selectedMap.values()];
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理勾选变化 */
|
||||||
function handleCheckboxAll({ records }: { records: MesMdItemApi.Item[] }) {
|
function handleCheckboxSelectChange() {
|
||||||
if (syncingSingleSelection.value) {
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理单选变化 */
|
||||||
|
function handleRadioChange(row: MesMdItemApi.Item) {
|
||||||
|
selectedRows.value = [row];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选模式下切换行勾选 */
|
||||||
|
async function toggleMultipleRow(row: MesMdItemApi.Item) {
|
||||||
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理行双击 */
|
||||||
|
async function handleCellDblclick({ row }: { row: MesMdItemApi.Item }) {
|
||||||
|
if (multiple.value) {
|
||||||
|
await toggleMultipleRow(row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = records;
|
selectedRows.value = [row];
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 按分类筛选物料 */
|
/** 按分类筛选物料 */
|
||||||
|
|
@ -78,18 +84,25 @@ function handleItemTypeNodeClick(row: MesMdItemTypeApi.ItemType | undefined) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选物料 */
|
/** 回显预选物料 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesMdItemApi.Item[];
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +111,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useItemSelectGridFormSchema(),
|
schema: useItemSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useItemSelectGridColumns(),
|
columns: useItemSelectGridColumns(true),
|
||||||
height: 560,
|
height: 560,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
|
|
@ -106,6 +119,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
range: true,
|
range: true,
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
radioConfig: {
|
||||||
|
highlight: true,
|
||||||
|
trigger: 'row',
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -129,8 +146,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<MesMdItemApi.Item>,
|
} as VxeTableGridOptions<MesMdItemApi.Item>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
checkboxAll: handleCheckboxAll,
|
cellDblclick: handleCellDblclick,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesMdItemApi.Item }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -140,6 +161,8 @@ async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
typeTreeRef.value?.reset();
|
typeTreeRef.value?.reset();
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,10 +175,13 @@ async function openModal(
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useItemSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭物料选择弹窗 */
|
/** 关闭物料选择弹窗 */
|
||||||
|
|
@ -166,14 +192,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择物料 */
|
/** 确认选择物料 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,16 @@ const selectedItem = ref<MesMdItemApi.Item>(); // 当前选中物料
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.clearable &&
|
props.clearable &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据物料编号回显选择器 */
|
/** 根据物料编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getItem(id as number);
|
selectedItem.value = await getItem(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdItemSelect] resolveItemById failed:', error);
|
console.error('[MdItemSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的物料 */
|
/** 回填选中的物料 */
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdItemApi } from '#/api/mes/md/item';
|
import type { MesMdItemApi } from '#/api/mes/md/item';
|
||||||
import type { MesMdProductBomApi } from '#/api/mes/md/item/productBom';
|
import type { MesMdProductBomApi } from '#/api/mes/md/item/productBom';
|
||||||
|
|
||||||
import { DICT_TYPE, h, markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
@ -360,9 +360,11 @@ export function useItemSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 物料选择弹窗列表字段 */
|
/** 物料选择弹窗列表字段 */
|
||||||
export function useItemSelectGridColumns(): VxeTableGridOptions<MesMdItemApi.Item>['columns'] {
|
export function useItemSelectGridColumns(
|
||||||
|
multiple = true,
|
||||||
|
): VxeTableGridOptions<MesMdItemApi.Item>['columns'] {
|
||||||
return [
|
return [
|
||||||
{ type: 'checkbox', width: 50 },
|
{ type: multiple ? 'checkbox' : 'radio', width: 50 },
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
title: '物料编码',
|
title: '物料编码',
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,14 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdItemTypeApi } from '#/api/mes/md/item/type';
|
import type { MesMdItemTypeApi } from '#/api/mes/md/item/type';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode, MesItemOrProductEnum } from '@vben/constants';
|
import {
|
||||||
|
CommonStatusEnum,
|
||||||
|
DICT_TYPE,
|
||||||
|
MesAutoCodeRuleCode,
|
||||||
|
MesItemOrProductEnum,
|
||||||
|
} from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,71 +16,86 @@ import {
|
||||||
useVendorSelectGridFormSchema,
|
useVendorSelectGridFormSchema,
|
||||||
} from '../data';
|
} from '../data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MdVendorSelectDialog' });
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
selected: [rows: MesMdVendorApi.Vendor[]];
|
selected: [rows: MesMdVendorApi.Vendor[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const open = ref(false); // 弹窗是否打开
|
const open = ref(false); // 弹窗是否打开
|
||||||
const multiple = ref(true); // 是否多选
|
const multiple = ref(true); // 是否多选
|
||||||
const syncingSingleSelection = ref(false); // 是否同步单选勾选状态
|
|
||||||
const selectedRows = ref<MesMdVendorApi.Vendor[]>([]); // 已选供应商列表
|
const selectedRows = ref<MesMdVendorApi.Vendor[]>([]); // 已选供应商列表
|
||||||
const preSelectedIds = ref<number[]>([]); // 预选供应商编号列表
|
const preSelectedIds = ref<number[]>([]); // 预选供应商编号列表
|
||||||
|
|
||||||
/** 单选模式下同步 VXE 勾选状态,避免跨页残留多选 */
|
/** 获取当前表格数据 */
|
||||||
async function syncSingleSelection(row?: MesMdVendorApi.Vendor) {
|
function getTableRows() {
|
||||||
syncingSingleSelection.value = true;
|
return gridApi.grid.getTableData().fullData as MesMdVendorApi.Vendor[];
|
||||||
await nextTick();
|
|
||||||
await gridApi.grid.clearCheckboxRow();
|
|
||||||
if (row) {
|
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
|
||||||
}
|
|
||||||
await nextTick();
|
|
||||||
syncingSingleSelection.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化,单选模式只保留最后一条 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function handleCheckboxChange({
|
function getMultipleSelectedRows() {
|
||||||
checked,
|
const selectedMap = new Map<number, MesMdVendorApi.Vendor>();
|
||||||
records,
|
const records = [
|
||||||
row,
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
}: {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
checked: boolean;
|
] as MesMdVendorApi.Vendor[];
|
||||||
records: MesMdVendorApi.Vendor[];
|
records.forEach((row) => {
|
||||||
row?: MesMdVendorApi.Vendor;
|
const rowId = row.id;
|
||||||
}) {
|
if (rowId != null) {
|
||||||
if (syncingSingleSelection.value) {
|
selectedMap.set(rowId, row);
|
||||||
return;
|
}
|
||||||
}
|
});
|
||||||
if (!multiple.value) {
|
return [...selectedMap.values()];
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理勾选变化 */
|
||||||
function handleCheckboxAll({ records }: { records: MesMdVendorApi.Vendor[] }) {
|
function handleCheckboxSelectChange() {
|
||||||
if (syncingSingleSelection.value) {
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理单选变化 */
|
||||||
|
function handleRadioChange(row: MesMdVendorApi.Vendor) {
|
||||||
|
selectedRows.value = [row];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选模式下切换行勾选 */
|
||||||
|
async function toggleMultipleRow(row: MesMdVendorApi.Vendor) {
|
||||||
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理行双击 */
|
||||||
|
async function handleCellDblclick({ row }: { row: MesMdVendorApi.Vendor }) {
|
||||||
|
if (multiple.value) {
|
||||||
|
await toggleMultipleRow(row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = records;
|
selectedRows.value = [row];
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选供应商 */
|
/** 回显预选供应商 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesMdVendorApi.Vendor[];
|
const rows = getTableRows();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +104,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useVendorSelectGridFormSchema(),
|
schema: useVendorSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useVendorSelectGridColumns(),
|
columns: useVendorSelectGridColumns(true),
|
||||||
height: 520,
|
height: 520,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
|
|
@ -97,6 +112,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
range: true,
|
range: true,
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
radioConfig: {
|
||||||
|
highlight: true,
|
||||||
|
trigger: 'row',
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -119,8 +138,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<MesMdVendorApi.Vendor>,
|
} as VxeTableGridOptions<MesMdVendorApi.Vendor>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
checkboxAll: handleCheckboxAll,
|
cellDblclick: handleCellDblclick,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesMdVendorApi.Vendor }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -128,6 +151,8 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
async function resetQueryState() {
|
async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,10 +165,13 @@ async function openModal(
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? true;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useVendorSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭供应商选择弹窗 */
|
/** 关闭供应商选择弹窗 */
|
||||||
|
|
@ -154,14 +182,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择供应商 */
|
/** 确认选择供应商 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,16 @@ const selectedItem = ref<MesMdVendorApi.Vendor>(); // 当前选中供应商
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.clearable &&
|
props.clearable &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据供应商编号回显选择器 */
|
/** 根据供应商编号回显选择器 */
|
||||||
async function resolveItemById(id: number | undefined) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
if (id === null) {
|
if (id == null) {
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selectedItem.value = await getVendor(id as number);
|
selectedItem.value = await getVendor(id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MdVendorSelect] resolveItemById failed:', error);
|
console.error('[MdVendorSelect] resolveItemById failed:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +87,8 @@ function handleClick(event: MouseEvent) {
|
||||||
clearSelected();
|
clearSelected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回填选中的供应商 */
|
/** 回填选中的供应商 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdVendorApi } from '#/api/mes/md/vendor';
|
import type { MesMdVendorApi } from '#/api/mes/md/vendor';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
@ -415,9 +415,11 @@ export function useVendorSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 供应商选择弹窗的字段 */
|
/** 供应商选择弹窗的字段 */
|
||||||
export function useVendorSelectGridColumns(): VxeTableGridOptions<MesMdVendorApi.Vendor>['columns'] {
|
export function useVendorSelectGridColumns(
|
||||||
|
multiple = true,
|
||||||
|
): VxeTableGridOptions<MesMdVendorApi.Vendor>['columns'] {
|
||||||
return [
|
return [
|
||||||
{ type: 'checkbox', width: 50 },
|
{ type: multiple ? 'checkbox' : 'radio', width: 50 },
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
title: '供应商编码',
|
title: '供应商编码',
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,11 @@ const selectedItem = ref<MesMdWorkstationApi.Workstation>(); // 选中的工作
|
||||||
|
|
||||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||||
const showClear = computed(
|
const showClear = computed(
|
||||||
// 是否显示清空图标
|
|
||||||
() =>
|
() =>
|
||||||
props.clearable &&
|
props.clearable &&
|
||||||
!props.disabled &&
|
!props.disabled &&
|
||||||
hovering.value &&
|
hovering.value &&
|
||||||
props.modelValue !== null,
|
props.modelValue != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 根据工作站编号回显选择器 */
|
/** 根据工作站编号回显选择器 */
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdWorkstationApi } from '#/api/mes/md/workstation';
|
import type { MesMdWorkstationApi } from '#/api/mes/md/workstation';
|
||||||
|
|
||||||
import { DICT_TYPE, h, markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesMdWorkshopApi } from '#/api/mes/md/workstation/workshop';
|
import type { MesMdWorkshopApi } from '#/api/mes/md/workstation/workshop';
|
||||||
|
|
||||||
import { DICT_TYPE, h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { CommonStatusEnum, MesAutoCodeRuleCode } from '@vben/constants';
|
import { CommonStatusEnum, DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
import { ElButton } from 'element-plus';
|
import { ElButton } from 'element-plus';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue