0.1.1 • Published 1 year ago

@pluve/lego-tree-vue v0.1.1

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year 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.1

1 year ago

0.1.0

1 year ago

0.0.15

2 years ago

0.0.16

2 years ago

0.0.15-beta.3

2 years ago

0.0.15-beta.4

2 years ago

0.0.15-beta.1

2 years ago

0.0.15-beta.2

2 years ago

0.0.14

2 years ago

0.0.13

2 years ago

0.0.12

2 years ago

0.0.11

2 years ago

0.0.10

2 years ago

0.0.9

2 years ago

0.0.8

2 years ago

0.0.7

2 years ago

0.0.6

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago