602 lines
21 KiB
Vue
602 lines
21 KiB
Vue
<template>
|
||
<BasicModal
|
||
wrapClassName="autherizeDialog"
|
||
v-bind="$attrs"
|
||
@register="registerRoleAuthModal"
|
||
:title="t('功能授权')"
|
||
destroy-on-close
|
||
@ok="handleSubmit"
|
||
:width=modalLength()
|
||
>
|
||
<template #title>
|
||
<div>功能授权<span style="color:red">(注意:修改角色权限后需要手动点击“登出角色用户”按钮,或用户重新登录后才会生效)</span></div>
|
||
</template>
|
||
<a-row :gutter="[16, 16]" class="h-full">
|
||
<a-col :span=spanLength() v-if="typeKey==4||typeKey==0">
|
||
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
|
||
t('系统功能')
|
||
}}</div>
|
||
<div class="treebox">
|
||
<BasicTree
|
||
:treeData="treeData"
|
||
checkable
|
||
ref="treeRef"
|
||
@check="handleTreeSelect"
|
||
:fieldNames="{ title: 'title', key: 'id' }"
|
||
>
|
||
<template #title="{ title, systemName, parentId }">
|
||
<div v-if="parentId == 0">{{ title }} 【{{ systemName }}】</div>
|
||
<div v-else>{{ title }}</div>
|
||
</template>
|
||
</BasicTree>
|
||
</div>
|
||
</a-col>
|
||
<a-col :span=spanLength() v-if="typeKey==4||typeKey==1">
|
||
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
|
||
t('按钮权限')
|
||
}}</div>
|
||
<div class="treebox">
|
||
<BasicTree
|
||
:treeData="buttonSelectData"
|
||
checkable
|
||
ref="ButtonRef"
|
||
@check="handleButtonSelect"
|
||
:fieldNames="{ title: 'title', key: 'id' }"
|
||
/>
|
||
</div>
|
||
</a-col>
|
||
<a-col :span=spanLength() v-if="typeKey==4||typeKey==2">
|
||
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
|
||
t('字段权限')
|
||
}}</div>
|
||
<div class="treebox">
|
||
<BasicTree
|
||
:treeData="columnSelectData"
|
||
checkable
|
||
ref="ColumnRef"
|
||
@check="handleColumnSelect"
|
||
:fieldNames="{ title: 'title', key: 'id' }"
|
||
/>
|
||
</div>
|
||
</a-col>
|
||
<a-col :span=spanLength() v-if="typeKey==4||typeKey==3">
|
||
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
|
||
t('表单权限')
|
||
}}</div>
|
||
<div class="treebox">
|
||
<BasicTree
|
||
:treeData="fieldSelectData"
|
||
checkable
|
||
ref="FieldRef"
|
||
@check="handleFieldSelect"
|
||
:fieldNames="{ title: 'title', key: 'id' }"
|
||
/>
|
||
</div>
|
||
</a-col>
|
||
</a-row>
|
||
</BasicModal>
|
||
</template>
|
||
<script lang="ts">
|
||
import { defineComponent, ref, unref, nextTick } from 'vue';
|
||
import { getMenuSimpleTree } from '/@/api/system/menu';
|
||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||
import { TreeItem, BasicTree, TreeActionType } from '/@/components/Tree';
|
||
import { getRoleAuth, RoleSetAuth } from '/@/api/system/role';
|
||
import { useMessage } from '/@/hooks/web/useMessage';
|
||
|
||
import { getMenuButtonList, getMenuColumnList, getMenuFieldList } from '/@/api/system/menuButton';
|
||
import { cloneDeep } from 'lodash-es';
|
||
import { useI18n } from '/@/hooks/web/useI18n';
|
||
|
||
export default defineComponent({
|
||
name: 'SelectUserModal',
|
||
components: { BasicModal, BasicTree },
|
||
emits: ['success', 'register'],
|
||
setup(_, { emit }) {
|
||
const { notification } = useMessage();
|
||
const { t } = useI18n();
|
||
const treeRef = ref<Nullable<TreeActionType>>(null);
|
||
const ButtonRef = ref<Nullable<TreeActionType>>(null);
|
||
const ColumnRef = ref<Nullable<TreeActionType>>(null);
|
||
const FieldRef = ref<Nullable<TreeActionType>>(null);
|
||
const treeData = ref<TreeItem[]>([]);
|
||
const buttonData = ref<TreeItem[]>([]);
|
||
const columnData = ref<TreeItem[]>([]);
|
||
const fieldData = ref<TreeItem[]>([]);
|
||
|
||
const buttonSelectData = ref<TreeItem[]>([]);
|
||
const columnSelectData = ref<TreeItem[]>([]);
|
||
const fieldSelectData = ref<TreeItem[]>([]);
|
||
const btnKeys = ref<string[]>([]);
|
||
const colKeys = ref<string[]>([]);
|
||
const menuKeys = ref<string[]>([]);
|
||
const fieldKeys = ref<string[]>([]);
|
||
|
||
const btnFilterKeys = ref<string[]>([]);
|
||
const colFilterKeys = ref<string[]>([]);
|
||
const fieldFilterKeys = ref<string[]>([]);
|
||
|
||
const rowId = ref('');
|
||
const typeKey = ref(4);
|
||
|
||
function getTree(tree) {
|
||
if (!tree) {
|
||
return null;
|
||
}
|
||
return tree;
|
||
}
|
||
|
||
function spanLength() {
|
||
if (typeKey.value == 4) {
|
||
return "6";
|
||
} else {
|
||
return "24";
|
||
}
|
||
}
|
||
|
||
function modalLength() {
|
||
if (typeKey.value == 4) {
|
||
return "90%";
|
||
} else {
|
||
return "40%";
|
||
}
|
||
}
|
||
|
||
const [registerRoleAuthModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||
setModalProps({ confirmLoading: false });
|
||
rowId.value = data.id;
|
||
typeKey.value = data.key;
|
||
treeData.value = await getMenuSimpleTree();
|
||
|
||
buttonData.value = await getMenuButtonList();
|
||
columnData.value = await getMenuColumnList();
|
||
fieldData.value = await getMenuFieldList();
|
||
|
||
const authList = await getRoleAuth(rowId.value);
|
||
menuKeys.value = authList.menuIds || [];
|
||
btnKeys.value = authList.buttonIds || [];
|
||
colKeys.value = authList.columnIds || [];
|
||
fieldKeys.value = authList.formIds || [];
|
||
let menuCheckedKey = [];
|
||
let btnCheckedKey = [];
|
||
let colCheckedKey = [];
|
||
let fieldCheckedKey = [];
|
||
if (typeKey.value == 4) {
|
||
menuKeys.value.forEach((o) => {
|
||
getParentKeys(menuCheckedKey, treeData.value, o);
|
||
});
|
||
menuKeys.value = menuCheckedKey;
|
||
getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
|
||
initTree(menuCheckedKey);
|
||
|
||
let lostBtnKey = [];
|
||
btnKeys.value.forEach((o) => {
|
||
// getParentKeys(btnCheckedKey, buttonSelectData.value, o, lostBtnKey);
|
||
getParentKeysAndLost(btnCheckedKey, buttonSelectData.value, o, lostBtnKey);
|
||
});
|
||
if (lostBtnKey) {
|
||
let menuIds = [];
|
||
buttonData.value.forEach((but) => {
|
||
if (lostBtnKey.includes(but.id)) {
|
||
menuIds.push(but.menuId);
|
||
}
|
||
});
|
||
menuIds.forEach((key) => {
|
||
getParentKeys(btnCheckedKey, treeData.value, key);
|
||
});
|
||
findMenuTree(buttonSelectData.value, treeData.value, btnCheckedKey, 'button');
|
||
}
|
||
btnKeys.value = Array.from(new Set([...btnKeys.value, ...btnCheckedKey]));
|
||
|
||
let lostColKey = [];
|
||
colKeys.value.forEach((o) => {
|
||
// getParentKeys(colCheckedKey, columnSelectData.value, o);
|
||
getParentKeysAndLost(colCheckedKey, columnSelectData.value, o, lostColKey);
|
||
});
|
||
if (lostColKey) {
|
||
let menuIds = [];
|
||
columnData.value.forEach((but) => {
|
||
if (lostColKey.includes(but.id)) {
|
||
menuIds.push(but.menuId);
|
||
}
|
||
});
|
||
menuIds.forEach((key) => {
|
||
getParentKeys(colCheckedKey, treeData.value, key);
|
||
});
|
||
findMenuTree(columnSelectData.value, treeData.value, colCheckedKey, 'column');
|
||
}
|
||
colKeys.value = Array.from(new Set([...colKeys.value, ...colCheckedKey]));
|
||
|
||
let lostFieldKey = [];
|
||
fieldKeys.value.forEach((o) => {
|
||
// getParentKeys(fieldCheckedKey, fieldSelectData.value, o);
|
||
getParentKeysAndLost(fieldCheckedKey, fieldSelectData.value, o, lostFieldKey);
|
||
});
|
||
if (lostFieldKey) {
|
||
let menuIds = [];
|
||
columnData.value.forEach((but) => {
|
||
if (lostFieldKey.includes(but.id)) {
|
||
menuIds.push(but.menuId);
|
||
}
|
||
});
|
||
menuIds.forEach((key) => {
|
||
getParentKeys(fieldCheckedKey, treeData.value, key);
|
||
});
|
||
findMenuTree(fieldSelectData.value, treeData.value, fieldCheckedKey, 'field');
|
||
}
|
||
fieldKeys.value = Array.from(new Set([...fieldKeys.value, ...fieldCheckedKey]));
|
||
|
||
nextTick(() => {
|
||
getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
|
||
getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
|
||
getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
|
||
getTree(unref(ButtonRef)).expandAll(true);
|
||
getTree(unref(ColumnRef)).expandAll(true);
|
||
getTree(unref(FieldRef)).expandAll(true);
|
||
});
|
||
|
||
getTree(unref(treeRef)).expandAll(true);
|
||
} else {
|
||
if (typeKey.value == 0) {
|
||
menuKeys.value.forEach((o) => {
|
||
getParentKeys(menuCheckedKey, treeData.value, o);
|
||
});
|
||
menuKeys.value = menuCheckedKey;
|
||
getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
|
||
getTree(unref(treeRef)).expandAll(true);
|
||
}
|
||
const fullMenuKey = [];
|
||
getFullMenu(fullMenuKey, treeData.value);
|
||
initTree(fullMenuKey);
|
||
if (typeKey.value == 1) {
|
||
btnKeys.value.forEach((o) => {
|
||
getParentKeys(btnCheckedKey, buttonData.value, o);
|
||
});
|
||
btnKeys.value = btnCheckedKey;
|
||
getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
|
||
getTree(unref(ButtonRef)).expandAll(true);
|
||
}
|
||
else if (typeKey.value == 2) {
|
||
colKeys.value.forEach((o) => {
|
||
getParentKeys(colCheckedKey, columnData.value, o);
|
||
});
|
||
colKeys.value = colCheckedKey;
|
||
nextTick(() => {
|
||
getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
|
||
getTree(unref(ColumnRef)).expandAll(true);
|
||
});
|
||
}
|
||
else if (typeKey.value == 3) {
|
||
fieldKeys.value.forEach((o) => {
|
||
getParentKeys(fieldCheckedKey, fieldData.value, o);
|
||
});
|
||
fieldKeys.value = fieldCheckedKey;
|
||
nextTick(() => {
|
||
getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
|
||
getTree(unref(FieldRef)).expandAll(true);
|
||
});
|
||
}
|
||
|
||
}
|
||
});
|
||
|
||
async function handleSubmit() {
|
||
try {
|
||
setModalProps({ confirmLoading: true });
|
||
|
||
//由于树组件的原因,提交之前先过滤一遍,没有选中的不提交
|
||
// btnKeys.value = getTree(unref(ButtonRef)).getCheckedKeys();
|
||
// colKeys.value = getTree(unref(ColumnRef)).getCheckedKeys();
|
||
// fieldKeys.value = getTree(unref(FieldRef)).getCheckedKeys();
|
||
|
||
// 过滤无效的权限 ID
|
||
btnKeys.value = btnKeys.value.filter((o) => btnFilterKeys.value.includes(o));
|
||
colKeys.value = colKeys.value.filter((o) => colFilterKeys.value.includes(o));
|
||
fieldKeys.value = fieldKeys.value.filter((o) => fieldFilterKeys.value.includes(o));
|
||
|
||
// btnKeys.value = btnKeys.value.filter((o) => {
|
||
// return btnFilterKeys.value.includes(o);
|
||
// });
|
||
// colKeys.value = colKeys.value.filter((o) => {
|
||
// return colFilterKeys.value.includes(o);
|
||
// });
|
||
// fieldKeys.value = fieldKeys.value.filter((o) => {
|
||
// return fieldFilterKeys.value.includes(o);
|
||
// });
|
||
|
||
// 提交更新后的权限数据
|
||
await RoleSetAuth({
|
||
id: rowId.value,
|
||
type: typeKey.value == 4?NaN:typeKey.value,
|
||
menuIds: menuKeys.value,
|
||
buttonIds: btnKeys.value,
|
||
columnIds: colKeys.value,
|
||
formIds: fieldKeys.value,
|
||
});
|
||
|
||
notification.success({
|
||
message: t('提示'),
|
||
description: t('功能授权更新成功'),
|
||
}); //提示消息
|
||
closeModal();
|
||
emit('success');
|
||
} catch (error) {
|
||
setModalProps({ confirmLoading: false });
|
||
}
|
||
}
|
||
function handleButtonSelect(keys, e) {
|
||
btnKeys.value = [...e.halfCheckedKeys, ...keys];
|
||
}
|
||
function handleColumnSelect(keys, e) {
|
||
colKeys.value = [...e.halfCheckedKeys, ...keys];
|
||
}
|
||
function handleFieldSelect(keys, e) {
|
||
fieldKeys.value = [...e.halfCheckedKeys, ...keys];
|
||
}
|
||
function handleTreeSelect(keys, e) {
|
||
//keys 所有全选中的key
|
||
//e.halfCheckedKeys 所有半选中的
|
||
|
||
//如果没有半选 就证明全部全选 直接使用keys
|
||
//如果有半选需要 使用keys + e.halfCheckedKeys
|
||
|
||
const menuSelect: string[] = [...e.halfCheckedKeys, ...keys];
|
||
|
||
//选择菜单的时候。对应后面的button column field 只进行增量添加
|
||
incrementTree(menuSelect);
|
||
|
||
menuKeys.value = menuSelect;
|
||
}
|
||
function initTree(menuSelect) {
|
||
buttonSelectData.value = [];
|
||
columnSelectData.value = [];
|
||
fieldSelectData.value = [];
|
||
|
||
btnFilterKeys.value = [];
|
||
colFilterKeys.value = [];
|
||
fieldFilterKeys.value = [];
|
||
|
||
findMenuTree(buttonSelectData.value, treeData.value, menuSelect, 'button');
|
||
findMenuTree(columnSelectData.value, treeData.value, menuSelect, 'column');
|
||
findMenuTree(fieldSelectData.value, treeData.value, menuSelect, 'field');
|
||
|
||
getTree(unref(ButtonRef))?.setExpandedKeys(menuSelect);
|
||
getTree(unref(ColumnRef))?.setExpandedKeys(menuSelect);
|
||
getTree(unref(FieldRef))?.setExpandedKeys(menuSelect);
|
||
}
|
||
function incrementTree(addMenuSelect) {
|
||
btnFilterKeys.value = [];
|
||
colFilterKeys.value = [];
|
||
fieldFilterKeys.value = [];
|
||
|
||
// 使用 Set 合并已选中和新增选中的菜单,避免重复
|
||
const allMenuKeys = new Set([...menuKeys.value, ...addMenuSelect]);
|
||
|
||
// 确保未选中菜单的子节点不会丢失
|
||
findMenuTree(buttonSelectData.value, treeData.value, Array.from(allMenuKeys), 'button');
|
||
findMenuTree(columnSelectData.value, treeData.value, Array.from(allMenuKeys), 'column');
|
||
findMenuTree(fieldSelectData.value, treeData.value, Array.from(allMenuKeys), 'field');
|
||
|
||
// 更新按钮、字段、表单的选中状态
|
||
btnKeys.value = Array.from(new Set([...btnKeys.value, ...addMenuSelect]));
|
||
colKeys.value = Array.from(new Set([...colKeys.value, ...addMenuSelect]));
|
||
fieldKeys.value = Array.from(new Set([...fieldKeys.value, ...addMenuSelect]));
|
||
|
||
// 扩展树的展开状态
|
||
getTree(unref(ButtonRef))?.setExpandedKeys(Array.from(allMenuKeys));
|
||
getTree(unref(ColumnRef))?.setExpandedKeys(Array.from(allMenuKeys));
|
||
getTree(unref(FieldRef))?.setExpandedKeys(Array.from(allMenuKeys));
|
||
}
|
||
function getParentKeys(checkedKey, arr, keys) {
|
||
for (let i = 0; i < arr.length; i++) {
|
||
let o = arr[i];
|
||
if (o.id == keys) {
|
||
checkedKey.push(o.id);
|
||
if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
|
||
checkedKey.push(o.parentId);
|
||
}
|
||
}
|
||
if (o.children?.length > 0) {
|
||
getParentKeys(checkedKey, o.children, keys);
|
||
}
|
||
}
|
||
}
|
||
// keys获取对应的菜单 返回给chackedKey,如果该keys 不在原先过滤后的数组arr中的话,把keys 记录lostKey抛出给外面二次处理,减少全数据过滤的内存处理
|
||
function getParentKeysAndLost(checkedKey, arr, keys, lostKey) {
|
||
for (let i = 0; i < arr.length; i++) {
|
||
let o = arr[i];
|
||
if (o.id == keys) {
|
||
checkedKey.push(o.id);
|
||
if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
|
||
checkedKey.push(o.parentId);
|
||
}
|
||
}
|
||
if (o.children?.length > 0) {
|
||
getParentKeys(checkedKey, o.children, keys);
|
||
}
|
||
}
|
||
if (!checkedKey.includes(keys)) {
|
||
lostKey.push(keys);
|
||
}
|
||
}
|
||
function findMenuTree(menuSelectTree, treeData, keys, type) {
|
||
for (let i = 0; i < treeData.length; i++) {
|
||
let o = cloneDeep(treeData[i]);
|
||
if (keys.includes(o.id)) {
|
||
let hadData = false;
|
||
let index = 0;
|
||
for (let j = 0; j < menuSelectTree.length; j++) {
|
||
if (menuSelectTree[j].id == o.id) {
|
||
hadData = true;
|
||
index = j;
|
||
break;
|
||
}
|
||
}
|
||
if (!hadData) {
|
||
o.children = [];
|
||
menuSelectTree.push(o);
|
||
} else {
|
||
o = menuSelectTree[index];
|
||
}
|
||
if (treeData[i].children?.length > 0) {
|
||
findMenuTree(o.children, treeData[i].children, keys, type);
|
||
} else {
|
||
let list =
|
||
type == 'button'
|
||
? buttonData.value
|
||
: type == 'column'
|
||
? columnData.value
|
||
: fieldData.value;
|
||
o.children = getAuthData(list, o.id, type);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
function getFullMenu(menuKeys, treeData) {
|
||
for (let i = 0; i < treeData.length; i++) {
|
||
let o = cloneDeep(treeData[i]);
|
||
menuKeys.push(o.id);
|
||
if (treeData[i].children?.length > 0) {
|
||
getFullMenu(menuKeys, treeData[i].children)
|
||
}
|
||
}
|
||
}
|
||
function getAuthData(list, id, type) {
|
||
let arr: TreeItem[] = [];
|
||
|
||
arr = list.filter((o) => {
|
||
return o.menuId == id;
|
||
});
|
||
|
||
arr.forEach((o) => {
|
||
o.parentId = o.menuId;
|
||
if (type == 'button') {
|
||
btnFilterKeys.value.push(o.id);
|
||
} else if (type == 'column') {
|
||
colFilterKeys.value.push(o.id);
|
||
} else {
|
||
if (o.children && o.children.length > 0) {
|
||
o.children?.forEach((k) => {
|
||
fieldFilterKeys.value.push(k.id);
|
||
});
|
||
}
|
||
fieldFilterKeys.value.push(o.id);
|
||
}
|
||
});
|
||
return arr;
|
||
}
|
||
// function findMenuTree(menuTree, menuSelectTree, keys) {
|
||
// let selected: any = {};
|
||
// menuTree.forEach((key) => {
|
||
// //找到node对象
|
||
|
||
// if (keys.includes(key.id)) {
|
||
// console.log(key, 'kkkkkkkkkk');
|
||
|
||
// selected = cloneDeep(key);
|
||
// if (key.children?.length > 0) {
|
||
// selected.children = [];
|
||
// findMenuTree(key.children, selected.children, keys);
|
||
// }
|
||
// }
|
||
// });
|
||
// // let obj = menuSelectTree.find((o) => {
|
||
// // return o.id == selected.id;
|
||
// // });
|
||
// // if (!obj) {
|
||
// // menuSelectTree.push(selected);
|
||
// // } else {
|
||
// // obj.children = obj.children.concat(selected.children);
|
||
// // }
|
||
// checkChild(menuSelectTree, selected);
|
||
// }
|
||
// function checkChild(menuTree, selected) {
|
||
// menuTree.forEach((o) => {
|
||
// if (o.id == selected.parentId) {
|
||
// o.children = o.children.concat(selected.children);
|
||
// checkChild(o.children, selected);
|
||
// } else {
|
||
// menuTree.push(selected);
|
||
// }
|
||
// });
|
||
// }
|
||
//将按钮塞入到菜单树
|
||
// function menuInsertButton(menuTree, buttonList) {
|
||
// menuTree.forEach((menu) => {
|
||
// const thisMenuButton = buttonList.filter((btn) => btn.menuId === menu.id);
|
||
// if (menu.children && menu.children.length > 0) {
|
||
// menuInsertButton(menu.children, buttonList);
|
||
// }
|
||
|
||
// // console.log('thisMenuButton', thisMenuButton);
|
||
|
||
// menu.children = menu.children?.concat(thisMenuButton);
|
||
// });
|
||
// }
|
||
|
||
return {
|
||
registerRoleAuthModal,
|
||
handleSubmit,
|
||
handleTreeSelect,
|
||
handleButtonSelect,
|
||
handleColumnSelect,
|
||
handleFieldSelect,
|
||
menuKeys,
|
||
treeData,
|
||
treeRef,
|
||
ButtonRef,
|
||
FieldRef,
|
||
ColumnRef,
|
||
buttonSelectData,
|
||
columnSelectData,
|
||
fieldSelectData,
|
||
t,
|
||
typeKey,
|
||
spanLength,
|
||
modalLength,
|
||
};
|
||
},
|
||
});
|
||
</script>
|
||
<style lang="less">
|
||
.autherizeDialog {
|
||
.ant-modal {
|
||
top: 20px;
|
||
height: calc(100% - 40px) !important;
|
||
|
||
.ant-modal-content {
|
||
height: 100%;
|
||
|
||
.ant-modal-body {
|
||
height: calc(100% - 120px) !important;
|
||
|
||
.scrollbar__view {
|
||
height: 100%;
|
||
|
||
& > div {
|
||
height: 100%;
|
||
max-height: none !important;
|
||
|
||
.ant-col {
|
||
height: 100%;
|
||
|
||
.treebox {
|
||
height: calc(100% - 42px);
|
||
overflow: auto;
|
||
padding-right: 15px;
|
||
margin-bottom: 10px;
|
||
border-right: solid 1px #ccc;
|
||
|
||
.vben-tree {
|
||
height: auto;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|