mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-01-23 20:00:19 +08:00
perf(tree): strengthen BasicTree function
This commit is contained in:
parent
9a1ba74920
commit
cd8e924d46
@ -11,8 +11,9 @@
|
|||||||
- 新增修改密码界面
|
- 新增修改密码界面
|
||||||
- 新增部门管理示例界面
|
- 新增部门管理示例界面
|
||||||
- 新增 WebSocket 示例和服务脚本
|
- 新增 WebSocket 示例和服务脚本
|
||||||
- BasicTree 组件新增 `renderIcon` 属性用于控制层级图标显示
|
- Tree 组件新增 `renderIcon` 属性用于控制层级图标显示
|
||||||
- BasicTree->actionItem 新增 show 属性,用于动态控制按钮显示
|
- Tree->actionItem 新增 show 属性,用于动态控制按钮显示
|
||||||
|
- Tree 新增工具栏/title/搜索功能
|
||||||
|
|
||||||
### ⚡ Performance Improvements
|
### ⚡ Performance Improvements
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/iconify": "^2.0.0-rc.6",
|
"@iconify/iconify": "^2.0.0-rc.6",
|
||||||
"@vueuse/core": "^4.3.1",
|
"@vueuse/core": "^4.3.1",
|
||||||
"@zxcvbn-ts/core": "^0.2.0",
|
"@zxcvbn-ts/core": "^0.3.0",
|
||||||
"ant-design-vue": "2.0.1",
|
"ant-design-vue": "2.0.1",
|
||||||
"apexcharts": "^3.25.0",
|
"apexcharts": "^3.25.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
import { Input } from 'ant-design-vue';
|
import { Input } from 'ant-design-vue';
|
||||||
|
|
||||||
import zxcvbn from '@zxcvbn-ts/core';
|
// @ts-ignore
|
||||||
|
import { zxcvbn } from '@zxcvbn-ts/core';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
|
||||||
|
110
src/components/Tree/src/TreeHeader.vue
Normal file
110
src/components/Tree/src/TreeHeader.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex px-2 py-1.5 items-center border-b-1">
|
||||||
|
<BasicTitle :helpMessage="helpMessage" v-if="title">{{ title }}</BasicTitle>
|
||||||
|
|
||||||
|
<div class="flex flex-1 justify-end items-center cursor-pointer" v-if="search || toolbar">
|
||||||
|
<div class="mr-1 w-2/3" v-if="search">
|
||||||
|
<InputSearch :placeholder="t('common.searchText')" size="small" @change="handleSearch" />
|
||||||
|
</div>
|
||||||
|
<Dropdown @click.prevent v-if="toolbar">
|
||||||
|
<Icon icon="ion:ellipsis-vertical" />
|
||||||
|
<template #overlay>
|
||||||
|
<Menu @click="handleMenuClick">
|
||||||
|
<MenuItem v-for="item in toolbarList" :key="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</template>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { defineComponent, ref } from 'vue';
|
||||||
|
|
||||||
|
import { Dropdown, Menu, Checkbox, Input } from 'ant-design-vue';
|
||||||
|
import { Icon } from '/@/components/Icon';
|
||||||
|
import { BasicTitle } from '/@/components/Basic';
|
||||||
|
|
||||||
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { useDebounce } from '/@/hooks/core/useDebounce';
|
||||||
|
|
||||||
|
import { ToolbarEnum } from './enum';
|
||||||
|
|
||||||
|
interface MenuInfo {
|
||||||
|
key: ToolbarEnum;
|
||||||
|
}
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BasicTreeHeader',
|
||||||
|
components: {
|
||||||
|
BasicTitle,
|
||||||
|
Icon,
|
||||||
|
Checkbox,
|
||||||
|
Dropdown,
|
||||||
|
Menu,
|
||||||
|
MenuItem: Menu.Item,
|
||||||
|
InputSearch: Input.Search,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
helpMessage: {
|
||||||
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
title: propTypes.string,
|
||||||
|
toolbar: propTypes.bool,
|
||||||
|
search: propTypes.bool,
|
||||||
|
checkAll: propTypes.func,
|
||||||
|
expandAll: propTypes.func,
|
||||||
|
},
|
||||||
|
emits: ['strictly-change', 'search'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const { t } = useI18n();
|
||||||
|
const toolbarList = ref([
|
||||||
|
{ label: t('component.tree.selectAll'), value: ToolbarEnum.SELECT_ALL },
|
||||||
|
{ label: t('component.tree.unSelectAll'), value: ToolbarEnum.UN_SELECT_ALL },
|
||||||
|
{ label: t('component.tree.expandAll'), value: ToolbarEnum.EXPAND_ALL },
|
||||||
|
{ label: t('component.tree.unExpandAll'), value: ToolbarEnum.UN_EXPAND_ALL },
|
||||||
|
{ label: t('component.tree.checkStrictly'), value: ToolbarEnum.CHECK_STRICTLY },
|
||||||
|
{ label: t('component.tree.checkUnStrictly'), value: ToolbarEnum.CHECK_UN_STRICTLY },
|
||||||
|
]);
|
||||||
|
|
||||||
|
function handleMenuClick(e: MenuInfo) {
|
||||||
|
const { key } = e;
|
||||||
|
switch (key) {
|
||||||
|
case ToolbarEnum.SELECT_ALL:
|
||||||
|
props.checkAll?.(true);
|
||||||
|
break;
|
||||||
|
case ToolbarEnum.UN_SELECT_ALL:
|
||||||
|
props.checkAll?.(false);
|
||||||
|
break;
|
||||||
|
case ToolbarEnum.EXPAND_ALL:
|
||||||
|
props.expandAll?.(true);
|
||||||
|
break;
|
||||||
|
case ToolbarEnum.UN_EXPAND_ALL:
|
||||||
|
props.expandAll?.(false);
|
||||||
|
break;
|
||||||
|
case ToolbarEnum.CHECK_STRICTLY:
|
||||||
|
emit('strictly-change', false);
|
||||||
|
break;
|
||||||
|
case ToolbarEnum.CHECK_UN_STRICTLY:
|
||||||
|
emit('strictly-change', true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitChange(value?: string): void {
|
||||||
|
emit('search', value);
|
||||||
|
}
|
||||||
|
const [debounceEmitChange] = useDebounce(emitChange, 200);
|
||||||
|
|
||||||
|
function handleSearch(e: ChangeEvent): void {
|
||||||
|
debounceEmitChange(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { t, toolbarList, handleMenuClick, handleSearch };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
8
src/components/Tree/src/enum.ts
Normal file
8
src/components/Tree/src/enum.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export enum ToolbarEnum {
|
||||||
|
SELECT_ALL,
|
||||||
|
UN_SELECT_ALL,
|
||||||
|
EXPAND_ALL,
|
||||||
|
UN_EXPAND_ALL,
|
||||||
|
CHECK_STRICTLY,
|
||||||
|
CHECK_UN_STRICTLY,
|
||||||
|
}
|
@ -1,23 +1,16 @@
|
|||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
|
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
|
||||||
|
|
||||||
import {
|
import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw } from 'vue';
|
||||||
defineComponent,
|
|
||||||
reactive,
|
|
||||||
computed,
|
|
||||||
unref,
|
|
||||||
ref,
|
|
||||||
watchEffect,
|
|
||||||
onMounted,
|
|
||||||
toRaw,
|
|
||||||
} from 'vue';
|
|
||||||
import { Tree } from 'ant-design-vue';
|
import { Tree } from 'ant-design-vue';
|
||||||
import { TreeIcon } from './TreeIcon';
|
import { TreeIcon } from './TreeIcon';
|
||||||
|
import TreeHeader from './TreeHeader.vue';
|
||||||
// import { DownOutlined } from '@ant-design/icons-vue';
|
// import { DownOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { omit, get } from 'lodash-es';
|
import { omit, get } from 'lodash-es';
|
||||||
import { isBoolean, isFunction } from '/@/utils/is';
|
import { isBoolean, isFunction } from '/@/utils/is';
|
||||||
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||||
|
import { filter } from '/@/utils/helper/treeHelper';
|
||||||
|
|
||||||
import { useTree } from './useTree';
|
import { useTree } from './useTree';
|
||||||
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
||||||
@ -30,18 +23,25 @@
|
|||||||
expandedKeys: Keys;
|
expandedKeys: Keys;
|
||||||
selectedKeys: Keys;
|
selectedKeys: Keys;
|
||||||
checkedKeys: CheckKeys;
|
checkedKeys: CheckKeys;
|
||||||
|
checkStrictly: boolean;
|
||||||
}
|
}
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicTree',
|
name: 'BasicTree',
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
|
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change'],
|
||||||
setup(props, { attrs, slots, emit }) {
|
setup(props, { attrs, slots, emit }) {
|
||||||
const state = reactive<State>({
|
const state = reactive<State>({
|
||||||
|
checkStrictly: props.checkStrictly,
|
||||||
expandedKeys: props.expandedKeys || [],
|
expandedKeys: props.expandedKeys || [],
|
||||||
selectedKeys: props.selectedKeys || [],
|
selectedKeys: props.selectedKeys || [],
|
||||||
checkedKeys: props.checkedKeys || [],
|
checkedKeys: props.checkedKeys || [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const searchState = reactive({
|
||||||
|
startSearch: false,
|
||||||
|
searchData: [] as TreeItem[],
|
||||||
|
});
|
||||||
|
|
||||||
const treeDataRef = ref<TreeItem[]>([]);
|
const treeDataRef = ref<TreeItem[]>([]);
|
||||||
|
|
||||||
const [createContextMenu] = useContextMenu();
|
const [createContextMenu] = useContextMenu();
|
||||||
@ -77,6 +77,7 @@
|
|||||||
expandedKeys: state.expandedKeys,
|
expandedKeys: state.expandedKeys,
|
||||||
selectedKeys: state.selectedKeys,
|
selectedKeys: state.selectedKeys,
|
||||||
checkedKeys: state.checkedKeys,
|
checkedKeys: state.checkedKeys,
|
||||||
|
checkStrictly: state.checkStrictly,
|
||||||
replaceFields: unref(getReplaceFields),
|
replaceFields: unref(getReplaceFields),
|
||||||
'onUpdate:expandedKeys': (v: Keys) => {
|
'onUpdate:expandedKeys': (v: Keys) => {
|
||||||
state.expandedKeys = v;
|
state.expandedKeys = v;
|
||||||
@ -88,21 +89,27 @@
|
|||||||
},
|
},
|
||||||
onCheck: (v: CheckKeys) => {
|
onCheck: (v: CheckKeys) => {
|
||||||
state.checkedKeys = v;
|
state.checkedKeys = v;
|
||||||
|
emit('change', v);
|
||||||
emit('update:value', v);
|
emit('update:value', v);
|
||||||
},
|
},
|
||||||
onRightClick: handleRightClick,
|
onRightClick: handleRightClick,
|
||||||
};
|
};
|
||||||
propsData = omit(propsData, 'treeData');
|
propsData = omit(propsData, 'treeData', 'class');
|
||||||
return propsData;
|
return propsData;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
|
const getTreeData = computed((): TreeItem[] =>
|
||||||
|
searchState.startSearch ? searchState.searchData : unref(treeDataRef)
|
||||||
const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
|
|
||||||
treeDataRef,
|
|
||||||
getReplaceFields
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
deleteNodeByKey,
|
||||||
|
insertNodeByKey,
|
||||||
|
filterByLevel,
|
||||||
|
updateNodeByKey,
|
||||||
|
getAllKeys,
|
||||||
|
} = useTree(treeDataRef, getReplaceFields);
|
||||||
|
|
||||||
function getIcon(params: Recordable, icon?: string) {
|
function getIcon(params: Recordable, icon?: string) {
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
if (props.renderIcon && isFunction(props.renderIcon)) {
|
if (props.renderIcon && isFunction(props.renderIcon)) {
|
||||||
@ -112,60 +119,6 @@
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAction(node: TreeItem) {
|
|
||||||
const { actionList } = props;
|
|
||||||
if (!actionList || actionList.length === 0) return;
|
|
||||||
return actionList.map((item, index) => {
|
|
||||||
if (isFunction(item.show)) {
|
|
||||||
return item.show?.(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBoolean(item.show)) {
|
|
||||||
return item.show;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span key={index} class={`${prefixCls}__action`}>
|
|
||||||
{item.render(node)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
|
|
||||||
if (!data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return data.map((item) => {
|
|
||||||
const { title: titleField, key: keyField, children: childrenField } = unref(
|
|
||||||
getReplaceFields
|
|
||||||
);
|
|
||||||
|
|
||||||
const propsData = omit(item, 'title');
|
|
||||||
const icon = getIcon({ ...item, level }, item.icon);
|
|
||||||
return (
|
|
||||||
<Tree.TreeNode {...propsData} node={toRaw(item)} key={get(item, keyField)}>
|
|
||||||
{{
|
|
||||||
title: () => (
|
|
||||||
<span class={`${prefixCls}-title`}>
|
|
||||||
{icon && <TreeIcon icon={icon} />}
|
|
||||||
<span
|
|
||||||
class={`${prefixCls}__content`}
|
|
||||||
// style={unref(getContentStyle)}
|
|
||||||
>
|
|
||||||
{get(item, titleField)}
|
|
||||||
</span>
|
|
||||||
<span class={`${prefixCls}__actions`}> {renderAction({ ...item, level })}</span>
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
default: () =>
|
|
||||||
renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
|
|
||||||
}}
|
|
||||||
</Tree.TreeNode>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleRightClick({ event, node }: any) {
|
async function handleRightClick({ event, node }: any) {
|
||||||
const { rightMenuList: menuList = [], beforeRightClick } = props;
|
const { rightMenuList: menuList = [], beforeRightClick } = props;
|
||||||
let rightMenuList: ContextMenuItem[] = [];
|
let rightMenuList: ContextMenuItem[] = [];
|
||||||
@ -205,6 +158,32 @@
|
|||||||
return state.checkedKeys;
|
return state.checkedKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkAll(checkAll: boolean) {
|
||||||
|
state.checkedKeys = checkAll ? getAllKeys() : ([] as Keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandAll(expandAll: boolean) {
|
||||||
|
state.expandedKeys = expandAll ? getAllKeys() : ([] as Keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStrictlyChange(strictly: boolean) {
|
||||||
|
state.checkStrictly = strictly;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSearch(searchValue: string) {
|
||||||
|
if (!searchValue) {
|
||||||
|
searchState.startSearch = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
searchState.startSearch = true;
|
||||||
|
|
||||||
|
searchState.searchData = filter(unref(treeDataRef), (node) => {
|
||||||
|
const { title } = node;
|
||||||
|
return title?.includes(searchValue) ?? false;
|
||||||
|
// || key?.includes(searchValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
treeDataRef.value = props.treeData as TreeItem[];
|
treeDataRef.value = props.treeData as TreeItem[];
|
||||||
state.expandedKeys = props.expandedKeys;
|
state.expandedKeys = props.expandedKeys;
|
||||||
@ -212,6 +191,16 @@
|
|||||||
state.checkedKeys = props.checkedKeys;
|
state.checkedKeys = props.checkedKeys;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (props.value) {
|
||||||
|
state.checkedKeys = props.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
state.checkStrictly = props.checkStrictly;
|
||||||
|
});
|
||||||
|
|
||||||
const instance: TreeActionType = {
|
const instance: TreeActionType = {
|
||||||
setExpandedKeys,
|
setExpandedKeys,
|
||||||
getExpandedKeys,
|
getExpandedKeys,
|
||||||
@ -222,6 +211,8 @@
|
|||||||
insertNodeByKey,
|
insertNodeByKey,
|
||||||
deleteNodeByKey,
|
deleteNodeByKey,
|
||||||
updateNodeByKey,
|
updateNodeByKey,
|
||||||
|
checkAll,
|
||||||
|
expandAll,
|
||||||
filterByLevel: (level: number) => {
|
filterByLevel: (level: number) => {
|
||||||
state.expandedKeys = filterByLevel(level);
|
state.expandedKeys = filterByLevel(level);
|
||||||
},
|
},
|
||||||
@ -229,19 +220,83 @@
|
|||||||
|
|
||||||
useExpose<TreeActionType>(instance);
|
useExpose<TreeActionType>(instance);
|
||||||
|
|
||||||
onMounted(() => {
|
function renderAction(node: TreeItem) {
|
||||||
emit('get', instance);
|
const { actionList } = props;
|
||||||
});
|
if (!actionList || actionList.length === 0) return;
|
||||||
|
return actionList.map((item, index) => {
|
||||||
|
if (isFunction(item.show)) {
|
||||||
|
return item.show?.(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBoolean(item.show)) {
|
||||||
|
return item.show;
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
return (
|
||||||
<Tree {...unref(getBindValues)} showIcon={false} class={[prefixCls]}>
|
<span key={index} class={`${prefixCls}__action`}>
|
||||||
|
{item.render(node)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.map((item) => {
|
||||||
|
const { title: titleField, key: keyField, children: childrenField } = unref(
|
||||||
|
getReplaceFields
|
||||||
|
);
|
||||||
|
|
||||||
|
const propsData = omit(item, 'title');
|
||||||
|
const icon = getIcon({ ...item, level }, item.icon);
|
||||||
|
return (
|
||||||
|
<Tree.TreeNode {...propsData} node={toRaw(item)} key={get(item, keyField)}>
|
||||||
|
{{
|
||||||
|
title: () => (
|
||||||
|
<span class={`${prefixCls}-title pl-2`}>
|
||||||
|
{icon && <TreeIcon icon={icon} />}
|
||||||
|
<span
|
||||||
|
class={`${prefixCls}__content`}
|
||||||
|
// style={unref(getContentStyle)}
|
||||||
|
>
|
||||||
|
{get(item, titleField)}
|
||||||
|
</span>
|
||||||
|
<span class={`${prefixCls}__actions`}> {renderAction({ ...item, level })}</span>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
default: () =>
|
||||||
|
renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
|
||||||
|
}}
|
||||||
|
</Tree.TreeNode>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
const { title, helpMessage, toolbar, search } = props;
|
||||||
|
return (
|
||||||
|
<div class={[prefixCls, 'h-full bg-white']}>
|
||||||
|
{(title || toolbar || search) && (
|
||||||
|
<TreeHeader
|
||||||
|
checkAll={checkAll}
|
||||||
|
expandAll={expandAll}
|
||||||
|
title={title}
|
||||||
|
search={search}
|
||||||
|
toolbar={toolbar}
|
||||||
|
helpMessage={helpMessage}
|
||||||
|
onStrictlyChange={onStrictlyChange}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Tree {...unref(getBindValues)} showIcon={false}>
|
||||||
{{
|
{{
|
||||||
// switcherIcon: () => <DownOutlined />,
|
// switcherIcon: () => <DownOutlined />,
|
||||||
default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
|
default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
|
||||||
...extendSlots(slots),
|
...extendSlots(slots),
|
||||||
}}
|
}}
|
||||||
</Tree>
|
</Tree>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -251,8 +306,6 @@
|
|||||||
@prefix-cls: ~'@{namespace}-basic-tree';
|
@prefix-cls: ~'@{namespace}-basic-tree';
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.ant-tree-node-content-wrapper {
|
.ant-tree-node-content-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@ -278,14 +331,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
display: inline-block;
|
// display: inline-block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__actions {
|
&__actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
right: 2px;
|
right: 3px;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,26 @@ import type { PropType } from 'vue';
|
|||||||
import type { ReplaceFields, ActionItem, Keys, CheckKeys } from './types';
|
import type { ReplaceFields, ActionItem, Keys, CheckKeys } from './types';
|
||||||
import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
|
||||||
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
|
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
|
||||||
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
|
||||||
export const basicProps = {
|
export const basicProps = {
|
||||||
|
value: {
|
||||||
|
type: Array as PropType<Keys>,
|
||||||
|
},
|
||||||
renderIcon: {
|
renderIcon: {
|
||||||
type: Function as PropType<(params: Recordable) => string>,
|
type: Function as PropType<(params: Recordable) => string>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
helpMessage: {
|
||||||
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
title: propTypes.string,
|
||||||
|
toolbar: propTypes.bool,
|
||||||
|
search: propTypes.bool,
|
||||||
|
checkStrictly: propTypes.bool,
|
||||||
|
|
||||||
replaceFields: {
|
replaceFields: {
|
||||||
type: Object as PropType<ReplaceFields>,
|
type: Object as PropType<ReplaceFields>,
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,8 @@ export type CheckKeys =
|
|||||||
| { checked: string[] | number[]; halfChecked: string[] | number[] };
|
| { checked: string[] | number[]; halfChecked: string[] | number[] };
|
||||||
|
|
||||||
export interface TreeActionType {
|
export interface TreeActionType {
|
||||||
|
checkAll: (checkAll: boolean) => void;
|
||||||
|
expandAll: (expandAll: boolean) => void;
|
||||||
setExpandedKeys: (keys: Keys) => void;
|
setExpandedKeys: (keys: Keys) => void;
|
||||||
getExpandedKeys: () => Keys;
|
getExpandedKeys: () => Keys;
|
||||||
setSelectedKeys: (keys: Keys) => void;
|
setSelectedKeys: (keys: Keys) => void;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { InsertNodeParams, ReplaceFields } from './types';
|
import type { InsertNodeParams, Keys, ReplaceFields } from './types';
|
||||||
import type { Ref, ComputedRef } from 'vue';
|
import type { Ref, ComputedRef } from 'vue';
|
||||||
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
|
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
|
||||||
|
|
||||||
@ -10,6 +10,23 @@ export function useTree(
|
|||||||
treeDataRef: Ref<TreeDataItem[]>,
|
treeDataRef: Ref<TreeDataItem[]>,
|
||||||
getReplaceFields: ComputedRef<ReplaceFields>
|
getReplaceFields: ComputedRef<ReplaceFields>
|
||||||
) {
|
) {
|
||||||
|
function getAllKeys(list?: TreeDataItem[]) {
|
||||||
|
const keys: string[] = [];
|
||||||
|
const treeData = list || unref(treeDataRef);
|
||||||
|
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||||
|
if (!childrenField || !keyField) return keys;
|
||||||
|
|
||||||
|
for (let index = 0; index < treeData.length; index++) {
|
||||||
|
const node = treeData[index];
|
||||||
|
keys.push(node[keyField]!);
|
||||||
|
const children = node[childrenField];
|
||||||
|
if (children && children.length) {
|
||||||
|
keys.push(...(getAllKeys(children) as string[]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys as Keys;
|
||||||
|
}
|
||||||
|
|
||||||
// Update node
|
// Update node
|
||||||
function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) {
|
function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) {
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
@ -94,5 +111,5 @@ export function useTree(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey };
|
return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey, getAllKeys };
|
||||||
}
|
}
|
||||||
|
9
src/locales/lang/en/component/tree.ts
Normal file
9
src/locales/lang/en/component/tree.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
selectAll: 'Select All',
|
||||||
|
unSelectAll: 'Cancel Select',
|
||||||
|
expandAll: 'Expand All',
|
||||||
|
unExpandAll: 'Collapse all',
|
||||||
|
|
||||||
|
checkStrictly: 'Hierarchical association',
|
||||||
|
checkUnStrictly: 'Hierarchical independence',
|
||||||
|
};
|
@ -12,7 +12,7 @@ export default {
|
|||||||
tree: 'Tree',
|
tree: 'Tree',
|
||||||
|
|
||||||
treeBasic: 'Basic',
|
treeBasic: 'Basic',
|
||||||
editTree: 'Right-click',
|
editTree: 'Searchable/toolbar',
|
||||||
actionTree: 'Function operation',
|
actionTree: 'Function operation',
|
||||||
|
|
||||||
modal: 'Modal',
|
modal: 'Modal',
|
||||||
|
8
src/locales/lang/zh_CN/component/tree.ts
Normal file
8
src/locales/lang/zh_CN/component/tree.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
selectAll: '选择全部',
|
||||||
|
unSelectAll: '取消选择',
|
||||||
|
expandAll: '展开全部',
|
||||||
|
unExpandAll: '折叠全部',
|
||||||
|
checkStrictly: '层级关联',
|
||||||
|
checkUnStrictly: '层级独立',
|
||||||
|
};
|
@ -11,7 +11,7 @@ export default {
|
|||||||
|
|
||||||
tree: 'Tree',
|
tree: 'Tree',
|
||||||
treeBasic: '基础树',
|
treeBasic: '基础树',
|
||||||
editTree: '右键示例',
|
editTree: '可搜索/工具栏',
|
||||||
actionTree: '函数操作示例',
|
actionTree: '函数操作示例',
|
||||||
|
|
||||||
modal: '弹窗扩展',
|
modal: '弹窗扩展',
|
||||||
|
@ -6,7 +6,10 @@ const menu: MenuModule = {
|
|||||||
menu: {
|
menu: {
|
||||||
name: t('routes.demo.comp.comp'),
|
name: t('routes.demo.comp.comp'),
|
||||||
path: '/comp',
|
path: '/comp',
|
||||||
|
tag: {
|
||||||
|
dot: true,
|
||||||
|
type: 'warn',
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'basic',
|
path: 'basic',
|
||||||
@ -154,6 +157,10 @@ const menu: MenuModule = {
|
|||||||
{
|
{
|
||||||
path: 'tree',
|
path: 'tree',
|
||||||
name: t('routes.demo.comp.tree'),
|
name: t('routes.demo.comp.tree'),
|
||||||
|
tag: {
|
||||||
|
dot: true,
|
||||||
|
type: 'warn',
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'basic',
|
path: 'basic',
|
||||||
@ -162,6 +169,10 @@ const menu: MenuModule = {
|
|||||||
{
|
{
|
||||||
path: 'editTree',
|
path: 'editTree',
|
||||||
name: t('routes.demo.comp.editTree'),
|
name: t('routes.demo.comp.editTree'),
|
||||||
|
tag: {
|
||||||
|
dot: true,
|
||||||
|
type: 'warn',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'actionTree',
|
path: 'actionTree',
|
||||||
@ -172,9 +183,6 @@ const menu: MenuModule = {
|
|||||||
{
|
{
|
||||||
name: t('routes.demo.editor.editor'),
|
name: t('routes.demo.editor.editor'),
|
||||||
path: 'editor',
|
path: 'editor',
|
||||||
tag: {
|
|
||||||
content: 'new',
|
|
||||||
},
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'markdown',
|
path: 'markdown',
|
||||||
|
@ -22,21 +22,21 @@ const menu: MenuModule = {
|
|||||||
path: 'role',
|
path: 'role',
|
||||||
name: t('routes.demo.system.role'),
|
name: t('routes.demo.system.role'),
|
||||||
tag: {
|
tag: {
|
||||||
content: 'new',
|
dot: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'menu',
|
path: 'menu',
|
||||||
name: t('routes.demo.system.menu'),
|
name: t('routes.demo.system.menu'),
|
||||||
tag: {
|
tag: {
|
||||||
content: 'new',
|
dot: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'dept',
|
path: 'dept',
|
||||||
name: t('routes.demo.system.dept'),
|
name: t('routes.demo.system.dept'),
|
||||||
tag: {
|
tag: {
|
||||||
content: 'new',
|
dot: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ const menu: MenuModule = {
|
|||||||
path: 'changePassword',
|
path: 'changePassword',
|
||||||
name: t('routes.demo.system.password'),
|
name: t('routes.demo.system.password'),
|
||||||
tag: {
|
tag: {
|
||||||
content: 'new',
|
dot: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -18,7 +18,7 @@ import { transformObjToRoute } from '/@/router/helper/routeHelper';
|
|||||||
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
|
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
|
||||||
|
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
// import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
|
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
|
||||||
|
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
@ -84,7 +84,7 @@ class Permission extends VuexModule {
|
|||||||
|
|
||||||
@Action
|
@Action
|
||||||
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
|
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
|
||||||
const { t } = useI18n();
|
// const { t } = useI18n();
|
||||||
let routes: AppRouteRecordRaw[] = [];
|
let routes: AppRouteRecordRaw[] = [];
|
||||||
const roleList = toRaw(userStore.getRoleListState);
|
const roleList = toRaw(userStore.getRoleListState);
|
||||||
|
|
||||||
@ -101,7 +101,8 @@ class Permission extends VuexModule {
|
|||||||
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
|
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
|
||||||
} else if (permissionMode === PermissionModeEnum.BACK) {
|
} else if (permissionMode === PermissionModeEnum.BACK) {
|
||||||
createMessage.loading({
|
createMessage.loading({
|
||||||
content: t('sys.app.menuLoading'),
|
content: 'Loading menu...',
|
||||||
|
// content: 't('sys.app.menuLoading')',
|
||||||
duration: 1,
|
duration: 1,
|
||||||
});
|
});
|
||||||
// Here to get the background routing menu logic to modify by yourself
|
// Here to get the background routing menu logic to modify by yourself
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageWrapper title="Tree函数操作示例" contentBackground contentClass="p-4">
|
<PageWrapper title="Tree函数操作示例" contentBackground contentClass="p-4">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
|
<a-button @click="expandAll(true)" class="mr-2"> 展开全部 </a-button>
|
||||||
|
<a-button @click="expandAll(false)" class="mr-2"> 折叠全部 </a-button>
|
||||||
|
<a-button @click="checkAll(true)" class="mr-2"> 全选 </a-button>
|
||||||
|
<a-button @click="checkAll(false)" class="mr-2"> 全不选 </a-button>
|
||||||
<a-button @click="handleLevel(2)" class="mr-2"> 显示到第2级 </a-button>
|
<a-button @click="handleLevel(2)" class="mr-2"> 显示到第2级 </a-button>
|
||||||
<a-button @click="handleLevel(1)" class="mr-2"> 显示到第1级 </a-button>
|
<a-button @click="handleLevel(1)" class="mr-2"> 显示到第1级 </a-button>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
<a-button @click="handleSetCheckData" class="mr-2"> 设置勾选数据 </a-button>
|
<a-button @click="handleSetCheckData" class="mr-2"> 设置勾选数据 </a-button>
|
||||||
<a-button @click="handleGetCheckData" class="mr-2"> 获取勾选数据 </a-button>
|
<a-button @click="handleGetCheckData" class="mr-2"> 获取勾选数据 </a-button>
|
||||||
<a-button @click="handleSetSelectData" class="mr-2"> 设置选中数据 </a-button>
|
<a-button @click="handleSetSelectData" class="mr-2"> 设置选中数据 </a-button>
|
||||||
@ -17,21 +23,18 @@
|
|||||||
<a-button @click="deleteNodeByKey('2-2')" class="mr-2"> 删除parent3节点 </a-button>
|
<a-button @click="deleteNodeByKey('2-2')" class="mr-2"> 删除parent3节点 </a-button>
|
||||||
<a-button @click="updateNodeByKey('1-1')" class="mr-2"> 更新parent2节点 </a-button>
|
<a-button @click="updateNodeByKey('1-1')" class="mr-2"> 更新parent2节点 </a-button>
|
||||||
</div>
|
</div>
|
||||||
<CollapseContainer title="函数操作" class="mr-4" :canExpan="false" :style="{ width: '33%' }">
|
<BasicTree :treeData="treeData" title="函数操作" ref="treeRef" :checkable="true" />
|
||||||
<BasicTree :treeData="treeData" ref="treeRef" :checkable="true" />
|
|
||||||
</CollapseContainer>
|
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, unref } from 'vue';
|
import { defineComponent, ref, unref } from 'vue';
|
||||||
import { BasicTree, TreeActionType } from '/@/components/Tree/index';
|
import { BasicTree, TreeActionType } from '/@/components/Tree/index';
|
||||||
import { treeData } from './data';
|
import { treeData } from './data';
|
||||||
import { CollapseContainer } from '/@/components/Container/index';
|
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import { PageWrapper } from '/@/components/Page';
|
import { PageWrapper } from '/@/components/Page';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicTree, CollapseContainer, PageWrapper },
|
components: { BasicTree, PageWrapper },
|
||||||
setup() {
|
setup() {
|
||||||
const treeRef = ref<Nullable<TreeActionType>>(null);
|
const treeRef = ref<Nullable<TreeActionType>>(null);
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
@ -75,6 +78,14 @@
|
|||||||
createMessage.success(JSON.stringify(keys));
|
createMessage.success(JSON.stringify(keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkAll(checkAll: boolean) {
|
||||||
|
getTree().checkAll(checkAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandAll(checkAll: boolean) {
|
||||||
|
getTree().expandAll(checkAll);
|
||||||
|
}
|
||||||
|
|
||||||
function appendNodeByKey(parentKey: string | null = null) {
|
function appendNodeByKey(parentKey: string | null = null) {
|
||||||
getTree().insertNodeByKey({
|
getTree().insertNodeByKey({
|
||||||
parentKey: parentKey,
|
parentKey: parentKey,
|
||||||
@ -112,6 +123,8 @@
|
|||||||
appendNodeByKey,
|
appendNodeByKey,
|
||||||
deleteNodeByKey,
|
deleteNodeByKey,
|
||||||
updateNodeByKey,
|
updateNodeByKey,
|
||||||
|
checkAll,
|
||||||
|
expandAll,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageWrapper title="Tree函数操作示例">
|
<PageWrapper title="Tree函数操作示例">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<CollapseContainer title="右侧操作按钮/自定义图标" class="mr-4" :style="{ width: '33%' }">
|
<BasicTree
|
||||||
<BasicTree :treeData="treeData" :actionList="actionList" :renderIcon="createIcon" />
|
class="w-1/3"
|
||||||
</CollapseContainer>
|
title="右侧操作按钮/自定义图标"
|
||||||
|
helpMessage="帮助信息"
|
||||||
<CollapseContainer title="右键菜单" class="mr-4" :style="{ width: '33%' }">
|
:treeData="treeData"
|
||||||
<BasicTree :treeData="treeData" :beforeRightClick="getRightMenuList" />
|
:actionList="actionList"
|
||||||
</CollapseContainer>
|
:renderIcon="createIcon"
|
||||||
|
/>
|
||||||
|
<BasicTree
|
||||||
|
class="w-1/3 mx-4"
|
||||||
|
title="右键菜单"
|
||||||
|
:treeData="treeData"
|
||||||
|
:beforeRightClick="getRightMenuList"
|
||||||
|
/>
|
||||||
|
<BasicTree
|
||||||
|
class="w-1/3"
|
||||||
|
title="工具栏使用"
|
||||||
|
toolbar
|
||||||
|
checkable
|
||||||
|
search
|
||||||
|
:treeData="treeData"
|
||||||
|
:beforeRightClick="getRightMenuList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
</template>
|
</template>
|
||||||
@ -15,12 +31,11 @@
|
|||||||
import { defineComponent, h } from 'vue';
|
import { defineComponent, h } from 'vue';
|
||||||
import { BasicTree, ActionItem, ContextMenuItem } from '/@/components/Tree/index';
|
import { BasicTree, ActionItem, ContextMenuItem } from '/@/components/Tree/index';
|
||||||
import { treeData } from './data';
|
import { treeData } from './data';
|
||||||
import { CollapseContainer } from '/@/components/Container/index';
|
|
||||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
||||||
import { PageWrapper } from '/@/components/Page';
|
import { PageWrapper } from '/@/components/Page';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicTree, CollapseContainer, PageWrapper },
|
components: { BasicTree, PageWrapper },
|
||||||
setup() {
|
setup() {
|
||||||
function handlePlus(node: any) {
|
function handlePlus(node: any) {
|
||||||
console.log(node);
|
console.log(node);
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageWrapper title="Tree基础示例">
|
<PageWrapper title="Tree基础示例">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<CollapseContainer title="基础示例" :style="{ width: '33%' }" class="mr-4">
|
<BasicTree :treeData="treeData" title="基础示例" class="w-1/3" />
|
||||||
<BasicTree :treeData="treeData" />
|
|
||||||
</CollapseContainer>
|
|
||||||
|
|
||||||
<CollapseContainer title="可勾选" class="mr-4" :style="{ width: '33%' }">
|
<BasicTree :treeData="treeData" title="可勾选" :checkable="true" class="w-1/3 mx-4" />
|
||||||
<BasicTree :treeData="treeData" :checkable="true" />
|
|
||||||
</CollapseContainer>
|
|
||||||
|
|
||||||
<CollapseContainer title="默认展开/勾选示例" :style="{ width: '33%' }">
|
|
||||||
<BasicTree
|
<BasicTree
|
||||||
|
title="默认展开/勾选示例"
|
||||||
:treeData="treeData"
|
:treeData="treeData"
|
||||||
:checkable="true"
|
:checkable="true"
|
||||||
:expandedKeys="['0-0']"
|
:expandedKeys="['0-0']"
|
||||||
:checkedKeys="['0-0']"
|
:checkedKeys="['0-0']"
|
||||||
|
class="w-1/3"
|
||||||
/>
|
/>
|
||||||
</CollapseContainer>
|
|
||||||
</div>
|
</div>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
</template>
|
</template>
|
||||||
@ -24,11 +20,10 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { BasicTree } from '/@/components/Tree/index';
|
import { BasicTree } from '/@/components/Tree/index';
|
||||||
import { treeData } from './data';
|
import { treeData } from './data';
|
||||||
import { CollapseContainer } from '/@/components/Container/index';
|
|
||||||
import { PageWrapper } from '/@/components/Page';
|
import { PageWrapper } from '/@/components/Page';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicTree, CollapseContainer, PageWrapper },
|
components: { BasicTree, PageWrapper },
|
||||||
setup() {
|
setup() {
|
||||||
return { treeData };
|
return { treeData };
|
||||||
},
|
},
|
||||||
|
@ -1791,10 +1791,10 @@
|
|||||||
micromatch "^4.0.2"
|
micromatch "^4.0.2"
|
||||||
windicss "^2.2.3"
|
windicss "^2.2.3"
|
||||||
|
|
||||||
"@zxcvbn-ts/core@^0.2.0":
|
"@zxcvbn-ts/core@^0.3.0":
|
||||||
version "0.2.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-0.2.0.tgz#ba3af1fed2213464ae12c0ab565798590afe8ef7"
|
resolved "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-0.3.0.tgz#1a021afef29b97a5f8f72458de005fa149628e32"
|
||||||
integrity sha512-1NVKw2Tz3Iv3NE4RFTTcF2EQlmHfkNi48U0H80ZR/KLt3ANOFsCDp/mxGawdzCnBrf64E121xI49mpZDAACYZw==
|
integrity sha512-H1SOAoC7MbccN/CU9ENZHXwvwTwh6aRt88SOkGROAN9nT88o/qDPJ5B5bElRSbjKLfmmO1LqK2K4u2lUxjbQKQ==
|
||||||
|
|
||||||
JSONStream@^1.0.4:
|
JSONStream@^1.0.4:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
|
Loading…
Reference in New Issue
Block a user