- 同步 IoT 物模型 Event dataType 类型,并修复 antdv-next 模拟器事件类型展示 - 修复 antdv-next 物模型选项模板字符串和校验规则写法 - 补齐 antdv-next BPM 审批附件上传限制与流程打印业务表单渲染 - 修复 antdv-next 缺失的组件导入、垂直按钮组导出,并删除未引用的部门树遗留文件 - 对齐 BPM 流程配置中 antd/antdv-next 的组件属性写法 - 修复 ele 流程创建跳转、好友拒绝文本框、客服回车发送、公告栏颜色表单项和部门选择弹窗选中状态 - 调整 BPM 流程实例 API 字段顺序,减少三端无意义差异
133 lines
3.7 KiB
Vue
133 lines
3.7 KiB
Vue
<script lang="ts" setup>
|
||
import type { SystemDeptApi } from '#/api/system/dept';
|
||
|
||
import { nextTick, ref } from 'vue';
|
||
|
||
import { useVbenModal } from '@vben/common-ui';
|
||
import { handleTree } from '@vben/utils';
|
||
|
||
import { ElCard, ElCol, ElRow, ElTree } from 'element-plus';
|
||
|
||
import { getSimpleDeptList } from '#/api/system/dept';
|
||
|
||
defineOptions({ name: 'DeptSelectModal' });
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
cancelText?: string; // 取消按钮文本
|
||
checkStrictly?: boolean; // checkable 状态下节点选择完全受控
|
||
confirmText?: string; // 确认按钮文本
|
||
multiple?: boolean; // 是否支持多选
|
||
title?: string; // 标题
|
||
}>(),
|
||
{
|
||
cancelText: '取消',
|
||
checkStrictly: false,
|
||
confirmText: '确认',
|
||
multiple: true,
|
||
title: '部门选择',
|
||
},
|
||
);
|
||
|
||
const emit = defineEmits<{
|
||
confirm: [deptList: SystemDeptApi.Dept[]];
|
||
}>();
|
||
|
||
const deptTree = ref<any[]>([]); // 部门树形结构
|
||
const selectedDeptIds = ref<number[]>([]); // 选中的部门 ID 列表
|
||
const deptData = ref<SystemDeptApi.Dept[]>([]); // 部门数据
|
||
const treeRef = ref(); // Tree 组件引用
|
||
|
||
const [Modal, modalApi] = useVbenModal({
|
||
async onConfirm() {
|
||
// 获取选中的部门ID(selectedDeptIds 由 handleCheck 实时维护,
|
||
// 严格/非严格模式下均与树勾选状态一致,无需依赖 treeRef 是否已挂载)
|
||
const selectedIds: number[] = selectedDeptIds.value;
|
||
|
||
const deptArray = deptData.value.filter((dept) =>
|
||
selectedIds.includes(dept.id!),
|
||
);
|
||
emit('confirm', deptArray);
|
||
// 关闭并提示
|
||
await modalApi.close();
|
||
},
|
||
async onOpenChange(isOpen: boolean) {
|
||
if (!isOpen) {
|
||
deptTree.value = [];
|
||
selectedDeptIds.value = [];
|
||
return;
|
||
}
|
||
// 加载数据
|
||
const data = modalApi.getData();
|
||
if (!data) {
|
||
return;
|
||
}
|
||
modalApi.lock();
|
||
try {
|
||
deptData.value = await getSimpleDeptList();
|
||
deptTree.value = handleTree(deptData.value);
|
||
// 等待 DOM 更新后再设置选中的节点
|
||
await nextTick();
|
||
// 设置已选择的部门
|
||
if (data.selectedList?.length) {
|
||
const selectedIds = data.selectedList
|
||
.map((dept: SystemDeptApi.Dept) => dept.id)
|
||
.filter((id: number) => id !== undefined);
|
||
selectedDeptIds.value = selectedIds;
|
||
treeRef.value.setCheckedKeys(selectedIds);
|
||
}
|
||
} finally {
|
||
modalApi.unlock();
|
||
}
|
||
},
|
||
destroyOnClose: true,
|
||
});
|
||
|
||
/** 处理选中状态变化 */
|
||
function handleCheck(
|
||
_data: any,
|
||
{ checkedKeys }: { checkedKeys: (number | string)[] },
|
||
) {
|
||
// 确保 checkedKeys 都是 number 类型
|
||
const keys = checkedKeys.map((key) =>
|
||
typeof key === 'string' ? Number(key) : key,
|
||
);
|
||
|
||
if (props.multiple) {
|
||
selectedDeptIds.value = keys;
|
||
} else {
|
||
// 单选模式下,只保留最后选择的节点
|
||
const lastSelectedId = keys[keys.length - 1];
|
||
if (lastSelectedId) {
|
||
selectedDeptIds.value = [lastSelectedId];
|
||
treeRef.value?.setCheckedKeys([lastSelectedId]);
|
||
} else {
|
||
selectedDeptIds.value = [];
|
||
treeRef.value?.setCheckedKeys([]);
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<template>
|
||
<Modal :title="title" key="dept-select-modal" class="w-3/5">
|
||
<ElRow class="h-full">
|
||
<ElCol :span="24">
|
||
<ElCard class="h-full">
|
||
<ElTree
|
||
v-if="deptTree.length > 0"
|
||
ref="treeRef"
|
||
:data="deptTree"
|
||
:props="{ label: 'name', children: 'children' }"
|
||
:check-strictly="checkStrictly"
|
||
:default-expand-all="true"
|
||
show-checkbox
|
||
check-on-click-node
|
||
node-key="id"
|
||
@check="handleCheck"
|
||
/>
|
||
</ElCard>
|
||
</ElCol>
|
||
</ElRow>
|
||
</Modal>
|
||
</template>
|