mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-01-24 02:00:25 +08:00
fix(tree): fix tree style (#99)
This commit is contained in:
parent
73c8e0c158
commit
e8ccdc7f34
@ -19,6 +19,10 @@
|
|||||||
- 缓存可以配置是否加密,默认生产环境开启 Aes 加密
|
- 缓存可以配置是否加密,默认生产环境开启 Aes 加密
|
||||||
- 新增标签页拖拽排序
|
- 新增标签页拖拽排序
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- 修复 tree 文本超出挡住操作按钮问题
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 更新 antdv 到`2.0.0-rc.2`
|
- 更新 antdv 到`2.0.0-rc.2`
|
||||||
|
@ -8,7 +8,7 @@ import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted
|
|||||||
import Icon from '/@/components/Icon';
|
import Icon from '/@/components/Icon';
|
||||||
import { Menu, Divider } from 'ant-design-vue';
|
import { Menu, Divider } from 'ant-design-vue';
|
||||||
|
|
||||||
import { props } from './props';
|
import { contextMenuProps } from './props';
|
||||||
|
|
||||||
const prefixCls = 'context-menu';
|
const prefixCls = 'context-menu';
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ const ItemContent: FunctionalComponent<ItemContentProps> = (props) => {
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ContextMenu',
|
name: 'ContextMenu',
|
||||||
props,
|
props: contextMenuProps,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const wrapRef = ref<ElRef>(null);
|
const wrapRef = ref<ElRef>(null);
|
||||||
const showRef = ref(false);
|
const showRef = ref(false);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import type { Axis, ContextMenuItem } from './types';
|
import type { Axis, ContextMenuItem } from './types';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
export const props = {
|
export const contextMenuProps = {
|
||||||
width: propTypes.number.def(156),
|
width: propTypes.number.def(156),
|
||||||
customEvent: {
|
customEvent: {
|
||||||
type: Object as PropType<Event>,
|
type: Object as PropType<Event>,
|
||||||
|
@ -17,6 +17,7 @@ import {
|
|||||||
import { Menu } from 'ant-design-vue';
|
import { Menu } from 'ant-design-vue';
|
||||||
import SearchInput from './SearchInput.vue';
|
import SearchInput from './SearchInput.vue';
|
||||||
import MenuContent from './MenuContent';
|
import MenuContent from './MenuContent';
|
||||||
|
// import { ScrollContainer } from '/@/components/Container';
|
||||||
|
|
||||||
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
|
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
|
||||||
import { ThemeEnum } from '/@/enums/appEnum';
|
import { ThemeEnum } from '/@/enums/appEnum';
|
||||||
@ -272,7 +273,10 @@ export default defineComponent({
|
|||||||
onClick={handleInputClick}
|
onClick={handleInputClick}
|
||||||
collapsed={unref(getCollapsed)}
|
collapsed={unref(getCollapsed)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* <section style={unref(getMenuWrapStyle)}> */}
|
||||||
<section style={unref(getMenuWrapStyle)} class="basic-menu__content">
|
<section style={unref(getMenuWrapStyle)} class="basic-menu__content">
|
||||||
|
{/* <ScrollContainer>{() => renderMenu()}</ScrollContainer> */}
|
||||||
{renderMenu()}
|
{renderMenu()}
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { Menu as MenuType } from '/@/router/types';
|
import type { Menu as MenuType } from '/@/router/types';
|
||||||
import type { PropType } from 'vue';
|
import { computed, PropType, unref } from 'vue';
|
||||||
|
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Icon from '/@/components/Icon/index';
|
import Icon from '/@/components/Icon/index';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MenuContent',
|
name: 'MenuContent',
|
||||||
@ -32,6 +33,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const getI18nName = computed(() => {
|
||||||
|
const { name } = props.item;
|
||||||
|
|
||||||
|
return t(name);
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* @description: 渲染图标
|
* @description: 渲染图标
|
||||||
*/
|
*/
|
||||||
@ -61,7 +69,8 @@ export default defineComponent({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { showTitle } = props;
|
const { showTitle } = props;
|
||||||
const { name, icon } = props.item;
|
const { icon } = props.item;
|
||||||
|
const name = unref(getI18nName);
|
||||||
const searchValue = props.searchValue || '';
|
const searchValue = props.searchValue || '';
|
||||||
const index = name.indexOf(searchValue);
|
const index = name.indexOf(searchValue);
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@
|
|||||||
&__content {
|
&__content {
|
||||||
/* 滚动槽 */
|
/* 滚动槽 */
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 5px;
|
||||||
height: 4px;
|
height: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
&::-webkit-scrollbar-track {
|
||||||
|
@ -38,12 +38,12 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
-webkit-transition: opacity 120ms ease-out;
|
-webkit-transition: opacity 80ms ease;
|
||||||
transition: opacity 120ms ease-out;
|
transition: opacity 80ms ease;
|
||||||
|
|
||||||
&.is-vertical {
|
&.is-vertical {
|
||||||
top: 2px;
|
top: 2px;
|
||||||
width: 6px;
|
width: 5px;
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
&.is-horizontal {
|
&.is-horizontal {
|
||||||
left: 2px;
|
left: 2px;
|
||||||
height: 6px;
|
height: 5px;
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -65,5 +65,5 @@
|
|||||||
.scrollbar:focus > .scrollbar__bar,
|
.scrollbar:focus > .scrollbar__bar,
|
||||||
.scrollbar:hover > .scrollbar__bar {
|
.scrollbar:hover > .scrollbar__bar {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 280ms ease-out;
|
transition: opacity 180ms ease;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import type { ReplaceFields, TreeItem, Keys, CheckKeys, InsertNodeParams } from './types';
|
import './index.less';
|
||||||
|
|
||||||
import { defineComponent, reactive, computed, unref, ref, watchEffect } from 'vue';
|
import type { ReplaceFields, TreeItem, Keys, CheckKeys } from './types';
|
||||||
|
|
||||||
|
import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue';
|
||||||
import { Tree } from 'ant-design-vue';
|
import { Tree } from 'ant-design-vue';
|
||||||
import { DownOutlined } from '@ant-design/icons-vue';
|
import { DownOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
||||||
|
|
||||||
import { isFunction } from '/@/utils/is';
|
import { isFunction } from '/@/utils/is';
|
||||||
import { omit, cloneDeep } from 'lodash-es';
|
import { omit } from 'lodash-es';
|
||||||
import { forEach } from '/@/utils/helper/treeHelper';
|
|
||||||
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||||
import { tryTsxEmit } from '/@/utils/helper/vueHelper';
|
import { tryTsxEmit } from '/@/utils/helper/vueHelper';
|
||||||
|
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
|
import { useTree } from './useTree';
|
||||||
import './index.less';
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
expandedKeys: Keys;
|
expandedKeys: Keys;
|
||||||
@ -49,17 +49,55 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const getTreeData = computed(() => {
|
const getContentStyle = computed(
|
||||||
return unref(treeDataRef);
|
(): CSSProperties => {
|
||||||
|
const { actionList } = props;
|
||||||
|
const width = actionList.length * 18;
|
||||||
|
return {
|
||||||
|
width: `calc(100% - ${width}px)`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getBindValues = computed(() => {
|
||||||
|
let propsData = {
|
||||||
|
blockNode: true,
|
||||||
|
...attrs,
|
||||||
|
...props,
|
||||||
|
expandedKeys: state.expandedKeys,
|
||||||
|
selectedKeys: state.selectedKeys,
|
||||||
|
checkedKeys: state.checkedKeys,
|
||||||
|
replaceFields: unref(getReplaceFields),
|
||||||
|
'onUpdate:expandedKeys': (v: Keys) => {
|
||||||
|
state.expandedKeys = v;
|
||||||
|
emit('update:expandedKeys', v);
|
||||||
|
},
|
||||||
|
'onUpdate:selectedKeys': (v: Keys) => {
|
||||||
|
state.selectedKeys = v;
|
||||||
|
emit('update:selectedKeys', v);
|
||||||
|
},
|
||||||
|
onCheck: (v: CheckKeys) => {
|
||||||
|
state.checkedKeys = v;
|
||||||
|
emit('update:value', v);
|
||||||
|
},
|
||||||
|
onRightClick: handleRightClick,
|
||||||
|
};
|
||||||
|
propsData = omit(propsData, 'treeData');
|
||||||
|
return propsData;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
|
||||||
|
|
||||||
|
const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
|
||||||
|
treeDataRef,
|
||||||
|
getReplaceFields
|
||||||
|
);
|
||||||
|
|
||||||
// 渲染操作按钮
|
// 渲染操作按钮
|
||||||
function renderAction(node: TreeItem) {
|
function renderAction(node: TreeItem) {
|
||||||
const { actionList } = props;
|
const { actionList } = props;
|
||||||
|
|
||||||
if (!actionList || actionList.length === 0) {
|
if (!actionList || actionList.length === 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return actionList.map((item, index) => {
|
return actionList.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
@ -81,12 +119,15 @@ export default defineComponent({
|
|||||||
const propsData = omit(item, 'title');
|
const propsData = omit(item, 'title');
|
||||||
const anyItem = item as any;
|
const anyItem = item as any;
|
||||||
return (
|
return (
|
||||||
<Tree.TreeNode {...propsData} key={keyField && anyItem[keyField]}>
|
<Tree.TreeNode {...propsData} key={anyItem?.[keyField]}>
|
||||||
{{
|
{{
|
||||||
title: () => (
|
title: () => (
|
||||||
<span class={`${prefixCls}-title`}>
|
<span class={`${prefixCls}-title`}>
|
||||||
{titleField && anyItem[titleField]}
|
<span class={`${prefixCls}__content`} style={unref(getContentStyle)}>
|
||||||
{renderAction(item)}
|
{' '}
|
||||||
|
{titleField && anyItem[titleField]}
|
||||||
|
</span>
|
||||||
|
<span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
default: () => renderTreeNode({ data: childrenField ? anyItem[childrenField] : [] }),
|
default: () => renderTreeNode({ data: childrenField ? anyItem[childrenField] : [] }),
|
||||||
@ -135,86 +176,6 @@ export default defineComponent({
|
|||||||
return state.checkedKeys;
|
return state.checkedKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 展开指定级别
|
|
||||||
function filterByLevel(level = 1, list?: TreeItem[], currentLevel = 1) {
|
|
||||||
if (!level) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const res: (string | number)[] = [];
|
|
||||||
const data = list || props.treeData || [];
|
|
||||||
for (let index = 0; index < data.length; index++) {
|
|
||||||
const item = data[index] as any;
|
|
||||||
|
|
||||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
|
||||||
const key = keyField ? item[keyField] : '';
|
|
||||||
const children = childrenField ? item[childrenField] : [];
|
|
||||||
res.push(key);
|
|
||||||
if (children && children.length && currentLevel < level) {
|
|
||||||
currentLevel += 1;
|
|
||||||
res.push(...filterByLevel(level, children, currentLevel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res as string[] | number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加节点
|
|
||||||
*/
|
|
||||||
function insertNodeByKey({ parentKey = null, node, push = 'push' }: InsertNodeParams) {
|
|
||||||
const treeData: any = cloneDeep(unref(treeDataRef));
|
|
||||||
if (!parentKey) {
|
|
||||||
treeData[push](node);
|
|
||||||
treeDataRef.value = treeData;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
|
||||||
forEach(treeData, (treeItem) => {
|
|
||||||
if (treeItem[keyField] === parentKey) {
|
|
||||||
treeItem[childrenField] = treeItem[childrenField] || [];
|
|
||||||
treeItem[childrenField][push](node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
treeDataRef.value = treeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除节点
|
|
||||||
function deleteNodeByKey(key: string, list: TreeItem[]) {
|
|
||||||
if (!key) return;
|
|
||||||
const treeData = list || unref(treeDataRef);
|
|
||||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
|
||||||
|
|
||||||
for (let index = 0; index < treeData.length; index++) {
|
|
||||||
const element: any = treeData[index];
|
|
||||||
const children = element[childrenField];
|
|
||||||
|
|
||||||
if (element[keyField] === key) {
|
|
||||||
treeData.splice(index, 1);
|
|
||||||
break;
|
|
||||||
} else if (children && children.length) {
|
|
||||||
deleteNodeByKey(key, element[childrenField]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新节点
|
|
||||||
function updateNodeByKey(key: string, node: TreeItem, list: TreeItem[]) {
|
|
||||||
if (!key) return;
|
|
||||||
const treeData = list || unref(treeDataRef);
|
|
||||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
|
||||||
|
|
||||||
for (let index = 0; index < treeData.length; index++) {
|
|
||||||
const element: any = treeData[index];
|
|
||||||
const children = element[childrenField];
|
|
||||||
|
|
||||||
if (element[keyField] === key) {
|
|
||||||
treeData[index] = { ...treeData[index], ...node };
|
|
||||||
break;
|
|
||||||
} else if (children && children.length) {
|
|
||||||
updateNodeByKey(key, node, element[childrenField]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
treeDataRef.value = props.treeData as TreeItem[];
|
treeDataRef.value = props.treeData as TreeItem[];
|
||||||
state.expandedKeys = props.expandedKeys;
|
state.expandedKeys = props.expandedKeys;
|
||||||
@ -237,31 +198,8 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
let propsData: any = {
|
|
||||||
blockNode: true,
|
|
||||||
...attrs,
|
|
||||||
...props,
|
|
||||||
expandedKeys: state.expandedKeys,
|
|
||||||
selectedKeys: state.selectedKeys,
|
|
||||||
checkedKeys: state.checkedKeys,
|
|
||||||
replaceFields: unref(getReplaceFields),
|
|
||||||
'onUpdate:expandedKeys': (v: Keys) => {
|
|
||||||
state.expandedKeys = v;
|
|
||||||
emit('update:expandedKeys', v);
|
|
||||||
},
|
|
||||||
'onUpdate:selectedKeys': (v: Keys) => {
|
|
||||||
state.selectedKeys = v;
|
|
||||||
emit('update:selectedKeys', v);
|
|
||||||
},
|
|
||||||
onCheck: (v: CheckKeys) => {
|
|
||||||
state.checkedKeys = v;
|
|
||||||
emit('update:value', v);
|
|
||||||
},
|
|
||||||
onRightClick: handleRightClick,
|
|
||||||
};
|
|
||||||
propsData = omit(propsData, 'treeData');
|
|
||||||
return (
|
return (
|
||||||
<Tree {...propsData} class={prefixCls}>
|
<Tree {...unref(getBindValues)} class={prefixCls}>
|
||||||
{{
|
{{
|
||||||
switcherIcon: () => <DownOutlined />,
|
switcherIcon: () => <DownOutlined />,
|
||||||
default: () => renderTreeNode({ data: unref(getTreeData) }),
|
default: () => renderTreeNode({ data: unref(getTreeData) }),
|
||||||
|
@ -2,19 +2,34 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
|
||||||
.basic-tree__action {
|
|
||||||
display: none;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.basic-tree__action {
|
.basic-tree__action {
|
||||||
display: inline-block;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__action {
|
||||||
|
margin-left: 4px;
|
||||||
|
// float: right;
|
||||||
|
// display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
97
src/components/Tree/src/useTree.ts
Normal file
97
src/components/Tree/src/useTree.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import type { InsertNodeParams, ReplaceFields, TreeItem } from './types';
|
||||||
|
import type { Ref, ComputedRef } from 'vue';
|
||||||
|
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { unref } from 'vue';
|
||||||
|
import { forEach } from '/@/utils/helper/treeHelper';
|
||||||
|
|
||||||
|
export function useTree(
|
||||||
|
treeDataRef: Ref<TreeItem[]>,
|
||||||
|
getReplaceFields: ComputedRef<ReplaceFields>
|
||||||
|
) {
|
||||||
|
// 更新节点
|
||||||
|
function updateNodeByKey(key: string, node: TreeItem, list: TreeItem[]) {
|
||||||
|
if (!key) return;
|
||||||
|
const treeData = list || unref(treeDataRef);
|
||||||
|
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||||
|
|
||||||
|
if (!childrenField || !keyField) return;
|
||||||
|
|
||||||
|
for (let index = 0; index < treeData.length; index++) {
|
||||||
|
const element: any = treeData[index];
|
||||||
|
const children = element[childrenField];
|
||||||
|
|
||||||
|
if (element[keyField] === key) {
|
||||||
|
treeData[index] = { ...treeData[index], ...node };
|
||||||
|
break;
|
||||||
|
} else if (children && children.length) {
|
||||||
|
updateNodeByKey(key, node, element[childrenField]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 展开指定级别
|
||||||
|
function filterByLevel(level = 1, list?: TreeItem[], currentLevel = 1) {
|
||||||
|
if (!level) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const res: (string | number)[] = [];
|
||||||
|
const data = list || unref(treeDataRef) || [];
|
||||||
|
for (let index = 0; index < data.length; index++) {
|
||||||
|
const item = data[index] as any;
|
||||||
|
|
||||||
|
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||||
|
const key = keyField ? item[keyField] : '';
|
||||||
|
const children = childrenField ? item[childrenField] : [];
|
||||||
|
res.push(key);
|
||||||
|
if (children && children.length && currentLevel < level) {
|
||||||
|
currentLevel += 1;
|
||||||
|
res.push(...filterByLevel(level, children, currentLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res as string[] | number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加节点
|
||||||
|
*/
|
||||||
|
function insertNodeByKey({ parentKey = null, node, push = 'push' }: InsertNodeParams) {
|
||||||
|
const treeData: any = cloneDeep(unref(treeDataRef));
|
||||||
|
if (!parentKey) {
|
||||||
|
treeData[push](node);
|
||||||
|
treeDataRef.value = treeData;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||||
|
if (!childrenField || !keyField) return;
|
||||||
|
|
||||||
|
forEach(treeData, (treeItem) => {
|
||||||
|
if (treeItem[keyField] === parentKey) {
|
||||||
|
treeItem[childrenField] = treeItem[childrenField] || [];
|
||||||
|
treeItem[childrenField][push](node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
treeDataRef.value = treeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除节点
|
||||||
|
function deleteNodeByKey(key: string, list: TreeItem[]) {
|
||||||
|
if (!key) return;
|
||||||
|
const treeData = list || unref(treeDataRef);
|
||||||
|
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||||
|
if (!childrenField || !keyField) return;
|
||||||
|
|
||||||
|
for (let index = 0; index < treeData.length; index++) {
|
||||||
|
const element: any = treeData[index];
|
||||||
|
const children = element[childrenField];
|
||||||
|
|
||||||
|
if (element[keyField] === key) {
|
||||||
|
treeData.splice(index, 1);
|
||||||
|
break;
|
||||||
|
} else if (children && children.length) {
|
||||||
|
deleteNodeByKey(key, element[childrenField]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey };
|
||||||
|
}
|
@ -17,10 +17,10 @@ import {
|
|||||||
getShallowMenus,
|
getShallowMenus,
|
||||||
} from '/@/router/menus';
|
} from '/@/router/menus';
|
||||||
import { permissionStore } from '/@/store/modules/permission';
|
import { permissionStore } from '/@/store/modules/permission';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
// import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { cloneDeep } from 'lodash-es';
|
// import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
const { t } = useI18n();
|
// const { t } = useI18n();
|
||||||
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
||||||
// Menu array
|
// Menu array
|
||||||
const menusRef = ref<Menu[]>([]);
|
const menusRef = ref<Menu[]>([]);
|
||||||
@ -45,13 +45,13 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit);
|
return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit);
|
||||||
});
|
});
|
||||||
|
|
||||||
const getI18nFlatMenus = computed(() => {
|
// const getI18nFlatMenus = computed(() => {
|
||||||
return setI18nName(flatMenusRef.value, true, false);
|
// return setI18nName(flatMenusRef.value, true, false);
|
||||||
});
|
// });
|
||||||
|
|
||||||
const getI18nMenus = computed(() => {
|
// const getI18nMenus = computed(() => {
|
||||||
return setI18nName(menusRef.value, true, true);
|
// return setI18nName(menusRef.value, true, true);
|
||||||
});
|
// });
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
[() => unref(currentRoute).path, () => unref(splitType)],
|
[() => unref(currentRoute).path, () => unref(splitType)],
|
||||||
@ -83,17 +83,19 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
genMenus();
|
genMenus();
|
||||||
});
|
});
|
||||||
|
|
||||||
function setI18nName(list: Menu[], clone = false, deep = true) {
|
// function setI18nName(list: Menu[], clone = false, deep = true) {
|
||||||
const menus = clone ? cloneDeep(list) : list;
|
// const menus = clone ? cloneDeep(list) : list;
|
||||||
menus.forEach((item) => {
|
// const arr: Menu[] = [];
|
||||||
if (!item.name.includes('.')) return;
|
// menus.forEach((item) => {
|
||||||
item.name = t(item.name);
|
// if (!item.name.includes('.')) return;
|
||||||
if (item.children && deep) {
|
// item.name = t(item.name);
|
||||||
setI18nName(item.children, false, deep);
|
|
||||||
}
|
// if (item.children && deep) {
|
||||||
});
|
// setI18nName(item.children, false, deep);
|
||||||
return menus;
|
// }
|
||||||
}
|
// });
|
||||||
|
// return menus;
|
||||||
|
// }
|
||||||
|
|
||||||
// Handle left menu split
|
// Handle left menu split
|
||||||
async function handleSplitLeftMenu(parentPath: string) {
|
async function handleSplitLeftMenu(parentPath: string) {
|
||||||
@ -133,5 +135,5 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { flatMenusRef: getI18nFlatMenus, menusRef: getI18nMenus };
|
return { flatMenusRef, menusRef };
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { TreeItem } from '/@/components/Tree/index';
|
|||||||
|
|
||||||
export const treeData: TreeItem[] = [
|
export const treeData: TreeItem[] = [
|
||||||
{
|
{
|
||||||
title: 'parent 1',
|
title: 'parent 1parent ',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
icon: 'home|svg',
|
icon: 'home|svg',
|
||||||
children: [
|
children: [
|
||||||
|
Loading…
Reference in New Issue
Block a user