@pluve/lego-tree-vue v0.1.0
@pluve/lego-tree-vue
乐高系列之 tree
组件系列,属于强业务组件。
@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 | 唯一 key | string | 否 |
name | 名称 | string | 是 |
parentId | 父 id | string | 是 |
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 | 唯一 key ,LegoTreeSelect 组件使用。走默认数据源取数逻辑 && 账号中心全量数据时,value 取值方式:code_storeCode;走默认数据源取数逻辑 && SSO 或 账号中心有效数据时,value 取值方式:code/storeCode; | string | 是 |
title | 节点名称 | string | 是 |
hierarchy | 组织机构级别:01(公司);02(中心);03(营运区);04(部门);05(组);06(片区);07(门店);若接口返回该字段为空,则组件内部处理为从1开始往下叠加 | string | 是 |
code | 原始 code | string | 是 |
storeCode | 原始 storeCode ,门店节点时才存在该字段 | string | 是 |
pid | 上一节点的 'code' 字段 | string | 是 |
trace | 父子节点路径,includeArea 为 true 时,该字段必须有值 | string | 是 |
disabled | 是否节点禁止操作 | boolean | 是 |
selectable | 【单选】节点是否可以选择 | boolean | 是 |
children | 子节点 | LegoTreeTypes.ITreeNodesType[] | 是 |
originNode | 原始树节点信息,keepOriginNode 开启后 该对象不为 undefined ,且在 includeArea 为 true 或 labelInValue 为 true 时返回给调用方 | 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 | 原始 code | string | 是 |
storeCode | 原始 storeCode ,门店节点时才存在该字段 | string | 是 |
originNode | 原始树节点信息,keepOriginNode 开启后 该对象不为 undefined ,且在 includeArea 为 true 时返回给调用方 | 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 | 唯一 key ,LegoTreeSelect 组件使用。走默认数据源取数逻辑 && 账号中心全量数据时,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 种情况:
dataListMap
为空对象:则调用LegoTreeUtils.generateListMap
方法来生成 扁平化数据源dataListMap
并存储在组件内部,同时给treeData
子节点增加trace
字段用作记录父子节点的路径。dataListMap
不为空对象:则默认调用方已经扁平化了数据源 且给子节点增加了trace
字段,直接存储在组件内部即可。
注意:
trace
字段主要用于组织机构树可以选择任意节点的场景,需要通过 trace 字段来判定父子节点间的关系。如果只需要选择子节点,则可以忽略所有针对trace
字段的要求。treeData
里面每个节点的originNode
字段需要自行处理。includeArea
为true
或labelInValue
为true
时,若开启keepOriginNode
,则 返回的值里面会增加originNode
字段。
2. request
若传值 treeData
为 undefined
,且 request
不为 undefined
,则组件认定是调用方需要通过自定义服务来自定义数据源,则完全信任调用方传入自定义服务,组件内部执行调用服务逻辑。
获取数据源后,通过调用 LegoTreeUtils.generateListMap
方法来生成 扁平化数据源 dataListMap
并存储在组件内部,同时给 treeData
子节点增加 trace
字段用作记录父子节点的路径。
注意:
trace
字段主要用于组织机构树可以选择任意节点的场景,需要通过 trace 字段来判定父子节点间的关系。如果只需要选择子节点,则可以忽略所有针对trace
字段的要求。treeData
里面每个节点的originNode
字段需要自行处理。includeArea
为true
或labelInValue
为true
时,若开启keepOriginNode
,则 返回的值里面会增加originNode
字段。
3. orgTree.json
若上述 2 个字段都为 undefined
,则组件认定调用方没有自定义的需求,则直接走组件默认的数据源取数逻辑:
- 根据
envType
字段区分走测试还是生产环境的接口调用——注意:此时获取到的数据没有做任何权限处理 - 根据
jsonFrom
字段区分走 SSO 还是走账号中心——注意:SSO 只返回有效的数据源,不包含已关停数据,如需已关停数据,请走账号中心 - 根据
jsonType
字段区分返回全量(包含已关停等)还是有效的数据源,获取全部的组织机构树的数据源 - 根据
hierarchyList
字段过滤不包含的节点信息,传空或不传则默认取全量数据源 - 调用
LegoTreeUtils.recursionTreeData
方法对数据源做处理,转化为Tree/TreeSelect
组件需要的数据源 - 根据
selectHierarchy
字段过滤子节点不包含selectHierarchy
层级的节点。例如,不包含门店节点的父节点全部过滤掉不展示,则selectHierarchy
为 '07'。 - 调用
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 \| prod | 是 | test |
jsonFrom | 组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonFromEnum | 是 | LegoTreeTypes.OrgTreeJsonFromEnum.SSO |
jsonType | 组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonTypeEnum | 是 | LegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE |
hierarchyList | 组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段 | string[] | 是 | - |
selectHierarchy | 选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段 | string | 是 | - |
enableSelectedHierarchy | 【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择,否则 selectable 为 false 不可选择 | string[] | 是 | [] |
treeData | antd vue TreeSelect 组件数据源(已经经过转化后的数据源) | LegoTreeTypes.ITreeNodesType[] | 是 | - |
loading | 外部数据源加载时的 loading 状态 | boolean | 是 | false |
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 (原始对象信息) | boolean | 是 | false |
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 \| prod | 是 | test |
jsonFrom | 组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonFromEnum | 是 | LegoTreeTypes.OrgTreeJsonFromEnum.SSO |
jsonType | 组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonTypeEnum | 是 | LegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE |
hierarchyList | 组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段 | string[] | 是 | - |
selectHierarchy | 选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段 | string | 是 | - |
enableSelectedHierarchy | 【单选】可选择的组织机构级别,不传或为空则都可以选择,传了则包含的级别才可以选择,否则 selectable 为 false 不可选择 | string[] | 是 | [] |
treeData | antd vue TreeSelect 组件数据源(已经经过转化后的数据源) | LegoTreeTypes.ITreeNodesType[] | 是 | - |
loading | 外部数据源加载时的 loading 状态 | boolean | 是 | false |
dataListMap | 扁平化 Map(已经经过转化后的数据源生成的 map) | Record<string, LegoTreeTypes.ITreeNodesType> | 是 | {} |
request | 自定义服务,用于获取组件树数据源 | () => Promise<LegoTreeTypes.ITreeNodesType[]> | 是 | - |
value(v-model) | 当前选中的值,区分单选、多选门店、多选节点三种类型 | string \| string[] \| LegoTreeTypes.ICheckedAreaItem[] | 是 | - |
headerTitle | 头部标题文案 | string | 是 | 选择门店 |
placeholder | Input.Search 输入框 placeholder | string | 是 | 搜索门店名称或编码 |
disabled | tree 选择是否禁用 | boolean | 是 | false |
selectType | 选择类型:单选/多选 | single \| multiple | 是 | 'single' |
includeArea | 【多选】是否包含区域选择,即是否允许选择各层级父子节点 | boolean | 是 | false |
width | 组件宽度 | string \| number | 是 | 280 |
virtualHeight | 组件 Tree 虚拟滚动高度 | number | 是 | 820 |
showSwitch | 是否展示 展开收起功能 开关 | boolean | 是 | true |
defaultIsShow | 默认是否处于展开状态 | boolean | 是 | true |
keepOriginNode | 是否树节点保留原始对象信息。若开启,配合 includeArea 为 true ,则会返回 originNode (原始对象信息) | boolean | 是 | false |
title | 自定义标题,在原始基础上,增加当前搜索值 searchValue 字段,供自定义判断处理 | slot({ key, title, ..., searchValue }) | 是 | - |
事件(emit)
事件名称 | 说明 | 回调参数 |
---|---|---|
change | 选中/反选树节点时调用此函数 | function(string \| string[] \| LegoTreeTypes.ICheckedAreaItem[]) |
switch | 展开/收起按钮切换时调用此函数 | function(boolean) |
checkBefore | Tree 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 \| prod | 是 | test |
jsonFrom | 组织机构树 json 来源。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonFromEnum | 是 | LegoTreeTypes.OrgTreeJsonFromEnum.SSO |
jsonType | 组织机构树 json 类型:全量(包含已关停等) or 有效的。走组件默认接口请求时使用,其余场景无需传该字段 | LegoTreeTypes.OrgTreeJsonTypeEnum | 是 | LegoTreeTypes.OrgTreeJsonTypeEnum.ENABLE |
hierarchyList | 组织机构级别数组,01-07,用于过滤不包含的节点信息,没传或为空则不过滤。走组件默认接口请求时使用,其余场景无需传该字段 | string[] | 是 | - |
selectHierarchy | 选择的组织机构级别,01-07,用于过滤子节点不包含 selectHierarchy 层级的节点。走组件默认接口请求时使用,其余场景无需传该字段 | string | 是 | - |
treeData | antd vue TreeSelect 组件数据源(已经经过转化后的数据源,若 includeArea 为 true ,则子节点需要包含 trace 字段) | LegoTreeTypes.ITreeNodesType[] | 是 | - |
loading | 外部数据源加载时的 loading 状态 | boolean | 是 | false |
dataListMap | 扁平化 map(已经经过转化后的数据源生成的 map) | Record<string, LegoTreeTypes.ITreeNodesType> | 是 | {} |
request | 自定义服务,用于获取组件树数据源 | () => Promise<LegoTreeTypes.ITreeNodesType[]> | 是 | - |
value(v-model) | 当前选中值,区分选择父子节点和子节点,有 2 种类型 | string[] \| LegoTreeTypes.ICheckedAreaItem[] | 否 | [] |
placeholder | Input.Search 输入框的 placeholder | string | 是 | '搜索关键词' |
disabled | tree 选择是否禁用 | boolean | 是 | false |
includeArea | 是否包含区域选择,即是否允许选择各层级父子节点 | boolean | 是 | false |
searchDomHeight | 实际业务中搜索输入框的高度,不同的样式主题高度会有差别 | number | 是 | 46 |
customFormatName | 自定义选中项内容展示,包含 input 输入框的回显和 Tree 选中后的汇总 | (value: (LegoTreeTypes.ICheckedAreaItem \| string)[], type: 'input' \| 'modal') => string \| undefined | 是 | - |
keepOriginNode | 是否树节点保留原始对象信息。若开启,配合 includeArea 为 true ,则会返回 originNode (原始对象信息) | boolean | 是 | false |
title | 自定义标题,在原始基础上,增加当前搜索值 searchValue 字段,供自定义判断处理 | slot({ key, title, ..., searchValue }) | 是 | - |
事件(emit)
事件名称 | 说明 | 回调参数 |
---|---|---|
change | 选中/反选树节点时调用此函数 | function(string[] \| LegoTreeTypes.ICheckedAreaItem[]) |
checkBefore | Tree 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
参数 | 说明 | 类型 | 是否可选 | 默认值 |
---|---|---|---|---|
title | Modal 弹窗的 title,优先级:titleslot > modalProps.title > titlestring | string \| slot | 是 | 选择区域 |
visible | 控制 Modal 弹窗的显隐 | boolean | 是 | false |
value(v-model) | 当前选中值,区分选择父子节点和子节点,有 2 种类型 | string[] \| LegoTreeTypes.ICheckedAreaItem[] | 否 | [] |
okLoading | 点击弹窗确定按钮的 loading | boolean | 是 | false |
onOk | 点击弹窗确定按钮触发 | (value: string[] \| LegoTreeTypes.ICheckedAreaItem[]) => void | 是 | - |
onCancel | 点击弹窗取消按钮触发 | () => void | 是 | - |
disabled | Modal 弹窗 和 tree 选择是否禁用 | boolean | 是 | false |
showStoreUploadBtn | 是否展示默认的导入门店按钮,导入任意节点,做全量覆盖处理。注意:1. 如果走全量数据源(包含已关停数据),则不能使用默认的导入功能;2. 如果开启 includeArea,则不区分导入的数据之间是否存在父子层级依赖关系,一并去重导入; | boolean | 是 | false |
modalProps | antd vue Modal 弹窗组件的额外的属性 | Omit<ModalProps, 'onOk' \| 'onCancel' \| 'visible' \| 'destroyOnClose' \| 'closable' \| 'keyboard' \| 'maskClosable'> | 是 | - |
transferProps | LegoTreeTransfer 组件的额外的属性 | Omit<ILegoTreeTransferProps, 'value' \| 'disabled'> | 是 | {} |
footer | Modal 弹窗的 footer,优先级最高 | slot | 是 | - |
renderFooterLeft | Modal 弹窗底部左侧的自定义区域 | slot | 是 | - |
renderUpload | Modal 弹窗底部右侧的自定义导入功能,disabled 为 false 时展示,优先级高于默认的导入功能 | slot | 是 | - |
bodyTop | Modal 弹窗 LegoTreeTransfer 组件上方的自定义区域 | slot | 是 | - |
bodyBottom | Modal 弹窗 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
参数 | 说明 | 类型 | 是否可选 | 默认值 |
---|---|---|---|---|
title | Modal 弹窗的 title | string \| slot | 是 | 选择区域 |
value(v-model) | 当前选中值,区分选择父子节点和子节点,有 2 种类型 | string[] \| LegoTreeTypes.ICheckedAreaItem[] | 否 | [] |
disabled | Input 、Modal 弹窗 和 tree 选择是否禁用 | boolean | 是 | false |
placeholder | Input 输入框的 placeholder | string | 是 | '请选择区域' |
limitSelectedNum | 限制最大门店勾选数量,仅限 transferProps.includeArea 为 false 时 | number | 是 | - |
onlyStoreCodeInDisabled | 禁用时,是否只展示门店编码,仅限输入框中展示用 | boolean | 是 | false |
showModalInDisabled | 禁用时,是否可以展示弹窗 | boolean | 是 | true |
customValidate | 点击弹窗确定按钮,触发自定义校验,优先级:customValidate > limitSelectedNum | (value: string[] \| ICheckedAreaItem[]) => Promise<boolean> | 是 | - |
customFormatName | 自定义选中项内容展示,包含 input 输入框的回显和 Tree 选中后的汇总 | (value: (LegoTreeTypes.ICheckedAreaItem \| string)[], type: 'input' \| 'modal') => string \| undefined | 是 | - |
default | 默认插槽,用于自定义展示形式,默认为 Input | slot({ 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)
参数 | 说明 | 类型 | 是否可选 | 默认值 |
---|---|---|---|---|
list | Tree/TreeSel |
14 days ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
7 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago