/**
 * 表单元素渲染插件
 * @version: 2.1.0
 *  # 版本修改：
 *      - 为了实现更加复杂的交互，提供laytpForm中的所有表单元素独立的渲染方法
 *          - renderOne(表单元素唯一标识/jquery对象, '表单元素class标识') // 统一渲染单个表单元素方法
 *          - renderSelect(表单元素唯一标识/jquery对象)                // 渲染单个select
 *          - renderXmSelect(表单元素唯一标识/jquery对象)              // 渲染单个xmSelect
 *          - renderUpload(表单元素唯一标识/jquery对象)                // 渲染单个upload
 *          - ...
 * @Author:  JunStar
 * @Date:    2020-08-17 18:13:50
 * @Last Modified by:   JunStar
 * @Last Modified time: 2022年8月29日14:59:11
 */
layui.define([
    'xmSelect',
    'laytpUpload',
    'laytpIcon',
    'laydate',
    'colorpicker'
], function (exports) {
    const MOD_NAME = "laytpForm";
    let $ = layui.$
        , facade = layui.facade
    ;

    window.xmSelectObj = {};
    window.xmSelectJqueryObj = {};
    window.xmSelectData = {};

    let laytpForm = {};

    window.linkageXmSelectData = {};
    window.linkageXmSelectJqueryObj = {};
    window.linkageXmSelectObj = {};

    //延迟对象数组
    let defArr = [];

    /**
     * 初始化所有表单元素的数据，比如下拉框的待选择项和选定项
     */
    laytpForm.initData = {
        select: function () {
            let obj = $("select");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.selectOne(item);
            });
        },

        xmSelect: function () {
            let obj = $(".xmSelect");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.xmSelectOne(item);
            });
        },

        linkageXmSelect: function () {
            let obj = $(".linkageXmSelect");

            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.linkageXmSelectOne(item);
            });
        },

        linkageSelect: function () {
            let obj = $(".linkageSelect");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.linkageSelectOne(item);
            });
        },

        upload: function () {
            let obj = $(".laytpUpload");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.uploadOne(item);
            });
        },

        icon: function () {
            let obj = $(".laytpIcon");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.iconOne(item);
            });
        },

        laydate: function () {
            let obj = $("input[type='text']").filter(".laydate");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.laydateOne(item);
            });
        },

        colorPicker: function () {
            let obj = $("div").filter(".colorPicker");
            layui.each(obj, function (key, item) {
                layui.laytpForm.initDataOne.colorPickerOne(item);
            });
        },

        /**
         * 编辑器
         *  此方法已废弃，实现方式变更，使用iframe调用编辑器页面进行展示
         *  原因：多种编辑器在单页面下进行加载展示，会有js、css冲突的情况，改成iframe就不会出现此问题
         */
        // editorRender: function () {
        //     let obj = $(".editor");
        //     layui.each(obj, function (key, item) {
        //         let type = $(item).data('type');
        //         let id = $(item).attr('id');
        //         layui.use(type, function () {
        //             layui[type].render(id);
        //         });
        //     });
        // },
    };

    // 将html标记元素渲染成指定的表单元素
    laytpForm.initDataOne = {
        /**
         * 默认下拉框
         * <select
         *  name="name"//提交表单时的name
         *  id="id"//节点的id值
         *  data-route="/plugin/core/auth.menu/getSelectOptionData" //数据源，请求后端的路由地址，默认会拼接{"paging": 0}的请求参数
         *  data-valueField="id" //option中value属性使用列表的哪个字段，默认为id
         *  data-showField="name" //option中，文本显示使用列表中哪个字段，默认为name
         *  data-selected="1" //选中项的valueField的值，如果data-valueField属性的值为id，那么当前属性data-selected的值就是数据源中某一个选项的id值，用于添加表单表单元素的默认选中值
         *  data-placeholder="请选择" //类似placeholder，允许为空，没有默认值，当没有定义当前属性，或者当前属性的值定义为空时，将不会有提示行，默认会选中数据源中的第一个数据
         * >
         * </select>
         * @param item 需要渲染的jquery对象
         */
        selectOne: function (item) {
            let route = $(item).data("route");
            if (route) {
                let selected = $(item).data("selected");
                let valueField = $(item).data("valuefield") ? $(item).data("valuefield") : 'id';
                let showField = $(item).data("showfield") ? $(item).data("showfield") : 'name';
                let placeholder = $(item).data("placeholder");
                //将ajax的延迟对象，存入延迟对象数组defArr中
                defArr.push(
                    facade.ajax({
                        method: "GET",
                        route: route,
                        data: {"paging": 0},
                        successAlert: false
                    }).then(function (res) {
                        if (placeholder) {
                            $(item).append("<option value=\"\">" + placeholder + "</option>");
                        }
                        for (key in res.data) {
                            let optionValue = (valueField !== "k") ? res.data[key][valueField] : key;
                            let optionText = (showField !== "v") ? res.data[key][showField] : res.data[key];
                            if (selected === optionValue) {
                                $(item).append("<option value='" + optionValue + "' selected='selected'>" + optionText + "</option>");
                            } else {
                                $(item).append("<option value='" + optionValue + "'>" + optionText + "</option>");
                            }
                        }
                    })
                );
            }
        },

        /**
         * xmSelect
         *  - 获取父级窗口xmSelect组件已经选中的值，console.log(parent.xmSelectObj[id].getValue());
         *  - 获取当前窗口xmSelect组件已经选中的值，console.log(xmSelectObj[id].getValue());
         *  - 动态更新xmSelect组件，
         *      - xmSelectObj[id].update(改变了的属性值); // 如果你很了解xmSelect手册，可以使用此方法
         *      - 更改html属性值，调用laytpForm.updateXmSelect(id);
         * <div class="xmSelect"//class="xmSelect"是xmSelect组件渲染的标识
         *      data-id="name"//非必设，组件唯一标识，id和name属性不能都为空
         *      data-name="name"//非必设，提交表单时的name，id和name属性不能都为空
         *      data-sourceType="route"//非必设，默认为data，标注数据类型，data=直接解析数据；route=ajax请求后台api接口数据；
         *      //必设，data-source支持两种数据结构数组和对象，url类型也可以返回这两种数据结构
         *      data-source='[{"name":"唱歌","id":"1"},{"name":"跳舞","id":"2"},{"name":"朗诵","id":"3"},{"name":"武术","id":"4"}]'//这种，对应的data-sourceType="data"，不需要指定data-textField和data-valueField，默认使用name的值作为展示的文本，id的值作为表单提交的值
         *      data-source='[{"text":"唱歌","value":"1"},{"text":"跳舞","value":"2"},{"text":"朗诵","value":"3"},{"text":"武术","value":"4"}]'//这种，对应的data-sourceType="data"，需要指定data-textField="text"，data-valueField="value"
         *      data-source='{1:"唱歌",2:"跳舞",3:"朗诵",4:"武术"}'//这种，对应的data-sourceType="data"，key就是表单提交的值，value就是展示的文本
         *      data-source="plugin/core/auth.menu/getTreeList" //这种，对应的data-sourceType="route"，这里是一个Api接口地址，返回的数据结构是数组或者对象，具体请参考当data-sourceType="data"时，data-source的说明
         *      data-param='{"name":{"value":1,"condition":"LIKE"}}'//非必填，2.1.0修改，请求后台接口地址时，需要传递的参数，json字符串，会拼接到search_param参数中进行请求
         *      data-customParam='{"name":"name的值"}'//非必填，2.1.0新增，自定义参数，原样在ajax请求中作为参数进行请求
         *      data-search="true"//非必设，2.1.0新增，是否开启自定义搜索，true=开启，false=不开启，默认true
         *      data-searchParam=''//非必设，2.1.0新增，进行自定义搜索时，数据源查询条件，json数据格式，会拼接到search_param参数中进行请求
         *          数据范例：{"字段名1":{"condition":"搜索条件"},"字段名2":{"condition":"搜索条件"}...}
         *              数据示例：{"name":{"condition":"LIKE"}}
         *              注意：
         *                  1.所有传递json数据格式时，html标记的属性值要使用单引号；
         *                  2.此处无需定义value，仅需定义字段和字段查询的条件，value会使用搜索框中输入的值填充；
         *                  3.当data-search为true，此值设置为空时，会默认使用{"data-textField的值":{"condition":"LIKE"}}作为此配置的值；
         *      data-searchCustomParam=''//非必设，2.1.0新增，进行自定义搜索时，数据源查询条件，json数据格式，原样在ajax请求中作为参数进行请求
         *      data-sourceTree="true"//非必设，是否展示成树形结构，与data-source连用，当为true时，需要展示data-source的值是树形结构的数据
         *      data-strict="false"//树形结构是否严格父子级
         *      data-treeType="tree"//非必设，树形结构展示方式，默认tree，可选项tree、tree-group和cascader，cascader为级联模式
         *      data-textField="name"//非必设，默认为name，当数据源的数据结构是一个数组时，显示的文本字段名称，当数据源数据结构是一个对象时，此设置无意义
         *      data-subTextField="value"//非必设，附属的文本字段名称，仅在下拉框列表中展示，如果返回的数据结果中有对象，比如后台是使用with关联得到的数据，支持使用.号取对象的数据
         *      data-valueField="value"//非必设，默认为value，当数据源的数据结构是一个数组时，提交表单的值，当数据源数据结构是一个对象时，此设置无意义
         *      data-iconField="icon"//非必设，当数据源的数据结构是一个数组时，显示文本前展示的图标字段名，为空或者不设置，则显示文本前无图标，当数据源数据结构是一个对象时，此设置无意义
         *      data-radio="true"//非必设，单选模式，true=开启单选模式，false=关闭单选模式，默认false
         *      data-selected="1,2"//非必设，默认选中的数据，需要在data中存在，默认不选中任何项
         *      data-max="2"//非必设，多选模式下，最多可选个数，默认不限制
         *      data-placeholder="请选择****"//非必设，类似placeholder，未选中数据时，提示文字，默认为"请选择"
         *      data-layVerify="required"//非必设，与layui的lay-verify相同
         *      data-layVerType="tips"//非必设，与layui的lay-verType相同
         *      data-direction="up"//非必设，下拉方向，增加这个参数是因为xmSelect没有做成漂浮，在弹出窗最底层有xmSelect时，会影响美观度
         *      data-paging="true"//非必设，是否分页，true=分页，false=不分页，默认false。目前仅在data-sourceType="route"且是非树形结构时有效，后台返回的数据结构需要使用thinkphp的paginate方法返回
         *      data-pageSize="10"//非必设，分页清空下，每页条数，默认10
         *      data-onchange="xmcb"//非必设，监听选中变化的函数名称，类似select元素的onchage事件，这里需要输入的是函数名称字符串，函数的定义方式和参数详解如下：
         *          window.xmcb = function(params){
         *              console.log(params);
         *              //params是一个对象，有arr、change、isAdd三个属性
         *              //arr是当前选中项组成的数组，是完成change或者说是click事件后留下的选中项
         *              //change是点击下拉框项组成的数组，因为xmSelect支持下拉框分组，树形结构列表，能点击一个按钮选中/取消选中多个项目，所以也是一个数组
         *              //isAdd表示change里面的内容是选中，还是取消选中操作
         *          }
         *          //params输出举例
         *          arr: Array(1)
         0: {name: "单行文本输入框", value: "input", __node: {…}}
         length: 1
         __proto__: Array(0)
         change: Array(1)
         0: {name: "文本域", value: "textarea", __node: {…}}
         length: 1
         __proto__: Array(0)
         isAdd: false
         __proto__: Object
         * ></div>
         * @param item 需要渲染的jquery对象
         * @returns {boolean}
         */
        xmSelectOne: function (item) {
            var obj, el;

            if (typeof item == "string") {
                el = ($('.xmSelect[data-id="' + item + '"]').length == 0) ? '.xmSelect[data-name="' + item + '"]' : '.xmSelect[data-id="' + item + '"]';
            } else {
                el = item;
            }

            obj = $(el);
            let id = obj.data("id");
            let name = obj.data("name");
            if (!id && !name) {
                facade.error("xmSelect组件data-id和data-name属性值均未定义");
                return false;
            }
            if (!id && name) id = name;

            if (window.xmSelectObj[id]) {
                return false;
            }

            let source = obj.data("source");
            if (!source) {
                facade.error('xmSelect插件' + id + '未定义data-source属性值');
                return false;
            }

            window.xmSelectData[id] = {
                id: id,
                name: name,
                sourceType: obj.data("sourcetype") ? obj.data("sourcetype") : "data",
                source: source,
                param: obj.data("param") ? obj.data("param") : {},
                customParam: obj.data("customparam") ? obj.data("customparam") : {},
                search: obj.data("search") ? obj.data("search") : false,
                searchParam: obj.data("searchparam") ? obj.data("searchparam") : {},
                searchCustomParam: obj.data("searchcustomparam") ? obj.data("searchcustomparam") : {},
                textField: obj.data("textfield") ? obj.data("textfield") : 'name',
                subTextField: obj.data("subtextfield") ? obj.data("subtextfield") : '',
                valueField: obj.data("valuefield") ? obj.data("valuefield") : "id",
                iconField: obj.data("iconfield") ? obj.data("iconfield") : "",
                sourceTree: obj.data("sourcetree") === true,
                treeType: (obj.data("treetype") === 'cascader') ? 'cascader' : 'tree',
                onchange: obj.data("onchange") ? obj.data("onchange") : "",
                paging: obj.data("paging") ? obj.data("paging") : false,
                pageSize: obj.data("pagesize") ? obj.data("pagesize") : 10,
                radio: obj.data("radio") === true,
                strict: (typeof obj.data("strict") !== "undefined") ? obj.data("strict") : !(obj.data("radio") === true),
                selected: obj.data("selected") ? obj.data("selected").toString() : '',
                max: obj.data("max") ? obj.data("max") : 0,
                direction: obj.data("direction") ? obj.data("direction") : "auto",
                layVerify: obj.data("layverify") ? obj.data("layverify") : "",
                layVerType: obj.data("layvertype") ? obj.data("layvertype") : "",
                placeholder: obj.data("placeholder") ? obj.data("placeholder") : "请选择",
                searchKeyword: '',
                onNum: 0,
            }

            var jsonTypeAttr = ['param', 'customParam', 'searchParam', 'searchCustomParam'];
            for (key in jsonTypeAttr) {
                if (typeof window.xmSelectData[id][jsonTypeAttr[key]] != "object") {
                    facade.error("data-id=" + id + "的xmSelect下拉框组件，data-" + jsonTypeAttr[key] + "属性值需要是一个正确的json字符串");
                    return false;
                }
            }

            if (window.xmSelectData[id].sourceType == 'data') {
                if (typeof window.xmSelectData[id].source != "object") {
                    facade.error("data-id=" + id + "的xmSelect下拉框组件，data-source属性值需要是一个正确的json字符串");
                    return false;
                }
            }

            // 定义树形结构渲染参数
            let renderTreeOptions = {};
            // 定义级联模式渲染参数
            let renderCascaderOptions = {};
            // 赋值树形结构渲染参数和级联模式渲染参数
            if (window.xmSelectData[id].sourceTree) {
                if (window.xmSelectData[id].treeType === 'tree') {
                    renderTreeOptions = {
                        //是否显示树状结构
                        show: true,
                        //是否展示三角图标
                        showFolderIcon: true,
                        //是否显示虚线
                        showLine: true,
                        //间距
                        indent: 20,
                        //默认展开节点的数组, 为 true 时, 展开所有节点
                        expandedKeys: true,
                        //是否严格遵守父子模式
                        strict: window.xmSelectData[id].strict,
                        //是否开启极简模式
                        simple: true,
                        clickExpand: false,
                        clickCheck: true,
                    };
                } else if (window.xmSelectData[id].treeType === 'tree-group') {
                    renderTreeOptions = {
                        //是否显示树状结构
                        show: false,
                        //是否展示三角图标
                        showFolderIcon: true,
                        //是否显示虚线
                        showLine: true,
                        //间距
                        indent: 20,
                        //默认展开节点的数组, 为 true 时, 展开所有节点
                        expandedKeys: true,
                        //是否严格遵守父子模式
                        strict: window.xmSelectData[id].strict,
                        //是否开启极简模式
                        simple: true,
                        clickExpand: false,
                        clickCheck: true,
                    };
                } else {
                    renderCascaderOptions.cascader = {
                        show: true,
                        indent: 200,
                        //是否严格遵守父子模式
                        strict: window.xmSelectData[id].strict,
                    };
                }
            }
            // 定义渲染参数
            let renderOptions = {
                el: el,
                id: id,
                name: name ? name : "",
                language: 'zn',
                data: [],
                filterable: true,
                filterMethod: function (val, item, index, prop) {
                    if (val) {
                        //主标题中包含的大小写都搜索出来
                        if (window.xmSelectData[id].textField && item[window.xmSelectData[id].textField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            return true;
                            //副标题中包含的大小写都搜索出来
                        } else if (window.xmSelectData[id].subTextField && item[window.xmSelectData[id].subTextField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            return true;
                        }
                        return false;//其他的就不要了
                    } else {
                        return true;
                    }
                },
                radio: window.xmSelectData[id].radio,
                searchTips: "输入关键字进行搜索",
                maxMethod: function (selectedData) {
                    facade.error("最多可选" + selectedData.length + "个数据");
                },
                layVerify: window.xmSelectData[id].layVerify,
                layVerType: window.xmSelectData[id].layVerType,
                clickClose: window.xmSelectData[id].radio,
                tips: window.xmSelectData[id].placeholder,
                toolbar: {
                    show: true,
                    list: !(obj.data("radio") === true) ? ['ALL', 'REVERSE', 'CLEAR'] : ['CLEAR']
                },
                theme: {
                    color: localStorage.getItem("theme-color-color")
                },
                direction: window.xmSelectData[id].direction,
                textField: window.xmSelectData[id].textField,
                subTextField: window.xmSelectData[id].subTextField,
                valueField: window.xmSelectData[id].valueField,
                iconField: window.xmSelectData[id].iconField,
                sourceTree: window.xmSelectData[id].sourceTree,
                treeType: window.xmSelectData[id].treeType,
                paging: window.xmSelectData[id].paging,
                pageSize: window.xmSelectData[id].pageSize,
                show: function () {
                    $('.xm-search-input', xmSelectObj[id].dom)
                        .val(xmSelectData[id].searchKeyword)
                        .focus();
                },
                on: function (params) {
                    window.xmSelectData[id].onNum++;
                    if (window.xmSelectData[id].onchange) {
                        if (typeof window[window.xmSelectData[id].onchange] === "function") {
                            if (!window.xmSelectData[id].selected) {
                                window[window.xmSelectData[id].onchange].call(this, params);
                            } else {
                                if (window.xmSelectData[id].paging) {
                                    if (window.xmSelectData[id].onNum > 1) {
                                        window[window.xmSelectData[id].onchange].call(this, params);
                                    }
                                } else {
                                    window[window.xmSelectData[id].onchange].call(this, params);
                                }
                            }
                        } else {
                            facade.error(window.xmSelectData[id].onchange + "回调函数未定义");
                        }
                    }
                },
                model: {
                    label: {
                        block: {
                            template: function (item) {
                                let template = item[window.xmSelectData[id].textField];
                                template = window.xmSelectData[id].iconField ? '<i class="' + item[window.xmSelectData[id].iconField] + ' margin-right5"></i>' + template : template;
                                return template;
                            },
                            showIcon: !(window.xmSelectData[id].radio === true)
                        },
                    },
                    icon: (window.xmSelectData[id].radio === true && !window.xmSelectData[id].sourceTree) ? "hidden" : "show",
                },
                template: function (item) {
                    let template = item.item[window.xmSelectData[id].textField];
                    template = window.xmSelectData[id].iconField ? '<i class="' + item.item[window.xmSelectData[id].iconField] + ' margin-right5"></i>' + template : template;
                    if (window.xmSelectData[id].subTextField.indexOf('.') !== -1) {
                        var subTextFieldArr = window.xmSelectData[id].subTextField.split('.');
                        if (item.item[subTextFieldArr[0]]) {
                            template = template + '<span style="position: absolute; right: 0;">' + item.item[subTextFieldArr[0]][subTextFieldArr[1]] + '</span>';
                        }
                    } else {
                        template = window.xmSelectData[id].subTextField ? template + '<span style="position: absolute; right: 0;">' + item.item[window.xmSelectData[id].subTextField] + '</span>' : template;
                    }
                    return template;
                },
                prop: {
                    name: window.xmSelectData[id].textField
                    , value: window.xmSelectData[id].valueField
                },
                tree: renderTreeOptions,
                cascader: renderCascaderOptions,
                autoRow: true, // 如果选中的项目过多，会自动变动输入框的高度
            };

            // 根据数据来源的不同，进行不同方式的渲染xmSelect组件
            if (window.xmSelectData[id].sourceType === "route") {
                // 只要是route方式获取数据进行渲染组件，那么就需要先组合查询条件
                let ajaxParams = {};
                var param, customParam, searchParam, searchCustomParam = {};
                var key;
                ajaxParams['search_param'] = {};
                if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                    ajaxParams.selected = window.xmSelectData[id].selected.split(',');
                    ajaxParams.selectedField = window.xmSelectData[id].valueField;
                }
                if (window.xmSelectData[id].param) {
                    param = window.xmSelectData[id].param;
                    for (key in param) {
                        ajaxParams['search_param'][key] = param[key];
                    }
                }
                if (window.xmSelectData[id].customParam) {
                    customParam = window.xmSelectData[id].customParam;
                    for (key in customParam) {
                        ajaxParams[key] = customParam[key];
                    }
                }

                // 如果是树形结构的数据，是先进行ajax请求，然后渲染组件
                if (window.xmSelectData[id].sourceTree) {
                    ajaxParams.is_tree = 1;
                    // 如果开启了search且searchParam或者searchCustomParam有值，就需要开启远程搜索
                    if (window.xmSelectData[id].search && (window.xmSelectData[id].searchParam || window.xmSelectData[id].searchCustomParam)) {
                        renderOptions.remoteSearch = true;
                        renderOptions.remoteMethod = function (val, cb, show, pageIndex) {
                            if (window.xmSelectData[id].searchParam) {
                                searchParam = window.xmSelectData[id].searchParam;
                                for (var searchParamKey in searchParam) {
                                    ajaxParams['search_param'][searchParamKey] = searchParam[searchParamKey];
                                    ajaxParams['search_param'][searchParamKey]['value'] = val;
                                }
                            }

                            if (window.xmSelectData[id].searchCustomParam) {
                                searchCustomParam = window.xmSelectData[id].searchCustomParam;
                                for (var searchCustomParamKey in searchCustomParam) {
                                    ajaxParams[searchCustomParamKey] = searchCustomParam[searchCustomParamKey];
                                    ajaxParams[searchCustomParamKey]['value'] = val;
                                }
                            }

                            if (val) {
                                if ($.isEmptyObject(window.xmSelectData[id].searchParam)) {
                                    ajaxParams['search_param'][window.xmSelectData[id].textField] = {
                                        "condition": "LIKE",
                                        "value": val
                                    };
                                }
                            } else {
                                // 1. 用户在页面上先输入搜索值，后删除搜索值，如果没有如下删除语句，ajaxParams对象不会有改变，还是会用有值时的val进行查询
                                // 2. 如果不进行任何判断，仅执行重新定义ajaxParams，会传递like空的查询条件

                                // 所以当没有搜索值时，最好是删除查询条件
                                Reflect.deleteProperty(ajaxParams['search_param'], window.xmSelectData[id].textField);
                            }
                        }
                    }
                    facade.ajax({
                        method: "GET",
                        route: source,
                        data: ajaxParams,
                        successAlert: false
                    }).done(function (res) {
                        renderOptions.paging = 0; // 是否分页的标识使用0和1，否则是一个字符串传递到后台
                        renderOptions.data = res.data;
                        window.xmSelectObj[id] = xmSelect.render(renderOptions);
                        if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                            window.xmSelectObj[id].setValue(window.xmSelectData[id].selected.split(','));
                        }
                    });
                } else {
                    // 非树形结构渲染组件，需要开启远程分页进行组件渲染
                    renderOptions.pageRemote = true;
                    renderOptions.remoteMethod = function (val, cb, show, pageIndex) {
                        window.xmSelectData[id].searchKeyword = val;
                        //val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
                        ajaxParams.paging = window.xmSelectData[id].paging ? 1 : 0;
                        ajaxParams.page = pageIndex;
                        ajaxParams.limit = window.xmSelectData[id].pageSize;

                        if (window.xmSelectData[id].searchParam) {
                            searchParam = window.xmSelectData[id].searchParam;
                            for (var searchParamKey in searchParam) {
                                ajaxParams['search_param'][searchParamKey] = searchParam[searchParamKey];
                                ajaxParams['search_param'][searchParamKey]['value'] = val;
                            }
                        }

                        if (window.xmSelectData[id].searchCustomParam) {
                            searchCustomParam = window.xmSelectData[id].searchCustomParam;
                            for (var searchCustomParamKey in searchCustomParam) {
                                ajaxParams[searchCustomParamKey] = searchCustomParam[searchCustomParamKey];
                                ajaxParams[searchCustomParamKey]['value'] = val;
                            }
                        }

                        if (val) {
                            if ($.isEmptyObject(window.xmSelectData[id].searchParam)) {
                                ajaxParams['search_param'][window.xmSelectData[id].textField] = {
                                    "condition": "LIKE",
                                    "value": val
                                };
                            }
                        } else {
                            // 1. 用户在页面上先输入搜索值，后删除搜索值，如果没有如下删除语句，ajaxParams对象不会有改变，还是会用有值时的val进行查询
                            // 2. 如果不进行任何判断，仅执行重新定义ajaxParams，会传递like空的查询条件

                            // 所以当没有搜索值时，最好是删除查询条件
                            Reflect.deleteProperty(ajaxParams['search_param'], window.xmSelectData[id].textField);
                        }

                        facade.ajax({
                            route: source,
                            data: ajaxParams,
                            successAlert: false,
                        }).done(response => {
                            //这里是success的处理
                            var res = window.xmSelectData[id].paging ? response.data : response;
                            if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                                var selectedArr = window.xmSelectData[id].selected.split(',');
                            }
                            for (var key in res.data) {
                                if (facade.inArray(res.data[key][window.xmSelectData[id].valueField], selectedArr)) {
                                    res.data[key]["selected"] = true;
                                } else {
                                    res.data[key]["selected"] = false;
                                }
                            }
                            //回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
                            window.xmSelectData[id].paging ? cb(res.data, res.last_page) : cb(res.data);
                        }).fail(err => {
                            //这里是error的处理
                            cb([], 0);
                        });
                    };
                    window.xmSelectObj[id] = xmSelect.render(renderOptions);
                }
            } else if (window.xmSelectData[id].sourceType === "data") {
                renderOptions.data = window.xmSelectData[id].source;
                window.xmSelectObj[id] = xmSelect.render(renderOptions);
                if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                    window.xmSelectObj[id].setValue(window.xmSelectData[id].selected.split(','));
                }
            }
        },

        /**
         * linkageXmSelect，使用xmSelect实现的联动下拉框组件
         * <select class="linkageXmSelect"//class="linkageXmSelect"是linkageXmSelect组件渲染的标识
         *         data-id=""//非必设，当前下拉框的唯一标识，id和name不能都为空
         *         data-name=""//非必设，提交表单时的name，id和name不能都为空，如果你不需要将此下拉框的值存入数据库，就不需要设置此值，但是在编辑时，需要自行查询出此值
         *         data-leftId=""//非必设，左关联linkageXmSelect组件的data-id属性值，为空表示联动下拉框的第一个下拉框
         *         data-rightId=""//非必设，右关联linkageXmSelect组件的data-id属性值，为空表示联动下拉框的最后一个下拉框
         *         data-route=""//非必设，route和url至少有一项不为空，优先使用route，数据源接口的路由，函数内部会自行兼容单域名和多域名部署模式
         *         data-url=""//非必设，route和url至少有一项不为空，优先使用route，数据源接口的完整url地址，如果仅设置了url参数，那么url的值是什么，ajax请求的地址就是什么
         *         data-param=''//非必设，数据源初始化查询条件，会合并到search_param中统一进行请求，json数据格式，数据范例：{"字段名1":{"value":搜索值,"condition":"搜索条件"},"字段名2":{"value":搜索值,"condition":"搜索条件"}...}，数据示例：{"pid":{"value":0,"condition":"="}}，注意：所有传递json数据格式时，html标记的属性值要使用单引号
         *         data-customParam=""//非必设，数据源初始化查询条件，不会合并到search_param中进行请求的自定义参数，json数据格式
         *         data-paging="true"//是否分页，true=分页，false=不分页。默认为false
         *         data-pageSize="10"//分页情况下，每页条数
         *         data-search="true"//非必设，是否开启自定义搜索框，true=开启，false=不开启，默认为false
         *         data-searchParam=''//非必设，进行自定义搜索时，数据源查询条件，会合并到search_param中统一进行请求，json数据格式，
         *              数据范例：{"字段名1":{"condition":"搜索条件"},"字段名2":{"condition":"搜索条件"}...}
         *              数据示例：{"name":{"condition":"LIKE"}}
         *              注意：
         *                  1.所有传递json数据格式时，html标记的属性值要使用单引号；
         *                  2.此处无需定义value，仅需定义字段和字段查询的条件，value会使用搜索框中输入的值填充；
         *                  3.当data-search为true，此值设置为空时，会默认使用{"data-textField的值":{"condition":"LIKE"}}作为此配置的值
         *         data-leftOnchangeParam=''//非必设，左关联改变选中项时，当前下拉框查询数据时需要设置的查询条件，会合并到search_param中统一进行请求，当为第一个下拉框时，此值为空。json数据格式，
         *              数据范例：{"字段名1":{"condition":"搜索条件"},"字段名2":{"condition":"搜索条件"}...}，
         *              数据示例：{"pid":{"condition":"="}}，
         *              注意，
         *                  1.所有传递json数据格式时，html标记的属性值要使用单引号；
         *                  2.此处无需定义value，仅需定义字段和字段查询的条件，value会使用左关联下拉框选中项的值
         *         data-leftOnchangeCustomParam='' // 非必设，左关联改变选中项时，当前下拉框查询数据时需要设置的查询条件，不会合并到search_param中进行请求的自定义参数
         *         data-textField=""//必设，显示的文本字段名称
         *         data-subTextField=""//非必设，附属的文本字段名称，仅在下拉框列表中展示
         *         data-iconField=""//非必设，显示文本前展示的图标字段名，为空或者不设置，则显示文本前无图标
         *         data-valueField="id"//非必设，默认为id，下拉框选项的值
         *         data-selected=""//非必设，已选中的值，编辑页面设置选中项
         *         data-onchange="lxmcb"//非必设，当前下拉框改变选中项后，需要执行的函数名，类似select元素的onchage事件，这里需要输入的是函数名称字符串，函数的定义方式和参数详解如下：
         *              window.lxmcb = function(params){
         *                  console.log(params);
         *                  //params是一个对象，有arr、change、isAdd三个属性
         *                  //arr是当前选中项组成的数组，是完成change或者说是click事件后留下的选中项，由于联动下拉框是单选模式的xmSelect，所以此数组仅一个元素
         *                  //change是点击下拉框项组成的数组，因为xmSelect支持下拉框分组，树形结构列表，能点击一个按钮选中/取消选中多个项目，所以也是一个数组，由于联动下拉框是单选模式的xmSelect，所以此数组仅一个元素
         *                  //isAdd表示change里面的内容是选中，还是取消选中操作
         *              }
         *         data-direction="up"//非必设，下拉方向，增加这个参数是因为xmSelect没有做成漂浮，在弹出窗最底层有xmSelect时，会影响美观度
         *         data-placeholder=""//非必设，类似placeholder，未选中数据时，提示文字，默认为"请选择"
         *         data-layVerify="required"//非必设，与layui的lay-verify相同
         *         data-layVerType="tips"//非必设，与layui的lay-verType相同
         * ></select>
         */
        linkageXmSelectOne: function (item) {
            let id = $.trim($(item).data('id'));//id属性
            let name = $.trim($(item).data('name'));//name属性
            if (!id && !name) {
                facade.error('linkageXmSelect组件data-id和data-name属性不能同时为空');
                return false;
            }
            if (!id && name) id = name;

            if (typeof window.linkageXmSelectObj[id] != "undefined") {
                facade.error("linkageXmSelect联动下拉框的data-id或data-name属性值" + id + "重复");
                return false;
            }

            let textField = $(item).data('textfield') ? $(item).data('textfield') : '';
            if (!textField) {
                facade.error('标识为' + id + '的linkageXmSelect联动下拉框组件未定义data-textField属性');
                return false;
            }

            let leftId = $(item).data('leftid') ? $(item).data('leftid') : '';
            let rightId = $(item).data('rightid') ? $(item).data('rightid') : '';
            if (!leftId && !rightId) {
                facade.error('标识为' + id + '的linkageXmSelect联动下拉框组件data-leftId和data-rightId属性不能同时为空');
                return false;
            }

            window.linkageXmSelectJqueryObj[id] = item;

            window.linkageXmSelectData[id] = {
                "id": id,
                "name": $(item).data('name') ? $(item).data('name') : '',
                "leftId": $(item).data('leftid') ? $(item).data('leftid') : '',
                "rightId": $(item).data('rightid') ? $(item).data('rightid') : '',
                "route": $(item).data('route') ? $(item).data('route') : '',
                "url": $(item).data('url') ? $(item).data('url') : '',
                "param": $(item).data('param') ? $(item).data('param') : {},
                "customParam": $(item).data('customparam') ? $(item).data('cutomparam') : {},
                "paging": $(item).data('paging') === true,
                "pageSize": $(item).data('pagesize') ? $(item).data('pagesize') : 10,
                "search": $(item).data('search') ? $(item).data('search') : true,
                "searchParam": $(item).data('searchparam') ? $(item).data('searchparam') : {},
                "leftOnchangeParam": $(item).data('leftonchangeparam') ? $(item).data('leftonchangeparam') : {},
                "leftOnchangeCustomParam": $(item).data('leftonchangecustomparam') ? $(item).data('leftonchangecustomparam') : {},
                "textField": textField,
                "subTextField": $(item).data('subtextfield') ? $(item).data('subtextfield') : '',
                "iconField": $(item).data('iconfield') ? $(item).data('iconfield') : '',
                "valueField": $(item).data('valuefield') ? $(item).data('valuefield') : 'id',
                "selected": $(item).data('selected') ? $(item).data('selected').toString() : '',
                "onchange": $(item).data('onchange') ? $(item).data('onchange') : '',
                "placeholder": $(item).data('placeholder') ? $(item).data('placeholder') : '请选择',
                "layVerify": $(item).data('layverify') ? $(item).data('layverify') : '',
                "layVerType": $(item).data('layvertype') ? $(item).data('layvertype') : '',
                "onNum": 0,
                "searchKeyword": '',
                direction: $(item).data("direction") ? $(item).data("direction") : "auto",
            }

            var jsonTypeAttr = ['param', 'customParam', 'searchParam', 'leftOnchangeParam', 'leftOnchangeCustomParam'];
            for (key in jsonTypeAttr) {
                if (typeof window.linkageXmSelectData[id][jsonTypeAttr[key]] != "object") {
                    facade.error("data-id=" + id + "的linkageXmSelect联动下拉框组件，data-" + jsonTypeAttr[key] + "属性值需要是一个正确的json字符串");
                    return false;
                }
            }

            if (window.linkageXmSelectData[id].search && $.isEmptyObject(window.linkageXmSelectData[id].searchParam)) {
                window.linkageXmSelectData[id].searchParam[textField] = {"condition": "LIKE"};
            }

            window.linkageXmSelectObj[id] = xmSelect.render({
                el: item,
                name: window.linkageXmSelectData[id].name,
                //配置搜索
                filterable: window.linkageXmSelectData[id].search,
                //配置远程分页
                paging: window.linkageXmSelectData[id].paging,
                pageSize: window.linkageXmSelectData[id].pageSize,
                pageRemote: true,
                prop: {
                    name: window.linkageXmSelectData[id].textField
                    , value: window.linkageXmSelectData[id].valueField
                },
                model: {
                    label: {
                        block: {
                            showIcon: false
                        }
                    },
                    icon: "hidden"
                },
                direction: window.linkageXmSelectData[id].direction,
                layVerify: window.linkageXmSelectData[id].layVerify,
                layVerType: window.linkageXmSelectData[id].layVerType,
                //template是设置下拉框的模板
                template: function (item) {
                    let template = item.item[window.linkageXmSelectData[id].textField];
                    template = window.linkageXmSelectData[id].iconField ? '<i class="' + item.item[window.linkageXmSelectData[id].iconField] + ' margin-right5"></i>' + template : template;
                    template = window.linkageXmSelectData[id].subTextField ? template + '<span style="position: absolute; right: 0;">' + item.item[window.linkageXmSelectData[id].subTextField] + '</span>' : template;
                    return template;
                },
                radio: true,
                clickClose: true,
                tips: window.linkageXmSelectData[id].placeholder,
                toolbar: {
                    show: true,
                    list: ['CLEAR']
                },
                theme: {
                    color: localStorage.getItem("theme-color-color")
                },
                filterMethod: function (val, item, index, prop) {
                    if (val) {
                        //主标题中包含的大小写都搜索出来
                        if (window.linkageXmSelectData[id].textField && item[window.linkageXmSelectData[id].textField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            return true;
                            //副标题中包含的大小写都搜索出来
                        } else if (window.linkageXmSelectData[id].subTextField && item[window.linkageXmSelectData[id].subTextField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            return true;
                        }
                        return false;//其他的就不要了
                    } else {
                        return true;
                    }
                },
                show: function () {
                    $('.xm-search-input', window.linkageXmSelectData[id].dom)
                        .val(linkageXmSelectData[id].searchKeyword)
                        .focus();
                },
                //数据处理
                remoteMethod: function (val, cb, show, pageIndex) {
                    window.linkageXmSelectData[id].searchKeyword = val;
                    if (window.linkageXmSelectData[id].leftId) {
                        if (!$(window.linkageXmSelectJqueryObj[window.linkageXmSelectData[id].leftId]).data('selected')) {
                            cb([], 0);
                            return false;
                        }
                    }
                    var remoteSearchParam = {};
                    var ajaxParams = {};
                    ajaxParams = {
                        paging: window.linkageXmSelectData[id].paging ? 1 : 0,
                        page: pageIndex,
                        limit: window.linkageXmSelectData[id].pageSize,
                        selected: window.linkageXmSelectData[id].selected,
                        selectedField: window.linkageXmSelectData[id].valueField,
                    };
                    remoteSearchParam = window.linkageXmSelectData[id].param;
                    if (window.linkageXmSelectData[id].searchParam) {
                        for (key in window.linkageXmSelectData[id].searchParam) {
                            remoteSearchParam[key] = {
                                value: val,
                                condition: window.linkageXmSelectData[id].searchParam[key].condition,
                            }
                        }
                    }
                    if (window.linkageXmSelectData[id].leftId) {
                        if ($(window.linkageXmSelectJqueryObj[window.linkageXmSelectData[id].leftId]).data('selected')) {
                            if (window.linkageXmSelectData[window.linkageXmSelectData[id].leftId].onNum <= 1) {
                                if (window.linkageXmSelectData[id].leftOnchangeParam) {
                                    for (key in window.linkageXmSelectData[id].leftOnchangeParam) {
                                        remoteSearchParam[key] = {
                                            value: $(window.linkageXmSelectJqueryObj[window.linkageXmSelectData[id].leftId]).data('selected'),
                                            condition: window.linkageXmSelectData[id].leftOnchangeParam[key].condition,
                                        }
                                    }
                                }
                                if (window.linkageXmSelectData[id].leftOnchangeCustomParam) {
                                    for (key in window.linkageXmSelectData[id].leftOnchangeCustomParam) {
                                        ajaxParams[key] = window.linkageXmSelectData[id].leftOnchangeCustomParam[key];
                                    }
                                }
                            }
                        }
                    }
                    ajaxParams.search_param = remoteSearchParam;
                    if (window.linkageXmSelectData[id].customParam) {
                        for (key in window.linkageXmSelectData[id].customParam) {
                            ajaxParams[key] = window.linkageXmSelectData[id].customParam[key];
                        }
                    }
                    //val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
                    facade.ajax({
                        route: window.linkageXmSelectData[id].route,
                        url: window.linkageXmSelectData[id].url,
                        data: ajaxParams,
                        successAlert: false,
                    }).done(response => {
                        //这里是success的处理
                        var res = response.data;
                        for (var key in res.data) {
                            if (res.data[key][window.linkageXmSelectData[id].valueField] == window.linkageXmSelectData[id].selected) {
                                res.data[key]["selected"] = true;
                            } else {
                                res.data[key]["selected"] = false;
                            }
                        }
                        //回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
                        window.linkageXmSelectData[id].paging ? cb(res.data, res.last_page) : cb(res);
                    }).fail(err => {
                        //这里是error的处理
                        cb([], 0);
                    });
                },
                on: function (params) {
                    window.linkageXmSelectData[id].onNum++;
                    if (window.linkageXmSelectData[id].selected > 0 && window.linkageXmSelectData[id].onNum <= 1) {
                        return true;
                    }
                    if (!window.linkageXmSelectData[id].rightId) {
                        return true;
                    }
                    // 下面这个数据说明是点击了分页进行了ajax触发了onChange
                    if (params.change.length == 0 && params.arr.length > 0) {
                        return true;
                    }
                    if (params.arr.length == 0) {
                        if (window.linkageXmSelectData[id].rightId) {
                            window.linkageXmSelectObj[window.linkageXmSelectData[id].rightId].update({
                                remoteMethod: function (val, cb, show, pageIndex) {
                                    cb([], 0);
                                    window.linkageXmSelectObj[window.linkageXmSelectData[id].rightId].setValue([]);
                                }
                            });
                            return true;
                        }
                    }
                    window.linkageXmSelectObj[window.linkageXmSelectData[id].rightId].update({
                        // val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
                        remoteMethod: function (val, cb, show, pageIndex) {
                            window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].searchKeyword = val;
                            var rightRemoteSearchParam = {};
                            rightRemoteSearchParam = window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].param;
                            if (window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].searchParam) {
                                for (key in window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].searchParam) {
                                    rightRemoteSearchParam[key] = {
                                        value: val,
                                        condition: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].searchParam[key].condition,
                                    }
                                }
                            }
                            if (window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].leftOnchangeParam) {
                                for (key in window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].leftOnchangeParam) {
                                    rightRemoteSearchParam[key] = {
                                        value: params["arr"][0][window.linkageXmSelectData[id].valueField],
                                        condition: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].leftOnchangeParam[key].condition,
                                    }
                                }
                            }

                            facade.ajax({
                                route: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].route,
                                url: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].url,
                                data: {
                                    paging: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].paging ? 1 : 0,
                                    page: pageIndex,
                                    pageSize: window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].pageSize,
                                    search_param: rightRemoteSearchParam
                                },
                                successAlert: false,
                            }).done(response => {
                                //这里是success的处理
                                var res = response.data;
                                //回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
                                window.linkageXmSelectData[window.linkageXmSelectData[id].rightId].paging ? cb(res.data, res.last_page) : cb(res);
                                window.linkageXmSelectObj[window.linkageXmSelectData[id].rightId].setValue([]);
                            }).fail(err => {
                                //这里是error的处理
                                cb([], 0);
                                window.linkageXmSelectObj[window.linkageXmSelectData[id].rightId].setValue([]);
                            });
                        }
                    });

                    if (window.linkageXmSelectData[id].onchange) {
                        if (typeof window[window.linkageXmSelectData[id].onchange] === "function") {
                            window[window.linkageXmSelectData[id].onchange].call(this, params);
                        } else {
                            facade.error(window.linkageXmSelectData[id].onchange + "回调函数未定义");
                        }
                    }
                }
            });
        },

        /**
         * 联动下拉框，linkage的下拉框会渲染成普通select下拉框组件
         * <select class="linkageSelect"
         *         lay-search="true"
         *         lay-filter="id"
         *         id="id"
         *         name="id"
         *         data-leftField=""//左关联字段，为空表示联动下拉框的第一个下拉框
         *         data-rightField=""//右关联字段，为空表示联动下拉框的最后一个下拉框
         *         data-url=""//下拉框数据源url地址，对应一个数据表的index
         *         data-params='{"field":{"value":"fieldVla","condition":"="}}'
         *         data-showField="short_name"
         *         data-searchField="pid"//数据源搜索字段
         *         data-searchCondition="="//数据源搜索条件，默认为=
         *         data-searchVal="0"//数据源搜索值
         *         data-selectedVal=""//已选中的值，编辑页面
         *         data-onchange="lscb"//非必设，监听选中变化的函数名称，类似select元素的onchage事件，这里需要输入的是函数名称字符串，函数的定义方式和参数详解如下：
         *         window.lscb = function(data){
         *              console.log(data);
         *              //data值与layui.form.on('select(' + id + ')', function (data) {});监听中的data值一样
         *         }
         * ></select>
         */
        linkageSelectOne: function (item) {
            let id = $(item).attr('id');//id属性，必须
            if (!id) {
                facade.error('linkageSelect组件未定义id属性');
                return false;
            }
            let showField = $(item).data('showfield') ? $(item).data('showfield') : 'name';//显示的字段，默认是name
            let url = $(item).data('url');//下拉框数据源url地址，对应一个数据表的index
            let params = $(item).data('params');
            let searchField = $(item).data('searchfield') ? $(item).data('searchfield') : 'pid';//搜索的字段，默认是pid
            let searchCondition = $(item).data('searchcondition') ? $(item).data('searchcondition') : '=';
            let searchVal = $(item).data('searchval') ? $(item).data('searchval') : 0;//搜索字段的值，默认0,如果只想选某个省下面的城市和地区可以设置这个值
            let selectedVal = $(item).data('selectedval');//选中的值，非必填
            let leftField = $(item).data('leftfield');//左关联字段，为空或者不设置时，表示第一个下拉框
            let rightField = $(item).data('rightfield');//右关联字段，为空或者不设置时，表示最后一个下拉框
            let onchange = $(item).data("onchange") ? $(item).data("onchange") : "";//onchange回调函数名
            if (!leftField && !rightField) {
                facade.error("linkageSelect组件的data-leftField和data-rightField属性不能都为空");
            }
            //填充联动的第一个下拉框数据
            if (leftField === "" || leftField === undefined) {
                let searchParam;
                if (params) {
                    searchParam = params;
                } else {
                    searchParam = {};
                }
                searchParam[searchField] = {};
                searchParam[searchField].value = searchVal;
                searchParam[searchField].condition = searchCondition;
                facade.ajax({
                    method: "GET",
                    route: url,
                    data: {search_param: searchParam, all_data: 1},
                    successAlert: false
                }).done(function (res) {
                    let optionTips = $(item).children().first().prop("outerHTML");
                    $(item).empty();
                    $(item).append(optionTips);
                    let optionHtml, key;
                    for (key in res.data) {
                        if (selectedVal === res.data[key]['id']) {
                            optionHtml = '<option value="' + res.data[key]['id'] + '" selected="selected">' + res.data[key][showField] + '</option>';
                        } else {
                            optionHtml = '<option value="' + res.data[key]['id'] + '">' + res.data[key][showField] + '</option>';
                        }

                        $(item).append(optionHtml);
                    }
                    layui.form.render('select');
                    // 如果第一个下拉框有onchange，就执行onchange
                    if (onchange) {
                        var nowData = {};
                        nowData.elem = $("#" + id);
                        nowData.othis = {};
                        nowData.value = selectedVal;
                        window[onchange].call(this, nowData);
                    }
                });
            }
            //监听所有下拉框onchange事件
            if (rightField) {
                layui.form.on('select(' + id + ')', function (data) {
                    if (data.value) {
                        let rightSearchUrl = $("#" + rightField).data('url');
                        let rightParams = $("#" + rightField).data('params');
                        let rightSearchField = $("#" + rightField).data('searchfield') ? $("#" + rightField).data('searchfield') : 'pid';//搜索的字段，默认是pid
                        let rightSearchParam;
                        if (rightParams) {
                            rightSearchParam = rightParams;
                        } else {
                            rightSearchParam = {}
                        }
                        rightSearchParam[rightSearchField] = {};
                        rightSearchParam[rightSearchField].value = data.value;
                        rightSearchParam[rightSearchField].condition = $("#" + rightField).data('searchcondition') ? $("#" + rightField).data('searchcondition') : "=";
                        facade.ajax({
                            method: "GET",
                            route: rightSearchUrl,
                            data: {search_param: rightSearchParam, all_data: 1},
                            successAlert: false
                        }).done(function (res) {
                            let rightOptionTips = $("#" + rightField).children().first().prop("outerHTML");
                            $("#" + rightField).empty();
                            $("#" + rightField).append(rightOptionTips);
                            let rightOptionHtml, key;
                            for (key in res.data) {
                                rightOptionHtml = '<option value="' + res.data[key]['id'] + '">' + res.data[key]['name'] + '</option>';
                                $("#" + rightField).append(rightOptionHtml);
                            }

                            let nextRightField = $("#" + rightField).data('rightfield');
                            let nextOptionTips = "";
                            while (nextRightField !== "" && nextRightField !== undefined) {
                                nextOptionTips = $("#" + nextRightField).children().first().prop("outerHTML");
                                $("#" + nextRightField).empty();
                                $("#" + nextRightField).append(nextOptionTips);
                                nextRightField = $("#" + nextRightField).data('rightfield');
                            }
                            layui.form.render('select');

                            // 如果有onchange 就执行onchage
                            if (onchange) {
                                var nowData = {};
                                nowData.elem = $("#" + id);
                                nowData.othis = {};
                                nowData.value = selectedVal;
                                window[onchange].call(this, nowData);
                            }
                        });
                    } else {
                        let rightOptionTips = $("#" + rightField).children().first().prop("outerHTML");
                        $("#" + rightField).empty();
                        $("#" + rightField).append(rightOptionTips);
                        let nextRightField = $("#" + rightField).data('rightfield');
                        let nextOptionTips = "";
                        while (nextRightField !== "" && nextRightField !== undefined) {
                            nextOptionTips = $("#" + nextRightField).children().first().prop("outerHTML");
                            $("#" + nextRightField).empty();
                            $("#" + nextRightField).append(nextOptionTips);
                            nextRightField = $("#" + nextRightField).data('rightfield');
                        }
                        layui.form.render('select');

                        // 如果有onchange 就执行onchange
                        if (onchange) {
                            var nowData = {};
                            nowData.elem = $("#" + id);
                            nowData.othis = {};
                            nowData.value = selectedVal;
                            window[onchange].call(this, nowData);
                        }
                    }
                });
            } else {
                // 如果有onchange 就执行onchage
                if (onchange) {
                    layui.form.on('select(' + id + ')', function (data) {
                        var nowData = {};
                        nowData.elem = $("#" + id);
                        nowData.othis = {};
                        nowData.value = selectedVal;
                        window[onchange].call(this, nowData);
                    });
                }
            }
            //如果有选中值，就请求渲染右侧下拉框
            if (selectedVal !== "" && selectedVal !== undefined) {
                if (rightField !== "" && rightField !== undefined) {
                    let selectedRightSearchUrl = $("#" + rightField).data('url');
                    let selectedRightParams = $("#" + rightField).data('params');
                    let selectedRightSearchField = $("#" + rightField).data('searchfield') ? $("#" + rightField).data('searchfield') : 'pid';//搜索的字段，默认是pid
                    let selectedRightSearchParam;
                    if (selectedRightParams) {
                        selectedRightSearchParam = selectedRightParams;
                    } else {
                        selectedRightSearchParam = {};
                    }
                    selectedRightSearchParam[selectedRightSearchField] = {};
                    selectedRightSearchParam[selectedRightSearchField].value = selectedVal;
                    selectedRightSearchParam[selectedRightSearchField].condition = $("#" + selectedRightSearchField).data('searchcondition') ? $("#" + selectedRightSearchField).data('searchcondition') : "=";
                    facade.ajax({
                        method: "GET",
                        route: selectedRightSearchUrl,
                        data: {search_param: selectedRightSearchParam, all_data: 1},
                        successAlert: false
                    }).done(function (res) {
                        let selectedRightOptionTips = $("#" + rightField).children().first().prop("outerHTML");
                        $("#" + rightField).empty();
                        $("#" + rightField).append(selectedRightOptionTips);
                        let rightSelectedVal = $("#" + rightField).data('selectedval');
                        let selectedOptionHtml, key;
                        for (key in res.data) {
                            if (rightSelectedVal === res.data[key]['id']) {
                                selectedOptionHtml = '<option value="' + res.data[key]['id'] + '" selected="selected">' + res.data[key][showField] + '</option>';
                            } else {
                                selectedOptionHtml = '<option value="' + res.data[key]['id'] + '">' + res.data[key][showField] + '</option>';
                            }
                            $("#" + rightField).append(selectedOptionHtml);
                        }
                        layui.form.render('select');

                        // 如果右侧下拉框有选中值和onchange，就执行右侧下拉框的onchange
                        var rightOnchange = $("#" + rightField).data('onchange');
                        if (rightSelectedVal && rightOnchange) {
                            var rightData = {};
                            rightData.elem = $("#" + rightField);
                            rightData.othis = {};
                            rightData.value = rightSelectedVal;
                            window[rightOnchange].call(this, rightData);
                        }
                    });
                }
            }
        },

        /**
         * 上传组件
         * <div class="laytpUpload"//class="laytpUpload"是上传组件渲染的标识
         *      data-name="name"//必设，提交表单时的name
         *      data-type="default"//非必设，上传方式，默认的值为default，目前允许使用的上传方式有
         *          - default=默认上传方式，系统会获取由系统配置，上传配置，默认上传方式配置项进行配置的上传方式;
         *          - local=本地上传;
         *          - ali-oss=阿里云OSS上传;
         *          - qiniu-kodo=七牛云KODO上传
         *      data-viaServer="via/unVia"//非必设，是否经过服务器端，默认via，经过服务器，此参数的有效性与data-type的值相关
         *          - 当data-type=local时，此参数无效
         *          - 当data-type=ali-oss时，且此参数为via时，是由客户端先把文件上传到服务器上，然后再由服务器上传到阿里云OSS
         *          - 当data-type=ali-oss时，且此参数为unVia时，是由客户端先请求服务器端得到阿里云的STS临时上传凭证，然后由客户端把文件直接上传到阿里云oss
         *          - 当data-type=qiniu-kodo时，情况与data-type=ali-oss时相似
         *      data-showUploadBtn="true"//非必设，是否显示上传按钮，默认true
         *      data-showChoiceBtn="true"//非必设，是否显示选择附件按钮，默认true
         *      data-fileCategoryId="integer"//非必设，所属分类的ID，默认0
         *      data-accept="image"//非必设，允许上传的类型，image=图片，video=视频，audio=音频，file=任意文件，默认为image
         *      data-width="500"//非必设，accept="image"时，允许上传图片的最大宽度，单位px，默认不限制
         *      data-height="300"//非必设，accept="image"时，允许上传图片的最大高度，单位px，默认不限制
         *      data-multi="true"//非必设，多文件模式，true=开启多文件模式，false=关闭多文件模式，默认false
         *      data-max="2"//非必设，多文件模式下有效的参数，设置允许最多上传的文件个数，默认不限制个数
         *      data-dir=""//非必设，上传的目录，允许不传，不传就传到storage目录下，如果不为空，则在storage目录下创建对应的目录，允许使用/指明多级目录
         *      data-route=""//非必设，文件上传请求的后台地址，默认为/admin.common/upload，自定义的url返回数据格式要和/admin.common/upload保持一致
         *      data-uploaded=""//非必设，已经上传的文件路径，多个以英文半角的逗号+空格进行分割，用于编辑页面展示已经上传的文件
         *      data-uploadedId=""//非必设，已经上传的文件列表的ID值，多个以英文半角的逗号进行分割，用于编辑页面展示已经上传的文件Id
         *      data-uploadedFilename=""//非必设，已经上传的文件列表的数据库存储的文件名，多个以英文半角逗号+空格进行分割，用于编辑页面展示已经上传的文件名，目前仅上传文件时需要展示
         *      data-uploadedCallback="callbackFun"//非必设，传入字符串，上传成功后的回调函数名称
         *          - 比如定义的值为callbackFun，然后在全局定义如下函数即可执行回调
         *              function callbackFun(file){
         *                  console.log(file);//得到file的信息
         *                  //这里写上传成功后的回调操作
         *                  return facade.success('上传成功');//如果你设置了回调函数，那么上传成功的提示要自己调用函数进行返回
         *              }
         *      data-mime="*"//非必设，允许上传的文件后缀名，为空使用后台常规管理->系统配置->上传配置设置mime的值
         *      data-size="100mb"//非必设，允许上传的文件大小，单位b,B,k,K,kb,KB,m,M,mb,MB,g,G,gb,GB，为空使用后台常规管理->系统配置->上传配置设置size的值
         *      data-layVerify="required"//非必设，与layui的lay-verify相同
         *      data-layVerType="tips"//非必设，与layui的lay-verType相同
         * ></div>
         */
        uploadOne: function (item) {
            let name = $(item).data("name");
            if (!name) {
                facade.error("laytpUpload组件未定义name属性");
                return false;
            }
            let options = {
                el: item,
                name: name,
                type: $(item).data("type") ? $(item).data("type") : "local",
                viaServer: $(item).data("viaserver") ? $(item).data("viaserver") : 'via',
                fileCategoryId: $(item).data("filecategoryid") ? $(item).data("filecategoryid") : 0,
                accept: $(item).data("accept") ? $(item).data("accept") : "image",
                width: $(item).data("width") ? $(item).data("width") : "0",
                height: $(item).data("height") ? $(item).data("height") : "0",
                mime: $(item).data("mime") ? $(item).data("mime") : "",
                size: $(item).data("size") ? $(item).data("size") : "",
                multi: $(item).data("multi") === true,
                max: $(item).data("max"),
                dir: $(item).data("dir") ? $(item).data("dir") : "",
                showUploadBtn: typeof $(item).data("showuploadbtn") === "undefined" || $(item).data("showuploadbtn") === true,
                showChoiceBtn: typeof $(item).data("showchoicebtn") === "undefined" || $(item).data("showchoicebtn") === true,
                uploaded: $(item).data("uploaded") && $(item).data("uploaded") !== "undefined" ? $(item).data("uploaded") : "",
                uploadedId: $(item).data("uploadedid") && $(item).data("uploadedid") !== "undefined" ? $(item).data("uploadedid") : "",
                uploadedFilename: $(item).data("uploadedfilename") && $(item).data("uploadedfilename") !== "undefined" ? $(item).data("uploadedfilename") : "",
                uploadedCallback: $(item).data("uploadedcallback") ? $(item).data("uploadedcallback") : "",
                route: $(item).data("route") ? $(item).data("route") : false,
            };
            options.layVerify = $(item).data("layverify") ? $(item).data("layverify") : "";
            options.layVerType = $(item).data("layvertype") ? $(item).data("layvertype") : "";
            options.params = {
                "accept": options.accept
            };
            if (options.dir) options.params.dir = options.dir;
            if (options.width) options.params.width = options.width;
            if (options.height) options.params.height = options.height;
            if (options.mime) options.params.mime = options.mime;
            if (options.size) options.params.size = options.size;
            if (options.type) options.params.upload_type = options.type;
            if (options.fileCategoryId) options.params.file_category_id = options.fileCategoryId;
            if (options.viaServer === 'via') {
                layui.laytpUpload.render(options);
            } else {
                if (options.type === 'ali-oss') {
                    layui.laytpUpload.renderStsOss(options);
                } else if (options.type === 'qiniu-kodo') {
                    layui.laytpUpload.renderTokenKodo(options);
                }
            }
        },

        /**
         * 选择图标组件
         * <div class="laytpIcon"//class="laytpIcon"是选择图标组件渲染的标识
         *      data-name="name"//提交表单时的name
         *      data-value="layui-icon layui-icon-rate-half"//已经选中的图标，用于编辑页面
         *      data-placeholder="请选择****"//非必设，默认为"请选择"，未选中数据时，提示文字
         *      data-layVerify="required"//非必设，与layui的lay-verify相同
         *      data-layVerType="tips"//非必设，与layui的lay-verType相同
         * ></div>
         */
        iconOne: function (item) {
            let name = $(item).data("name");
            if (!name) {
                facade.error("laytpIcon组件未定义name属性");
                return false;
            }
            let options = {
                el: item
                , name: name
                , value: $(item).data("value") ? $(item).data("value") : ""
                , placeholder: $(item).data("placeholder") ? $(item).data("placeholder") : "请选择"
                , layVerify: $(item).data("layverify") ? $(item).data("layverify") : ""
                , layVerType: $(item).data("layvertype") ? $(item).data("layvertype") : ""
            };
            layui.laytpIcon.render(options);
        },

        /**
         * 时间选择器
         * <input //必须为input元素
         *  readonly // 只读状态。加上这个属性，时间选择器输入框就不允许手动修改
         *  type="text" //type必须等于text，单行输入框
         *  class="layui-input laydate" //class中有laydate表示这个单行输入框需要渲染成时间选择器
         *  data-type="month" //data-type表示时间选择器的类型，默认为datetime，
         *      - year=年选择器，只提供年列表选择，
         *      - month=年月选择器，只提供年-月选择，
         *      - date=日期选择器，可选择格式：年-月-日，
         *      - time=时间选择器，可选择格式为时:分:秒，
         *      - datetime=日期时间选择器，可选择格式为：年-月-日 时:分:秒
         *  date-isRange="false" // 表示是否为范围选择器，默认为false
         *  data-shortcuts="" // 允许没有，用于开启面板左侧的快捷选择栏，此处需要使用layui.react.regData注册的数据，注册数据的写法：
         *  layui.use(['react'],function(){
         *      shortcuts:[
         *          {
                        text: "昨天",
                        value: function(){
                            var now = new Date();
                            now.setDate(now.getDate() - 1);
                            return now;
                        }
                    }
         *      ]
         *  }).use(['laytp'],funciton(){
         *
         *  });
         *  data-done="时间选择完毕之后的回调函数名" // 非必填
         - 比如定义的值为callbackFun，然后在全局定义如下函数即可执行回调
         function callbackFun(value, date, endDate){
                    console.log(value); //得到日期生成的值，如：2017-08-18
                    console.log(date); //得到日期时间对象：{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                    console.log(endDate); //得结束的日期时间对象，开启范围选择（range: true）才会返回。对象成员同上。
               }
         *  name="date" //提交表单时的name
         *  id="date" //元素的id值
         *  autocomplete="off" //不要浏览器记住已经输入过的值进行输入提示
         *  placeholder="请选择时间" //输入框为空时的提示文字
         *  />
         */
        laydateOne: function (item) {
            var obj, el;

            if (typeof item == "string") {
                el = ($('.laydate[id="' + item + '"]').length == 0) ? '.laydate[name="' + item + '"]' : '.laydate[id="' + item + '"]';
            } else {
                el = item;
            }

            obj = $(el);
            let id = obj.attr('id');
            if(!id){
                facade.error('laydate时间选择器没有定义id属性');
                return false;
            }
            let type = obj.data('type') ? obj.data('type') : 'datetime';
            let isRange = obj.data('isrange');
            let doneFun = obj.data('done');
            let shortcuts = obj.data('shortcuts');
            if(isRange){
                $('#' + obj.attr('id')).css('width','292px');
                $('#' + obj.attr('id')).parent().removeClass('layui-input-inline').addClass('layui-input-block');
            }
            $('#' + obj.attr('id')).attr('autocomplete','off');
            layui.laydate.render({
                elem: '#' + obj.attr('id') //指定元素
                , type: type
                , range: isRange
                , rangeLinked: true
                , shortcuts: layui.react.data[shortcuts]
                , done: function (value, date, endDate) {
                    if (doneFun) {
                        window[doneFun].call(this, value, date, endDate);
                    }
                    // doneFun(value, date, endDate);
                    // console.log(value); //得到日期生成的值，如：2017-08-18
                    // console.log(date); //得到日期时间对象：{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                    // console.log(endDate); //得到结束的日期时间对象，开启范围选择（range: true）才会返回。对象成员同上。
                }
            });
        },

        /**
         * 颜色选择器，colorPicker
         * <div class="colorPicker"
         *  data-id="color_picker"//输入框的id属性值，默认和name相同，当name有中括号时，jquery获取不到对象，需要单独设置id值
         *  data-name="color_picker"//提交表单的name
         *  data-color="#000"//默认颜色
         *  data-format="hex"//颜色格式，hex(16进制色值，例:#000)，rgb(例：rgb(255,255,255))
         *  data-alpha="true"//开启透明度，默认false
         *  data-predefine="true"//是否开启预定义颜色
         *  data-colors="['#ff4500','#1e90ff','rgba(255, 69, 0, 0.68)','rgb(255, 120, 0)']"//开启预定义颜色后，设置预定义颜色的数组
         * ></div>
         */
        colorPickerOne: function (item) {
            var obj, el;

            if (typeof item == "string") {
                el = ($('.colorPicker[data-id="' + item + '"]').length == 0) ? '.colorPicker[data-name="' + item + '"]' : '.colorPicker[data-id="' + item + '"]';
            } else {
                el = item;
            }

            obj = $(el);
            let name = obj.data("name");
            let id = obj.data("id") ? obj.data("id") : name;
            let colorPickerTemplate =
                '<div class="layui-input-inline" style="margin-right: -1px;">' +
                '   <input type="text" class="layui-input" id="' + id + '" name="' + name + '" readonly="readonly" />' +
                '</div>' +
                '<div class="layui-input-inline">' +
                '   <div id="color_picker_' + id + '"></div>' +
                '</div>'
            ;
            obj.html(colorPickerTemplate);

            let options = {};
            options.elem = "#color_picker_" + id;
            let color = obj.data("color");
            if (color) {
                options.color = color;
                $("#" + id).val(color);
            }
            let format = obj.data("format");
            if (format) options.format = format;
            let alpha = obj.data("alpha");
            if (alpha) options.alpha = alpha;
            let predefine = obj.data("predefine");
            if (predefine) options.predefine = predefine;
            let colors = obj.data("colors");
            if (colors) options.colors = eval(colors);
            options.size = 'xs';

            options.change = function (color) {
                $("#" + id).val(color);
            };

            options.done = function (color) {
                $("#" + id).val(color);
            };
            layui.colorpicker.render(options);
        },
    };

    /**
     * 渲染所有的表单元素
     */
    laytpForm.render = function (callback) {
        //执行表单初始化方法
        layui.each(laytpForm.initData, function (key, item) {
            if (typeof item == "function") {
                item();
            }
        });

        // 在表单初始化方法中，如果有ajax请求，允许将ajax延迟对象存入全局的defArr数组
        // 接下来，等待所有的延迟对象ajax请求执行完成，渲染表单元素
        $.when.apply($, defArr).done(function () {
            layui.form.render();
            if (typeof callback == "function") {
                callback();
            }
        });
    };

    /**
     * 渲染某一个具体的表单元素
     * @param item      需要渲染的jquery对象
     * @param formType  表单元素的class标识
     */
    laytpForm.renderOne = function (item, formType) {
        var funName = facade.underlineToCamel(formType) + "One";
        if (typeof layui.laytpForm.initDataOne[funName] == "function") {
            layui.laytpForm.initData[options.onchange].call(this, item);
        }
    };

    /**
     * 渲染某一个具体的select
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderSelect = function (item) {
        layui.laytpForm.initDataOne['selectOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的xmSelect
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderXmSelect = function (item) {
        layui.laytpForm.initDataOne['xmSelectOne'].call(this, item);
    };

    /**
     * 动态更新某一个具体的xmSelect
     * @param id xmSelect的id属性值
     * @param options object，需要更新的值
     */
    laytpForm.updateXmSelect = function (id, options) {
        window.xmSelectData[id] = {
            id: options.hasOwnProperty('id') ? options.id : window.xmSelectData[id].id,
            name: options.hasOwnProperty('name') ? options.name : window.xmSelectData[id].name,
            sourceType: options.hasOwnProperty('sourceType') ? options.sourceType : window.xmSelectData[id].sourceType,
            source: options.hasOwnProperty('source') ? options.source : window.xmSelectData[id].source,
            param: options.hasOwnProperty('param') ? options.param : window.xmSelectData[id].param,
            customParam: options.hasOwnProperty('customParam') ? options.customParam : window.xmSelectData[id].customParam,
            search: options.hasOwnProperty('search') ? options.search : window.xmSelectData[id].search,
            searchParam: options.hasOwnProperty('search') ? options.search : window.xmSelectData[id].search,
            searchCustomParam: options.hasOwnProperty('searchCustomParam') ? options.searchCustomParam : window.xmSelectData[id].searchCustomParam,
            textField: options.hasOwnProperty('textField') ? options.textField : window.xmSelectData[id].textField,
            subTextField: options.hasOwnProperty('subTextField') ? options.subTextField : window.xmSelectData[id].subTextField,
            valueField: options.hasOwnProperty('valueField') ? options.valueField : window.xmSelectData[id].valueField,
            iconField: options.hasOwnProperty('iconField') ? options.iconField : window.xmSelectData[id].iconField,
            sourceTree: options.hasOwnProperty('sourceTree') ? options.sourceTree : window.xmSelectData[id].sourceTree,
            treeType: options.hasOwnProperty('treeType') ? options.treeType : window.xmSelectData[id].treeType,
            onchange: options.hasOwnProperty('onchange') ? options.onchange : window.xmSelectData[id].onchange,
            paging: options.hasOwnProperty('paging') ? options.paging : window.xmSelectData[id].paging,
            pageSize: options.hasOwnProperty('pageSize') ? options.pageSize : window.xmSelectData[id].pageSize,
            radio: options.hasOwnProperty('radio') ? options.radio : window.xmSelectData[id].radio,
            strict: options.hasOwnProperty('strict') ? options.strict : (options.hasOwnProperty('radio') ? !(options.radio === true) : window.xmSelectData[id].strict),
            selected: options.hasOwnProperty('selected') ? options.selected : window.xmSelectData[id].selected,
            max: options.hasOwnProperty('max') ? options.max : window.xmSelectData[id].max,
            direction: options.hasOwnProperty('direction') ? options.direction : window.xmSelectData[id].direction,
            layVerify: options.hasOwnProperty('layVerify') ? options.layVerify : window.xmSelectData[id].layVerify,
            layVerType: options.hasOwnProperty('layVerType') ? options.layVerType : window.xmSelectData[id].layVerType,
            placeholder: options.hasOwnProperty('placeholder') ? options.placeholder : window.xmSelectData[id].placeholder,
            searchKeyword: '',
            onNum: 0,
        }

        if (window.xmSelectData[id].sourceType != 'data') {
            var jsonTypeAttr = ['param', 'customParam', 'searchParam', 'searchCustomParam'];
            for (key in jsonTypeAttr) {
                if (typeof window.xmSelectData[id][jsonTypeAttr[key]] != "object") {
                    facade.error(id + "在调用updateXmSelect时， " + jsonTypeAttr[key] + "属性值需要是一个对象");
                    return false;
                }
            }
        }

        if (window.xmSelectData[id].sourceType == 'data') {
            if (typeof window.xmSelectData[id].source != "object") {
                facade.error(id + '在调用updateXmSelect时，source属性值需要是一个对象');
                return false;
            }
        }

        // 定义树形结构渲染参数
        let renderTreeOptions = {};
        // 定义级联模式渲染参数
        let renderCascaderOptions = {};
        // 赋值树形结构渲染参数和级联模式渲染参数
        if (window.xmSelectData[id].sourceTree) {
            if (window.xmSelectData[id].treeType === 'tree') {
                renderTreeOptions = {
                    //是否显示树状结构
                    show: true,
                    //是否展示三角图标
                    showFolderIcon: true,
                    //是否显示虚线
                    showLine: true,
                    //间距
                    indent: 20,
                    //默认展开节点的数组, 为 true 时, 展开所有节点
                    expandedKeys: true,
                    //是否严格遵守父子模式
                    strict: window.xmSelectData[id].strict,
                    //是否开启极简模式
                    simple: true,
                    clickExpand: false,
                    clickCheck: true,
                };
            } else if (window.xmSelectData[id].treeType === 'tree-group') {
                renderTreeOptions = {
                    //是否显示树状结构
                    show: false,
                    //是否展示三角图标
                    showFolderIcon: true,
                    //是否显示虚线
                    showLine: true,
                    //间距
                    indent: 20,
                    //默认展开节点的数组, 为 true 时, 展开所有节点
                    expandedKeys: true,
                    //是否严格遵守父子模式
                    strict: window.xmSelectData[id].strict,
                    //是否开启极简模式
                    simple: true,
                    clickExpand: false,
                    clickCheck: true,
                };
            } else {
                renderCascaderOptions.cascader = {
                    show: true,
                    indent: 200,
                    //是否严格遵守父子模式
                    strict: window.xmSelectData[id].strict,
                };
            }
        }
        // 定义渲染参数
        let renderOptions = {
            language: 'zn',
            data: [],
            filterable: true,
            filterMethod: function (val, item, index, prop) {
                if (val) {
                    //主标题中包含的大小写都搜索出来
                    if (window.xmSelectData[id].textField && item[window.xmSelectData[id].textField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                        return true;
                        //副标题中包含的大小写都搜索出来
                    } else if (window.xmSelectData[id].subTextField && item[window.xmSelectData[id].subTextField].toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                        return true;
                    }
                    return false;//其他的就不要了
                } else {
                    return true;
                }
            },
            radio: window.xmSelectData[id].radio,
            searchTips: "输入关键字进行搜索",
            maxMethod: function (selectedData) {
                facade.error("最多可选" + selectedData.length + "个数据");
            },
            layVerify: window.xmSelectData[id].layVerify,
            layVerType: window.xmSelectData[id].layVerType,
            clickClose: window.xmSelectData[id].radio,
            tips: window.xmSelectData[id].placeholder,
            toolbar: {
                show: true,
                list: !(window.xmSelectData[id].radio === true) ? ['ALL', 'REVERSE', 'CLEAR'] : ['CLEAR']
            },
            theme: {
                color: localStorage.getItem("theme-color-color")
            },
            direction: window.xmSelectData[id].direction,
            textField: window.xmSelectData[id].textField,
            subTextField: window.xmSelectData[id].subTextField,
            valueField: window.xmSelectData[id].valueField,
            iconField: window.xmSelectData[id].iconField,
            sourceTree: window.xmSelectData[id].sourceTree,
            treeType: window.xmSelectData[id].treeType,
            paging: window.xmSelectData[id].paging,
            pageSize: window.xmSelectData[id].pageSize,
            show: function () {
                $('.xm-search-input', xmSelectObj[id].dom)
                    .val(xmSelectData[id].searchKeyword)
                    .focus();
            },
            on: function (params) {
                window.xmSelectData[id].onNum++;
                if (window.xmSelectData[id].onchange) {
                    if (typeof window[window.xmSelectData[id].onchange] === "function") {
                        if (!window.xmSelectData[id].selected) {
                            window[window.xmSelectData[id].onchange].call(this, params);
                        } else {
                            if (window.xmSelectData[id].paging) {
                                if (window.xmSelectData[id].onNum > 1) {
                                    window[window.xmSelectData[id].onchange].call(this, params);
                                }
                            } else {
                                window[window.xmSelectData[id].onchange].call(this, params);
                            }
                        }
                    } else {
                        facade.error(window.xmSelectData[id].onchange + "回调函数未定义");
                    }
                }
            },
            model: {
                label: {
                    block: {
                        template: function (item) {
                            let template = item[window.xmSelectData[id].textField];
                            template = window.xmSelectData[id].iconField ? '<i class="' + item[window.xmSelectData[id].iconField] + ' margin-right5"></i>' + template : template;
                            return template;
                        },
                        showIcon: !(window.xmSelectData[id].radio === true)
                    },
                },
                icon: (window.xmSelectData[id].radio === true && !window.xmSelectData[id].sourceTree) ? "hidden" : "show",
            },
            template: function (item) {
                let template = item.item[window.xmSelectData[id].textField];
                template = window.xmSelectData[id].iconField ? '<i class="' + item.item[window.xmSelectData[id].iconField] + ' margin-right5"></i>' + template : template;
                if (window.xmSelectData[id].subTextField.indexOf('.') !== -1) {
                    var subTextFieldArr = window.xmSelectData[id].subTextField.split('.');
                    if (item.item[subTextFieldArr[0]]) {
                        template = template + '<span style="position: absolute; right: 0;">' + item.item[subTextFieldArr[0]][subTextFieldArr[1]] + '</span>';
                    }
                } else {
                    template = window.xmSelectData[id].subTextField ? template + '<span style="position: absolute; right: 0;">' + item.item[window.xmSelectData[id].subTextField] + '</span>' : template;
                }
                return template;
            },
            prop: {
                name: window.xmSelectData[id].textField
                , value: window.xmSelectData[id].valueField
            },
            tree: renderTreeOptions,
            cascader: renderCascaderOptions,
            autoRow: true, // 如果选中的项目过多，会自动变动输入框的高度
        };

        // 根据数据来源的不同，进行不同方式的渲染xmSelect组件
        if (window.xmSelectData[id].sourceType === "route") {
            // 只要是route方式获取数据进行渲染组件，那么就需要先组合查询条件
            let ajaxParams = {};
            var param, customParam, searchParam, searchCustomParam = {};
            var key;
            ajaxParams['search_param'] = {};
            if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                ajaxParams.selected = window.xmSelectData[id].selected.split(',');
                ajaxParams.selectedField = window.xmSelectData[id].valueField;
            }
            if (window.xmSelectData[id].param) {
                param = window.xmSelectData[id].param;
                for (key in param) {
                    ajaxParams['search_param'][key] = param[key];
                }
            }
            if (window.xmSelectData[id].customParam) {
                customParam = window.xmSelectData[id].customParam;
                for (key in customParam) {
                    ajaxParams[key] = customParam[key];
                }
            }

            // 如果是树形结构的数据，是先进行ajax请求，然后渲染组件
            if (window.xmSelectData[id].sourceTree) {
                ajaxParams.is_tree = 1;
                // 如果开启了search且searchParam或者searchCustomParam有值，就需要开启远程搜索
                if (window.xmSelectData[id].search && (window.xmSelectData[id].searchParam || window.xmSelectData[id].searchCustomParam)) {
                    renderOptions.remoteSearch = true;
                    renderOptions.remoteMethod = function (val, cb, show, pageIndex) {
                        if (window.xmSelectData[id].searchParam) {
                            searchParam = window.xmSelectData[id].searchParam;
                            for (var searchParamKey in searchParam) {
                                ajaxParams['search_param'][searchParamKey] = searchParam[searchParamKey];
                                ajaxParams['search_param'][searchParamKey]['value'] = val;
                            }
                        }

                        if (window.xmSelectData[id].searchCustomParam) {
                            searchCustomParam = window.xmSelectData[id].searchCustomParam;
                            for (var searchCustomParamKey in searchCustomParam) {
                                ajaxParams[searchCustomParamKey] = searchCustomParam[searchCustomParamKey];
                                ajaxParams[searchCustomParamKey]['value'] = val;
                            }
                        }

                        if (val) {
                            if ($.isEmptyObject(window.xmSelectData[id].searchParam)) {
                                ajaxParams['search_param'][window.xmSelectData[id].textField] = {
                                    "condition": "LIKE",
                                    "value": val
                                };
                            }
                        } else {
                            // 1. 用户在页面上先输入搜索值，后删除搜索值，如果没有如下删除语句，ajaxParams对象不会有改变，还是会用有值时的val进行查询
                            // 2. 如果不进行任何判断，仅执行重新定义ajaxParams，会传递like空的查询条件

                            // 所以当没有搜索值时，最好是删除查询条件
                            Reflect.deleteProperty(ajaxParams['search_param'], window.xmSelectData[id].textField);
                        }
                    }
                }
                facade.ajax({
                    method: "GET",
                    route: window.xmSelectData[id].source,
                    data: ajaxParams,
                    successAlert: false
                }).done(function (res) {
                    renderOptions.paging = 0; // 是否分页的标识使用0和1，否则是一个字符串传递到后台
                    renderOptions.data = res.data;
                    window.xmSelectObj[id].update(renderOptions);
                    if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                        window.xmSelectObj[id].setValue(window.xmSelectData[id].selected.split(','));
                    }
                });
            } else {
                // 非树形结构渲染组件，需要开启远程分页进行组件渲染
                renderOptions.pageRemote = true;
                renderOptions.remoteMethod = function (val, cb, show, pageIndex) {
                    window.xmSelectData[id].searchKeyword = val;
                    //val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
                    ajaxParams.paging = window.xmSelectData[id].paging ? 1 : 0;
                    ajaxParams.page = pageIndex;
                    ajaxParams.limit = window.xmSelectData[id].pageSize;

                    if (window.xmSelectData[id].searchParam) {
                        searchParam = window.xmSelectData[id].searchParam;
                        for (var searchParamKey in searchParam) {
                            ajaxParams['search_param'][searchParamKey] = searchParam[searchParamKey];
                            ajaxParams['search_param'][searchParamKey]['value'] = val;
                        }
                    }

                    if (window.xmSelectData[id].searchCustomParam) {
                        searchCustomParam = window.xmSelectData[id].searchCustomParam;
                        for (var searchCustomParamKey in searchCustomParam) {
                            ajaxParams[searchCustomParamKey] = searchCustomParam[searchCustomParamKey];
                            ajaxParams[searchCustomParamKey]['value'] = val;
                        }
                    }

                    if (val) {
                        if ($.isEmptyObject(window.xmSelectData[id].searchParam)) {
                            ajaxParams['search_param'][window.xmSelectData[id].textField] = {
                                "condition": "LIKE",
                                "value": val
                            };
                        }
                    } else {
                        // 1. 用户在页面上先输入搜索值，后删除搜索值，如果没有如下删除语句，ajaxParams对象不会有改变，还是会用有值时的val进行查询
                        // 2. 如果不进行任何判断，仅执行重新定义ajaxParams，会传递like空的查询条件

                        // 所以当没有搜索值时，最好是删除查询条件
                        Reflect.deleteProperty(ajaxParams['search_param'], window.xmSelectData[id].textField);
                    }

                    facade.ajax({
                        route: source,
                        data: ajaxParams,
                        successAlert: false,
                    }).done(response => {
                        //这里是success的处理
                        var res = window.xmSelectData[id].paging ? response.data : response;
                        if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                            var selectedArr = window.xmSelectData[id].selected.split(',');
                        }
                        for (var key in res.data) {
                            if (facade.inArray(res.data[key][window.xmSelectData[id].valueField], selectedArr)) {
                                res.data[key]["selected"] = true;
                            } else {
                                res.data[key]["selected"] = false;
                            }
                        }
                        //回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
                        window.xmSelectData[id].paging ? cb(res.data, res.last_page) : cb(res.data);
                    }).fail(err => {
                        //这里是error的处理
                        cb([], 0);
                    });
                };
                window.xmSelectObj[id].update(renderOptions);
            }
        } else if (window.xmSelectData[id].sourceType === "data") {
            renderOptions.data = window.xmSelectData[id].source;
            window.xmSelectObj[id].update(renderOptions);
            if (window.xmSelectData[id].selected && window.xmSelectData[id].selected !== "undefined") {
                window.xmSelectObj[id].setValue(window.xmSelectData[id].selected.split(','));
            }
        }
    };

    /**
     * 渲染某一个具体的linkageXmSelect
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderLinkageXmSelect = function (item) {
        layui.laytpForm.initDataOne['linkageXmSelectOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的linkageSelect
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderLinkageSelect = function (item) {
        layui.laytpForm.initDataOne['linkageSelectOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的upload
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderUpload = function (item) {
        layui.laytpForm.initDataOne['uploadOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的icon
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderIcon = function (item) {
        layui.laytpForm.initDataOne['iconOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的laydate
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderLaydate = function (item) {
        layui.laytpForm.initDataOne['laydateOne'].call(this, item);
    };

    /**
     * 渲染某一个具体的ColorPicker
     * @param item      需要渲染的jquery对象
     */
    laytpForm.renderColorPicker = function (item) {
        layui.laytpForm.initDataOne['colorPickerOne'].call(this, item);
    };

    /**
     * 数据表格表单元素的渲染
     */
    laytpForm.tableForm = {
        /**
         * 开关类型单选
         * @param field 字段名
         * @param d 数据表格所有数据集合
         * @param dataList 值举例：{"open":{"value":1,"text":"是"},"close":{"value":0,"text":"否"}}
         * @param filter 自定义filter，用于自定义监听表格单选按钮点击事件
         * @param isTreeTable 是否为树形表格
         * @param switchVal 新增参数，当前按钮选中状态值。
         *                  当按钮的选中状态不是由数据结果的某个字段值定义，而是使用多个字段进行判断或者使用数据集中某个对象里面的值进行判断得到时，
         *                  在调用switch前，自行判断得到按钮状态值，然后使用此参数传递。此参数的优先级高于d[field]的值
         * @returns {string}
         */
        switch: function (field, d, dataList, filter, isTreeTable, switchVal) {
            var switchNowVal = switchVal ? switchVal : d[field];
            let funcName = facade.underlineToCamel(field, true);
            let url = window.apiPrefix + "set" + funcName;
            if (facade.hasAuth(url)) {
                if (typeof filter === "undefined") {
                    filter = "laytp-table-switch";
                }
                let layText = dataList.open.text + "|" + dataList.close.text;
                return "<input openValue='" + dataList.open.value + "' closeValue='" + dataList.close.value + "' idVal='" + d.id + "' type='checkbox' name='" + field + "' value='" + dataList.open.value + "' lay-skin='switch' lay-text='" + layText + "' lay-filter='" + filter + "' " + ((switchNowVal == dataList.open.value) ? "checked='checked'" : "") + " />";
            } else {
                return laytp.tableFormatter.status(field, switchNowVal, {
                    "value": [dataList.open.value, dataList.close.value],
                    "text": [dataList.open.text, dataList.close.text]
                }, isTreeTable);
            }
        },

        /**
         * 回收站开关类型单选，回收站开关和普通开关分开的原因是，回收站开关请求后台的url不同
         * @param field 字段名
         * @param d 数据表格所有数据集合
         * @param dataList 值举例：{"open":{"value":1,"text":"是"},"close":{"value":0,"text":"否"}}
         * @param filter 自定义filter，用于自定义监听表格单选按钮点击事件
         * @param isTreeTable 是否为树形表格
         * @returns {string}
         */
        recycleSwitch: function (field, d, dataList, filter, isTreeTable) {
            let funcName = facade.underlineToCamel(field, true);
            let url = window.apiPrefix + "set" + funcName;
            if (facade.hasAuth(url)) {
                if (typeof filter === "undefined") {
                    filter = "laytp-recycle-table-switch";
                }
                let layText = dataList.open.text + "|" + dataList.close.text;
                return "<input openValue='" + dataList.open.value + "' closeValue='" + dataList.close.value + "' idVal='" + d.id + "' type='checkbox' name='" + field + "' value='" + dataList.open.value + "' lay-skin='switch' lay-text='" + layText + "' lay-filter='" + filter + "' " + ((d[field] == dataList.open.value) ? "checked='checked'" : "") + " />";
            } else {
                return laytp.tableFormatter.status(field, d[field], {
                    "value": [dataList.open.value, dataList.close.value],
                    "text": [dataList.open.text, dataList.close.text]
                }, isTreeTable);
            }
        },

        /**
         * 开启表格编辑的单行输入框，如果当前登录者有设置这个字段的权限，数据表格中渲染成单行输入框
         * @param field
         * @param d
         * @param url
         * @param callback
         * @returns {string|boolean}
         */
        editInput: function (field, d, url, callback) {
            if (typeof url === "undefined") {
                return d[field];
            }
            if (typeof callback === "undefined") {
                callback = '';
            }
            if (facade.hasAuth(url)) {
                return '' +
                    '<div class="layui-input-inline">' +
                    '   <div class="layui-input-inline layui-table-input-inline">' +
                    '       <input type="text" class="layui-input layui-table-input" autocomplete="off" ' +
                    'style="height:28px;" id="layui-table-input_' + d.id + '" value="' + d[field] + '" ' +
                    'data-id="' + d.id + '" ' +
                    'data-value="' + d[field] + '" ' +
                    'data-field="' + field + '" ' +
                    'data-callback="' + callback + '" ' +
                    'data-url="' + url + '" />' +
                    '   </div>' +
                    '</div>';
            } else {
                return d[field];
            }
        },

        /**
         * 开启表格编辑的单行输入框，如果当前登录者有设置这个字段的权限，则数据表格中渲染成单行输入框
         * @param field
         * @param d
         * @param url
         * @returns {string|boolean}
         */
        recycleEditInput: function (field, d, url) {
            if (typeof url === "undefined") {
                return d[field];
            }
            if (facade.hasAuth(url)) {
                return '' +
                    '<div class="layui-input-inline">' +
                    '   <div class="layui-input-inline layui-table-input-inline">' +
                    '       <input type="text" class="layui-input layui-recycle-table-input" autocomplete="off" style="height:28px;" id="layui-recycle-table-input_' + d.id + '" value="' + d[field] + '" data-id="' + d.id + '" data-value="' + d[field] + '" data-field="' + field + '" data-url="' + url + '" />' +
                    '   </div>' +
                    '</div>';
            } else {
                return d[field];
            }
        },
    };

    /**
     * 监听数据表格表单元素相关事件
     */
    laytpForm.onTableForm = {
        /**
         * 监听，数据表格，单选按钮点击事件
         */
        laytpTableSwitch: function () {
            layui.form.on("switch(laytp-table-switch)", function (obj) {
                if (!window.apiPrefix) {
                    facade.error("window.apiPrefix未定义");
                    return false;
                }
                let openValue = obj.elem.attributes["openValue"].nodeValue;
                let closeValue = obj.elem.attributes["closeValue"].nodeValue;
                let idVal = obj.elem.attributes["idVal"].nodeValue;
                let funcName = facade.underlineToCamel(this.name, true);
                let url = window.apiPrefix + "set" + funcName;
                if (facade.hasAuth(url)) {
                    let postData = {};
                    if (obj.elem.checked) {
                        postData = {field_val: openValue, id: idVal, is_recycle: 0};
                    } else {
                        postData = {field_val: closeValue, id: idVal, is_recycle: 0};
                    }
                    facade.ajax({route: url, data: postData});
                } else {
                    facade.error("无权进行此操作");
                }
            });
        },

        /**
         * 监听，回收站数据表格，单选按钮点击事件
         */
        laytpRecycleTableSwitch: function () {
            layui.form.on("switch(laytp-recycle-table-switch)", function (obj) {
                if (!window.apiPrefix) {
                    facade.error("window.apiPrefix未定义");
                    return false;
                }
                let openValue = obj.elem.attributes["openValue"].nodeValue;
                let closeValue = obj.elem.attributes["closeValue"].nodeValue;
                let idVal = obj.elem.attributes["idVal"].nodeValue;
                let funcName = facade.underlineToCamel(this.name, true);
                let url = window.apiPrefix + "set" + funcName;
                if (facade.hasAuth(url)) {
                    let postData = {};
                    if (obj.elem.checked) {
                        postData = {field_val: openValue, id: idVal, is_recycle: 1};
                    } else {
                        postData = {field_val: closeValue, id: idVal, is_recycle: 1};
                    }
                    facade.ajax({route: url, data: postData, showLoading: true});
                } else {
                    facade.error("无权进行此操作");
                }
            });
        },

        /**
         * 监听，数据表格，可编辑单行输入框，失去焦点事件，进行编辑
         */
        tableEditInput: function () {
            $(document).off("blur", ".layui-table-input").on('blur', '.layui-table-input', function () {
                let obj = $(this);
                let url = obj.data('url');
                if (!url) {
                    facade.error("输入框编辑url未定义");
                    return false;
                }
                let id = obj.data('id');
                let value = obj.val();
                let field = obj.data('field');
                let oldVal = obj.data('value');
                let callback = obj.data('callback');
                if (value.toString() !== oldVal.toString()) {
                    if (facade.hasAuth(url)) {
                        facade.ajax({
                            route: url,
                            data: {"field": field, "field_val": value, "id": id, is_recycle: 0},
                            successAlert: true
                        }).done(function (res) {
                            if (res.code === 0) {
                                if (callback) {
                                    eval(callback + "()");
                                } else {
                                    funController.tableRender();
                                }
                            }
                        });
                    } else {
                        facade.error("无权进行此操作");
                    }
                }
            });
        },

        /**
         * 监听，回收站数据表格，可编辑单行输入框，失去焦点事件，进行编辑
         */
        recycleTableEditInput: function () {
            $(document).off("blur", ".layui-recycle-table-input").on('blur', '.layui-recycle-table-input', function () {
                let obj = $(this);
                let url = obj.data('url');
                if (!url) {
                    facade.error("输入框编辑url未定义");
                    return false;
                }
                let id = obj.data('id');
                let value = obj.val();
                let field = obj.data('field');
                let oldVal = obj.data('value');
                if (value.toString() !== oldVal.toString()) {
                    if (facade.hasAuth(url)) {
                        facade.ajax({
                            route: url,
                            data: {"field": field, "field_val": value, "id": id, is_recycle: 1},
                            successAlert: true,
                            showLoading: true
                        }).done(function (res) {
                            if (res.code === 0) {
                                funRecycleController.tableRender();
                            }
                        });
                    } else {
                        facade.error("无权进行此操作");
                    }
                }
            });
        },

        /**
         * 监听搜索表单提交事件
         */
        laytpSearchFormSubmit: function () {
            layui.form.on("submit(laytp-search-form)", function (obj) {
                funController.tableRender(obj.field);
                return false;
            });
        },

        /**
         * 监听回收站搜索表单提交事件
         */
        laytpRecycleSearchFormSubmit: function () {
            layui.form.on('submit(laytp-recycle-search-form)', function (obj) {
                funRecycleController.tableRender(obj.field);
                return false;
            });
        },

        /**
         * 重置搜索表单的搜索条件
         */
        laytpSearchFormReset: function () {
            $(document).off("click", ".laytp-search-form-reset").on("click", ".laytp-search-form-reset", function () {
                var thisObj = $(this);
                var formObj = thisObj.closest("form");
                // 设置这个表单下所有xmSelect的值为空
                $(".xmSelect", formObj).each(function (index, item) {
                    xmSelectObj[$(item).data('name')].setValue([]);
                });
                formObj.trigger("reset");
                funController.tableRender();
            });
        },

        /**
         * 重置回收站搜索表单的搜索条件
         */
        laytpRecycleSearchFormReset: function () {
            $(document).off("click", ".laytp-recycle-search-form-reset").on("click", ".laytp-recycle-search-form-reset", function () {
                var thisObj = $(this);
                var formObj = thisObj.closest("form");
                // 设置这个表单下所有xmSelect的值为空
                $(".xmSelect", formObj).each(function (index, item) {
                    xmSelectObj[$(item).data('name')].setValue([]);
                });
                formObj.trigger("reset");
                funRecycleController.tableRender();
            });
        },

        /**
         * 导出搜索条件下的数据
         */
        laytpSearchFormExport: function () {
            $(document).off("click", ".laytp-search-form-export").on("click", ".laytp-search-form-export", function () {
                let data = layui.form.val("search-form");
                facade.ajax({
                    route: apiPrefix + "export",
                    params: data
                }).done(function (res) {
                    if (res.code === 0) {
                        // 创建a标签，设置属性，并触发点击下载
                        var $a = $("<a>");
                        $a.attr("href", res.data.file);
                        $a.attr("download", res.data.filename);
                        $("body").append($a);
                        $a[0].click();
                        $a.remove();
                    }
                });
            });
        },

        /**
         * 导出回收站搜索条件下的数据
         */
        laytpRecycleSearchFormExport: function () {
            $(document).off("click", ".laytp-recycle-search-form-export").on("click", ".laytp-recycle-search-form-export", function () {
                let data = layui.form.val("recycle-search-form");
                facade.ajax({
                    route: apiPrefix + "recycleExport",
                    params: data
                }).done(function (res) {
                    if (res.code === 0) {
                        // 创建a标签，设置属性，并触发点击下载
                        var $a = $("<a>");
                        $a.attr("href", res.data.file);
                        $a.attr("download", res.data.filename);
                        $("body").append($a);
                        $a[0].click();
                        $a.remove();
                    }
                });
            });
        },
    };

    /**
     * 监听数据表格表单元素
     */
    layui.each(laytpForm.onTableForm, function (key, item) {
        if (typeof item == "function") {
            item()
        }
    });

    //输出模块
    exports(MOD_NAME, laytpForm);

    //注入layui组件中，供全局调用
    layui.laytpForm = laytpForm;

    //注入window全局对象中，供全局调用
    window.laytpForm = laytpForm;
});