Commit cd8e924d4641fc46cacd4a934478d8861e8c3c04

Authored by Vben
1 parent 9a1ba749

perf(tree): strengthen BasicTree function

CHANGELOG.zh_CN.md
... ... @@ -11,8 +11,9 @@
11 11 - 新增修改密码界面
12 12 - 新增部门管理示例界面
13 13 - 新增 WebSocket 示例和服务脚本
14   -- BasicTree 组件新增 `renderIcon` 属性用于控制层级图标显示
15   -- BasicTree->actionItem 新增 show 属性,用于动态控制按钮显示
  14 +- Tree 组件新增 `renderIcon` 属性用于控制层级图标显示
  15 +- Tree->actionItem 新增 show 属性,用于动态控制按钮显示
  16 +- Tree 新增工具栏/title/搜索功能
16 17  
17 18 ### ⚡ Performance Improvements
18 19  
... ...
package.json
... ... @@ -29,7 +29,7 @@
29 29 "dependencies": {
30 30 "@iconify/iconify": "^2.0.0-rc.6",
31 31 "@vueuse/core": "^4.3.1",
32   - "@zxcvbn-ts/core": "^0.2.0",
  32 + "@zxcvbn-ts/core": "^0.3.0",
33 33 "ant-design-vue": "2.0.1",
34 34 "apexcharts": "^3.25.0",
35 35 "axios": "^0.21.1",
... ...
src/components/StrengthMeter/src/index.vue
... ... @@ -23,7 +23,8 @@
23 23  
24 24 import { Input } from 'ant-design-vue';
25 25  
26   - import zxcvbn from '@zxcvbn-ts/core';
  26 + // @ts-ignore
  27 + import { zxcvbn } from '@zxcvbn-ts/core';
27 28 import { useDesign } from '/@/hooks/web/useDesign';
28 29 import { propTypes } from '/@/utils/propTypes';
29 30  
... ...
src/components/Tree/src/TreeHeader.vue 0 → 100644
  1 +<template>
  2 + <div class="flex px-2 py-1.5 items-center border-b-1">
  3 + <BasicTitle :helpMessage="helpMessage" v-if="title">{{ title }}</BasicTitle>
  4 +
  5 + <div class="flex flex-1 justify-end items-center cursor-pointer" v-if="search || toolbar">
  6 + <div class="mr-1 w-2/3" v-if="search">
  7 + <InputSearch :placeholder="t('common.searchText')" size="small" @change="handleSearch" />
  8 + </div>
  9 + <Dropdown @click.prevent v-if="toolbar">
  10 + <Icon icon="ion:ellipsis-vertical" />
  11 + <template #overlay>
  12 + <Menu @click="handleMenuClick">
  13 + <MenuItem v-for="item in toolbarList" :key="item.value">
  14 + {{ item.label }}
  15 + </MenuItem>
  16 + </Menu>
  17 + </template>
  18 + </Dropdown>
  19 + </div>
  20 + </div>
  21 +</template>
  22 +<script lang="ts">
  23 + import type { PropType } from 'vue';
  24 + import { defineComponent, ref } from 'vue';
  25 +
  26 + import { Dropdown, Menu, Checkbox, Input } from 'ant-design-vue';
  27 + import { Icon } from '/@/components/Icon';
  28 + import { BasicTitle } from '/@/components/Basic';
  29 +
  30 + import { propTypes } from '/@/utils/propTypes';
  31 +
  32 + import { useI18n } from '/@/hooks/web/useI18n';
  33 + import { useDebounce } from '/@/hooks/core/useDebounce';
  34 +
  35 + import { ToolbarEnum } from './enum';
  36 +
  37 + interface MenuInfo {
  38 + key: ToolbarEnum;
  39 + }
  40 + export default defineComponent({
  41 + name: 'BasicTreeHeader',
  42 + components: {
  43 + BasicTitle,
  44 + Icon,
  45 + Checkbox,
  46 + Dropdown,
  47 + Menu,
  48 + MenuItem: Menu.Item,
  49 + InputSearch: Input.Search,
  50 + },
  51 + props: {
  52 + helpMessage: {
  53 + type: [String, Array] as PropType<string | string[]>,
  54 + default: '',
  55 + },
  56 + title: propTypes.string,
  57 + toolbar: propTypes.bool,
  58 + search: propTypes.bool,
  59 + checkAll: propTypes.func,
  60 + expandAll: propTypes.func,
  61 + },
  62 + emits: ['strictly-change', 'search'],
  63 + setup(props, { emit }) {
  64 + const { t } = useI18n();
  65 + const toolbarList = ref([
  66 + { label: t('component.tree.selectAll'), value: ToolbarEnum.SELECT_ALL },
  67 + { label: t('component.tree.unSelectAll'), value: ToolbarEnum.UN_SELECT_ALL },
  68 + { label: t('component.tree.expandAll'), value: ToolbarEnum.EXPAND_ALL },
  69 + { label: t('component.tree.unExpandAll'), value: ToolbarEnum.UN_EXPAND_ALL },
  70 + { label: t('component.tree.checkStrictly'), value: ToolbarEnum.CHECK_STRICTLY },
  71 + { label: t('component.tree.checkUnStrictly'), value: ToolbarEnum.CHECK_UN_STRICTLY },
  72 + ]);
  73 +
  74 + function handleMenuClick(e: MenuInfo) {
  75 + const { key } = e;
  76 + switch (key) {
  77 + case ToolbarEnum.SELECT_ALL:
  78 + props.checkAll?.(true);
  79 + break;
  80 + case ToolbarEnum.UN_SELECT_ALL:
  81 + props.checkAll?.(false);
  82 + break;
  83 + case ToolbarEnum.EXPAND_ALL:
  84 + props.expandAll?.(true);
  85 + break;
  86 + case ToolbarEnum.UN_EXPAND_ALL:
  87 + props.expandAll?.(false);
  88 + break;
  89 + case ToolbarEnum.CHECK_STRICTLY:
  90 + emit('strictly-change', false);
  91 + break;
  92 + case ToolbarEnum.CHECK_UN_STRICTLY:
  93 + emit('strictly-change', true);
  94 + break;
  95 + }
  96 + }
  97 +
  98 + function emitChange(value?: string): void {
  99 + emit('search', value);
  100 + }
  101 + const [debounceEmitChange] = useDebounce(emitChange, 200);
  102 +
  103 + function handleSearch(e: ChangeEvent): void {
  104 + debounceEmitChange(e.target.value);
  105 + }
  106 +
  107 + return { t, toolbarList, handleMenuClick, handleSearch };
  108 + },
  109 + });
  110 +</script>
... ...
src/components/Tree/src/enum.ts 0 → 100644
  1 +export enum ToolbarEnum {
  2 + SELECT_ALL,
  3 + UN_SELECT_ALL,
  4 + EXPAND_ALL,
  5 + UN_EXPAND_ALL,
  6 + CHECK_STRICTLY,
  7 + CHECK_UN_STRICTLY,
  8 +}
... ...
src/components/Tree/src/index.vue
1 1 <script lang="tsx">
2 2 import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
3 3  
4   - import {
5   - defineComponent,
6   - reactive,
7   - computed,
8   - unref,
9   - ref,
10   - watchEffect,
11   - onMounted,
12   - toRaw,
13   - } from 'vue';
  4 + import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw } from 'vue';
14 5 import { Tree } from 'ant-design-vue';
15 6 import { TreeIcon } from './TreeIcon';
  7 + import TreeHeader from './TreeHeader.vue';
16 8 // import { DownOutlined } from '@ant-design/icons-vue';
17 9  
18 10 import { omit, get } from 'lodash-es';
19 11 import { isBoolean, isFunction } from '/@/utils/is';
20 12 import { extendSlots } from '/@/utils/helper/tsxHelper';
  13 + import { filter } from '/@/utils/helper/treeHelper';
21 14  
22 15 import { useTree } from './useTree';
23 16 import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
... ... @@ -30,18 +23,25 @@
30 23 expandedKeys: Keys;
31 24 selectedKeys: Keys;
32 25 checkedKeys: CheckKeys;
  26 + checkStrictly: boolean;
33 27 }
34 28 export default defineComponent({
35 29 name: 'BasicTree',
36 30 props: basicProps,
37   - emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
  31 + emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change'],
38 32 setup(props, { attrs, slots, emit }) {
39 33 const state = reactive<State>({
  34 + checkStrictly: props.checkStrictly,
40 35 expandedKeys: props.expandedKeys || [],
41 36 selectedKeys: props.selectedKeys || [],
42 37 checkedKeys: props.checkedKeys || [],
43 38 });
44 39  
  40 + const searchState = reactive({
  41 + startSearch: false,
  42 + searchData: [] as TreeItem[],
  43 + });
  44 +
45 45 const treeDataRef = ref<TreeItem[]>([]);
46 46  
47 47 const [createContextMenu] = useContextMenu();
... ... @@ -77,6 +77,7 @@
77 77 expandedKeys: state.expandedKeys,
78 78 selectedKeys: state.selectedKeys,
79 79 checkedKeys: state.checkedKeys,
  80 + checkStrictly: state.checkStrictly,
80 81 replaceFields: unref(getReplaceFields),
81 82 'onUpdate:expandedKeys': (v: Keys) => {
82 83 state.expandedKeys = v;
... ... @@ -88,21 +89,27 @@
88 89 },
89 90 onCheck: (v: CheckKeys) => {
90 91 state.checkedKeys = v;
  92 + emit('change', v);
91 93 emit('update:value', v);
92 94 },
93 95 onRightClick: handleRightClick,
94 96 };
95   - propsData = omit(propsData, 'treeData');
  97 + propsData = omit(propsData, 'treeData', 'class');
96 98 return propsData;
97 99 });
98 100  
99   - const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
100   -
101   - const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
102   - treeDataRef,
103   - getReplaceFields
  101 + const getTreeData = computed((): TreeItem[] =>
  102 + searchState.startSearch ? searchState.searchData : unref(treeDataRef)
104 103 );
105 104  
  105 + const {
  106 + deleteNodeByKey,
  107 + insertNodeByKey,
  108 + filterByLevel,
  109 + updateNodeByKey,
  110 + getAllKeys,
  111 + } = useTree(treeDataRef, getReplaceFields);
  112 +
106 113 function getIcon(params: Recordable, icon?: string) {
107 114 if (!icon) {
108 115 if (props.renderIcon && isFunction(props.renderIcon)) {
... ... @@ -112,60 +119,6 @@
112 119 return icon;
113 120 }
114 121  
115   - function renderAction(node: TreeItem) {
116   - const { actionList } = props;
117   - if (!actionList || actionList.length === 0) return;
118   - return actionList.map((item, index) => {
119   - if (isFunction(item.show)) {
120   - return item.show?.(node);
121   - }
122   -
123   - if (isBoolean(item.show)) {
124   - return item.show;
125   - }
126   -
127   - return (
128   - <span key={index} class={`${prefixCls}__action`}>
129   - {item.render(node)}
130   - </span>
131   - );
132   - });
133   - }
134   -
135   - function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
136   - if (!data) {
137   - return null;
138   - }
139   - return data.map((item) => {
140   - const { title: titleField, key: keyField, children: childrenField } = unref(
141   - getReplaceFields
142   - );
143   -
144   - const propsData = omit(item, 'title');
145   - const icon = getIcon({ ...item, level }, item.icon);
146   - return (
147   - <Tree.TreeNode {...propsData} node={toRaw(item)} key={get(item, keyField)}>
148   - {{
149   - title: () => (
150   - <span class={`${prefixCls}-title`}>
151   - {icon && <TreeIcon icon={icon} />}
152   - <span
153   - class={`${prefixCls}__content`}
154   - // style={unref(getContentStyle)}
155   - >
156   - {get(item, titleField)}
157   - </span>
158   - <span class={`${prefixCls}__actions`}> {renderAction({ ...item, level })}</span>
159   - </span>
160   - ),
161   - default: () =>
162   - renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
163   - }}
164   - </Tree.TreeNode>
165   - );
166   - });
167   - }
168   -
169 122 async function handleRightClick({ event, node }: any) {
170 123 const { rightMenuList: menuList = [], beforeRightClick } = props;
171 124 let rightMenuList: ContextMenuItem[] = [];
... ... @@ -205,6 +158,32 @@
205 158 return state.checkedKeys;
206 159 }
207 160  
  161 + function checkAll(checkAll: boolean) {
  162 + state.checkedKeys = checkAll ? getAllKeys() : ([] as Keys);
  163 + }
  164 +
  165 + function expandAll(expandAll: boolean) {
  166 + state.expandedKeys = expandAll ? getAllKeys() : ([] as Keys);
  167 + }
  168 +
  169 + function onStrictlyChange(strictly: boolean) {
  170 + state.checkStrictly = strictly;
  171 + }
  172 +
  173 + function handleSearch(searchValue: string) {
  174 + if (!searchValue) {
  175 + searchState.startSearch = false;
  176 + return;
  177 + }
  178 + searchState.startSearch = true;
  179 +
  180 + searchState.searchData = filter(unref(treeDataRef), (node) => {
  181 + const { title } = node;
  182 + return title?.includes(searchValue) ?? false;
  183 + // || key?.includes(searchValue);
  184 + });
  185 + }
  186 +
208 187 watchEffect(() => {
209 188 treeDataRef.value = props.treeData as TreeItem[];
210 189 state.expandedKeys = props.expandedKeys;
... ... @@ -212,6 +191,16 @@
212 191 state.checkedKeys = props.checkedKeys;
213 192 });
214 193  
  194 + watchEffect(() => {
  195 + if (props.value) {
  196 + state.checkedKeys = props.value;
  197 + }
  198 + });
  199 +
  200 + watchEffect(() => {
  201 + state.checkStrictly = props.checkStrictly;
  202 + });
  203 +
215 204 const instance: TreeActionType = {
216 205 setExpandedKeys,
217 206 getExpandedKeys,
... ... @@ -222,6 +211,8 @@
222 211 insertNodeByKey,
223 212 deleteNodeByKey,
224 213 updateNodeByKey,
  214 + checkAll,
  215 + expandAll,
225 216 filterByLevel: (level: number) => {
226 217 state.expandedKeys = filterByLevel(level);
227 218 },
... ... @@ -229,19 +220,83 @@
229 220  
230 221 useExpose<TreeActionType>(instance);
231 222  
232   - onMounted(() => {
233   - emit('get', instance);
234   - });
  223 + function renderAction(node: TreeItem) {
  224 + const { actionList } = props;
  225 + if (!actionList || actionList.length === 0) return;
  226 + return actionList.map((item, index) => {
  227 + if (isFunction(item.show)) {
  228 + return item.show?.(node);
  229 + }
  230 +
  231 + if (isBoolean(item.show)) {
  232 + return item.show;
  233 + }
  234 +
  235 + return (
  236 + <span key={index} class={`${prefixCls}__action`}>
  237 + {item.render(node)}
  238 + </span>
  239 + );
  240 + });
  241 + }
  242 +
  243 + function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
  244 + if (!data) {
  245 + return null;
  246 + }
  247 + return data.map((item) => {
  248 + const { title: titleField, key: keyField, children: childrenField } = unref(
  249 + getReplaceFields
  250 + );
235 251  
  252 + const propsData = omit(item, 'title');
  253 + const icon = getIcon({ ...item, level }, item.icon);
  254 + return (
  255 + <Tree.TreeNode {...propsData} node={toRaw(item)} key={get(item, keyField)}>
  256 + {{
  257 + title: () => (
  258 + <span class={`${prefixCls}-title pl-2`}>
  259 + {icon && <TreeIcon icon={icon} />}
  260 + <span
  261 + class={`${prefixCls}__content`}
  262 + // style={unref(getContentStyle)}
  263 + >
  264 + {get(item, titleField)}
  265 + </span>
  266 + <span class={`${prefixCls}__actions`}> {renderAction({ ...item, level })}</span>
  267 + </span>
  268 + ),
  269 + default: () =>
  270 + renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
  271 + }}
  272 + </Tree.TreeNode>
  273 + );
  274 + });
  275 + }
236 276 return () => {
  277 + const { title, helpMessage, toolbar, search } = props;
237 278 return (
238   - <Tree {...unref(getBindValues)} showIcon={false} class={[prefixCls]}>
239   - {{
240   - // switcherIcon: () => <DownOutlined />,
241   - default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
242   - ...extendSlots(slots),
243   - }}
244   - </Tree>
  279 + <div class={[prefixCls, 'h-full bg-white']}>
  280 + {(title || toolbar || search) && (
  281 + <TreeHeader
  282 + checkAll={checkAll}
  283 + expandAll={expandAll}
  284 + title={title}
  285 + search={search}
  286 + toolbar={toolbar}
  287 + helpMessage={helpMessage}
  288 + onStrictlyChange={onStrictlyChange}
  289 + onSearch={handleSearch}
  290 + />
  291 + )}
  292 + <Tree {...unref(getBindValues)} showIcon={false}>
  293 + {{
  294 + // switcherIcon: () => <DownOutlined />,
  295 + default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
  296 + ...extendSlots(slots),
  297 + }}
  298 + </Tree>
  299 + </div>
245 300 );
246 301 };
247 302 },
... ... @@ -251,8 +306,6 @@
251 306 @prefix-cls: ~'@{namespace}-basic-tree';
252 307  
253 308 .@{prefix-cls} {
254   - position: relative;
255   -
256 309 .ant-tree-node-content-wrapper {
257 310 position: relative;
258 311  
... ... @@ -278,14 +331,14 @@
278 331 }
279 332  
280 333 &__content {
281   - display: inline-block;
  334 + // display: inline-block;
282 335 overflow: hidden;
283 336 }
284 337  
285 338 &__actions {
286 339 position: absolute;
287 340 top: 2px;
288   - right: 2px;
  341 + right: 3px;
289 342 display: flex;
290 343 }
291 344  
... ...
src/components/Tree/src/props.ts
... ... @@ -2,11 +2,26 @@ import type { PropType } from &#39;vue&#39;;
2 2 import type { ReplaceFields, ActionItem, Keys, CheckKeys } from './types';
3 3 import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
4 4 import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
  5 +import { propTypes } from '/@/utils/propTypes';
5 6  
6 7 export const basicProps = {
  8 + value: {
  9 + type: Array as PropType<Keys>,
  10 + },
7 11 renderIcon: {
8 12 type: Function as PropType<(params: Recordable) => string>,
9 13 },
  14 +
  15 + helpMessage: {
  16 + type: [String, Array] as PropType<string | string[]>,
  17 + default: '',
  18 + },
  19 +
  20 + title: propTypes.string,
  21 + toolbar: propTypes.bool,
  22 + search: propTypes.bool,
  23 + checkStrictly: propTypes.bool,
  24 +
10 25 replaceFields: {
11 26 type: Object as PropType<ReplaceFields>,
12 27 },
... ...
src/components/Tree/src/types.ts
... ... @@ -21,6 +21,8 @@ export type CheckKeys =
21 21 | { checked: string[] | number[]; halfChecked: string[] | number[] };
22 22  
23 23 export interface TreeActionType {
  24 + checkAll: (checkAll: boolean) => void;
  25 + expandAll: (expandAll: boolean) => void;
24 26 setExpandedKeys: (keys: Keys) => void;
25 27 getExpandedKeys: () => Keys;
26 28 setSelectedKeys: (keys: Keys) => void;
... ...
src/components/Tree/src/useTree.ts
1   -import type { InsertNodeParams, ReplaceFields } from './types';
  1 +import type { InsertNodeParams, Keys, ReplaceFields } from './types';
2 2 import type { Ref, ComputedRef } from 'vue';
3 3 import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
4 4  
... ... @@ -10,6 +10,23 @@ export function useTree(
10 10 treeDataRef: Ref<TreeDataItem[]>,
11 11 getReplaceFields: ComputedRef<ReplaceFields>
12 12 ) {
  13 + function getAllKeys(list?: TreeDataItem[]) {
  14 + const keys: string[] = [];
  15 + const treeData = list || unref(treeDataRef);
  16 + const { key: keyField, children: childrenField } = unref(getReplaceFields);
  17 + if (!childrenField || !keyField) return keys;
  18 +
  19 + for (let index = 0; index < treeData.length; index++) {
  20 + const node = treeData[index];
  21 + keys.push(node[keyField]!);
  22 + const children = node[childrenField];
  23 + if (children && children.length) {
  24 + keys.push(...(getAllKeys(children) as string[]));
  25 + }
  26 + }
  27 + return keys as Keys;
  28 + }
  29 +
13 30 // Update node
14 31 function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) {
15 32 if (!key) return;
... ... @@ -94,5 +111,5 @@ export function useTree(
94 111 }
95 112 }
96 113 }
97   - return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey };
  114 + return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey, getAllKeys };
98 115 }
... ...
src/locales/lang/en/component/tree.ts 0 → 100644
  1 +export default {
  2 + selectAll: 'Select All',
  3 + unSelectAll: 'Cancel Select',
  4 + expandAll: 'Expand All',
  5 + unExpandAll: 'Collapse all',
  6 +
  7 + checkStrictly: 'Hierarchical association',
  8 + checkUnStrictly: 'Hierarchical independence',
  9 +};
... ...
src/locales/lang/en/routes/demo/comp.ts
... ... @@ -12,7 +12,7 @@ export default {
12 12 tree: 'Tree',
13 13  
14 14 treeBasic: 'Basic',
15   - editTree: 'Right-click',
  15 + editTree: 'Searchable/toolbar',
16 16 actionTree: 'Function operation',
17 17  
18 18 modal: 'Modal',
... ...
src/locales/lang/zh_CN/component/tree.ts 0 → 100644
  1 +export default {
  2 + selectAll: '选择全部',
  3 + unSelectAll: '取消选择',
  4 + expandAll: '展开全部',
  5 + unExpandAll: '折叠全部',
  6 + checkStrictly: '层级关联',
  7 + checkUnStrictly: '层级独立',
  8 +};
... ...
src/locales/lang/zh_CN/routes/demo/comp.ts
... ... @@ -11,7 +11,7 @@ export default {
11 11  
12 12 tree: 'Tree',
13 13 treeBasic: '基础树',
14   - editTree: '右键示例',
  14 + editTree: '可搜索/工具栏',
15 15 actionTree: '函数操作示例',
16 16  
17 17 modal: '弹窗扩展',
... ...
src/router/menus/modules/demo/comp.ts
... ... @@ -6,7 +6,10 @@ const menu: MenuModule = {
6 6 menu: {
7 7 name: t('routes.demo.comp.comp'),
8 8 path: '/comp',
9   -
  9 + tag: {
  10 + dot: true,
  11 + type: 'warn',
  12 + },
10 13 children: [
11 14 {
12 15 path: 'basic',
... ... @@ -154,6 +157,10 @@ const menu: MenuModule = {
154 157 {
155 158 path: 'tree',
156 159 name: t('routes.demo.comp.tree'),
  160 + tag: {
  161 + dot: true,
  162 + type: 'warn',
  163 + },
157 164 children: [
158 165 {
159 166 path: 'basic',
... ... @@ -162,6 +169,10 @@ const menu: MenuModule = {
162 169 {
163 170 path: 'editTree',
164 171 name: t('routes.demo.comp.editTree'),
  172 + tag: {
  173 + dot: true,
  174 + type: 'warn',
  175 + },
165 176 },
166 177 {
167 178 path: 'actionTree',
... ... @@ -172,9 +183,6 @@ const menu: MenuModule = {
172 183 {
173 184 name: t('routes.demo.editor.editor'),
174 185 path: 'editor',
175   - tag: {
176   - content: 'new',
177   - },
178 186 children: [
179 187 {
180 188 path: 'markdown',
... ...
src/router/menus/modules/demo/system.ts
... ... @@ -22,21 +22,21 @@ const menu: MenuModule = {
22 22 path: 'role',
23 23 name: t('routes.demo.system.role'),
24 24 tag: {
25   - content: 'new',
  25 + dot: true,
26 26 },
27 27 },
28 28 {
29 29 path: 'menu',
30 30 name: t('routes.demo.system.menu'),
31 31 tag: {
32   - content: 'new',
  32 + dot: true,
33 33 },
34 34 },
35 35 {
36 36 path: 'dept',
37 37 name: t('routes.demo.system.dept'),
38 38 tag: {
39   - content: 'new',
  39 + dot: true,
40 40 },
41 41 },
42 42  
... ... @@ -44,7 +44,7 @@ const menu: MenuModule = {
44 44 path: 'changePassword',
45 45 name: t('routes.demo.system.password'),
46 46 tag: {
47   - content: 'new',
  47 + dot: true,
48 48 },
49 49 },
50 50 ],
... ...
src/store/modules/permission.ts
... ... @@ -18,7 +18,7 @@ import { transformObjToRoute } from &#39;/@/router/helper/routeHelper&#39;;
18 18 import { transformRouteToMenu } from '/@/router/helper/menuHelper';
19 19  
20 20 import { useMessage } from '/@/hooks/web/useMessage';
21   -import { useI18n } from '/@/hooks/web/useI18n';
  21 +// import { useI18n } from '/@/hooks/web/useI18n';
22 22 import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
23 23  
24 24 const { createMessage } = useMessage();
... ... @@ -84,7 +84,7 @@ class Permission extends VuexModule {
84 84  
85 85 @Action
86 86 async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
87   - const { t } = useI18n();
  87 + // const { t } = useI18n();
88 88 let routes: AppRouteRecordRaw[] = [];
89 89 const roleList = toRaw(userStore.getRoleListState);
90 90  
... ... @@ -101,7 +101,8 @@ class Permission extends VuexModule {
101 101 // If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
102 102 } else if (permissionMode === PermissionModeEnum.BACK) {
103 103 createMessage.loading({
104   - content: t('sys.app.menuLoading'),
  104 + content: 'Loading menu...',
  105 + // content: 't('sys.app.menuLoading')',
105 106 duration: 1,
106 107 });
107 108 // Here to get the background routing menu logic to modify by yourself
... ...
src/views/demo/tree/ActionTree.vue
1 1 <template>
2 2 <PageWrapper title="Tree函数操作示例" contentBackground contentClass="p-4">
3 3 <div class="mb-4">
  4 + <a-button @click="expandAll(true)" class="mr-2"> 展开全部 </a-button>
  5 + <a-button @click="expandAll(false)" class="mr-2"> 折叠全部 </a-button>
  6 + <a-button @click="checkAll(true)" class="mr-2"> 全选 </a-button>
  7 + <a-button @click="checkAll(false)" class="mr-2"> 全不选 </a-button>
4 8 <a-button @click="handleLevel(2)" class="mr-2"> 显示到第2级 </a-button>
5 9 <a-button @click="handleLevel(1)" class="mr-2"> 显示到第1级 </a-button>
  10 + </div>
  11 + <div class="mb-4">
6 12 <a-button @click="handleSetCheckData" class="mr-2"> 设置勾选数据 </a-button>
7 13 <a-button @click="handleGetCheckData" class="mr-2"> 获取勾选数据 </a-button>
8 14 <a-button @click="handleSetSelectData" class="mr-2"> 设置选中数据 </a-button>
... ... @@ -17,21 +23,18 @@
17 23 <a-button @click="deleteNodeByKey('2-2')" class="mr-2"> 删除parent3节点 </a-button>
18 24 <a-button @click="updateNodeByKey('1-1')" class="mr-2"> 更新parent2节点 </a-button>
19 25 </div>
20   - <CollapseContainer title="函数操作" class="mr-4" :canExpan="false" :style="{ width: '33%' }">
21   - <BasicTree :treeData="treeData" ref="treeRef" :checkable="true" />
22   - </CollapseContainer>
  26 + <BasicTree :treeData="treeData" title="函数操作" ref="treeRef" :checkable="true" />
23 27 </PageWrapper>
24 28 </template>
25 29 <script lang="ts">
26 30 import { defineComponent, ref, unref } from 'vue';
27 31 import { BasicTree, TreeActionType } from '/@/components/Tree/index';
28 32 import { treeData } from './data';
29   - import { CollapseContainer } from '/@/components/Container/index';
30 33 import { useMessage } from '/@/hooks/web/useMessage';
31 34 import { PageWrapper } from '/@/components/Page';
32 35  
33 36 export default defineComponent({
34   - components: { BasicTree, CollapseContainer, PageWrapper },
  37 + components: { BasicTree, PageWrapper },
35 38 setup() {
36 39 const treeRef = ref<Nullable<TreeActionType>>(null);
37 40 const { createMessage } = useMessage();
... ... @@ -75,6 +78,14 @@
75 78 createMessage.success(JSON.stringify(keys));
76 79 }
77 80  
  81 + function checkAll(checkAll: boolean) {
  82 + getTree().checkAll(checkAll);
  83 + }
  84 +
  85 + function expandAll(checkAll: boolean) {
  86 + getTree().expandAll(checkAll);
  87 + }
  88 +
78 89 function appendNodeByKey(parentKey: string | null = null) {
79 90 getTree().insertNodeByKey({
80 91 parentKey: parentKey,
... ... @@ -112,6 +123,8 @@
112 123 appendNodeByKey,
113 124 deleteNodeByKey,
114 125 updateNodeByKey,
  126 + checkAll,
  127 + expandAll,
115 128 };
116 129 },
117 130 });
... ...
src/views/demo/tree/EditTree.vue
1 1 <template>
2 2 <PageWrapper title="Tree函数操作示例">
3 3 <div class="flex">
4   - <CollapseContainer title="右侧操作按钮/自定义图标" class="mr-4" :style="{ width: '33%' }">
5   - <BasicTree :treeData="treeData" :actionList="actionList" :renderIcon="createIcon" />
6   - </CollapseContainer>
7   -
8   - <CollapseContainer title="右键菜单" class="mr-4" :style="{ width: '33%' }">
9   - <BasicTree :treeData="treeData" :beforeRightClick="getRightMenuList" />
10   - </CollapseContainer>
  4 + <BasicTree
  5 + class="w-1/3"
  6 + title="右侧操作按钮/自定义图标"
  7 + helpMessage="帮助信息"
  8 + :treeData="treeData"
  9 + :actionList="actionList"
  10 + :renderIcon="createIcon"
  11 + />
  12 + <BasicTree
  13 + class="w-1/3 mx-4"
  14 + title="右键菜单"
  15 + :treeData="treeData"
  16 + :beforeRightClick="getRightMenuList"
  17 + />
  18 + <BasicTree
  19 + class="w-1/3"
  20 + title="工具栏使用"
  21 + toolbar
  22 + checkable
  23 + search
  24 + :treeData="treeData"
  25 + :beforeRightClick="getRightMenuList"
  26 + />
11 27 </div>
12 28 </PageWrapper>
13 29 </template>
... ... @@ -15,12 +31,11 @@
15 31 import { defineComponent, h } from 'vue';
16 32 import { BasicTree, ActionItem, ContextMenuItem } from '/@/components/Tree/index';
17 33 import { treeData } from './data';
18   - import { CollapseContainer } from '/@/components/Container/index';
19 34 import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
20 35 import { PageWrapper } from '/@/components/Page';
21 36  
22 37 export default defineComponent({
23   - components: { BasicTree, CollapseContainer, PageWrapper },
  38 + components: { BasicTree, PageWrapper },
24 39 setup() {
25 40 function handlePlus(node: any) {
26 41 console.log(node);
... ...
src/views/demo/tree/index.vue
1 1 <template>
2 2 <PageWrapper title="Tree基础示例">
3 3 <div class="flex">
4   - <CollapseContainer title="基础示例" :style="{ width: '33%' }" class="mr-4">
5   - <BasicTree :treeData="treeData" />
6   - </CollapseContainer>
  4 + <BasicTree :treeData="treeData" title="基础示例" class="w-1/3" />
7 5  
8   - <CollapseContainer title="可勾选" class="mr-4" :style="{ width: '33%' }">
9   - <BasicTree :treeData="treeData" :checkable="true" />
10   - </CollapseContainer>
  6 + <BasicTree :treeData="treeData" title="可勾选" :checkable="true" class="w-1/3 mx-4" />
11 7  
12   - <CollapseContainer title="默认展开/勾选示例" :style="{ width: '33%' }">
13   - <BasicTree
14   - :treeData="treeData"
15   - :checkable="true"
16   - :expandedKeys="['0-0']"
17   - :checkedKeys="['0-0']"
18   - />
19   - </CollapseContainer>
  8 + <BasicTree
  9 + title="默认展开/勾选示例"
  10 + :treeData="treeData"
  11 + :checkable="true"
  12 + :expandedKeys="['0-0']"
  13 + :checkedKeys="['0-0']"
  14 + class="w-1/3"
  15 + />
20 16 </div>
21 17 </PageWrapper>
22 18 </template>
... ... @@ -24,11 +20,10 @@
24 20 import { defineComponent } from 'vue';
25 21 import { BasicTree } from '/@/components/Tree/index';
26 22 import { treeData } from './data';
27   - import { CollapseContainer } from '/@/components/Container/index';
28 23 import { PageWrapper } from '/@/components/Page';
29 24  
30 25 export default defineComponent({
31   - components: { BasicTree, CollapseContainer, PageWrapper },
  26 + components: { BasicTree, PageWrapper },
32 27 setup() {
33 28 return { treeData };
34 29 },
... ...
yarn.lock
... ... @@ -1791,10 +1791,10 @@
1791 1791 micromatch "^4.0.2"
1792 1792 windicss "^2.2.3"
1793 1793  
1794   -"@zxcvbn-ts/core@^0.2.0":
1795   - version "0.2.0"
1796   - resolved "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-0.2.0.tgz#ba3af1fed2213464ae12c0ab565798590afe8ef7"
1797   - integrity sha512-1NVKw2Tz3Iv3NE4RFTTcF2EQlmHfkNi48U0H80ZR/KLt3ANOFsCDp/mxGawdzCnBrf64E121xI49mpZDAACYZw==
  1794 +"@zxcvbn-ts/core@^0.3.0":
  1795 + version "0.3.0"
  1796 + resolved "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-0.3.0.tgz#1a021afef29b97a5f8f72458de005fa149628e32"
  1797 + integrity sha512-H1SOAoC7MbccN/CU9ENZHXwvwTwh6aRt88SOkGROAN9nT88o/qDPJ5B5bElRSbjKLfmmO1LqK2K4u2lUxjbQKQ==
1798 1798  
1799 1799 JSONStream@^1.0.4:
1800 1800 version "1.3.5"
... ...