0.1.0 • Published 14 days ago

@pluve/lego-tree-vue v0.1.0

Weekly downloads
-
License
MIT
Repository
-
Last release
14 days ago

@pluve/lego-tree-vue

乐高系列之 tree 组件系列,属于强业务组件。

npm (scoped)

@pluve/lego-tree-vue 一期二期规划的功能已上线,目前已在【营销工具 - 一元券】等项目中使用。

安装

# 依赖 vue@3.x/ant-design-vue@3.x/@ant-design/icons-vue@6.x/@pluve/lego-excel-vue@*
yarn add @pluve/lego-tree-vue

公共类型 LegoTreeTypes

LegoTreeTypes.OrgTreeJsonFromEnum

组织机构树 orgTree.json 来源枚举。当走 SSO 方式时,不区分全量 或者 有效 的数据源

export enum OrgTreeJsonFromEnum {
  SSO = 'sso', // SSO(默认,不区分全量 or 有效)
  USER = 'user', // 账号中心
}

LegoTreeTypes.OrgTreeJsonTypeEnum

组织机构树 json 类型:全量(包含已关停等) or 有效的,提供枚举。

export enum OrgTreeJsonTypeEnum {
  ALL = 'all', // 全量的数据
  ENABLE = 'enable', // 有效的数据(默认)
}

LegoTreeTypes.CommonHierarchyEnum

组织机构树原始树结构返回的 hierarchy 字段枚举。

export enum CommonHierarchyEnum {
  COMPANY = '01', // 公司
  CENTER = '02', // 中心
  OPERATING_AREA = '03', // 营运区
  DEPARTMENT = '04', // 部门
  GROUP = '05', // 组
  AREA = '06', // 片区
  STORE = '07', // 门店
}

LegoTreeTypes.IOriginTreeNode

接口返回的原始节点信息,除 [key: string] 外,其他字段都为 通用组织机构树接口 返回的字段。

参数说明类型是否可选
code节点编码string
hierarchy(SSO)组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);string
rank(账号中心)组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);LegoTreeTypes.CommonHierarchyEnum
id唯一 keystring
name名称string
parentId父 idstring
storeCode门店编码string
disabled是否节点禁用boolean
selectable【单选】节点是否可以选择boolean
sub(SSO)子节点LegoTreeTypes.IOriginTreeNode[]
children(账号中心)子节点LegoTreeTypes.IOriginTreeNode[]
[key: string]其他字段,用于匹配非组织机构树接口的返回字段any

LegoTreeTypes.ITreeNodesType

接口返回数据转化后的节点信息,必须按照如下类型来传输。

参数说明类型是否可选
key唯一 key。走默认数据源取数逻辑 && 账号中心全量数据时,key 取值方式:code_storeCode;走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,key 取值方式:code/storeCode;string
value唯一 keyLegoTreeSelect 组件使用。走默认数据源取数逻辑 && 账号中心全量数据时,value 取值方式:code_storeCode;走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,value 取值方式:code/storeCode;string
title节点名称string
hierarchy组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);若接口返回该字段为空,则组件内部处理为从1开始往下叠加string
code原始 codestring
storeCode原始 storeCode,门店节点时才存在该字段string
pid上一节点的 'code' 字段string
trace父子节点路径,includeAreatrue 时,该字段必须有值string
disabled是否节点禁止操作boolean
selectable【单选】节点是否可以选择boolean
children子节点LegoTreeTypes.ITreeNodesType[]
originNode原始树节点信息,keepOriginNode 开启后 该对象不为 undefined,且在 includeAreatruelabelInValuetrue 时返回给调用方LegoTreeTypes.IOriginTreeNode

LegoTreeTypes.ICheckedAreaItem

可选择父子层级的选中项节点信息

参数说明类型是否可选
key唯一 key。走默认数据源取数逻辑 && 账号中心全量数据时,key 取值方式:code_storeCode;走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,key 取值方式:code/storeCode;string
title节点名称string
hierarchy组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);若接口返回该字段为空,则组件内部处理为从1开始往下叠加string
code原始 codestring
storeCode原始 storeCode,门店节点时才存在该字段string
originNode原始树节点信息,keepOriginNode 开启后 该对象不为 undefined,且在 includeAreatrue时返回给调用方LegoTreeTypes.IOriginTreeNode

LegoTreeTypes.ITreeSelectLabelInValue

LegoTreeSelect 组件 开启 labelInValue 时的 value 类型,即 当前节点的信息 & antd TreeSelect 组件返回的当前节点的信息的并集

export interface ITreeSelectLabelInValue extends Partial<LegoTreeTypes.ITreeNodesType> {
  /**
   * @description 走默认数据源取数逻辑 && 账号中心全量数据时,value 取值方式:code_storeCode
   * 走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,value 取值方式:code/storeCode
   * @author yangwen
   * @type {string}
   * @memberof ITreeSelectLabelInValue
   */
  value: string;
  label?: string;
  disabled?: boolean;
}
参数说明类型是否可选
value唯一 keyLegoTreeSelect 组件使用。走默认数据源取数逻辑 && 账号中心全量数据时,value 取值方式:code_storeCode;走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,value 取值方式:code/storeCode;string
label节点名称,与 title 字段取值一致string
disabled是否节点禁止操作boolean

树数据源处理

优先级:treeData > request > orgTree.json

1. treeData

若传值 treeData 不为 undefined,则组件认定是调用方需要自定义数据源,则完全信任调用方传入的数据源,组件内部不对 treeData 做处理。 同时接收 loading 字段 和 dataListMap 字段,作为加载数据源的 加载状态扁平化的数据源。 此时需要区分 2 种情况:

  1. dataListMap 为空对象:则调用 LegoTreeUtils.generateListMap 方法来生成 扁平化数据源 dataListMap 并存储在组件内部,同时给 treeData 子节点增加 trace 字段用作记录父子节点的路径。

  2. dataListMap 不为空对象:则默认调用方已经扁平化了数据源 且给子节点增加了 trace 字段,直接存储在组件内部即可。

注意:

  • trace 字段主要用于组织机构树可以选择任意节点的场景,需要通过 trace 字段来判定父子节点间的关系。如果只需要选择子节点,则可以忽略所有针对 trace 字段的要求。
  • treeData 里面每个节点的 originNode 字段需要自行处理includeAreatruelabelInValuetrue 时,若开启 keepOriginNode,则 返回的值里面会增加 originNode 字段。

2. request

若传值 treeDataundefined,且 request 不为 undefined,则组件认定是调用方需要通过自定义服务来自定义数据源,则完全信任调用方传入自定义服务,组件内部执行调用服务逻辑。 获取数据源后,通过调用 LegoTreeUtils.generateListMap 方法来生成 扁平化数据源 dataListMap 并存储在组件内部,同时给 treeData 子节点增加 trace 字段用作记录父子节点的路径。

注意:

  • trace 字段主要用于组织机构树可以选择任意节点的场景,需要通过 trace 字段来判定父子节点间的关系。如果只需要选择子节点,则可以忽略所有针对 trace 字段的要求。
  • treeData 里面每个节点的 originNode 字段需要自行处理includeAreatruelabelInValuetrue 时,若开启 keepOriginNode,则 返回的值里面会增加 originNode 字段。

3. orgTree.json

若上述 2 个字段都为 undefined,则组件认定调用方没有自定义的需求,则直接走组件默认的数据源取数逻辑:

  1. 根据 envType 字段区分走测试还是生产环境的接口调用——注意:此时获取到的数据没有做任何权限处理
  2. 根据 jsonFrom 字段区分走 SSO 还是走账号中心——注意:SSO 只返回有效的数据源,不包含已关停数据,如需已关停数据,请走账号中心
  3. 根据 jsonType 字段区分返回全量(包含已关停等)还是有效的数据源,获取全部的组织机构树的数据源
  4. 根据 hierarchyList 字段过滤不包含的节点信息,传空或不传则默认取全量数据源
  5. 调用 LegoTreeUtils.recursionTreeData 方法对数据源做处理,转化为 Tree/TreeSelect 组件需要的数据源
  6. 根据 selectHierarchy 字段过滤子节点不包含 selectHierarchy 层级的节点。例如,不包含门店节点的父节点全部过滤掉不展示,则 selectHierarchy 为 '07'。
  7. 调用 LegoTreeUtils.generateListMap 方法来生成 扁平化数据源 dataListMap 并存储在组件内部,同时给 treeData 子节点增加 trace 字段用作记录父子节点的路径,并更新 treeData 且展示在树上。

相关源码

const loadOrgTreeNodeByLevel = async () => {
  if (state.loading) {
    return;
  }

  state.loading = true;

  // 此处 使用 toRaw 针对 props.treeData/props.dataListMap(响应式对象) 做转化
  if (Object.prototype.toString.call(props.treeData) === '[object Array]') {
    // 此处需要确保传的 treeData 已经做了数据处理且包含 trace 字段
    state.treeData = toRaw(props.treeData || []);
    // dataListMap 有值则直接取
    if (Object.values(toRaw(props.dataListMap || {})).length) {
      // 此处需要确保传的 dataListMap 已经做了数据处理
      state.dataListMap = toRaw(props.dataListMap || {});
    } else {
      // dataListMap 没有值则计算再赋值
      const { dataList, dataListMap } = LegoTreeUtils.generateListMap(
        toRaw(props.treeData || [])
      );
      // 此时 treeData 增加了 trace 字段
      state.treeData = dataList;
      state.dataListMap = dataListMap;
    }

    state.loading = false;
    // 接口请求成功后,往外触发 getTreeInfo 事件,获取树相关数据
    emit('getTreeInfo', {
      treeData: toRaw(state.treeData),
      dataListMap: toRaw(state.dataListMap),
    });
    return;
  }

  LegoTreeUtils.loadOrgTreeNodeByLevel(
    {
      request: props.request,
      selectHierarchy: props.selectHierarchy,
      envType: props.envType,
      jsonFrom: props.jsonFrom,
      jsonType: props.jsonType,
      hierarchyList: props.hierarchyList,
      keepOriginNode: props.keepOriginNode ?? false,
    },
    (dataList, dataListMap) => {
      state.treeData = dataList;
      state.dataListMap = dataListMap;
      state.loading = false;
      // 接口请求成功后,往外触发 getTreeInfo 事件,获取树相关数据
      emit('getTreeInfo', {
        treeData: dataList,
        dataListMap: dataListMap,
      });
    }
  );
};
const loadOrgTreeNodeByLevel = async (
  {
    request,
    selectHierarchy = '',
    envType = 'test',
    jsonFrom = LegoTreeTypes.OrgTreeJsonFromEnum.SSO,
    jsonType = LegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE,
    hierarchyList = [],
    enableSelectedHierarchy = [],
    keepOriginNode = false,
  }: {
    request?: () => Promise<LegoTreeTypes.ITreeNodesType[]>; // 自定义 request 接口请求
    selectHierarchy?: string; // 选择的组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);
    envType?: 'test' | 'prod'; // 环境(测试 | 生产)
    jsonFrom?: LegoTreeTypes.OrgTreeJsonFromEnum; // 组织机构树 orgTree.json 来源
    jsonType?: LegoTreeTypes.OrgTreeJsonTypeEnum; // 组织机构树 json 类型:全量(包含已关停等) or 有效的
    hierarchyList?: string[]; // 组织机构级别数组,默认全部
    enableSelectedHierarchy?: string[]; // 【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择
    keepOriginNode?: boolean; // 是否树节点保留原始对象信息
  },
  callback: (
    treeData: LegoTreeTypes.ITreeNodesType[],
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>
  ) => void
) => {
  try {
    let newTreeData: LegoTreeTypes.ITreeNodesType[] = [];
    // 直接传接口进来,则直接调接口,接口中已经对数据做了处理
    if (typeof request !== 'undefined') {
      newTreeData = await request();
    } else {
      // 否则走默认接口,组件中做处理
      const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
        hierarchyList,
        envType,
        jsonFrom,
        jsonType,
      });
      // 将接口返回的数据结构转化为 TreeSelect/Tree 组件需要的数据结构
      newTreeData = LegoTreeUtils.recursionTreeData({
        list:
          result?.[0][jsonFrom === LegoTreeTypes.OrgTreeJsonFromEnum.SSO ? 'sub' : 'children'] ||
          [],
        childrenKey: jsonFrom === LegoTreeTypes.OrgTreeJsonFromEnum.SSO ? 'sub' : 'children',
        hierarchyKey: jsonFrom === LegoTreeTypes.OrgTreeJsonFromEnum.SSO ? 'hierarchy' : 'rank',
        pid: undefined,
        enableSelectedHierarchy, // 【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择
        keepOriginNode,
        includeDisabledData: LegoTreeUtils.isAllIncludeDisabledData({ jsonFrom, jsonType }),
      });
      // 过滤树底层没有 selectHierarchy 的节点
      LegoTreeUtils.excludeNode(newTreeData, selectHierarchy);
    }

    const { dataList, dataListMap } = LegoTreeUtils.generateListMap(newTreeData);
    callback(dataList, dataListMap);
  } catch (error) {
    callback([], {});
  }
};

LegoTreeSelect

通常用于单选组织架构,例如选择门店、公司、各组织机构等。props 继承自 antd vue TreeSelectProps

export interface ILegoTreeSelectProps
  extends Omit<
    TreeSelectProps,
    | 'defaultValue'
    | 'fieldNames'
    | 'multiple'
    | 'replaceFields'
    | 'searchValue'
    | 'showSearch'
    | 'treeCheckable'
    | 'treeCheckStrictly'
    | 'treeData'
    | 'treeDataSimpleMode'
    | 'virtual'
    | 'onSearch'
    | 'loading'
    | 'value'
    | 'onChange'
  > {
  envType?: 'test' | 'prod';
  jsonFrom?: OrgTreeJsonFromEnum;
  jsonType?: OrgTreeJsonTypeEnum;
  hierarchyList?: string[];
  selectHierarchy?: string;
  enableSelectedHierarchy?: string[];

  treeData?: LegoTreeTypes.ITreeNodesType[];
  loading?: boolean;
  dataListMap?: Record<string, LegoTreeTypes.ITreeNodesType>;
  request?: () => Promise<LegoTreeTypes.ITreeNodesType[]>;

  defaultValue?: string | LegoTreeTypes.ITreeSelectLabelInValue;
  value?: string | LegoTreeTypes.ITreeSelectLabelInValue;

  keepOriginNode?: boolean;
}

API

参数说明类型是否可选默认值
envType环境(测试 | 生产)。走组件默认接口请求时使用,其余场景无需传该字段test \| prodtest
jsonFrom组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonFromEnumLegoTreeTypes.OrgTreeJsonFromEnum.SSO
jsonType组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonTypeEnumLegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE
hierarchyList组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段string[]-
selectHierarchy选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段string-
enableSelectedHierarchy【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择,否则 selectablefalse 不可选择string[][]
treeDataantd vue TreeSelect 组件数据源(已经经过转化后的数据源)LegoTreeTypes.ITreeNodesType[]-
loading外部数据源加载时的 loading 状态booleanfalse
dataListMap扁平化 Map(已经经过转化后的数据源生成的 map)Record<string, LegoTreeTypes.ITreeNodesType>{}
request自定义服务,用于获取组件树数据源() => Promise<LegoTreeTypes.ITreeNodesType[]>-
defaultValue默认选中的值string \| LegoTreeTypes.ITreeSelectLabelInValue-
value(v-model)当前选中的值string \| LegoTreeTypes.ITreeSelectLabelInValue-
keepOriginNode是否树节点保留原始对象信息。若开启,配合 labelInValue 字段为 true,则会返回 originNode(原始对象信息)booleanfalse
title自定义标题,在原始基础上,增加当前搜索值 searchValue 字段,供自定义判断处理slot({ key, title, ..., searchValue })-

事件(emit)

事件名称说明回调参数
change选中树节点时调用此函数function(string \| LegoTreeTypes.ITreeSelectLabelInValue)
getTreeInfo接口请求完成后,调用此函数,返回当前组件内部的树数据源function({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; })

ref

通过 ref 获取组件提供的方法或属性。以下是提供的方法或属性: | 方法/属性名称 | 说明 | 类型 | | --- | --- | --- | | getTreeInfo | 【方法】提供组件内部的树数据源 | () => ({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; }) |

效果展示

测试环境地址:https://yf-test-oss.yifengx.com/webtest/yangwen/legoTree/index.html#/treeSelect

使用示例

<template>
  <ConfigProvider :locale="zh_CN">
    <div :class="$style.wrap">
      <Form :colon="false" autocomplete="off">
        <Row :gutter="20">
          <!-- 有效数据源 -->
          <Col :span="12">
            <FormItem label="labelInValue true" v-bind="form.validateInfos.rangeCodeObj">
              <LegoTreeSelect
                :hierarchyList="['01', '02', '03', '04', '06', '07']"
                selectHierarchy="07"
                :enable-selected-hierarchy="['01', '07']"
                v-model:value="modelRef.rangeCodeObj"
                :labelInValue="true"
                :default-value="{ value: 'H535' }"
                :keep-origin-node="true"
                ref="treeRef"
                @get-tree-info="getTreeInfo"
              >
                <template #title="{ value: val, title, label, storeCode }">
                  <b v-if="val === '5024'" style="color: #08c">{{ title || label }}</b>
                  <b v-else-if="storeCode === '5500'" style="color: #f90">{{ title || label }}</b>
                  <template v-else>{{ title || label }}</template>
                </template>
              </LegoTreeSelect>
            </FormItem>
          </Col>
          <Col :span="12">
            <FormItem label="labelInValue false" v-bind="form.validateInfos.rangeCode">
              <LegoTreeSelect
                :treeData="state.treeData"
                :loading="state.loading"
                v-model:value="modelRef.rangeCode"
                :labelInValue="false"
              ></LegoTreeSelect>
            </FormItem>
          </Col>

          <!-- 账号中心 && 全部数据源(包含已关停) -->
          <Col :span="24" style="font-weight: bold; color: red; margin-bottom: 24px">
            以下数据源为账号中心全量数据源(包含已关停数据):
          </Col>
          <Col :span="12">
            <FormItem label="labelInValue true" v-bind="form.validateInfos.rangeCodeObjAll">
              <LegoTreeSelect
                :json-from="LegoTreeTypes.OrgTreeJsonFromEnum.USER"
                :json-type="LegoTreeTypes.OrgTreeJsonTypeEnum.ALL"
                :hierarchyList="['01', '02', '03', '04', '06', '07']"
                selectHierarchy="07"
                :enable-selected-hierarchy="['01', '07']"
                v-model:value="modelRef.rangeCodeObjAll"
                :labelInValue="true"
                :default-value="{ value: '10025961_H535' }"
                :keep-origin-node="true"
                ref="treeRefAll"
                @get-tree-info="getTreeInfoAll"
              >
                <template #title="{ value: val, title, label, storeCode }">
                  <b v-if="val === '10004575_5024'" style="color: #08c">{{ title || label }}</b>
                  <b v-else-if="storeCode === '5500'" style="color: #f90">{{ title || label }}</b>
                  <template v-else>{{ title || label }}</template>
                </template>
              </LegoTreeSelect>
            </FormItem>
          </Col>
          <Col :span="12">
            <FormItem label="labelInValue false" v-bind="form.validateInfos.rangeCodeAll">
              <LegoTreeSelect
                :treeData="state.treeDataAll"
                :loading="state.loadingAll"
                v-model:value="modelRef.rangeCodeAll"
                :labelInValue="false"
              ></LegoTreeSelect>
            </FormItem>
          </Col>
          <Col :span="6">
            <Button @click="onQuery" style="margin-left: 10px" type="primary">查询</Button>
          </Col>
        </Row>
      </Form>
    </div>
  </ConfigProvider>
</template>

<script setup lang="ts">
import zh_CN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import type { Rule } from 'ant-design-vue/es/form';
import { ConfigProvider, Form, FormItem, Row, Col, Button } from 'ant-design-vue';
import { reactive, onMounted, ref } from 'vue';
import { LegoTreeSelect, LegoTreeUtils, LegoTreeTypes, LegoTreeServices } from '@pluve/lego-tree-vue';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');

const treeRef = ref();
const treeRefAll = ref();

// 查询条件 ref
const modelRef = reactive<{
  rangeCodeObj?: LegoTreeTypes.ITreeSelectLabelInValue;
  rangeCodeObjAll?: LegoTreeTypes.ITreeSelectLabelInValue;
  rangeCode?: string;
  rangeCodeAll?: string;
}>({
  rangeCodeObj: undefined,
  rangeCodeObjAll: undefined,
  rangeCode: '5024',
  rangeCodeAll: '10004575_5024', // 全量数据源时:需要使用 code_storeCode 格式
});

const rulesRef: Record<string, Rule[]> = reactive({
  rangeCodeObj: [
    {
      required: true,
      validator: (_rule: Rule, value?: LegoTreeTypes.ITreeSelectLabelInValue) => {
        if (!value) {
          return Promise.reject(new Error('请选择'));
        }
        return Promise.resolve();
      },
    },
  ],
  rangeCodeObjAll: [
    {
      required: false,
    },
  ],
  rangeCode: [
    {
      required: false,
    },
  ],
  rangeCodeAll: [
    {
      required: true,
      validator: (_rule: Rule, value?: string) => {
        if (!value) {
          return Promise.reject(new Error('请选择'));
        }
        return Promise.resolve();
      },
    },
  ],
});

// 查询条件 form
const form = Form.useForm(modelRef, rulesRef);

const state = reactive<{
  treeData: LegoTreeTypes.ITreeNodesType[];
  treeDataAll: LegoTreeTypes.ITreeNodesType[];
  loading: boolean;
  loadingAll: boolean;
}>({
  treeData: [],
  treeDataAll: [],
  loading: false,
  loadingAll: false,
});

// 获取 SSO 有效数据源
const loadOrgTreeNodeByLevel = async () => {
  state.loading = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].sub || [],
      pid: undefined,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeData = newTreeData;
  } catch (error) {
    state.treeData = [];
  } finally {
    state.loading = false;
  }
};

// 获取账号中心全量数据源
const loadOrgTreeNodeByLevelAll = async () => {
  state.loadingAll = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
      jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
      jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].children || [],
      pid: undefined,
      childrenKey: 'children',
      hierarchyKey: 'rank',
      includeDisabledData: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeDataAll = newTreeData;
  } catch (error) {
    state.treeDataAll = [];
  } finally {
    state.loadingAll = false;
  }
};

onMounted(() => {
  loadOrgTreeNodeByLevel();
  loadOrgTreeNodeByLevelAll();
});

const onQuery = () => {
  console.log('treeRef.value', treeRef.value?.getTreeInfo());
  console.log('treeRefAll.value', treeRefAll.value?.getTreeInfo());

  form
    .validate()
    .then(() => {
      console.log('查询条件:', modelRef);
    })
    .catch((err) => {
      console.log('err->', err);
    });
};

// 接口请求成功后返回对应的树数据
const getTreeInfo = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfo', { treeData, dataListMap });
};

// 接口请求成功后返回对应的树数据
const getTreeInfoAll = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfoAll', { treeData, dataListMap });
};
</script>

<style lang="less" module>
.wrap {
  position: relative;
  background-color: #fff;
  padding: 40px 80px;
  border-radius: 4px;
}
</style>

LegoLeftTree

通常用于页面左右侧布局,左侧展示组织机构树,右侧展示业务内容。左侧操作后右侧同步更新。

export interface ILegoLeftTreeProps
  extends Omit<
    TreeProps,
    | 'blockNode'
    | 'fieldNames'
    | 'multiple'
    | 'treeData'
    | 'virtual'
    | 'checkable'
    | 'selectable'
    | 'checkedKeys'
    | 'selectedKeys'
    | 'autoExpandParent'
    | 'expandedKeys'
    | 'height'
  > {
  envType?: 'test' | 'prod';
  jsonFrom?: OrgTreeJsonFromEnum;
  jsonType?: OrgTreeJsonTypeEnum;
  hierarchyList?: string[];
  selectHierarchy?: string;
  enableSelectedHierarchy?: string[];

  treeData?: LegoTreeTypes.ITreeNodesType[];
  loading?: boolean;
  dataListMap?: Record<string, LegoTreeTypes.ITreeNodesType>;
  request?: () => Promise<LegoTreeTypes.ITreeNodesType[]>;

  value?: string | string[] | LegoTreeTypes.ICheckedAreaItem[];
  headerTitle?: string;
  placeholder?: string;
  disabled?: boolean;
  selectType?: 'single' | 'multiple';
  includeArea?: boolean;
  width?: number | string;
  virtualHeight?: number;
  showSwitch?: boolean;
  defaultIsShow?: boolean;

  keepOriginNode?: boolean;
}

API

参数说明类型是否可选默认值
envType环境(测试 | 生产)。走组件默认接口请求时使用,其余场景无需传该字段test \| prodtest
jsonFrom组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonFromEnumLegoTreeTypes.OrgTreeJsonFromEnum.SSO
jsonType组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonTypeEnumLegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE
hierarchyList组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段string[]-
selectHierarchy选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段string-
enableSelectedHierarchy【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择,否则 selectablefalse 不可选择string[][]
treeDataantd vue TreeSelect 组件数据源(已经经过转化后的数据源)LegoTreeTypes.ITreeNodesType[]-
loading外部数据源加载时的 loading 状态booleanfalse
dataListMap扁平化 Map(已经经过转化后的数据源生成的 map)Record<string, LegoTreeTypes.ITreeNodesType>{}
request自定义服务,用于获取组件树数据源() => Promise<LegoTreeTypes.ITreeNodesType[]>-
value(v-model)当前选中的值,区分单选、多选门店、多选节点三种类型string \| string[] \| LegoTreeTypes.ICheckedAreaItem[]-
headerTitle头部标题文案string选择门店
placeholderInput.Search 输入框 placeholderstring搜索门店名称或编码
disabledtree 选择是否禁用booleanfalse
selectType选择类型:单选/多选single \| multiple'single'
includeArea【多选】是否包含区域选择,即是否允许选择各层级父子节点booleanfalse
width组件宽度string \| number280
virtualHeight组件 Tree 虚拟滚动高度number820
showSwitch是否展示 展开收起功能 开关booleantrue
defaultIsShow默认是否处于展开状态booleantrue
keepOriginNode是否树节点保留原始对象信息。若开启,配合 includeAreatrue,则会返回 originNode(原始对象信息)booleanfalse
title自定义标题,在原始基础上,增加当前搜索值 searchValue 字段,供自定义判断处理slot({ key, title, ..., searchValue })-

事件(emit)

事件名称说明回调参数
change选中/反选树节点时调用此函数function(string \| string[] \| LegoTreeTypes.ICheckedAreaItem[])
switch展开/收起按钮切换时调用此函数function(boolean)
checkBeforeTree onCheck 触发时优先调用此函数,此函数第三个参数返回 组件内部的树数据源function(checked: Key[] \| { checked: Key[]; halfChecked: Key[]; }, info: CheckInfo, treeInfo: { treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType> })
getTreeInfo接口请求完成后,调用此函数,返回当前组件内部的树数据源function({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; })

ref

通过 ref 获取组件提供的方法或属性。以下是提供的方法或属性: | 方法/属性名称 | 说明 | 类型 | | --- | --- | --- | | getTreeInfo | 【方法】提供组件内部的树数据源 | () => ({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; }) |

效果展示

测试环境地址:https://yf-test-oss.yifengx.com/webtest/yangwen/legoTree/index.html#/leftTree

使用示例

<template>
  <div :class="$style.top">
    <RadioGroup v-model:value="state.dataType">
      <Radio value="all">全量(包含已关停)</Radio>
      <Radio value="enable">有效</Radio>
    </RadioGroup>
    <Button type="primary" size="small" @click="getTreeInfoWithRef" style="margin-left: 50px">
      点我获取tree数据源
    </Button>
  </div>

  <!-- 有效数据源 -->
  <div :class="$style.wrap" :style="{ display: state.dataType === 'all' ? 'none' : 'flex' }">
    <LegoLeftTree
      env-type="prod"
      :hierarchyList="['01', '02', '03', '04', '06', '07']"
      selectHierarchy="07"
      :enable-selected-hierarchy="['01', '07']"
      header-title="选择范围"
      placeholder="搜索范围名称或编码"
      v-model:value="state.storeCode"
      :show-switch="false"
      ref="treeRef"
      @get-tree-info="getTreeInfo"
      @change="(val) => onChange1(val)"
    >
      <template #title="{ value: val, title, label }">
        <div>
          <span style="margin-right: 10px">{{ title || label }}</span>
          <exclamation-circle-outlined @click="onIconClick1(val)" />
        </div>
      </template>
    </LegoLeftTree>

    <div style="margin-left: 20px; width: auto; height: 100%">
      <LegoLeftTree
        :request="customRequest"
        v-model:value="state.storeCodes"
        header-title="选择渠道"
        placeholder="搜索渠道名称或编码"
        select-type="multiple"
        width="300px"
        :default-is-show="true"
        @switch="onSwitch2"
        @change="(val) => onChange2(val)"
      >
        <template #title="{ value: val, title, label, searchValue }">
          <div>
            <span
              style="margin-right: 10px"
              :style="{ color: searchValue === val ? 'red' : '#222222' }"
            >
              {{ title || label }}
            </span>
            <up-circle-outlined @click="onIconClick2(val)" />
          </div>
        </template>
      </LegoLeftTree>
    </div>

    <div style="margin-left: 20px; width: auto; height: 100%">
      <LegoLeftTree
        :treeData="state.treeData"
        :loading="state.loading"
        v-model:value="state.storeNodes"
        header-title="选择组织机构"
        select-type="multiple"
        include-area
        :virtual-height="600"
        :default-is-show="false"
        :keep-origin-node="true"
        @switch="onSwitch3"
        @change="(val) => onChange3(val)"
        @check-before="onCheckBefore"
      />
    </div>

    <div :class="$style.right">我是右侧业务内容</div>
  </div>

  <!-- 账号中心 && 全部数据源(包含已关停) -->
  <div :class="$style.wrap" :style="{ display: state.dataType === 'all' ? 'flex' : 'none' }">
    <LegoLeftTree
      :json-from="LegoTreeTypes.OrgTreeJsonFromEnum.USER"
      :json-type="LegoTreeTypes.OrgTreeJsonTypeEnum.ALL"
      env-type="test"
      :hierarchyList="['01', '02', '03', '04', '06', '07']"
      selectHierarchy="07"
      :enable-selected-hierarchy="['01', '07']"
      header-title="选择范围"
      placeholder="搜索范围名称或编码"
      v-model:value="state.storeCodeAll"
      :show-switch="false"
      ref="treeRefAll"
      @get-tree-info="getTreeInfoAll"
      @change="(val) => onChange1(val)"
    >
      <template #title="{ value: val, title, label }">
        <div>
          <span style="margin-right: 10px">{{ title || label }}</span>
          <exclamation-circle-outlined @click="onIconClick1(val)" />
        </div>
      </template>
    </LegoLeftTree>

    <div style="margin-left: 20px; width: auto; height: 100%">
      <LegoLeftTree
        :treeData="state.treeDataAll"
        :loading="state.loadingAll"
        v-model:value="state.storeCodesAll"
        header-title="选择渠道"
        placeholder="搜索渠道名称或编码"
        select-type="multiple"
        width="300px"
        :default-is-show="true"
        @switch="onSwitch2"
        @change="(val) => onChange2(val)"
      >
        <template #title="{ value: val, title, label, searchValue }">
          <div>
            <span
              style="margin-right: 10px"
              :style="{ color: searchValue === LegoTreeUtils.getRealKey(val) ? 'red' : '#222222' }"
            >
              {{ title || label }}
            </span>
            <up-circle-outlined @click="onIconClick2(val)" />
          </div>
        </template>
      </LegoLeftTree>
    </div>

    <div style="margin-left: 20px; width: auto; height: 100%">
      <LegoLeftTree
        :treeData="state.treeDataAll"
        :loading="state.loadingAll"
        v-model:value="state.storeNodesAll"
        header-title="选择组织机构"
        select-type="multiple"
        include-area
        :virtual-height="600"
        :default-is-show="false"
        :keep-origin-node="true"
        @switch="onSwitch3"
        @change="(val) => onChange3(val)"
        @check-before="onCheckBeforeAll"
      />
    </div>

    <div :class="$style.right">我是右侧业务内容</div>
  </div>
</template>

<script setup lang="ts">
import { UpCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
import zh_CN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import { ConfigProvider, Button, RadioGroup, Radio } from 'ant-design-vue';
import { reactive, onMounted, ref } from 'vue';
import { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
import { LegoLeftTree, LegoTreeUtils, LegoTreeTypes, LegoTreeServices } from '@pluve/lego-tree-vue';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
import { originList } from '@/constant/channel';

const treeRef = ref();
const treeRefAll = ref();

const state = reactive<{
  dataType: 'all' | 'enable';
  treeData: LegoTreeTypes.ITreeNodesType[];
  treeDataAll: LegoTreeTypes.ITreeNodesType[];
  loading: boolean;
  loadingAll: boolean;
  storeCode?: string;
  storeCodeAll?: string;
  storeCodes: string[];
  storeCodesAll: string[];
  storeNodes: LegoTreeTypes.ICheckedAreaItem[];
  storeNodesAll: LegoTreeTypes.ICheckedAreaItem[];
}>({
  dataType: 'enable',
  treeData: [],
  treeDataAll: [],
  loading: false,
  loadingAll: false,
  storeCode: '5500',
  storeCodeAll: '10010357_5500',
  storeCodes: ['5500'],
  storeCodesAll: ['10010357_5500'],
  storeNodes: [{ key: '5500', hierarchy: '07' }],
  storeNodesAll: [{ key: '10010357_5500', code: '10010357', storeCode: '5500', hierarchy: '07' }],
});

const customRequest = async () => {
  try {
    const result: any[] = await new Promise((resolve) => {
      setTimeout(() => {
        resolve(originList);
      }, 800);
    });
    const convertedData = LegoTreeUtils.recursionTreeData({
      list: result ?? [],
      valKey: 'id',
      nameKey: 'text',
      childrenKey: 'children',
    });
    return convertedData;
  } catch (error) {
    return [];
  }
};

const onChange1 = (val: string) => {
  console.log('单选选择范围 val:', val);
};

const onChange2 = (val: string[]) => {
  console.log('多选选择渠道 val:', val);
};

const onChange3 = (val: LegoTreeTypes.ICheckedAreaItem[]) => {
  console.log('多选选择组织机构 val:', val);
};

const onSwitch2 = (bool: boolean) => {
  console.log('多选选择渠道,当前展开收起状态:', bool);
};

const onSwitch3 = (bool: boolean) => {
  console.log('多选选择组织机构,当前展开收起状态:', bool);
};

const onIconClick1 = (val: string) => {
  console.log('单选选择范围,点击图标后获取对应的 value:', val);
};

const onIconClick2 = (val: string) => {
  console.log('多选选择渠道,点击图标后获取对应的 value:', val);
};

const loadOrgTreeNodeByLevel = async () => {
  state.loading = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].sub || [],
      pid: undefined,
      keepOriginNode: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeData = newTreeData;
  } catch (error) {
    state.treeData = [];
  } finally {
    state.loading = false;
  }
};

const loadOrgTreeNodeByLevelAll = async () => {
  state.loadingAll = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
      jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
      jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].children || [],
      pid: undefined,
      childrenKey: 'children',
      hierarchyKey: 'rank',
      keepOriginNode: true,
      includeDisabledData: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeDataAll = newTreeData;
  } catch (error) {
    state.treeDataAll = [];
  } finally {
    state.loadingAll = false;
  }
};

onMounted(() => {
  loadOrgTreeNodeByLevel();
  loadOrgTreeNodeByLevelAll();
});

// 接口请求成功后返回对应的树数据
const getTreeInfo = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfo', { treeData, dataListMap });
};

// 接口请求成功后返回对应的树数据
const getTreeInfoAll = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfoAll', { treeData, dataListMap });
};

const getTreeInfoWithRef = () => {
  if (state.dataType === 'enable') {
    console.log('treeRef.value', treeRef.value?.getTreeInfo());
  } else {
    console.log('treeRefAll.value', treeRefAll.value?.getTreeInfo());
  }
};

const onCheckBefore = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfo', treeInfo);
};

const onCheckBeforeAll = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfoAll', treeInfo);
};
</script>

<style lang="less" module>
body {
  background-color: #f1f4f5;
  width: 100%;
  height: 100%;
}

.top {
  position: relative;
  padding: 10px 50px 0;
}

.wrap {
  position: relative;
  min-height: 52px;
  background-color: #f1f4f5;
  padding: 10px 50px;
  border-radius: 4px;
  height: calc(100vh - 120px);
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

.right {
  width: 300px;
  height: 100%;
  background: #fff;
  margin-left: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>

LegoTreeTransfer

通常作为最底层组件向外提供,可以嵌在 tab 内、Modal 弹窗内等任何场景,左右侧布局展示。props 继承自 antd vue TreeProps

export interface ILegoTreeTransferProps
  extends Omit<
    TreeProps,
    | 'blockNode'
    | 'fieldNames'
    | 'multiple'
    | 'treeData'
    | 'virtual'
    | 'checkable'
    | 'selectable'
    | 'checkedKeys'
    | 'selectedKeys'
    | 'onSelect'
    | 'autoExpandParent'
    | 'expandedKeys'
    | 'height'
  > {
  envType?: 'test' | 'prod';
  jsonFrom?: OrgTreeJsonFromEnum;
  jsonType?: OrgTreeJsonTypeEnum;
  hierarchyList?: string[];
  selectHierarchy?: string;

  treeData?: LegoTreeTypes.ITreeNodesType[];
  loading?: boolean;
  dataListMap?: Record<string, LegoTreeTypes.ITreeNodesType>;
  request?: () => Promise<LegoTreeTypes.ITreeNodesType[]>;

  value: string[] | LegoTreeTypes.ICheckedAreaItem[];
  placeholder?: string;
  disabled?: boolean;
  includeArea?: boolean;
  searchDomHeight?: number;
  customFormatName?: (
    value: (LegoTreeTypes.ICheckedAreaItem | string)[],
    type: 'input' | 'modal'
  ) => string | undefined;

  keepOriginNode?: boolean;
}

API

参数说明类型是否可选默认值
envType环境(测试 | 生产)。走组件默认接口请求时使用,其余场景无需传该字段test \| prodtest
jsonFrom组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonFromEnumLegoTreeTypes.OrgTreeJsonFromEnum.SSO
jsonType组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段LegoTreeTypes.OrgTreeJsonTypeEnumLegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE
hierarchyList组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段string[]-
selectHierarchy选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段string-
treeDataantd vue TreeSelect 组件数据源(已经经过转化后的数据源,若 includeAreatrue,则子节点需要包含 trace 字段)LegoTreeTypes.ITreeNodesType[]-
loading外部数据源加载时的 loading 状态booleanfalse
dataListMap扁平化 map(已经经过转化后的数据源生成的 map)Record<string, LegoTreeTypes.ITreeNodesType>{}
request自定义服务,用于获取组件树数据源() => Promise<LegoTreeTypes.ITreeNodesType[]>-
value(v-model)当前选中值,区分选择父子节点和子节点,有 2 种类型string[] \| LegoTreeTypes.ICheckedAreaItem[][]
placeholderInput.Search 输入框的 placeholderstring'搜索关键词'
disabledtree 选择是否禁用booleanfalse
includeArea是否包含区域选择,即是否允许选择各层级父子节点booleanfalse
searchDomHeight实际业务中搜索输入框的高度,不同的样式主题高度会有差别number46
customFormatName自定义选中项内容展示,包含 input 输入框的回显和 Tree 选中后的汇总(value: (LegoTreeTypes.ICheckedAreaItem \| string)[], type: 'input' \| 'modal') => string \| undefined-
keepOriginNode是否树节点保留原始对象信息。若开启,配合 includeAreatrue,则会返回 originNode(原始对象信息)booleanfalse
title自定义标题,在原始基础上,增加当前搜索值 searchValue 字段,供自定义判断处理slot({ key, title, ..., searchValue })-

事件(emit)

事件名称说明回调参数
change选中/反选树节点时调用此函数function(string[] \| LegoTreeTypes.ICheckedAreaItem[])
checkBeforeTree onCheck 触发时优先调用此函数,此函数第三个参数返回 组件内部的树数据源function(checked: Key[] \| { checked: Key[]; halfChecked: Key[]; }, info: CheckInfo, treeInfo: { treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType> })
getTreeInfo接口请求完成后,调用此函数,返回当前组件内部的树数据源function({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; })

ref

通过 ref 获取组件提供的方法或属性。以下是提供的方法或属性: | 方法/属性名称 | 说明 | 类型 | | --- | --- | --- | | getTreeInfo | 【方法】提供组件内部的树数据源 | () => ({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; }) |

效果展示

测试环境地址:https://yf-test-oss.yifengx.com/webtest/yangwen/legoTree/index.html#/treeTransfer

使用示例

<template>
  <ConfigProvider :locale="zh_CN">
    <div :class="$style.wrap">
      <!-- 有效数据源 -->
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeTransfer demo:{{ JSON.stringify(state.storeCodes) }}
      </h4>
      <div style="width: 536px; margin: 30px 0 0">
        <LegoTreeTransfer
          :treeData="state.treeData"
          :loading="state.loading"
          :include-area="true"
          :keep-origin-node="true"
          v-model:value="state.storeCodes"
        />
      </div>
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeTransfer demo:{{ JSON.stringify(state.storeCodes1) }}
      </h4>
      <Button type="primary" @click="getTreeInfoWithRef" style="margin-top: 10px">
        点我获取tree数据源
      </Button>
      <div style="width: 536px; margin: 30px 0 0">
        <LegoTreeTransfer
          :include-area="false"
          v-model:value="state.storeCodes1"
          :custom-format-name="customFormatName"
          :request="customRequest"
          ref="treeRef"
          @get-tree-info="getTreeInfo"
          @check-before="onCheckBefore"
        />
      </div>

      <!-- 账号中心 && 全部数据源(包含已关停) -->
      <div style="font-weight: bold; color: red; margin-top: 10px; margin-bottom: 10px">
        以下数据源为账号中心全量数据源(包含已关停数据):
      </div>
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeTransfer demo:{{ JSON.stringify(state.storeCodesAll) }}
      </h4>
      <div style="width: 536px; margin: 30px 0 0">
        <LegoTreeTransfer
          :treeData="state.treeDataAll"
          :loading="state.loadingAll"
          :include-area="true"
          :keep-origin-node="true"
          v-model:value="state.storeCodesAll"
        />
      </div>
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeTransfer demo:{{ JSON.stringify(state.storeCodes1All) }}
      </h4>
      <Button type="primary" @click="getTreeInfoWithRefAll" style="margin-top: 10px">
        点我获取tree数据源
      </Button>
      <div style="width: 536px; margin: 30px 0 0">
        <LegoTreeTransfer
          :json-from="LegoTreeTypes.OrgTreeJsonFromEnum.USER"
          :json-type="LegoTreeTypes.OrgTreeJsonTypeEnum.ALL"
          env-type="test"
          :hierarchyList="['01', '02', '03', '04', '06', '07']"
          selectHierarchy="07"
          :include-area="false"
          v-model:value="state.storeCodes1All"
          ref="treeRefAll"
          @get-tree-info="getTreeInfoAll"
          @check-before="onCheckBeforeAll"
        />
      </div>
    </div>
  </ConfigProvider>
</template>

<script setup lang="ts">
import zh_CN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import { ConfigProvider, Button } from 'ant-design-vue';
import { reactive, onMounted, ref } from 'vue';
import { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
import { LegoTreeTransfer, LegoTreeUtils, LegoTreeTypes, LegoTreeServices } from '@pluve/lego-tree-vue';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
import { originList } from '@/constant/channel';

const treeRef = ref();
const treeRefAll = ref();

const state = reactive<{
  treeData: LegoTreeTypes.ITreeNodesType[];
  treeDataAll: LegoTreeTypes.ITreeNodesType[];
  loading: boolean;
  loadingAll: boolean;
  storeCodes: LegoTreeTypes.ICheckedAreaItem[];
  storeCodesAll: LegoTreeTypes.ICheckedAreaItem[];
  storeCodes1: string[];
  storeCodes1All: string[];
}>({
  treeData: [],
  treeDataAll: [],
  loading: false,
  loadingAll: false,
  storeCodes: [],
  storeCodesAll: [],
  storeCodes1: [],
  storeCodes1All: [],
});

const loadOrgTreeNodeByLevel = async () => {
  state.loading = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].sub || [],
      pid: undefined,
      keepOriginNode: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeData = newTreeData;
  } catch (error) {
    state.treeData = [];
  } finally {
    state.loading = false;
  }
};

const loadOrgTreeNodeByLevelAll = async () => {
  state.loadingAll = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
      jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
      jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].children || [],
      pid: undefined,
      childrenKey: 'children',
      hierarchyKey: 'rank',
      keepOriginNode: true,
      includeDisabledData: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeDataAll = newTreeData;
  } catch (error) {
    state.treeDataAll = [];
  } finally {
    state.loadingAll = false;
  }
};

onMounted(() => {
  loadOrgTreeNodeByLevel();
  loadOrgTreeNodeByLevelAll();
});

const customRequest = async () => {
  try {
    const result: any[] = await new Promise((resolve) => {
      setTimeout(() => {
        resolve(originList);
      }, 800);
    });
    const convertedData = LegoTreeUtils.recursionTreeData({
      list: result ?? [],
      valKey: 'id',
      nameKey: 'text',
      childrenKey: 'children',
    });
    return convertedData;
  } catch (error) {
    return [];
  }
};

const customFormatName = (
  values: (LegoTreeTypes.ICheckedAreaItem | string)[],
  type: 'input' | 'modal'
) => {
  const checkedStr = (values as LegoTreeTypes.ICheckedAreaItem[])
    .map((item) => item.title)
    .join(',');

  if (type === 'input') {
    return checkedStr ? `${checkedStr}被选择` : undefined;
  }

  return checkedStr ? `已选:${checkedStr}` : '已选:0条数据';
};

// 接口请求成功后返回对应的树数据
const getTreeInfo = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfo', { treeData, dataListMap });
};

// 接口请求成功后返回对应的树数据
const getTreeInfoAll = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfoAll', { treeData, dataListMap });
};

const onCheckBefore = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfo', treeInfo);
};

const onCheckBeforeAll = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfoAll', treeInfo);
};

const getTreeInfoWithRef = () => {
  console.log('treeRef.value', treeRef.value?.getTreeInfo());
};

const getTreeInfoWithRefAll = () => {
  console.log('treeRefAll.value', treeRefAll.value?.getTreeInfo());
};
</script>

<style lang="less" module>
.wrap {
  position: relative;
  min-height: 52px;
  background-color: #fff;
  padding: 0 80px 40px;
  border-radius: 4px;
}
</style>

LegoTreeModal

通常作为 选择组织机构树的弹窗使用,Modal 内部引用 LegoTreeTransfer 组件来实现。故部分属性可以参考 LegoTreeTransfer 组件。

export interface ILegoTreeModalProps {
  title?: string;
  visible?: boolean;
  value: string[] | LegoTreeTypes.ICheckedAreaItem[];
  okLoading?: boolean;
  onOk?: (value: string[] | LegoTreeTypes.ICheckedAreaItem[]) => void;
  onCancel?: () => void;
  disabled?: boolean;
  showStoreUploadBtn?: boolean;
  modalProps?: Omit<
    ModalProps,
    'onOk' | 'onCancel' | 'visible' | 'destroyOnClose' | 'closable' | 'keyboard' | 'maskClosable'
  >;
  transferProps?: Omit<ILegoTreeTransferProps, 'value' | 'disabled'>;
}

API

参数说明类型是否可选默认值
titleModal 弹窗的 title,优先级:titleslot > modalProps.title > titlestringstring \| slot选择区域
visible控制 Modal 弹窗的显隐booleanfalse
value(v-model)当前选中值,区分选择父子节点和子节点,有 2 种类型string[] \| LegoTreeTypes.ICheckedAreaItem[][]
okLoading点击弹窗确定按钮的 loadingbooleanfalse
onOk点击弹窗确定按钮触发(value: string[] \| LegoTreeTypes.ICheckedAreaItem[]) => void-
onCancel点击弹窗取消按钮触发() => void-
disabledModal 弹窗 和 tree 选择是否禁用booleanfalse
showStoreUploadBtn是否展示默认的导入门店按钮,导入任意节点,做全量覆盖处理。注意:1. 如果走全量数据源(包含已关停数据),则不能使用默认的导入功能;2. 如果开启 includeArea,则不区分导入的数据之间是否存在父子层级依赖关系,一并去重导入;booleanfalse
modalPropsantd vue Modal 弹窗组件的额外的属性Omit<ModalProps, 'onOk' \| 'onCancel' \| 'visible' \| 'destroyOnClose' \| 'closable' \| 'keyboard' \| 'maskClosable'>-
transferPropsLegoTreeTransfer 组件的额外的属性Omit<ILegoTreeTransferProps, 'value' \| 'disabled'>{}
footerModal 弹窗的 footer,优先级最高slot-
renderFooterLeftModal 弹窗底部左侧的自定义区域slot-
renderUploadModal 弹窗底部右侧的自定义导入功能,disabledfalse 时展示,优先级高于默认的导入功能slot-
bodyTopModal 弹窗 LegoTreeTransfer 组件上方的自定义区域slot-
bodyBottomModal 弹窗 LegoTreeTransfer 组件下方的自定义区域slot-
treeTitle用于传递给 LegoTreeTransfer 组件的 title 插槽(避免插槽名字冲突)slot-

事件(emit)

事件名称说明回调参数
getTreeInfo接口请求完成后,调用此函数,返回当前组件内部的树数据源function({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; })

ref

通过 ref 获取组件提供的方法或属性。以下是提供的方法或属性: | 方法/属性名称 | 说明 | 类型 | | --- | --- | --- | | getTreeInfo | 【方法】提供组件内部的树数据源 | () => ({ treeData: LegoTreeTypes.ITreeNodesType[]; dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>; }) |

效果展示

测试环境地址:https://yf-test-oss.yifengx.com/webtest/yangwen/legoTree/index.html#/treeModal

使用示例

<template>
  <ConfigProvider :locale="zh_CN">
    <div :class="$style.wrap">
      <!-- 有效数据源 -->
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeModal demo:{{ JSON.stringify(state.storeCodes) }}
      </h4>
      <Button style="margin-top: 20px" type="primary" @click="showTreeModal">
        点我打开组织机构树弹窗
      </Button>
      <LegoTreeModal
        :visible="state.treeModalVisible"
        v-model:value="state.storeCodes"
        @cancel="
          () => {
            state.treeModalVisible = false;
          }
        "
        @ok="
          (value) => {
            state.treeModalVisible = false;
          }
        "
        :showStoreUploadBtn="true"
        :transfer-props="{
          hierarchyList: ['01', '02', '03', '04', '06', '07'],
          selectHierarchy: '07',
          includeArea: false,
          onCheck: onTreeCheck,
        }"
        ref="treeRef"
        @get-tree-info="getTreeInfo"
      >
        <template #title>我是 LegoTreeModal 弹窗组件的自定义 title</template>
        <template #bodyTop>我是 LegoTreeModal 弹窗组件的自定义 bodyTop</template>
        <template #bodyBottom>我是 LegoTreeModal 弹窗组件的自定义 bodyBottom</template>
        <template #renderFooterLeft>我是 LegoTreeModal 弹窗组件的自定义 renderFooterLeft</template>
      </LegoTreeModal>

      <!-- 账号中心 && 全部数据源(包含已关停) -->
      <div style="font-weight: bold; color: red; margin-top: 40px; margin-bottom: 0px">
        以下数据源为账号中心全量数据源(包含已关停数据):
      </div>
      <h4
        style="margin: 30px 50px 0 0; word-break: break-word; max-height: 100px; overflow-y: auto"
      >
        LegoTreeModal demo:{{ JSON.stringify(state.storeCodesAll) }}
      </h4>
      <Button style="margin-top: 20px" type="primary" @click="showTreeModalAll">
        点我打开组织机构树弹窗
      </Button>
      <LegoTreeModal
        :visible="state.treeModalVisibleAll"
        v-model:value="state.storeCodesAll"
        @cancel="
          () => {
            state.treeModalVisibleAll = false;
          }
        "
        @ok="
          (value) => {
            state.treeModalVisibleAll = false;
          }
        "
        :showStoreUploadBtn="false"
        :transfer-props="{
          jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
          jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
          hierarchyList: ['01', '02', '03', '04', '06', '07'],
          selectHierarchy: '07',
          includeArea: false,
          onCheck: onTreeCheckAll,
        }"
        ref="treeRefAll"
        @get-tree-info="getTreeInfoAll"
      >
        <template #title>我是 LegoTreeModal 弹窗组件的自定义 title</template>
        <template #bodyTop>我是 LegoTreeModal 弹窗组件的自定义 bodyTop</template>
        <template #bodyBottom>我是 LegoTreeModal 弹窗组件的自定义 bodyBottom</template>
        <template #renderFooterLeft>我是 LegoTreeModal 弹窗组件的自定义 renderFooterLeft</template>
      </LegoTreeModal>
    </div>
  </ConfigProvider>
</template>

<script setup lang="ts">
import zh_CN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import { ConfigProvider, Button } from 'ant-design-vue';
import { reactive, ref } from 'vue';
import { LegoTreeModal, LegoTreeTypes, LegoTreeUtils, LegoTreeServices } from '@pluve/lego-tree-vue';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');

const treeRef = ref();
const treeRefAll = ref();

const state = reactive<{
  storeCodes: string[];
  storeCodesAll: string[];
  treeModalVisible: boolean;
  treeModalVisibleAll: boolean;
}>({
  storeCodes: [],
  storeCodesAll: [],
  treeModalVisible: false,
  treeModalVisibleAll: false,
});

const showTreeModal = () => {
  state.treeModalVisible = true;
};

const showTreeModalAll = () => {
  state.treeModalVisibleAll = true;
};

// 接口请求成功后返回对应的树数据
const getTreeInfo = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfo', { treeData, dataListMap });
};

// 接口请求成功后返回对应的树数据
const getTreeInfoAll = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfoAll', { treeData, dataListMap });
};

const onTreeCheck = () => {
  console.log('treeRef.value', treeRef.value?.getTreeInfo());
};

const onTreeCheckAll = () => {
  console.log('treeRefAll.value', treeRefAll.value?.getTreeInfo());
};
</script>

<style lang="less" module>
.wrap {
  position: relative;
  min-height: 52px;
  background-color: #fff;
  padding: 20px 80px;
  border-radius: 4px;
}
</style>

LegoTree

通常用于多选组织架构,与 FormItem 进行绑定,内部引用 LegoTreeModal 组件来实现。故部分属性可以参考 LegoTreeModal 组件。

export interface ILegoTreeProps
  extends Omit<
    ILegoTreeModalProps,
    'title' | 'visible' | 'value' | 'onOk' | 'onCancel' | 'disabled'
  > {
  title?: string;
  value: string[] | LegoTreeTypes.ICheckedAreaItem[];
  disabled?: boolean;
  placeholder?: string;
  limitSelectedNum?: number;
  onlyStoreCodeInDisabled?: boolean;
  showModalInDisabled?: boolean;
  customValidate?: (value: string[] | LegoTreeTypes.ICheckedAreaItem[]) => Promise<boolean>;
  customFormatName?: (
    value: (LegoTreeTypes.ICheckedAreaItem | string)[],
    type: 'input' | 'modal'
  ) => string | undefined;
}

API

参数说明类型是否可选默认值
titleModal 弹窗的 titlestring \| slot选择区域
value(v-model)当前选中值,区分选择父子节点和子节点,有 2 种类型string[] \| LegoTreeTypes.ICheckedAreaItem[][]
disabledInputModal 弹窗 和 tree 选择是否禁用booleanfalse
placeholderInput 输入框的 placeholderstring'请选择区域'
limitSelectedNum限制最大门店勾选数量,仅限 transferProps.includeArea 为 false 时number-
onlyStoreCodeInDisabled禁用时,是否只展示门店编码,仅限输入框中展示用booleanfalse
showModalInDisabled禁用时,是否可以展示弹窗booleantrue
customValidate点击弹窗确定按钮,触发自定义校验,优先级:customValidate > limitSelectedNum(value: string[] \| ICheckedAreaItem[]) => Promise<boolean>-
customFormatName自定义选中项内容展示,包含 input 输入框的回显和 Tree 选中后的汇总(value: (LegoTreeTypes.ICheckedAreaItem \| string)[], type: 'input' \| 'modal') => string \| undefined-
default默认插槽,用于自定义展示形式,默认为 Inputslot({ show })-

事件(emit)

事件名称说明回调参数
change弹窗选中/反选树节点后,点击【确定】按钮时调用此函数function(string[] \| LegoTreeTypes.ICheckedAreaItem[])

效果展示

测试环境地址:https://yf-test-oss.yifengx.com/webtest/yangwen/legoTree/index.html#/tree

使用示例

<template>
  <ConfigProvider :locale="zh_CN">
    <div :class="$style.wrap">
      <Form :colon="false" autocomplete="off">
        <Row>
          <!-- 有效数据源 -->
          <Col :span="12">
            <FormItem label="Tree自定义request">
              <LegoTree
                title="选择渠道"
                placeholder="请选择"
                v-model:value="modelRef.storeCodes"
                :showStoreUploadBtn="true"
                :transfer-props="{
                  request: customRequest,
                  includeArea: false,
                }"
                :custom-format-name="customFormatName"
                :disabled="true"
                :show-modal-in-disabled="true"
              ></LegoTree>
            </FormItem>
          </Col>
          <Col :span="12"></Col>
          <Col :span="12">
            <FormItem label="Tree使用默认json">
              <LegoTree
                title="选择门店"
                placeholder="选择门店"
                v-model:value="modelRef.channelList"
                :limit-selected-num="100"
                :showStoreUploadBtn="true"
                :transfer-props="{
                  jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
                  jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE,
                  hierarchyList: ['01', '02', '03', '04', '06', '07'],
                  selectHierarchy: '07',
                  includeArea: true,
                  keepOriginNode: true,
                  onCheckBefore,
                }"
                :custom-validate="customValidate"
                :disabled="false"
                :show-modal-in-disabled="true"
                @get-tree-info="getTreeInfo"
              >
                <template #treeTitle="{ key: val, title, label }">
                  <b v-if="val === '5024'" style="color: #08c">{{ title || label }}</b>
                  <template v-else>{{ title || label }}</template>
                </template>
              </LegoTree>
            </FormItem>
          </Col>
          <Col :span="12"></Col>

          <!-- 账号中心 && 全部数据源(包含已关停) -->
          <Col :span="24" style="font-weight: bold; color: red; margin-bottom: 24px">
            以下数据源为账号中心全量数据源(包含已关停数据):
          </Col>
          <Col :span="12">
            <FormItem label="Tree自定义treeData">
              <LegoTree
                title="选择渠道"
                placeholder="请选择"
                v-model:value="modelRef.storeCodesAll"
                :limit-selected-num="100"
                :showStoreUploadBtn="false"
                :transfer-props="{
                  treeData: state.treeDataAll,
                  loading: state.loadingAll,
                  includeArea: false,
                  keepOriginNode: true,
                  onCheckBefore: onCheckBeforeAll,
                }"
                :custom-validate="customValidate"
                :disabled="false"
                @get-tree-info="getTreeInfoAll"
              >
                <template #treeTitle="{ key: val, title, label, storeCode }">
                  <b v-if="val === '10004575_5024'" style="color: #08c">{{ title || label }}</b>
                  <b v-else-if="storeCode === '5500'" style="color: #f90">{{ title || label }}</b>
                  <template v-else>{{ title || label }}</template>
                </template>
              </LegoTree>
            </FormItem>
          </Col>
          <Col :span="12"></Col>
          <Col :span="12">
            <FormItem label="Tree使用默认json">
              <LegoTree
                title="选择门店"
                placeholder="选择门店"
                v-model:value="modelRef.channelListAll"
                :showStoreUploadBtn="false"
                :transfer-props="{
                  jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
                  jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
                  hierarchyList: ['01', '02', '03', '04', '06', '07'],
                  selectHierarchy: '07',
                  includeArea: true,
                  keepOriginNode: true,
                }"
                :disabled="true"
                :show-modal-in-disabled="true"
                :only-store-code-in-disabled="true"
              ></LegoTree>
            </FormItem>
          </Col>
          <Col :span="12"></Col>

          <Col :span="6">
            <Button @click="onQuery" style="margin-left: 10px" type="primary">查询</Button>
          </Col>
        </Row>
      </Form>
    </div>
  </ConfigProvider>
</template>

<script setup lang="ts">
import zh_CN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import { ConfigProvider, Form, FormItem, Row, Col, Button } from 'ant-design-vue';
import { reactive, onMounted } from 'vue';
import { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
import { LegoTree, LegoTreeUtils, LegoTreeTypes, LegoTreeServices } from '@pluve/lego-tree-vue';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
import { originList } from '@/constant/channel';

// 查询条件 ref
const modelRef = reactive<{
  storeCodes: string[];
  storeCodesAll: string[];
  channelList: LegoTreeTypes.ICheckedAreaItem[];
  channelListAll: LegoTreeTypes.ICheckedAreaItem[];
}>({
  storeCodes: ['5024', '5032', '5979', 'E520'],
  storeCodesAll: [],
  channelList: [],
  channelListAll: [
    {
      key: '10014212_7971',
      code: '10014212',
      storeCode: '7971',
      hierarchy: '07',
      title: '7971-南昌怡园路店',
    },
  ],
});

const state = reactive<{
  treeDataAll: LegoTreeTypes.ITreeNodesType[];
  loadingAll: boolean;
}>({
  treeDataAll: [],
  loadingAll: false,
});

// 查询条件 form
const form = Form.useForm(modelRef, undefined);

const customValidate = async (e: string[] | LegoTreeTypes.ICheckedAreaItem[]) => {
  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('1秒的自定义校验');
      resolve(true);
    }, 1000);
  });
  return true;
};

const customRequest = async () => {
  try {
    const result: any[] = await new Promise((resolve) => {
      setTimeout(() => {
        resolve(originList);
      }, 800);
    });
    const convertedData = LegoTreeUtils.recursionTreeData({
      list: result ?? [],
      valKey: 'id',
      nameKey: 'text',
      childrenKey: 'children',
    });
    return convertedData;
  } catch (error) {
    return [];
  }
};

const customFormatName = (
  values: (LegoTreeTypes.ICheckedAreaItem | string)[],
  type: 'input' | 'modal'
) => {
  if (type === 'input') {
    const checkedStr = (values as string[]).join(',');
    return checkedStr ? `${checkedStr}被选择` : undefined;
  }

  const checkedStr = (values as LegoTreeTypes.ICheckedAreaItem[])
    .map((item) => item.title)
    .join(',');
  return checkedStr ? `已选:${checkedStr}` : '已选:0条数据';
};

const loadOrgTreeNodeByLevelAll = async () => {
  state.loadingAll = true;
  try {
    const result = await LegoTreeServices.getAllOrgTreeNodesByOss({
      hierarchyList: ['01', '02', '03', '04', '06', '07'],
      envType: 'test',
      jsonFrom: LegoTreeTypes.OrgTreeJsonFromEnum.USER,
      jsonType: LegoTreeTypes.OrgTreeJsonTypeEnum.ALL,
    });
    const newTreeData = LegoTreeUtils.recursionTreeData({
      list: result?.[0].children || [],
      pid: undefined,
      childrenKey: 'children',
      hierarchyKey: 'rank',
      keepOriginNode: true,
      includeDisabledData: true,
    });
    LegoTreeUtils.excludeNode(newTreeData, '07');
    state.treeDataAll = newTreeData;
  } catch (error) {
    state.treeDataAll = [];
  } finally {
    state.loadingAll = false;
  }
};

onMounted(() => {
  loadOrgTreeNodeByLevelAll();
});

const onQuery = () => {
  console.log('查询条件:', modelRef);
};

// 接口请求成功后返回对应的树数据
const getTreeInfo = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfo', { treeData, dataListMap });
};

// 接口请求成功后返回对应的树数据
const getTreeInfoAll = ({
  treeData,
  dataListMap,
}: {
  treeData: LegoTreeTypes.ITreeNodesType[];
  dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
}) => {
  console.log('getTreeInfoAll', { treeData, dataListMap });
};

const onCheckBefore = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfo', treeInfo);
};

const onCheckBeforeAll = (
  _: any,
  e: CheckInfo,
  treeInfo: {
    treeData: LegoTreeTypes.ITreeNodesType[];
    dataListMap: Record<string, LegoTreeTypes.ITreeNodesType>;
  }
) => {
  console.log('treeInfoAll', treeInfo);
};
</script>

<style lang="less" module>
.wrap {
  position: relative;
  min-height: 52px;
  background-color: #fff;
  margin: 20px 0 0 100px;
  border-radius: 4px;
}
</style>

LegoTreeUtils

提供一系列 Tree 相关方法

HIERARCHY_LIST

提供 hierarchy 的枚举数组,枚举值:LegoTreeTypes.CommonHierarchyEnum

示例

import { LegoTreeUtils } from '@pluve/lego-tree-vue';

const aaa = LegoTreeUtils.HIERARCHY_LIST;

excludeNode

过滤树底层没有 primaryKey 的节点

Params

excludeNode(list: LegoTreeTypes.ITreeNodesType[], primaryKey?: string)

参数说明类型是否可选默认值
listTree/TreeSel
0.1.0

14 days ago

0.0.15

5 months ago

0.0.16

5 months ago

0.0.15-beta.3

5 months ago

0.0.15-beta.4

5 months ago

0.0.15-beta.1

5 months ago

0.0.15-beta.2

5 months ago

0.0.14

7 months ago

0.0.13

10 months ago

0.0.12

10 months ago

0.0.11

10 months ago

0.0.10

10 months ago

0.0.9

10 months ago

0.0.8

10 months ago

0.0.7

10 months ago

0.0.6

10 months ago

0.0.5

10 months ago

0.0.4

10 months ago

0.0.3

10 months ago

0.0.2

10 months ago

0.0.1

10 months ago