@pluve/lego-tree-vue
v0.1.1
Published
乐高系列之 tree 组件
Downloads
19
Readme
@pluve/lego-tree-vue
乐高系列之 tree
组件系列,属于强业务组件。
@pluve/lego-tree-vue
一期二期规划的功能已上线,目前已在【营销工具 - 一元券】等项目中使用。
安装
# 依赖 [email protected]/[email protected]/@ant-design/[email protected]/@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,优先级:title[slot] > modalProps.title > title[string] | 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