🔱: [client] sync upgrade with 5 commits [trident-sync]

build: publish success
perf: antdv 异步加载,加快首页打开速度
perf: 精简lodash
chore: 兼容手机版
pull/91/head
GitHub Actions Bot 2025-03-04 19:24:24 +00:00
parent 335d175d57
commit 140606744b
26 changed files with 245 additions and 70 deletions

View File

@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.25.4](https://github.com/fast-crud/fast-crud/compare/v1.25.3...v1.25.4) (2025-03-04)
### Performance Improvements
* 精简lodash ([21f59e8](https://github.com/fast-crud/fast-crud/commit/21f59e80db56cf0968b2739b9bc7ff1e8b7be4e4))
* antdv 异步加载,加快首页打开速度 ([4eb4283](https://github.com/fast-crud/fast-crud/commit/4eb4283ad66e856814962ca2bde416dddbac0868))
## [1.25.3](https://github.com/fast-crud/fast-crud/compare/v1.25.2...v1.25.3) (2025-02-23)
**Note:** Version bump only for package @fast-crud/fs-admin-antdv4

View File

@ -13,6 +13,11 @@ https://github.com/fast-crud/fs-server-js
* [fs-admin-naive](https://github.com/fast-crud/fs-admin-naive-ui) naive版示例
* [fs-in-vben-starter](https://github.com/fast-crud/fs-in-vben-starter) vben示例
# build
```sh
set NODE_OPTIONS=--max-old-space-size=32768 && npm run build
```
# 感谢
### 依赖

View File

@ -1,6 +1,6 @@
{
"name": "@fast-crud/fs-admin-antdv4",
"version": "1.25.3",
"version": "1.25.4",
"private": true,
"scripts": {
"dev": "vite",
@ -9,7 +9,7 @@
"debug": "vite --mode debug --open",
"debug:pm": "vite --mode debugpm",
"debug:force": "vite --force --mode debug",
"build": " vite build ",
"build": "vite build ",
"serve": "vite preview",
"preview": "vite preview",
"pretty-quick": "pretty-quick",
@ -26,11 +26,11 @@
"@ant-design/icons-vue": "^7.0.1",
"@aws-sdk/client-s3": "^3.535.0",
"@aws-sdk/s3-request-presigner": "^3.535.0",
"@fast-crud/fast-crud": "^1.25.3",
"@fast-crud/fast-extends": "^1.25.3",
"@fast-crud/ui-antdv4": "^1.25.3",
"@fast-crud/ui-interface": "^1.25.3",
"@ctrl/tinycolor": "^4.1.0",
"@fast-crud/fast-crud": "^1.25.4",
"@fast-crud/fast-extends": "^1.25.4",
"@fast-crud/ui-antdv4": "^1.25.4",
"@fast-crud/ui-interface": "^1.25.4",
"@iconify/tailwind": "^1.2.0",
"@iconify/vue": "^4.1.1",
"@manypkg/get-packages": "^2.2.2",

View File

@ -1,9 +1,9 @@
<template>
<a-config-provider :locale="locale" :theme="tokenTheme">
<AConfigProvider :locale="locale" :theme="tokenTheme">
<fs-form-provider>
<router-view v-if="routerEnabled" />
</fs-form-provider>
</a-config-provider>
</AConfigProvider>
</template>
<script lang="ts" setup>
@ -16,7 +16,7 @@ import dayjs from "dayjs";
import { usePreferences, preferences } from "/@/vben/preferences";
import { useAntdDesignTokens } from "/@/vben/hooks";
import { theme } from "ant-design-vue";
import AConfigProvider from "ant-design-vue/es/config-provider";
defineOptions({
name: "App"
});

View File

@ -22,14 +22,14 @@
<script lang="ts">
import i18n from "../../../i18n";
import { computed, inject } from "vue";
import _ from "lodash-es";
import { forEach } from "lodash-es";
export default {
name: "FsLocale",
setup() {
const languages = computed(() => {
const map: any = i18n.global.messages?.value || {};
const list: any = [];
_.forEach(map, (item, key) => {
forEach(map, (item, key) => {
list.push({
key,
label: item.label

View File

@ -1,6 +1,6 @@
import { useRoute, useRouter } from "vue-router";
import { ref, watch, onMounted, onUnmounted, resolveComponent, nextTick, defineComponent } from "vue";
import _ from "lodash-es";
import { forEach } from "lodash-es";
import BScroll from "better-scroll";
import "./index.less";
import { utils } from "@fast-crud/fast-crud";
@ -161,7 +161,7 @@ export default defineComponent({
return;
}
if (value.path === fullPath) {
_.forEach(context.parents, (item) => {
forEach(context.parents, (item) => {
if (item.value instanceof Array) {
return;
}

View File

@ -1,11 +1,11 @@
import { createApp } from "vue";
import App from "./App.vue";
import Antd from "ant-design-vue";
// import Antd from "ant-design-vue";
import Antd from "./plugin/antdv-async/index";
import "./style/common.less";
import i18n from "./i18n";
import components from "./components";
import router from "./router";
import store from "./store";
import plugin from "./plugin/";
// 正式项目请删除mock避免影响性能
import "./mock";
@ -15,6 +15,7 @@ import { initPreferences } from "/@/vben/preferences";
// @ts-ignore
async function bootstrap() {
const app = createApp(App);
// app.use(Antd);
app.use(Antd);
await setupVben(app);
app.use(router);

View File

@ -1,8 +1,8 @@
import _ from "lodash-es";
import { cloneDeep, mergeWith, isArray } from "lodash-es";
function copyList(originList: any, newList: any, options: any, parentId?: any) {
for (const item of originList) {
const newItem: any = _.cloneDeep(item);
if(parentId!= null && newItem.parentId == null){
const newItem: any = cloneDeep(item);
if (parentId != null && newItem.parentId == null) {
newItem.parentId = parentId;
}
@ -218,7 +218,7 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: _.cloneDeep(req.body)
data: cloneDeep(req.body)
};
}
},
@ -228,12 +228,12 @@ const mockUtil: any = {
handle(req: any): any {
const item = findById(req.body.id, list);
if (item) {
_.mergeWith(item, req.body, (objValue, srcValue) => {
mergeWith(item, req.body, (objValue, srcValue) => {
if (srcValue == null) {
return;
}
// 如果被合并对象为数组,则直接被覆盖对象覆盖,只要覆盖对象不为空
if (_.isArray(objValue)) {
if (isArray(objValue)) {
return srcValue;
}
});
@ -305,12 +305,12 @@ const mockUtil: any = {
console.log("req", req);
let item = findById(req.body.id, list);
if (item) {
_.mergeWith(item, { [req.body.key]: req.body.value }, (objValue, srcValue) => {
mergeWith(item, { [req.body.key]: req.body.value }, (objValue, srcValue) => {
if (srcValue == null) {
return;
}
// 如果被合并对象为数组,则直接被覆盖对象覆盖,只要覆盖对象不为空
if (_.isArray(objValue)) {
if (isArray(objValue)) {
return srcValue;
}
});
@ -336,12 +336,12 @@ const mockUtil: any = {
for (const item of req.body) {
const item2 = findById(item.id, list);
if (item2) {
_.mergeWith(item2, item, (objValue, srcValue) => {
mergeWith(item2, item, (objValue, srcValue) => {
if (srcValue == null) {
return;
}
// 如果被合并对象为数组,则直接被覆盖对象覆盖,只要覆盖对象不为空
if (_.isArray(objValue)) {
if (isArray(objValue)) {
return srcValue;
}
});

View File

@ -3,7 +3,7 @@ import cascaderData from "./cascader-data";
import pcaDataLittle from "./pca-data-little";
// @ts-ignore
import { TreeNodesLazyLoader, getPcaData } from "./pcas-data";
import _ from "lodash-es";
import { cloneDeep } from "lodash-es";
const openStatus = [
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
{ value: "2", label: "停止", color: "cyan" },
@ -29,7 +29,7 @@ let manyStatus = [
];
let tempManyStatus: any[] = [];
for (let i = 0; i < 100; i++) {
tempManyStatus = tempManyStatus.concat(_.cloneDeep(manyStatus));
tempManyStatus = tempManyStatus.concat(cloneDeep(manyStatus));
}
manyStatus = tempManyStatus;
let idIndex = 0;

View File

@ -1,4 +1,4 @@
import _ from "lodash-es";
import {cloneDeep} from "lodash-es";
export async function getPcasData() {
// @ts-ignore
const pcasData = () => import("china-division/dist/pcas-code.json");
@ -22,7 +22,7 @@ export const TreeNodesLazyLoader = {
for (const value of values) {
const found = this.getNode(data, value);
if (found) {
const target = _.cloneDeep(found);
const target = cloneDeep(found);
delete target.children;
nodes.push(target);
}

View File

@ -1,6 +1,6 @@
import { mock } from "../api/service";
import * as tools from "../api/tools";
import _ from "lodash-es";
import { forEach } from "lodash-es";
import { utils } from "@fast-crud/fast-crud";
// @ts-ignore
const commonMocks: any = import.meta.glob("./common/mock.*.[j|t]s", { eager: true });
@ -10,13 +10,13 @@ const apiMocks: any = import.meta.glob("../api/modules/*.mock.ts", { eager: true
const viewMocks: any = import.meta.glob("../views/**/mock.[j|t]s", { eager: true });
const list: any = [];
_.forEach(commonMocks, (value: any) => {
forEach(commonMocks, (value: any) => {
list.push(value.default);
});
_.forEach(apiMocks, (value) => {
forEach(apiMocks, (value) => {
list.push(value.default);
});
_.forEach(viewMocks, (value) => {
forEach(viewMocks, (value) => {
list.push(value.default);
});

View File

@ -0,0 +1,162 @@
import { defineAsyncComponent } from "vue";
export default {
install(app: any) {
app.component(
"AInput",
defineAsyncComponent(() => import("ant-design-vue/es/input/Input"))
);
app.component(
"AInputPassword",
defineAsyncComponent(() => import("ant-design-vue/es/input/Password"))
);
app.component(
"AButton",
defineAsyncComponent(() => import("ant-design-vue/es/button/button"))
);
app.component(
"AButtonGroup",
defineAsyncComponent(() => import("ant-design-vue/es/button/button-group"))
);
app.component(
"ARadio",
defineAsyncComponent(() => import("ant-design-vue/es/radio/Radio"))
);
app.component(
"ARadioGroup",
defineAsyncComponent(() => import("ant-design-vue/es/radio/Group"))
);
app.component(
"ATable",
defineAsyncComponent(() => import("ant-design-vue/es/table/Table"))
);
app.component(
"AModal",
defineAsyncComponent(() => import("ant-design-vue/es/modal/Modal"))
);
app.component(
"AForm",
defineAsyncComponent(() => import("ant-design-vue/es/form/Form"))
);
app.component(
"AFormItem",
defineAsyncComponent(() => import("ant-design-vue/es/form/FormItem"))
);
app.component(
"ATabs",
defineAsyncComponent(() => import("ant-design-vue/es/tabs/src/Tabs"))
);
app.component(
"ATabPane",
defineAsyncComponent(() => import("ant-design-vue/es/tabs/src/TabPanelList/TabPane"))
);
app.component(
"ATextarea",
defineAsyncComponent(() => import("ant-design-vue/es/input/TextArea"))
);
app.component(
"AInputNumber",
defineAsyncComponent(() => import("ant-design-vue/es/input-number/index"))
);
app.component(
"ASelect",
defineAsyncComponent(() => import("ant-design-vue/es/select/index"))
);
app.component(
"ADrawer",
defineAsyncComponent(() => import("ant-design-vue/es/drawer/index"))
);
app.component(
"ASwitch",
defineAsyncComponent(() => import("ant-design-vue/es/switch/index"))
);
app.component(
"AUpload",
defineAsyncComponent(() => import("ant-design-vue/es/upload/index"))
);
app.component(
"ADatePicker",
defineAsyncComponent(() => import("ant-design-vue/es/date-picker/index"))
);
app.component(
"ARangePicker",
defineAsyncComponent(async () => {
const { RangePicker } = await import("ant-design-vue/es/date-picker/index");
return RangePicker;
})
);
app.component(
"ATimePicker",
defineAsyncComponent(() => import("ant-design-vue/es/time-picker/index"))
);
app.component(
"ATag",
defineAsyncComponent(() => import("ant-design-vue/es/tag/index"))
);
app.component(
"AAlert",
defineAsyncComponent(() => import("ant-design-vue/es/alert/index"))
);
app.component(
"AInputAutoComplete",
defineAsyncComponent(() => import("ant-design-vue/es/auto-complete/index"))
);
app.component(
"ACard",
defineAsyncComponent(() => import("ant-design-vue/es/card/index"))
);
app.component(
"ACascader",
defineAsyncComponent(() => import("ant-design-vue/es/cascader/index"))
);
app.component(
"ACheckbox",
defineAsyncComponent(() => import("ant-design-vue/es/checkbox"))
);
app.component(
"ACheckboxGroup",
defineAsyncComponent(() => import("ant-design-vue/es/checkbox/Group"))
);
app.component(
"ACol",
defineAsyncComponent(() => import("ant-design-vue/es/col"))
);
app.component(
"ARow",
defineAsyncComponent(() => import("ant-design-vue/es/row"))
);
app.component(
"ADropdown",
defineAsyncComponent(() => import("ant-design-vue/es/dropdown"))
);
app.component(
"AGrid",
defineAsyncComponent(() => import("ant-design-vue/es/grid"))
);
app.component(
"AImage",
defineAsyncComponent(() => import("ant-design-vue/es/image"))
);
app.component(
"APagination",
defineAsyncComponent(() => import("ant-design-vue/es/pagination"))
);
app.component(
"ATooltip",
defineAsyncComponent(() => import("ant-design-vue/es/tooltip"))
);
app.component(
"ATree",
defineAsyncComponent(() => import("ant-design-vue/es/tree"))
);
app.component(
"ATreeSelect",
defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
);
app.component(
"AToar",
defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
);
}
};

View File

@ -6,7 +6,7 @@ import { FsExtendsCopyable, FsExtendsEditor, FsExtendsJson, FsExtendsTime, FsExt
import "@fast-crud/fast-extends/dist/style.css";
import UiAntdv from "@fast-crud/ui-antdv4";
import "@fast-crud/ui-antdv4/dist/style.css";
import _ from "lodash-es";
import { merge } from "lodash-es";
import { useCrudPermission } from "../permission";
import { GetSignedUrl } from "/@/views/crud/component/uploader/s3/api";
import { notification } from "ant-design-vue";
@ -362,7 +362,7 @@ function install(app: any, options: any = {}) {
// 比如你可以定义一个readonly的公共属性处理该字段只读不能编辑
if (columnProps.readonly) {
// 合并column配置
_.merge(columnProps, {
merge(columnProps, {
form: { show: false },
viewForm: { show: true }
});

View File

@ -1,5 +1,5 @@
import { usePermission } from "/@/plugin/permission";
import _ from "lodash-es";
import { merge as LodashMerge } from "lodash-es";
export type UseCrudPermissionExtraProps = {
hasActionPermission: (action: string) => boolean;
@ -30,7 +30,7 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
return hasPermissions(prefix + ":" + action);
}
function buildCrudPermission() {
function buildCrudPermission(): any {
if (permission == null) {
return {};
}
@ -43,7 +43,7 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
}
}
return _.merge(
return LodashMerge(
{
actionbar: {
buttons: {
@ -64,7 +64,7 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
function merge(userOptions: any) {
const permissionOptions = buildCrudPermission();
_.merge(permissionOptions, userOptions);
LodashMerge(permissionOptions, userOptions);
return permissionOptions;
}

View File

@ -1,5 +1,5 @@
import LayoutPass from "/src/layout/layout-pass.vue";
import _ from "lodash-es";
import { cloneDeep } from "lodash-es";
import { outsideResource } from "./source/outside";
import { headerResource } from "./source/header";
import { frameworkResource } from "./source/framework";
@ -19,7 +19,7 @@ function transformOneResource(resource: any, parent: any) {
if (meta.isMenu === false) {
menu = null;
} else {
menu = _.cloneDeep(resource);
menu = cloneDeep(resource);
delete menu.component;
if (menu.path?.startsWith("/")) {
menu.fullPath = menu.path;
@ -32,7 +32,7 @@ function transformOneResource(resource: any, parent: any) {
//没有route
route = null;
} else {
route = _.cloneDeep(resource);
route = cloneDeep(resource);
if (route.component && typeof route.component === "string") {
const path = "/src/views" + route.component;
route.component = modules[path];

View File

@ -1,10 +1,10 @@
import _ from "lodash-es";
import { isArray } from "lodash-es";
export default {
arrayToMap(array: any) {
if (!array) {
return {};
}
if (!_.isArray(array)) {
if (!isArray(array)) {
return array;
}
const map: any = {};
@ -19,7 +19,7 @@ export default {
if (!map) {
return [];
}
if (_.isArray(map)) {
if (isArray(map)) {
return map;
}
const array: any = [];

View File

@ -1,4 +1,4 @@
import _ from "lodash-es";
import {forEach} from "lodash-es";
export function getEnvValue(key: string) {
// @ts-ignore
return import.meta.env["VITE_APP_" + key];
@ -19,7 +19,7 @@ export class EnvConfig {
init() {
// @ts-ignore
_.forEach(import.meta.env, (value, key) => {
forEach(import.meta.env, (value, key) => {
if (key.startsWith("VITE_APP")) {
key = key.replace("VITE_APP_", "");
// @ts-ignore

View File

@ -1,6 +1,5 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
import _ from "lodash-es";
const options: any = {
name: "AdvancedCard",
idGenerator: 0

View File

@ -1,7 +1,7 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, dict } from "@fast-crud/fast-crud";
import { GetCrud } from "./api";
import _ from "lodash-es";
import { merge } from "lodash-es";
/**
* options
@ -43,7 +43,7 @@ export default async function (props: CreateCrudOptionsProps): Promise<CreateCru
// 本示例返回的是一个方法字符串所以要先执行这个方法获取options
const remoteCrudOptions = crudBackend({ crudExpose, dict });
// 与本地options合并
const crudOptions = _.merge(localCrudOptions, remoteCrudOptions);
const crudOptions = merge(localCrudOptions, remoteCrudOptions);
return {
crudOptions

View File

@ -1,6 +1,6 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
import _ from "lodash-es";
import { omit } from "lodash-es";
const options: any = {
name: "FormLinkage",
idGenerator: 0
@ -71,7 +71,7 @@ const mock = mockUtil.buildMock(options);
function omitChildren(originalList: any) {
const list: any = [];
originalList.forEach((item: any) => {
list.push(_.omit(item, "children"));
list.push(omit(item, "children"));
});
return list;
}

View File

@ -1,5 +1,5 @@
import * as api from "./api.js";
import _ from "lodash-es";
import { merge } from "lodash-es";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
@ -45,7 +45,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const tableData = localDataRef.value;
for (const item of tableData) {
if (item.id === form.id) {
_.merge(item, form);
merge(item, form);
}
}
};

View File

@ -13,7 +13,7 @@
<script lang="ts" setup>
import { onMounted } from "vue";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, useFsAsync, useFsRef, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import _ from "lodash-es";
import { cloneDeep, find, merge, remove, maxBy } from "lodash-es";
//crudOptions
const createCrudOptions = async function ({}: CreateCrudOptionsProps): Promise<CreateCrudOptionsRet> {
@ -21,26 +21,26 @@ const createCrudOptions = async function ({}: CreateCrudOptionsProps): Promise<C
const records = [{ id: 1, name: "Hello World", type: 1 }];
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return {
records: _.cloneDeep(records),
records: cloneDeep(records),
offset: 0, //transformRescurrentPage
limit: 20, //transformRespageSize
total: records.length
};
};
const editRequest = async ({ form, row }: EditReq) => {
const target = _.find(records, (item) => {
const target = find(records, (item) => {
return row.id === item.id;
});
_.merge(target, form);
merge(target, form);
return target;
};
const delRequest = async ({ row }: DelReq) => {
_.remove(records, (item) => {
remove(records, (item) => {
return item.id === row.id;
});
};
const addRequest = async ({ form }: AddReq) => {
const maxRecord = _.maxBy(records, (item) => {
const maxRecord = maxBy(records, (item: any) => {
return item.id;
});
form.id = (maxRecord?.id || 0) + 1;

View File

@ -15,17 +15,18 @@
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { CrudOptions, DynamicType, useFs, UseFsProps, useFsRef } from "@fast-crud/fast-crud";
import { CrudOptions, DynamicType, useFs, UseFsProps, useFsRef, useMerge } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud.js";
import _ from "lodash-es";
export default defineComponent({
name: "BasisReset",
setup() {
const { crudBinding, crudRef, crudExpose, context, crudOptions, resetCrudOptions, appendBindingOptions } = useFs({ createCrudOptions, context: { text: 111 } });
debugger;
const { merge } = useMerge();
setTimeout(() => {
//crudOptions
const newOptions: DynamicType<CrudOptions> = _.merge(crudOptions, {
const newOptions: DynamicType<CrudOptions> = merge(crudOptions, {
columns: {
text: {
title: "追加字段",

View File

@ -2,7 +2,7 @@ import * as api from "./api";
import { requestForMock } from "/src/api/service";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, DictOnReadyContext, EditReq, UserPageQuery, UserPageRes, useUi, utils } from "@fast-crud/fast-crud";
import { ref } from "vue";
import _ from "lodash-es";
import { debounce } from "lodash-es";
function useSearchRemote() {
let lastFetchId = 0;
@ -10,7 +10,7 @@ function useSearchRemote() {
data: ref([]),
fetching: ref(false)
};
const fetchUser = _.debounce((value) => {
const fetchUser = debounce((value) => {
utils.logger.info("fetching user", value);
lastFetchId += 1;

View File

@ -19,7 +19,7 @@ import { useFsRef, utils, useFsAsync } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import * as api from "./api";
import { message } from "ant-design-vue";
import { usePageStore } from "/@/store/modules/page";
import { useTabbarStore } from "/@/vben/stores/modules/tabbar";
export default defineComponent({
name: "FormNewPageEdit",
@ -27,7 +27,7 @@ export default defineComponent({
const { crudRef, crudBinding, crudExpose, context } = useFsRef();
const formRef = ref();
const formOptions = ref();
const pageStore = usePageStore();
const tabbarStore = useTabbarStore();
const route = useRoute();
//
onMounted(async () => {
@ -48,7 +48,7 @@ export default defineComponent({
doSubmit(context);
//
message.success("保存成功");
pageStore.close({ tagName: route.fullPath });
tabbarStore.getTabByPath(route.fullPath);
};
if (id) {

View File

@ -26,7 +26,7 @@
<script lang="ts">
import { utils } from "@fast-crud/fast-crud";
import _ from "lodash-es";
import { cloneDeep } from "lodash-es";
import { computed, defineComponent, ref } from "vue";
export default defineComponent({
@ -53,7 +53,7 @@ export default defineComponent({
if (props.tree == null) {
return null;
}
const clone = _.cloneDeep(props.tree);
const clone = cloneDeep(props.tree);
utils.deepdash.forEachDeep(clone, (value: any, key: any, pNode: any, context: any) => {
if (value == null) {
return;