mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-11-04 15:53:43 +08:00 
			
		
		
		
	refactor(projects): remove page examples: tree [去除tree相关示例页面]
This commit is contained in:
		@@ -32,48 +32,6 @@ const component: AuthRoute.Route = {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        icon: 'mdi:table-large'
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'component_tree',
 | 
			
		||||
      path: '/component/tree',
 | 
			
		||||
      component: 'multi',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          name: 'component_tree_tree-basic',
 | 
			
		||||
          path: '/component/tree/tree-basic',
 | 
			
		||||
          component: 'self',
 | 
			
		||||
          meta: {
 | 
			
		||||
            title: '基础树',
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            icon: 'fluent:tree-deciduous-20-regular'
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: 'component_tree_tree-custom',
 | 
			
		||||
          path: '/component/tree/tree-custom',
 | 
			
		||||
          component: 'self',
 | 
			
		||||
          meta: {
 | 
			
		||||
            title: '自定义树',
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            icon: 'fluent:tree-deciduous-20-filled'
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: 'component_tree_tree-functions',
 | 
			
		||||
          path: '/component/tree/tree-functions',
 | 
			
		||||
          component: 'self',
 | 
			
		||||
          meta: {
 | 
			
		||||
            title: '函数示例',
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            icon: 'fluent:tree-evergreen-20-filled'
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      meta: {
 | 
			
		||||
        title: '树',
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        icon: 'carbon:tree-view-alt'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  meta: {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								src/typings/page-route.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								src/typings/page-route.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -30,10 +30,6 @@ declare namespace PageRoute {
 | 
			
		||||
    | 'component_button'
 | 
			
		||||
    | 'component_card'
 | 
			
		||||
    | 'component_table'
 | 
			
		||||
    | 'component_tree'
 | 
			
		||||
    | 'component_tree_tree-basic'
 | 
			
		||||
    | 'component_tree_tree-custom'
 | 
			
		||||
    | 'component_tree_tree-functions'
 | 
			
		||||
    | 'dashboard'
 | 
			
		||||
    | 'dashboard_analysis'
 | 
			
		||||
    | 'dashboard_workbench'
 | 
			
		||||
@@ -93,9 +89,6 @@ declare namespace PageRoute {
 | 
			
		||||
    | 'component_button'
 | 
			
		||||
    | 'component_card'
 | 
			
		||||
    | 'component_table'
 | 
			
		||||
    | 'component_tree_tree-basic'
 | 
			
		||||
    | 'component_tree_tree-custom'
 | 
			
		||||
    | 'component_tree_tree-functions'
 | 
			
		||||
    | 'dashboard_analysis'
 | 
			
		||||
    | 'dashboard_workbench'
 | 
			
		||||
    | 'document_naive'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,383 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * 基础树组件
 | 
			
		||||
 * @author: SonnyLeo
 | 
			
		||||
 * @since: 2023-03-30
 | 
			
		||||
 * index.vue
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <n-card title="基础组件" class="h-full shadow-sm rounded-16px">
 | 
			
		||||
      <n-grid :x-gap="20" :y-gap="20" cols="0 600:2 1000:3">
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="基础实例 | 默认展开第一层" :segmented="segmented" class="shadow-sm rounded-16px">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              ref="caseOneTreeRef"
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              checkable
 | 
			
		||||
              selectable
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              :cascade="cascade"
 | 
			
		||||
              :default-expanded-keys="caseOneDefaultExpandedKeys"
 | 
			
		||||
              @update-checked-keys="caseOneUpdateCheckedKeys"
 | 
			
		||||
            />
 | 
			
		||||
            <template #footer> 当前选中的节点是: {{ caseOneCheckedKeys }} </template>
 | 
			
		||||
          </n-card></n-grid-item
 | 
			
		||||
        >
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="可勾选 | 默认全部展开" :segmented="segmented" class="shadow-sm rounded-16px">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              checkable
 | 
			
		||||
              selectable
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              default-expand-all
 | 
			
		||||
              :cascade="cascade"
 | 
			
		||||
              :checked-keys="caseTwoCheckedKeys"
 | 
			
		||||
              @update:checked-keys="caseTwoCheckedKeysChange"
 | 
			
		||||
            /> </n-card
 | 
			
		||||
        ></n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="指定项目 | 展开或勾选" class="shadow-sm rounded-16px">
 | 
			
		||||
            <template #header-extra>
 | 
			
		||||
              <n-space justify="space-around">
 | 
			
		||||
                <n-button rounded @click="caseThreeExpandAll">全部展开</n-button>
 | 
			
		||||
                <n-button rounded type="primary" @click="caseThreeCheckedAll">全部勾选</n-button>
 | 
			
		||||
              </n-space>
 | 
			
		||||
            </template>
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              checkable
 | 
			
		||||
              selectable
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              :checked-keys="caseThreeCheckedKeys"
 | 
			
		||||
              :expanded-keys="caseThreeExpandedKeys"
 | 
			
		||||
              @update:checked-keys="caseThreeCheckedKeysChange"
 | 
			
		||||
              @update:expanded-keys="caseThreeExpandKeysChange"
 | 
			
		||||
            />
 | 
			
		||||
            <template #footer> 当前选中的节点是: {{ caseThreeCheckedKeys }} </template>
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="懒加载" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              checkable
 | 
			
		||||
              draggable
 | 
			
		||||
              :data="remoteData"
 | 
			
		||||
              :checked-keys="caseFourCheckedKeys"
 | 
			
		||||
              :on-load="handleLoad"
 | 
			
		||||
              :expanded-keys="caseFourExpandedKeys"
 | 
			
		||||
              check-strategy="all"
 | 
			
		||||
              :allow-checking-not-loaded="true"
 | 
			
		||||
              :cascade="cascade"
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              @update:checked-keys="caseFourCheckedKeysChange"
 | 
			
		||||
              @update:expanded-keys="caseFourExpandKeysChange"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="异步数据 | 默认全部展开" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <template #header-extra>
 | 
			
		||||
              <n-button @click="handleInitData">加载数据</n-button>
 | 
			
		||||
            </template>
 | 
			
		||||
            <n-spin :show="loading">
 | 
			
		||||
              <n-tree
 | 
			
		||||
                block-line
 | 
			
		||||
                :data="caseFiveData"
 | 
			
		||||
                checkable
 | 
			
		||||
                selectable
 | 
			
		||||
                expand-on-click
 | 
			
		||||
                :cascade="cascade"
 | 
			
		||||
                :checked-keys="caseFiveCheckedKeys"
 | 
			
		||||
                :default-expanded-keys="caseFiveDefaultExpandedKeys"
 | 
			
		||||
                @update:checked-keys="caseFiveCheckedKeysChange"
 | 
			
		||||
              />
 | 
			
		||||
              <template #description> 正在加载数据中... </template>
 | 
			
		||||
            </n-spin>
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="为节点绑定点击事件" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              :default-expanded-keys="caseSixDefaultExpandedKeys"
 | 
			
		||||
              :node-props="nodeProps"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="自定义前缀 | 文件树" class="shadow-sm rounded-16px" :segmented="segmented"
 | 
			
		||||
            ><n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              :data="caseSevenData"
 | 
			
		||||
              :node-props="nodeProps"
 | 
			
		||||
              :default-expanded-keys="caseSevenDefaultExpandedKeys"
 | 
			
		||||
              :on-update:expanded-keys="updatePrefixWithExpanded"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="自定义开关 | 打开和关闭的图标" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              :data="data"
 | 
			
		||||
              :default-expanded-keys="caseEightDefaultExpandedKeys"
 | 
			
		||||
              :render-switcher-icon="renderSwitcherIconWithExpaned"
 | 
			
		||||
              selectable
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
      </n-grid>
 | 
			
		||||
    </n-card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="tsx">
 | 
			
		||||
import { ref, h } from 'vue';
 | 
			
		||||
import type { TreeOption, TreeInst } from 'naive-ui';
 | 
			
		||||
import { NIcon } from 'naive-ui';
 | 
			
		||||
import { repeat } from 'seemly';
 | 
			
		||||
import { useIconRender } from '@/composables';
 | 
			
		||||
import { useLoading } from '@/hooks';
 | 
			
		||||
 | 
			
		||||
const { iconRender } = useIconRender();
 | 
			
		||||
 | 
			
		||||
const cascade = ref<boolean>(true);
 | 
			
		||||
const segmented = ref<boolean>(true);
 | 
			
		||||
 | 
			
		||||
const caseOneTreeRef = ref<TreeInst | null>(null);
 | 
			
		||||
const caseOneCheckedKeys = ref<string[]>([]);
 | 
			
		||||
const caseOneDefaultExpandedKeys = ref<string[]>(['20']);
 | 
			
		||||
function caseOneUpdateCheckedKeys(checkedKeys: string[]) {
 | 
			
		||||
  caseOneCheckedKeys.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const caseTwoCheckedKeys = ref<string[]>([]);
 | 
			
		||||
function caseTwoCheckedKeysChange(checkedKeys: Array<string>) {
 | 
			
		||||
  caseTwoCheckedKeys.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const caseThreeCheckedKeys = ref<string[]>([]);
 | 
			
		||||
const caseThreeExpandedKeys = ref<string[]>([]);
 | 
			
		||||
function caseThreeCheckedKeysChange(checkedKeys: Array<string>) {
 | 
			
		||||
  caseThreeCheckedKeys.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
function caseThreeExpandKeysChange(expandKeys: Array<string>) {
 | 
			
		||||
  caseThreeExpandedKeys.value = expandKeys;
 | 
			
		||||
}
 | 
			
		||||
function caseThreeCheckedAll() {
 | 
			
		||||
  caseThreeCheckedKeys.value = getAllKeys(createData());
 | 
			
		||||
}
 | 
			
		||||
function caseThreeExpandAll() {
 | 
			
		||||
  caseThreeExpandedKeys.value = ['20', '21'];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const caseFourCheckedKeys = ref<string[]>([]);
 | 
			
		||||
const caseFourExpandedKeys = ref<string[]>([]);
 | 
			
		||||
function caseFourCheckedKeysChange(checkedKeys: Array<string>) {
 | 
			
		||||
  caseFourCheckedKeys.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
function caseFourExpandKeysChange(expandKeys: Array<string>) {
 | 
			
		||||
  caseFourExpandedKeys.value = expandKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleLoad(node: TreeOption) {
 | 
			
		||||
  return new Promise<void>(resolve => {
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      node.children = [
 | 
			
		||||
        {
 | 
			
		||||
          label: nextLabel(node.label),
 | 
			
		||||
          key: node.key + nextLabel(node.label),
 | 
			
		||||
          isLeaf: false
 | 
			
		||||
        }
 | 
			
		||||
      ];
 | 
			
		||||
      resolve();
 | 
			
		||||
    }, 1000);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const { startLoading, endLoading, loading } = useLoading();
 | 
			
		||||
const caseFiveData = ref<TreeOption[]>();
 | 
			
		||||
const caseFiveCheckedKeys = ref<string[]>([]);
 | 
			
		||||
const caseFiveDefaultExpandedKeys = ref<string[]>(['20', '21']);
 | 
			
		||||
 | 
			
		||||
function caseFiveCheckedKeysChange(checkedKeys: Array<string>) {
 | 
			
		||||
  caseFiveCheckedKeys.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleInitData() {
 | 
			
		||||
  loadRemoteData().then(res => {
 | 
			
		||||
    caseFiveData.value = res as any;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadRemoteData() {
 | 
			
		||||
  startLoading();
 | 
			
		||||
  return new Promise<void>(resolve => {
 | 
			
		||||
    const tempData: any = createData();
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      endLoading();
 | 
			
		||||
      resolve(tempData);
 | 
			
		||||
    }, 1000);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const caseSixDefaultExpandedKeys = ref<string[]>(['20']);
 | 
			
		||||
 | 
			
		||||
const updatePrefixWithExpanded = (
 | 
			
		||||
  _keys: Array<string | number>,
 | 
			
		||||
  _option: Array<TreeOption | null>,
 | 
			
		||||
  meta: {
 | 
			
		||||
    node: TreeOption | null;
 | 
			
		||||
    action: 'expand' | 'collapse' | 'filter';
 | 
			
		||||
  }
 | 
			
		||||
) => {
 | 
			
		||||
  if (!meta.node) return;
 | 
			
		||||
  switch (meta.action) {
 | 
			
		||||
    case 'expand':
 | 
			
		||||
      meta.node.prefix = () =>
 | 
			
		||||
        h(NIcon, null, {
 | 
			
		||||
          default: () => <icon-ph-folder-open />
 | 
			
		||||
        });
 | 
			
		||||
      break;
 | 
			
		||||
    case 'collapse':
 | 
			
		||||
      meta.node.prefix = () =>
 | 
			
		||||
        h(NIcon, null, {
 | 
			
		||||
          default: () => <icon-ph-folder-fill />
 | 
			
		||||
        });
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
const nodeProps = ({ option }: { option: TreeOption }) => {
 | 
			
		||||
  return {
 | 
			
		||||
    onClick() {
 | 
			
		||||
      if (!option.children && !option.disabled) {
 | 
			
		||||
        window.$message?.info(`[Click] ${option.label}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const caseSevenData = [
 | 
			
		||||
  {
 | 
			
		||||
    key: '文件夹',
 | 
			
		||||
    label: '文件夹',
 | 
			
		||||
    prefix: () =>
 | 
			
		||||
      h(NIcon, null, {
 | 
			
		||||
        default: () => h(<icon-ph-folder-fill />)
 | 
			
		||||
      }),
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        key: '空的',
 | 
			
		||||
        label: '空的',
 | 
			
		||||
        disabled: true,
 | 
			
		||||
        prefix: () =>
 | 
			
		||||
          h(NIcon, null, {
 | 
			
		||||
            default: () => h(<icon-ph-folder-open />)
 | 
			
		||||
          })
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        key: '我的文件',
 | 
			
		||||
        label: '我的文件',
 | 
			
		||||
        prefix: () =>
 | 
			
		||||
          h(NIcon, null, {
 | 
			
		||||
            default: () => h(<icon-ph-folder-fill />)
 | 
			
		||||
          }),
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            label: 'template.txt',
 | 
			
		||||
            key: 'template.txt',
 | 
			
		||||
            prefix: () =>
 | 
			
		||||
              h(NIcon, null, {
 | 
			
		||||
                default: () => h(<icon-bi-filetype-txt />)
 | 
			
		||||
              })
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const caseSevenDefaultExpandedKeys = ref<string[]>(['文件夹', '我的文件']);
 | 
			
		||||
const caseEightDefaultExpandedKeys = ref<string[]>(['20']);
 | 
			
		||||
 | 
			
		||||
const renderSwitcherIconWithExpaned = ({ expanded }: { expanded: boolean }) =>
 | 
			
		||||
  h(NIcon, null, {
 | 
			
		||||
    default: () => h(expanded ? iconRender({ icon: 'solar:moon-broken' }) : iconRender({ icon: 'solar:sun-broken' }))
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
function createRemoteData() {
 | 
			
		||||
  return [
 | 
			
		||||
    {
 | 
			
		||||
      label: nextLabel(),
 | 
			
		||||
      key: 1,
 | 
			
		||||
      isLeaf: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      label: nextLabel(),
 | 
			
		||||
      key: 2,
 | 
			
		||||
      isLeaf: false
 | 
			
		||||
    }
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function nextLabel(currentLabel?: string): string {
 | 
			
		||||
  if (!currentLabel) return 'Out of Tao, One is born';
 | 
			
		||||
  if (currentLabel === 'Out of Tao, One is born') return 'Out of One, Two';
 | 
			
		||||
  if (currentLabel === 'Out of One, Two') return 'Out of Two, Three';
 | 
			
		||||
  if (currentLabel === 'Out of Two, Three') {
 | 
			
		||||
    return 'Out of Three, the created universe';
 | 
			
		||||
  }
 | 
			
		||||
  if (currentLabel === 'Out of Three, the created universe') {
 | 
			
		||||
    return 'Out of Tao, One is born';
 | 
			
		||||
  }
 | 
			
		||||
  return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const remoteData = ref(createRemoteData());
 | 
			
		||||
 | 
			
		||||
function createData(level = 2, baseKey = ''): TreeOption[] | undefined {
 | 
			
		||||
  if (!level) return undefined;
 | 
			
		||||
  return repeat(4 - level, undefined).map((_, index) => {
 | 
			
		||||
    const key = String(baseKey) + level + index;
 | 
			
		||||
    return {
 | 
			
		||||
      label: createLabel(level),
 | 
			
		||||
      key,
 | 
			
		||||
      children: createData(level - 1, key)
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createLabel(level: number): string {
 | 
			
		||||
  if (level === 2) return '道生一';
 | 
			
		||||
  if (level === 1) return '一生二';
 | 
			
		||||
  return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getAllKeys(data: TreeOption[] | undefined): string[] {
 | 
			
		||||
  const keys: string[] = [];
 | 
			
		||||
  if (data !== undefined) {
 | 
			
		||||
    data.forEach(item => {
 | 
			
		||||
      keys.push(item.key as string);
 | 
			
		||||
      if (item.children) {
 | 
			
		||||
        keys.push(...getAllKeys(item.children as TreeOption[]));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return keys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const data = ref(createData());
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
@@ -1,226 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * 可搜索树组件
 | 
			
		||||
 * @author: SonnyLeo
 | 
			
		||||
 * @since: 2023-03-30
 | 
			
		||||
 * index.vue
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <n-card title="自定义树" class="h-full shadow-sm rounded-16px">
 | 
			
		||||
      <n-grid :x-gap="20" :y-gap="20" cols="0 600:2 1000:3">
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="右侧自定义后缀图标" :segmented="segmented" class="shadow-sm rounded-16px">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="caseOneData"
 | 
			
		||||
              expand-on-click
 | 
			
		||||
              :selectable="false"
 | 
			
		||||
              :default-expanded-keys="caseOneDefaultExpandedKeys"
 | 
			
		||||
            /> </n-card
 | 
			
		||||
        ></n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="右键菜单" :segmented="segmented" class="shadow-sm rounded-16px">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              :default-expanded-keys="caseTwoDefaultExpandedKeys"
 | 
			
		||||
              :node-props="caseTwoNodeProps"
 | 
			
		||||
            />
 | 
			
		||||
            <n-dropdown
 | 
			
		||||
              trigger="manual"
 | 
			
		||||
              placement="bottom-start"
 | 
			
		||||
              :show="showDropdown"
 | 
			
		||||
              :options="options"
 | 
			
		||||
              :x="x"
 | 
			
		||||
              :y="y"
 | 
			
		||||
              @select="handleSelect"
 | 
			
		||||
              @clickoutside="handleClickOutside"
 | 
			
		||||
            /> </n-card
 | 
			
		||||
        ></n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="可搜索的树组件" class="shadow-sm rounded-16px">
 | 
			
		||||
            <n-space vertical :size="12">
 | 
			
		||||
              <n-input v-model:value="pattern" placeholder="搜索" />
 | 
			
		||||
              <n-switch v-model:value="showIrrelevantNodes">
 | 
			
		||||
                <template #checked> 展示搜索无关的节点 </template>
 | 
			
		||||
                <template #unchecked> 隐藏搜索无关的节点 </template>
 | 
			
		||||
              </n-switch>
 | 
			
		||||
              <n-tree :show-irrelevant-nodes="showIrrelevantNodes" :pattern="pattern" :data="data" block-line />
 | 
			
		||||
            </n-space>
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="自定义前缀和后缀" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="caseFourData"
 | 
			
		||||
              :default-expanded-keys="caseFourDefaultExpandedKeys"
 | 
			
		||||
              :selectable="false"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="批量渲染前缀和后缀" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <n-tree
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              :default-expanded-keys="caseFiveDefaultExpandedKeys"
 | 
			
		||||
              :render-prefix="renderPrefix"
 | 
			
		||||
              :render-label="renderLabel"
 | 
			
		||||
              :render-suffix="renderSuffix"
 | 
			
		||||
              :selectable="false"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
        <n-grid-item>
 | 
			
		||||
          <n-card title="滚动到指定节点" class="shadow-sm rounded-16px" :segmented="segmented">
 | 
			
		||||
            <template #header-extra>
 | 
			
		||||
              <n-button @click="handleCaseSixClick">滚动</n-button>
 | 
			
		||||
            </template>
 | 
			
		||||
            <n-tree
 | 
			
		||||
              ref="caseSixTreeRef"
 | 
			
		||||
              block-line
 | 
			
		||||
              :data="data"
 | 
			
		||||
              default-expand-all
 | 
			
		||||
              virtual-scroll
 | 
			
		||||
              style="height: 120px"
 | 
			
		||||
            />
 | 
			
		||||
          </n-card>
 | 
			
		||||
        </n-grid-item>
 | 
			
		||||
      </n-grid>
 | 
			
		||||
    </n-card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="tsx">
 | 
			
		||||
import { ref, h } from 'vue';
 | 
			
		||||
import type { TreeOption, DropdownOption, TreeInst } from 'naive-ui';
 | 
			
		||||
import { NSpace, NButton } from 'naive-ui';
 | 
			
		||||
import { repeat } from 'seemly';
 | 
			
		||||
import { useIconRender } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const { iconRender } = useIconRender();
 | 
			
		||||
const segmented = ref<boolean>(true);
 | 
			
		||||
 | 
			
		||||
/** 实例一相关 */
 | 
			
		||||
const caseOneData = ref<TreeOption[] | undefined>(createSuffixData());
 | 
			
		||||
const caseOneDefaultExpandedKeys = ref<string[]>([]);
 | 
			
		||||
 | 
			
		||||
/** 实例二相关 */
 | 
			
		||||
const caseTwoDefaultExpandedKeys = ref<string[]>(['20']);
 | 
			
		||||
const showDropdown = ref<boolean>(false);
 | 
			
		||||
const x = ref<number>(0);
 | 
			
		||||
const y = ref<number>(0);
 | 
			
		||||
const options = ref<DropdownOption[] | undefined>([
 | 
			
		||||
  { label: '编辑', key: 'edit', icon: iconRender({ icon: 'mdi:pencil', fontSize: 18 }) },
 | 
			
		||||
  { label: '删除', key: 'delete', icon: iconRender({ icon: 'mdi:trash-can-outline', fontSize: 18 }) }
 | 
			
		||||
]);
 | 
			
		||||
/** 右键单击事件 */
 | 
			
		||||
function handleClickOutside() {
 | 
			
		||||
  showDropdown.value = false;
 | 
			
		||||
}
 | 
			
		||||
/** 左键单击事件 */
 | 
			
		||||
function handleSelect(key: string | number, option: DropdownOption) {
 | 
			
		||||
  console.log(key, option);
 | 
			
		||||
  showDropdown.value = false;
 | 
			
		||||
}
 | 
			
		||||
/** 树节点绑定事件 */
 | 
			
		||||
function caseTwoNodeProps() {
 | 
			
		||||
  return {
 | 
			
		||||
    onContextmenu(e: MouseEvent): void {
 | 
			
		||||
      showDropdown.value = true;
 | 
			
		||||
      x.value = e.clientX;
 | 
			
		||||
      y.value = e.clientY;
 | 
			
		||||
      e.preventDefault();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 实例三相关 */
 | 
			
		||||
const pattern = ref<string>('');
 | 
			
		||||
const showIrrelevantNodes = ref(false);
 | 
			
		||||
 | 
			
		||||
/** 实例四相关 */
 | 
			
		||||
const caseFourData = ref<TreeOption[] | undefined>(createPrefixAndSuffixData());
 | 
			
		||||
const caseFourDefaultExpandedKeys = ref<string[]>(['20', '21']);
 | 
			
		||||
 | 
			
		||||
/** 实例五相关 */
 | 
			
		||||
const caseFiveDefaultExpandedKeys = ref<string[]>(['20', '21']);
 | 
			
		||||
 | 
			
		||||
function renderPrefix({ option }: { option: TreeOption }) {
 | 
			
		||||
  return h(NButton, { text: true, type: 'primary' }, { default: () => `Prefix-${option.level}` });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function renderLabel({ option }: { option: TreeOption }) {
 | 
			
		||||
  return `${option.label} :)`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function renderSuffix({ option }: { option: TreeOption }) {
 | 
			
		||||
  return h(NButton, { text: true, type: 'primary' }, { default: () => `Suffix-${option.level}` });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 实例六相关 */
 | 
			
		||||
const caseSixTreeRef = ref<TreeInst | null>(null);
 | 
			
		||||
function handleCaseSixClick() {
 | 
			
		||||
  caseSixTreeRef.value?.scrollTo({ key: '21' });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 模拟数据相关 */
 | 
			
		||||
function createPrefixAndSuffixData(level = 2, baseKey = ''): TreeOption[] | undefined {
 | 
			
		||||
  if (!level) return undefined;
 | 
			
		||||
  return repeat(4 - level, undefined).map((_, index) => {
 | 
			
		||||
    const key = String(baseKey) + level + index;
 | 
			
		||||
    return {
 | 
			
		||||
      label: createLabel(level),
 | 
			
		||||
      key,
 | 
			
		||||
      children: createPrefixAndSuffixData(level - 1, key),
 | 
			
		||||
      suffix: () => h(NButton, { text: true, type: 'primary' }, { default: () => 'Suffix' }),
 | 
			
		||||
      prefix: () => h(NButton, { text: true, type: 'primary' }, { default: () => 'Prefix' })
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createSuffixData(level = 2, baseKey = ''): TreeOption[] | undefined {
 | 
			
		||||
  if (!level) return undefined;
 | 
			
		||||
  return repeat(4 - level, undefined).map((_, index) => {
 | 
			
		||||
    const key = String(baseKey) + level + index;
 | 
			
		||||
    return {
 | 
			
		||||
      label: createLabel(level),
 | 
			
		||||
      key,
 | 
			
		||||
      children: createSuffixData(level - 1, key),
 | 
			
		||||
      suffix: () =>
 | 
			
		||||
        h(NSpace, { justify: 'space-evenly' }, () => [
 | 
			
		||||
          h(NButton, { text: true, class: 'pt-1.5' }, { default: () => <icon-mdi-plus class="text-18px" /> }),
 | 
			
		||||
          h(
 | 
			
		||||
            NButton,
 | 
			
		||||
            { text: true, class: 'pt-1.5' },
 | 
			
		||||
            { default: () => <icon-mdi-trash-can-outline class="text-18px" /> }
 | 
			
		||||
          )
 | 
			
		||||
        ])
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createData(level = 2, baseKey = ''): TreeOption[] | undefined {
 | 
			
		||||
  if (!level) return undefined;
 | 
			
		||||
  return repeat(4 - level, undefined).map((_, index) => {
 | 
			
		||||
    const key = String(baseKey) + level + index;
 | 
			
		||||
    return {
 | 
			
		||||
      label: createLabel(level),
 | 
			
		||||
      level,
 | 
			
		||||
      key,
 | 
			
		||||
      children: createData(level - 1, key)
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createLabel(level: number): string {
 | 
			
		||||
  if (level === 2) return '道生一';
 | 
			
		||||
  if (level === 1) return '一生二';
 | 
			
		||||
  return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const data = ref(createData());
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
@@ -1,245 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * 树的相关函数
 | 
			
		||||
 * @author: SonnyLeo
 | 
			
		||||
 * @since: 2023-03-30
 | 
			
		||||
 * index.vue
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <n-card class="h-full shadow-sm rounded-16px">
 | 
			
		||||
    <n-space :vertical="true">
 | 
			
		||||
      <n-card title="函数示例">
 | 
			
		||||
        <n-card>
 | 
			
		||||
          <template #header-extra>
 | 
			
		||||
            <n-space justify="space-around">
 | 
			
		||||
              <n-button dashed type="primary" @click="handleGenerateTreeData">重置数据</n-button>
 | 
			
		||||
              <n-button dashed type="warning" @click="handleNotSelectAll">清空选择</n-button>
 | 
			
		||||
            </n-space>
 | 
			
		||||
          </template>
 | 
			
		||||
          <n-grid :y-gap="20" cols="1 s:3 m:4 l:5 xl:6 2xl:7" responsive="screen">
 | 
			
		||||
            <n-grid-item><n-button @click="handleExpandAll">展开全部</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleCollapseAll">折叠全部</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleSelectAll">全选</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleNotSelectAll">全不选</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleSelectedSecondLevel">显示到第二级</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleSelectedThirdLevel">显示到第三级</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleSelectData">设置勾选节点</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleGetCheckedData">获取选中数据</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleGetIndeterminateData">获取半选数据</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleAddRootDOM">添加根节点</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleAddChildrenDOM">增加子节点</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleDeleteTreeNode">删除子节点</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleUpdateTreeNode">更新节点</n-button></n-grid-item>
 | 
			
		||||
            <n-grid-item><n-button @click="handleScrollTo">滚动至某节点</n-button></n-grid-item>
 | 
			
		||||
          </n-grid>
 | 
			
		||||
        </n-card>
 | 
			
		||||
      </n-card>
 | 
			
		||||
      <n-card title="结构预览" segmented>
 | 
			
		||||
        <template #header-extra>
 | 
			
		||||
          <n-space>
 | 
			
		||||
            <n-switch v-model:value="cascade" size="large">
 | 
			
		||||
              <template #checked-icon>
 | 
			
		||||
                <n-icon>
 | 
			
		||||
                  <icon-ic:round-arrow-circle-right color="#1890ff" />
 | 
			
		||||
                </n-icon>
 | 
			
		||||
              </template>
 | 
			
		||||
              <template #unchecked-icon>
 | 
			
		||||
                <n-icon>
 | 
			
		||||
                  <icon-ic:round-arrow-circle-left />
 | 
			
		||||
                </n-icon>
 | 
			
		||||
              </template>
 | 
			
		||||
            </n-switch>
 | 
			
		||||
 | 
			
		||||
            <n-button text>Cascade</n-button>
 | 
			
		||||
          </n-space>
 | 
			
		||||
        </template>
 | 
			
		||||
        <n-tree
 | 
			
		||||
          ref="treeRef"
 | 
			
		||||
          block-line
 | 
			
		||||
          :data="treeDataRef"
 | 
			
		||||
          checkable
 | 
			
		||||
          :selectable="true"
 | 
			
		||||
          :cascade="cascade"
 | 
			
		||||
          :checked-keys="checkedKeysRef"
 | 
			
		||||
          :expanded-keys="expandedKeysRef"
 | 
			
		||||
          :check-on-click="false"
 | 
			
		||||
          virtual-scroll
 | 
			
		||||
          style="height: 320px"
 | 
			
		||||
          @update-checked-keys="handleUpdateCheckedKeys"
 | 
			
		||||
          @update-expanded-keys="handleUpdateExpandedKeys"
 | 
			
		||||
        />
 | 
			
		||||
        <template #footer> 当前选中的数据是 {{ checkedKeysRef }} </template>
 | 
			
		||||
      </n-card>
 | 
			
		||||
    </n-space>
 | 
			
		||||
  </n-card>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, toRaw } from 'vue';
 | 
			
		||||
import type { TreeInst } from 'naive-ui';
 | 
			
		||||
import { repeat } from 'seemly';
 | 
			
		||||
 | 
			
		||||
type TreeNode = {
 | 
			
		||||
  label: string;
 | 
			
		||||
  level: number;
 | 
			
		||||
  key: string;
 | 
			
		||||
  children?: TreeNode[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cascade = ref<boolean>(true);
 | 
			
		||||
const checkedKeysRef = ref<string[]>([]);
 | 
			
		||||
const expandedKeysRef = ref<string[]>([]);
 | 
			
		||||
 | 
			
		||||
const treeRef = ref<TreeInst | null>();
 | 
			
		||||
const treeDataRef = ref(createData());
 | 
			
		||||
 | 
			
		||||
function handleExpandAll() {
 | 
			
		||||
  expandedKeysRef.value = getKeysByRange(toRaw(treeDataRef.value), 1, 4);
 | 
			
		||||
}
 | 
			
		||||
function handleCollapseAll() {
 | 
			
		||||
  expandedKeysRef.value = [];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleSelectAll() {
 | 
			
		||||
  checkedKeysRef.value = getKeysByRange(toRaw(treeDataRef.value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleNotSelectAll() {
 | 
			
		||||
  checkedKeysRef.value = [];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleSelectedSecondLevel() {
 | 
			
		||||
  expandedKeysRef.value = getKeysByRange(toRaw(treeDataRef.value), 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleSelectedThirdLevel() {
 | 
			
		||||
  expandedKeysRef.value = getKeysByRange(toRaw(treeDataRef.value), 3, 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleSelectData() {
 | 
			
		||||
  checkedKeysRef.value = ['40302010', '40302011'];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleGetCheckedData() {
 | 
			
		||||
  window.$message?.info('请打开浏览器控制台查看.');
 | 
			
		||||
  const checkedData = treeRef.value?.getCheckedData();
 | 
			
		||||
  console.log(checkedData!.keys, checkedData!.options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleGetIndeterminateData() {
 | 
			
		||||
  window.$message?.info('请打开浏览器控制台查看.');
 | 
			
		||||
  const checkedData = treeRef.value?.getIndeterminateData();
 | 
			
		||||
  console.log(checkedData!.keys, checkedData!.options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleAddRootDOM() {
 | 
			
		||||
  treeDataRef.value?.push({
 | 
			
		||||
    label: `根节点`,
 | 
			
		||||
    key: `${Date.now()}`,
 | 
			
		||||
    level: 4
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleAddChildrenDOM() {
 | 
			
		||||
  if (treeDataRef.value !== undefined) {
 | 
			
		||||
    treeDataRef.value[0].children?.push({
 | 
			
		||||
      label: `子节点`,
 | 
			
		||||
      key: `${Date.now()}`,
 | 
			
		||||
      level: 3
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleDeleteTreeNode() {
 | 
			
		||||
  if (treeDataRef.value !== undefined) {
 | 
			
		||||
    const treeDOM = treeDataRef.value[0];
 | 
			
		||||
    treeDOM.children = treeDOM.children?.filter(item => item.key !== '4031');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleUpdateTreeNode() {
 | 
			
		||||
  if (treeDataRef.value !== undefined) {
 | 
			
		||||
    treeDataRef.value[0]?.children?.forEach((item, index) => (item.label = `${item.label}-${index} 已更新`));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleScrollTo() {
 | 
			
		||||
  treeRef.value?.scrollTo({ key: '40302213' });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleUpdateCheckedKeys(checkedKeys: Array<string>) {
 | 
			
		||||
  checkedKeysRef.value = checkedKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleGenerateTreeData() {
 | 
			
		||||
  treeDataRef.value = createData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleUpdateExpandedKeys(expandedKeys: Array<string>) {
 | 
			
		||||
  expandedKeysRef.value = expandedKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createData(level = 4, baseKey = ''): TreeNode[] | undefined {
 | 
			
		||||
  if (!level) return undefined;
 | 
			
		||||
  return repeat(5 - level, undefined).map((_, index) => {
 | 
			
		||||
    const key = String(baseKey) + level + index;
 | 
			
		||||
    return {
 | 
			
		||||
      label: `${createLabel(level)} - ${index}`,
 | 
			
		||||
      level,
 | 
			
		||||
      key,
 | 
			
		||||
      children: createData(level - 1, key)
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createLabel(level: number): string {
 | 
			
		||||
  if (level === 4) return '第一层';
 | 
			
		||||
  if (level === 3) return '第二层';
 | 
			
		||||
  if (level === 2) return '第三层';
 | 
			
		||||
  if (level === 1) return '第四层';
 | 
			
		||||
  return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 根据传入的层级 level 对 data 进行筛选并返回节点的key数组
 | 
			
		||||
 * 包含三种情况:
 | 
			
		||||
 *  1. 传入 data 时, 返回所有节点的 key 数组
 | 
			
		||||
 *  2. 传入 data 和 任意 level (startLevel 或 endLevel) 时, 返回一级目录到该级目录的所有节点的 key 数组
 | 
			
		||||
 *  3. 传入 data 和 startLevel 和 endLevel 时, 返回指定 level 范围节点对应的 key 数组
 | 
			
		||||
 *
 | 
			
		||||
 *  注意: startLevel 必须小于 endLevel
 | 
			
		||||
 * @param data
 | 
			
		||||
 * @param startLevel
 | 
			
		||||
 * @param endLevel
 | 
			
		||||
 */
 | 
			
		||||
function getKeysByRange(data: TreeNode[] | undefined, startLevel?: number, endLevel?: number): string[] {
 | 
			
		||||
  const result: string[] = [];
 | 
			
		||||
 | 
			
		||||
  function traverseTree(treeData: TreeNode[]) {
 | 
			
		||||
    treeData.forEach(node => {
 | 
			
		||||
      if (startLevel === undefined && endLevel === undefined) {
 | 
			
		||||
        result.push(node.key);
 | 
			
		||||
      } else if (startLevel !== undefined && endLevel === undefined && node.level === startLevel) {
 | 
			
		||||
        result.push(node.key);
 | 
			
		||||
      } else if (
 | 
			
		||||
        startLevel !== undefined &&
 | 
			
		||||
        endLevel !== undefined &&
 | 
			
		||||
        node.level >= startLevel &&
 | 
			
		||||
        node.level <= endLevel
 | 
			
		||||
      ) {
 | 
			
		||||
        result.push(node.key);
 | 
			
		||||
      }
 | 
			
		||||
      if (node.children) {
 | 
			
		||||
        traverseTree(node.children);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (data) {
 | 
			
		||||
    traverseTree(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
@@ -16,9 +16,6 @@ export const views: Record<
 | 
			
		||||
  component_button: () => import('./component/button/index.vue'),
 | 
			
		||||
  component_card: () => import('./component/card/index.vue'),
 | 
			
		||||
  component_table: () => import('./component/table/index.vue'),
 | 
			
		||||
  'component_tree_tree-basic': () => import('./component/tree/tree-basic/index.vue'),
 | 
			
		||||
  'component_tree_tree-custom': () => import('./component/tree/tree-custom/index.vue'),
 | 
			
		||||
  'component_tree_tree-functions': () => import('./component/tree/tree-functions/index.vue'),
 | 
			
		||||
  dashboard_analysis: () => import('./dashboard/analysis/index.vue'),
 | 
			
		||||
  dashboard_workbench: () => import('./dashboard/workbench/index.vue'),
 | 
			
		||||
  document_naive: () => import('./document/naive/index.vue'),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user