199 lines
4.3 KiB
Vue
199 lines
4.3 KiB
Vue
<template>
|
||
<div style="height: 100%">
|
||
<vue3-tree-org
|
||
ref="treeOrgRef"
|
||
:props="props"
|
||
:data="data"
|
||
:label-style="style"
|
||
:define-menus="defineMenus"
|
||
:default-expand-level="expandLevel"
|
||
center
|
||
:horizontal="horizontal"
|
||
:collapsable="collapsable"
|
||
:only-one-node="onlyOneNode"
|
||
:filter-node-method="filterNodeMethod"
|
||
:clone-node-drag="cloneNodeDrag"
|
||
:node-add="addNode"
|
||
:node-delete="delNode"
|
||
:node-edit="editNode"
|
||
@on-node-click="onNodeClick"
|
||
/>
|
||
</div>
|
||
<dept-form ref="deptDialogRef" @refresh="getOrgData()" />
|
||
</template>
|
||
|
||
<script lang="ts" name="treeView" setup>
|
||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||
import { delObj, deptTree } from '/@/api/admin/dept';
|
||
import { getObj } from '/@/api/admin/tenant';
|
||
import { Session } from '/@/utils/storage';
|
||
import { useI18n } from 'vue-i18n';
|
||
import { storeToRefs } from 'pinia';
|
||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||
|
||
const DeptForm = defineAsyncComponent(() => import('./form.vue'));
|
||
|
||
const { t } = useI18n();
|
||
|
||
// 定义org组件key-value定义
|
||
const props = reactive({ id: 'id', pid: 'parentId', label: 'name', expand: 'expand', children: 'children' });
|
||
const data = reactive({});
|
||
|
||
// 定义org组件右键定义
|
||
const defineMenus = reactive([
|
||
{ name: t('sysdept.addNodeText'), command: 'add' },
|
||
{ name: t('sysdept.editNodeText'), command: 'edit' },
|
||
{ name: t('sysdept.delNodeText'), command: 'delete' },
|
||
]);
|
||
|
||
const cloneNodeDrag = ref(true);
|
||
const collapsable = ref(false);
|
||
const expandLevel = ref(2); //默认展开层级
|
||
const horizontal = ref(false);
|
||
const onlyOneNode = ref(false);
|
||
const treeOrgRef = ref();
|
||
const deptDialogRef = ref();
|
||
|
||
// 添加主题配置
|
||
const themeConfig = useThemeConfig();
|
||
const { themeConfig: theme } = storeToRefs(themeConfig);
|
||
|
||
// 添加 style 定义
|
||
const style = computed(() => ({
|
||
background: theme.value.isDark ? 'var(--el-bg-color-overlay)' : 'var(--el-bg-color-page)',
|
||
color: theme.value.isDark ? 'var(--el-text-color-primary)' : '#5e6d82',
|
||
}));
|
||
|
||
/**
|
||
* 过滤节点
|
||
*/
|
||
const filter = (deptName: string) => {
|
||
treeOrgRef.value.filter(deptName);
|
||
};
|
||
|
||
/**
|
||
* 节点过滤方法
|
||
* @param {string} value 过滤条件
|
||
* @param {object} data 节点数据
|
||
* @returns {boolean} 返回过滤结果
|
||
*/
|
||
const filterNodeMethod = (value, data) => {
|
||
if (!value) return true;
|
||
return data.label.indexOf(value) !== -1;
|
||
};
|
||
|
||
/**
|
||
* 处理展开/折叠树
|
||
*/
|
||
const handleExpand = async () => {
|
||
collapsable.value = !collapsable.value;
|
||
};
|
||
|
||
/**
|
||
* 检查节点是否是根租户节点
|
||
* @param {object} node 节点对象
|
||
* @returns {boolean} 如果节点是根租户节点,返回true;否则返回false
|
||
*/
|
||
const checkNode = (node) => {
|
||
if (node?.id === '0') {
|
||
useMessage().error(t('sysdept.tenantNodeErrorText'));
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* 当用户左键点击节点,模拟触发组件的右键事件
|
||
* @param e
|
||
*/
|
||
const onNodeClick = (e: any) => {
|
||
const { clientX, clientY } = e;
|
||
const rightFun = new MouseEvent('contextmenu', {
|
||
bubbles: true,
|
||
cancelable: false,
|
||
view: window,
|
||
button: 2,
|
||
buttons: 0,
|
||
clientX,
|
||
clientY,
|
||
});
|
||
e.target.dispatchEvent(rightFun);
|
||
};
|
||
|
||
/**
|
||
* 添加部门
|
||
* @param {object} node 节点对象
|
||
*/
|
||
const addNode = (node) => {
|
||
deptDialogRef.value.openDialog('add', node?.id);
|
||
};
|
||
|
||
/**
|
||
* 编辑部门
|
||
* @param {object} node 节点对象
|
||
*/
|
||
const editNode = (node) => {
|
||
if (!checkNode(node)) {
|
||
return;
|
||
}
|
||
deptDialogRef.value.openDialog('edit', node?.id);
|
||
};
|
||
|
||
/**
|
||
* 删除部门
|
||
* @param {object} node 节点对象
|
||
*/
|
||
const delNode = async (node) => {
|
||
if (!checkNode(node)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||
} catch {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await delObj(node.id);
|
||
await getOrgData();
|
||
useMessage().success(t('common.delSuccessText'));
|
||
} catch (err: any) {
|
||
useMessage().error(err.msg);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 查询部门数据
|
||
*/
|
||
const getOrgData = async () => {
|
||
// 查询当前租户信息
|
||
const tenant = await getObj(Session.getTenant());
|
||
deptTree().then((res) => {
|
||
Object.assign(data, { id: '0', name: tenant.data.name });
|
||
data.children = res.data;
|
||
});
|
||
};
|
||
|
||
onMounted(() => {
|
||
getOrgData();
|
||
});
|
||
|
||
// 暴露变量
|
||
defineExpose({
|
||
getOrgData,
|
||
handleExpand,
|
||
filter,
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
:deep(.zm-tree-org) {
|
||
height: 100%;
|
||
padding: 15px;
|
||
position: relative;
|
||
background: var(--el-bg-color);
|
||
box-sizing: border-box;
|
||
}
|
||
</style>
|