forked from kidgrow-microservices-platform

侯瑞军
2020-04-08 6325ff05bb15908b3dd975e958737c5dddf0e50d
1.新增地区管理功能
2.加入treetable2.0版本源码
3.treetable1.0加载慢未优化
8 files modified
4 files added
2302 ■■■■■ changed files
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-api/src/main/java/com/kidgrow/usercenter/model/SysArea.java 22 ●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/mapper/SysAreaMapper.java 8 ●●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/service/ISysAreaService.java 8 ●●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/service/impl/SysAreaServiceImpl.java 26 ●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/resources/mapper/SysAreaMapper.xml 5 ●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-server/src/main/java/com/kidgrow/usercenter/controller/SysAreaController.java 45 ●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/assets/js/common.js 1 ●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/module/treetable2/treeTable.css 396 ●●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/module/treetable2/treeTable.js 1494 ●●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/opration/feedback.html 6 ●●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/system/sysArea.html 183 ●●●●● patch | view | raw | blame | history
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/system/sysArea_form.html 108 ●●●●● patch | view | raw | blame | history
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-api/src/main/java/com/kidgrow/usercenter/model/SysArea.java
@@ -1,11 +1,12 @@
package com.kidgrow.usercenter.model;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.kidgrow.common.model.SuperModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotEmpty;
/**
 * 石家庄喜高科技有限责任公司 版权所有 © Copyright 2020<br>
@@ -21,12 +22,17 @@
@NoArgsConstructor
@AllArgsConstructor
@TableName("sys_area")
public class SysArea extends SuperModel {
    private static final long serialVersionUID = 1L;
public class SysArea {
    /**
     * 区域id
     */
    @NotEmpty(message = "区域id不能为空")
    private Long Id;
    /**
     * 区域名称
     */
    @NotEmpty(message = "区域名称不能为空")
    private String areaName;
    /**
     * 父级区域id
@@ -39,6 +45,7 @@
    /**
     * 省市区级别
     */
    @NotEmpty(message = "区域级别不能为空")
    private Integer areaLeveltype;
    /**
     * 区号
@@ -60,4 +67,13 @@
     * 名称拼音
     */
    private String areaCh;
    /**
     * 状态,1启用,0停用
     */
    private Boolean enabled;
    /**
     * 是否删除,1删除,0未删除
     */
    @TableLogic
    private Boolean isDel;
}
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/mapper/SysAreaMapper.java
@@ -1,8 +1,7 @@
package com.kidgrow.usercenter.mapper;
import com.kidgrow.usercenter.model.SysArea;
import com.kidgrow.db.mapper.SuperMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kidgrow.usercenter.model.SysArea;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -18,12 +17,11 @@
 */
public interface SysAreaMapper extends SuperMapper<SysArea> {
    /**
     * 分页查询省市区数据表列表
     * @param page
     * 查询省市区数据表列表
     * @param params
     * @return
     */
    List<SysArea> findList(Page<SysArea> page, @Param("p") Map<String, Object> params);
    List<SysArea> findList(@Param("p") Map<String, Object> params);
    /**
     * 根据SysArea对象当做查询条件进行查询
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/service/ISysAreaService.java
@@ -1,5 +1,6 @@
package com.kidgrow.usercenter.service;
import com.kidgrow.common.model.ResultBody;
import com.kidgrow.usercenter.model.SysArea;
import com.kidgrow.common.model.PageResult;
import com.kidgrow.common.service.ISuperService;
@@ -29,5 +30,12 @@
    * @return SysArea对象
    */
    SysArea findByObject(SysArea sysArea);
    /**
     * 状态变更
     * @param params
     * @return
     */
    ResultBody updateEnabled(Map<String, Object> params);
}
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/java/com/kidgrow/usercenter/service/impl/SysAreaServiceImpl.java
@@ -1,7 +1,7 @@
package com.kidgrow.usercenter.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kidgrow.common.model.PageResult;
import com.kidgrow.common.model.ResultBody;
import com.kidgrow.common.service.impl.SuperServiceImpl;
import com.kidgrow.usercenter.mapper.SysAreaMapper;
import com.kidgrow.usercenter.model.SysArea;
@@ -31,9 +31,8 @@
     */
    @Override
    public PageResult<SysArea> findList(Map<String, Object> params){
        Page<SysArea> page = new Page<>(MapUtils.getInteger(params, "page"), MapUtils.getInteger(params, "limit"));
        List<SysArea> list  =  baseMapper.findList(page, params);
        return PageResult.<SysArea>builder().data(list).code(0).count(page.getTotal()).build();
        List<SysArea> list  =  baseMapper.findList(params);
        return PageResult.<SysArea>builder().data(list).code(0).count((long) list.size()).build();
    }
    /**
@@ -45,4 +44,23 @@
    public SysArea findByObject(SysArea sysArea){
        return baseMapper.findByObject(sysArea);
    }
    /**
     * 根据id和启用禁用值更新数据
     * @param params
     * @return ResultBody
     */
    @Override
    public ResultBody updateEnabled(Map<String, Object> params) {
        Long id = MapUtils.getLong(params, "id");
        Boolean enabled = MapUtils.getBoolean(params, "enabled");
        SysArea area = baseMapper.selectById(id);
        if (area == null) {
            return ResultBody.failed("该数据不存在!");
        }
        area.setEnabled(enabled);
        int i = baseMapper.updateById(area);
        return i > 0 ? ResultBody.ok().data(area).msg("更新成功") : ResultBody.failed("更新失败");
    }
}
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-biz/src/main/resources/mapper/SysAreaMapper.xml
@@ -42,6 +42,9 @@
            <if test="p.areaCh != null and p.areaCh !=''">
                and area_ch = #{p.areaCh}
            </if>
            <if test="p.enabled != null and p.enabled !=''">
                and enabled = #{p.enabled}
            </if>
        </where>
    </sql>
@@ -61,6 +64,6 @@
        <include refid="Column_List"/>
        from sys_area
        <include refid="where"/>
        order by id desc
        order by id
    </select>
</mapper>
kidgrow-business/kidgrow-usercenter/kidgrow-usercenter-server/src/main/java/com/kidgrow/usercenter/controller/SysAreaController.java
@@ -41,17 +41,9 @@
     * 列表
     */
    @ApiOperation(value = "查询列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
            @ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer")
    })
    @GetMapping
    public ResultBody<PageResult> list(@RequestParam Map<String, Object> params) {
        if(params.size()==0){
            params.put("page",1);
            params.put("limit",10);
        }
        return ResultBody.ok().data(sysAreaService.findList(params));
    @GetMapping("/findAlls")
    public PageResult<SysArea> findAlls(@RequestParam Map<String, Object> params) {
        return sysAreaService.findList(params);
    }
    /**
@@ -87,6 +79,18 @@
            }
            return ResultBody.failed().msg(errMsg.toString());
        } else {
            //如果父级id是空的,默认填-1
            if (sysArea.getAreaParentId().toString()=="") {
                sysArea.setAreaParentId(-1L);
            }
            //添加的时候得判断主键唯一
             if (sysArea.getIsDel()==null) {
                 SysArea model =sysAreaService.getById(sysArea.getId());
                 if (model!=null)
                 {
                     return ResultBody.failed().msg("区域编号已存在!");
                 }
            }
            boolean v= sysAreaService.saveOrUpdate(sysArea);
            if(v) {
                return ResultBody.ok().data(sysArea).msg("保存成功");
@@ -111,4 +115,23 @@
            return ResultBody.failed().msg("删除失败");
        }
    }
    /**
     * 修改状态
     *
     * @param params
     * @return
     */
    @ApiOperation(value = "修改反馈数据状态")
    @GetMapping("/updateEnabled")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "Integer"),
            @ApiImplicitParam(name = "enabled", value = "是否启用", required = true, dataType = "Boolean")
    })
    public ResultBody updateEnabled(@RequestParam Map<String, Object> params) {
        if (params.size()==0)
        {
            return ResultBody.failed().msg("参数异常!");
        }
        return sysAreaService.updateEnabled(params);
    }
}
kidgrow-web/kidgrow-web-manager/src/main/resources/static/assets/js/common.js
@@ -4,6 +4,7 @@
}).extend({
    formSelects: 'formSelects/formSelects-v4',
    treetable: 'treetable-lay/treetable',
    treetable2: 'treetable2/TreeTable',
    step: 'step-lay/step'
}).use(['layer','config', 'index', 'element'], function () {
    var $ = layui.jquery;
kidgrow-web/kidgrow-web-manager/src/main/resources/static/module/treetable2/treeTable.css
New file
@@ -0,0 +1,396 @@
/* 最外层容器 */
.ew-tree-table {
    margin: 10px 0;
    position: relative;
}
.ew-tree-table .layui-table {
    margin: 0;
    table-layout: fixed;
}
/* 表格容器 */
.ew-tree-table-group {
    position: relative;
}
/* 主体表格容器 */
.ew-tree-table > .ew-tree-table-group > .ew-tree-table-box {
    overflow: auto;
    position: relative;
    box-sizing: border-box;
}
/* 表头表格容器 */
.ew-tree-table > .ew-tree-table-group > .ew-tree-table-head {
    overflow: hidden;
    position: relative;
    box-sizing: border-box;
    background-color: #f2f2f2;
}
/* 容器加边框 */
.ew-tree-table .ew-tree-table-border {
    position: absolute;
    background-color: #e6e6e6;
}
.ew-tree-table .ew-tree-table-border.top {
    left: 0;
    right: 0;
    top: 0;
    height: 1px;
}
.ew-tree-table .ew-tree-table-border.left {
    top: 0;
    left: 0;
    bottom: 0;
    width: 1px;
}
.ew-tree-table .ew-tree-table-border.right {
    top: 0;
    right: 0;
    bottom: 0;
    width: 0.52px;
}
.ew-tree-table .ew-tree-table-border.bottom {
    left: 0;
    right: 0;
    bottom: 0;
    height: 0.52px;
}
/* table的loading */
.ew-tree-table .ew-tree-table-box > .ew-tree-table-loading {
    padding: 10px 0;
    text-align: center;
}
.ew-tree-table .ew-tree-table-box > .ew-tree-table-loading > i {
    color: #999;
    font-size: 30px;
}
.ew-tree-table .ew-tree-table-box > .ew-tree-table-loading.ew-loading-float {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
}
/* 空数据提示 */
.ew-tree-table .ew-tree-table-box > .ew-tree-table-empty {
    color: #666;
    font-size: 14px;
    text-align: center;
}
/* 折叠箭头 */
.ew-tree-table .ew-tree-table-arrow {
    margin-right: 5px;
    vertical-align: middle;
}
.ew-tree-table .ew-tree-table-arrow:before {
    content: "\e623";
}
.ew-tree-table .ew-tree-table-open .ew-tree-table-arrow:before {
    content: "\e625";
}
.ew-tree-table .ew-tree-table-arrow.arrow2 {
    font-size: 13px;
    font-weight: 600;
    line-height: 16px;
    height: 16px;
    width: 16px;
    display: inline-block;
    text-align: center;
    color: #888;
}
.ew-tree-table .ew-tree-table-arrow.arrow2:before {
    content: "\e602";
}
.ew-tree-table .ew-tree-table-open .ew-tree-table-arrow.arrow2:before {
    content: "\e61a";
}
/* 箭头隐藏 */
.ew-tree-table-arrow.ew-tree-table-arrow-hide {
    visibility: hidden;
}
/* 箭头变加载中状态 */
.ew-tree-table .ew-tree-table-loading > td .ew-tree-pack > .ew-tree-table-arrow:before {
    content: "\e63d" !important;
}
.ew-tree-table .ew-tree-table-loading > td .ew-tree-pack > .ew-tree-table-arrow {
    margin-right: 0;
}
.ew-tree-table .ew-tree-table-loading > td .ew-tree-pack > .ew-tree-table-arrow + * {
    margin-left: 5px;
}
/* tr加载中禁用事件 */
.ew-tree-table tr.ew-tree-table-loading > * {
    pointer-events: none !important;
}
/* 图标列 */
.ew-tree-table .ew-tree-pack {
    cursor: pointer;
    line-height: 16px;
    display: inline-block;
    vertical-align: middle;
}
.ew-tree-table .ew-tree-pack > span {
    height: 16px;
    line-height: 16px;
    display: inline-block;
    vertical-align: middle;
}
/* 折叠行 */
.ew-tree-table .ew-tree-tb-hide {
    display: none;
}
/* 缩进 */
.ew-tree-table .ew-tree-table-indent {
    margin-right: 5px;
    padding-left: 16px;
}
/* 图标 */
.ew-tree-table .ew-tree-icon {
    margin-right: 5px;
    display: inline-block;
    vertical-align: middle;
}
.ew-tree-table .ew-tree-icon-folder, .ew-tree-table .ew-tree-icon-file {
    width: 22px;
    height: 16px;
    line-height: 16px;
    position: relative;
}
.ew-tree-table .ew-tree-icon-folder:after, .ew-tree-table .ew-tree-icon-file:after {
    content: "";
    width: 22px;
    height: 22px;
    position: absolute;
    left: 0;
    top: -3px;
    background-size: cover;
    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc0MDYyMzE3MTQ3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjIxNTgiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTE4MSA4MjNoLTMxLjFjLTI4LjYgMC01MS45LTIzLjItNTEuOS01MS45VjI1Mi40YzAtMjguNiAyMy4yLTUxLjkgNTEuOS01MS45SDQzMGw4MyA3Ny44aDMzMmM0NS42IDAgODMgMzUgODMgNzcuOHYzODkuMWMwIDQyLjgtMzcuMyA3Ny44LTgzIDc3LjhIMTgxeiIgcC1pZD0iMjE1OSIgZmlsbD0iI0ZGQTUwMCI+PC9wYXRoPjwvc3ZnPg==")
}
.ew-tree-table tr.ew-tree-table-open > td > .ew-tree-pack .ew-tree-icon-folder:after {
    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc0MDYyMzA5MDQwIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE5NzciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTMyNi40IDQ2MC4xSDkyOGwtODIuMyAzMjRjLTUuOCAyMy0yNi42IDM5LjEtNTAuMyAzOS4xSDE0OS45Yy0yOC42IDAtNTEuOS0yMy4yLTUxLjktNTEuOVYyNTIuNmMwLTI4LjYgMjMuMi01MS45IDUxLjktNTEuOUg0MTNsMTA1IDEwMy43aDI5MS44YzE0LjMgMCAyNS45IDExLjYgMjUuOSAyNS45djc3LjhoLTUyN0wyMDMuNCA1NjMuOWg1Mi43bDcwLjMtMTAzLjh6IiBwLWlkPSIxOTc4IiBmaWxsPSIjRkZBNTAwIj48L3BhdGg+PC9zdmc+")
}
.ew-tree-table .ew-tree-icon-file:after {
    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc0MDYyNTE1MDUxIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEzNTE4IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0Ij48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwvc3R5bGU+PC9kZWZzPjxwYXRoIGQ9Ik03NDEuMyAxNjEuNmgtNDIuNGMtMTAuNSAwLTE5LjEgOC42LTE5LjEgMTkuMXM4LjYgMTkuMSAxOS4xIDE5LjFoNDIuNGM0MiAwIDc2LjIgMzQuMiA3Ni4yIDc2LjN2NDc3LjRjMCA0Mi4xLTM0LjMgNzYuMy03Ni40IDc2LjNIMjgyLjljLTQyLjEgMC03Ni4zLTM0LjItNzYuMy03Ni4zVjI3Ni4xYzAtNDIuMSAzNC4yLTc2LjMgNzYuMy03Ni4zaDQ0LjljMTAuNSAwIDE5LjEtOC42IDE5LjEtMTkuMXMtOC42LTE5LjEtMTkuMS0xOS4xaC00NC45Yy02My4xIDAtMTE0LjUgNTEuNC0xMTQuNSAxMTQuNXY0NzcuNGMwIDYzLjEgNTEuNCAxMTQuNSAxMTQuNSAxMTQuNWg0NTguM2M2My4xIDAgMTE0LjUtNTEuNCAxMTQuNS0xMTQuNVYyNzYuMWMtMC4xLTYzLjEtNTEuNC0xMTQuNS0xMTQuNC0xMTQuNXoiIHAtaWQ9IjEzNTE5IiBmaWxsPSIjRkZBNTAwIj48L3BhdGg+PHBhdGggZD0iTTY4MC42IDUwNS4zSDM0My40Yy0xMi4zIDAtMjIuMyA4LjYtMjIuMyAxOS4xczEwIDE5LjEgMjIuMyAxOS4xaDMzNy4yYzEyLjMgMCAyMi4zLTguNiAyMi4zLTE5LjEgMC0xMC42LTEwLTE5LjEtMjIuMy0xOS4xek00MzkuMyAyMTMuM2gxNDQuNmMxOSAwIDM0LjQtMTIuOCAzNC40LTI4LjZzLTE1LjQtMjguNi0zNC40LTI4LjZINDM5LjNjLTE5IDAtMzQuNCAxMi44LTM0LjQgMjguNi0wLjEgMTUuNyAxNS4zIDI4LjYgMzQuNCAyOC42ek02ODAuNiA2NThIMzQzLjRjLTEyLjMgMC0yMi4zIDguNS0yMi4zIDE5LjEgMCAxMC41IDEwIDE5LjEgMjIuMyAxOS4xaDMzNy4yYzEyLjMgMCAyMi4zLTguNiAyMi4zLTE5LjEgMC0xMC42LTEwLTE5LjEtMjIuMy0xOS4xek02ODAuNiAzNTIuNUgzNDMuNGMtMTIuMyAwLTIyLjMgOC42LTIyLjMgMTkuMXMxMCAxOS4xIDIyLjMgMTkuMWgzMzcuMmMxMi4zIDAgMjIuMy04LjYgMjIuMy0xOS4xIDAtMTAuNS0xMC0xOS4xLTIyLjMtMTkuMXoiIHAtaWQ9IjEzNTIwIiBmaWxsPSIjRkZBNTAwIj48L3BhdGg+PC9zdmc+")
}
/* 序号列调整 */
.ew-tree-table td[data-type="numbers"] {
    padding-left: 0;
    padding-right: 0;
    text-align: center;
}
/* 单元格内表单元素样式调整 */
.ew-tree-table .layui-form-switch {
    margin-top: 0;
}
.ew-tree-table .layui-form-radio {
    margin: 0;
}
/* checkbox和radio列调整 */
.ew-tree-table-checkbox + .layui-form-checkbox {
    padding: 0;
}
.ew-tree-table-checkbox + .layui-form-checkbox > .layui-icon {
    color: transparent;
    transition: background-color .1s linear;
}
.ew-tree-table-checkbox + .layui-form-checkbox.layui-form-checked > .layui-icon {
    color: #fff;
}
.ew-tree-table-radio + .layui-form-radio {
    padding: 0;
    height: 20px;
    line-height: 20px;
}
.ew-tree-table-radio + .layui-form-radio > i {
    margin: 0;
    height: 20px;
    font-size: 20px;
    line-height: 20px;
}
/* checkbox半选状态 */
.ew-tree-table .layui-form-checked.ew-form-indeterminate > .layui-icon:before {
    content: "";
    width: 9px;
    height: 2px;
    display: inline-block;
    background-color: #eee;
    vertical-align: middle;
}
.ew-tree-table .layui-form-checked.ew-form-indeterminate > .layui-icon {
    line-height: 14px;
}
/* 单元格编辑 */
.ew-tree-table .layui-table td[data-edit] {
    cursor: text;
}
.ew-tree-table .ew-tree-table-edit {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    border-radius: 0;
    box-shadow: 1px 1px 20px rgba(0, 0, 0, .15);
}
.ew-tree-table .ew-tree-table-edit:focus {
    border-color: #5FB878 !important;
}
.ew-tree-table .ew-tree-table-edit.layui-form-danger {
    border-color: #FF5722 !important;
}
/* 搜索数据隐藏行 */
.ew-tree-table tr.ew-tree-table-filter-hide {
    display: none !important;
}
/* 单元格超出隐藏 */
.ew-tree-table-td-single {
    position: relative;
}
.ew-tree-table-td-single > .ew-tree-tips {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.ew-tree-table-td-single > .ew-tree-tips-c {
    position: absolute;
    right: -10px;
    top: -6px;
    width: 24px;
    height: 24px;
    line-height: 24px;
    font-size: 18px;
    text-align: center;
    color: #fff;
    border-radius: 50%;
    background-color: #666;
    cursor: pointer;
    display: none;
}
.ew-tree-table table tr:first-child .ew-tree-table-td-single > .ew-tree-tips-c {
    top: 2px;
    bottom: auto;
    right: -12px;
}
.ew-tree-table-td-single.ew-tree-tips-open {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 5;
    background-color: #fff;
    min-height: 100%;
    box-sizing: border-box;
    box-shadow: 3px 3px 8px rgba(0, 0, 0, .15);
}
.ew-tree-table table thead .ew-tree-table-td-single.ew-tree-tips-open {
    background-color: #f2f2f2;
}
.ew-tree-table-td-single.ew-tree-tips-open.ew-show-left {
    right: 0;
    left: auto;
    box-shadow: -3px 3px 8px rgba(0, 0, 0, .15);
}
.ew-tree-table-td-single.ew-tree-tips-open.ew-show-bottom {
    bottom: 0;
    top: auto;
    box-shadow: 3px -3px 8px rgba(0, 0, 0, .15);
}
.ew-tree-table-td-single.ew-tree-tips-open.ew-show-left.ew-show-bottom {
    box-shadow: -3px -3px 8px rgba(0, 0, 0, .15);
}
.ew-tree-table-td-single.ew-tree-tips-open > .ew-tree-tips {
    padding: 9px 15px;
    overflow: auto;
    max-width: 280px;
    max-height: 100px;
    width: max-content;
    white-space: normal;
}
.ew-tree-table-td-single.ew-tree-tips-open > .ew-tree-tips-c {
    display: block;
}
.ew-tree-table-td-single.ew-tree-tips-open.ew-show-left > .ew-tree-tips-c {
    left: -10px;
    right: auto !important;
}
.ew-tree-table td > .layui-table-grid-down {
    bottom: 0;
    height: auto;
}
/* 辅助样式 */
.pd-tb-0 {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}
.break-all {
    word-break: break-all !important;
}
/* 列宽拖拽调整 */
/*.ew-tree-table .ew-tb-resize {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 10px;
    cursor: col-resize;
}*/
kidgrow-web/kidgrow-web-manager/src/main/resources/static/module/treetable2/treeTable.js
New file
@@ -0,0 +1,1494 @@
/**
 * 树形表格 2.x
 * date:2019-11-08   License By http://easyweb.vip
 */
layui.define(['layer', 'laytpl', 'form'], function (exports) {
    var $ = layui.jquery;
    var layer = layui.layer;
    var laytpl = layui.laytpl;
    var form = layui.form;
    var device = layui.device();
    var MOD_NAME = 'treeTable2';  // 绑定事件的模块名
    // 改为同步加载css,避免滚动条补丁首次进入无效
    $.ajax({
        url: layui.cache.base + 'treeTable2/treeTable.css',
        async: false,
        success: function (res) {
            $('head').append('<style id="ew-tree-table-css">' + res + '</style>');
        }
    });
    /** TreeTable类构造方法 */
    var TreeTable = function (options) {
        // 表格默认参数
        var defaultOption = {
            elem: undefined,   // table容器
            data: [],  // 数据
            cols: [],  // 列配置
            reqData: undefined,  // 异步加载数据的方法
            width: undefined,  // 容器宽度
            height: undefined,  // 容器高度
            cellMinWidth: 100,  // 单元格最小宽度
            skin: undefined,  // 表格风格
            size: undefined,  // 表格尺寸
            even: undefined,  // 是否开启隔行变色
            style: undefined,   // 容器样式
            getThead: function () {  // 获取表头
                return getThead(this);
            },
            getAllChooseBox: function () {  // 获取全选按钮
                return getAllChooseBox(this);
            },
            getColgroup: function () {  // 获取colgroup
                return getColgroup(this);
            },
            getTbWidth: function () {  // 计算table的宽度
                return getTbWidth(this);
            },
            tree: {},
            text: {}
        };
        // 默认tree参数
        var treeDefaultOption = {
            idName: 'id',  // id的字段名
            pidName: 'pid',  // pid的字段名
            childName: 'children',  // children的字段名
            haveChildName: 'haveChild',  // 是否有children标识的字段名
            openName: 'open',  // 是否默认展开的字段名
            isPidData: false,  // 是否是pid形式的数据
            iconIndex: 0,  // 图标列的索引
            arrowType: undefined,  // 箭头类型
            onlyIconControl: false,  // 仅允许点击图标折叠
            getIcon: function (d) {  // 自定义图标
                return getIcon(d, this);
            }
        };
        // 默认提示文本
        var textDefaultOption = {
            none: '<div style="padding: 18px 0;">暂无数据</div>'  // 空文本提示文字
        };
        this.options = $.extend(defaultOption, options);
        this.options.tree = $.extend(treeDefaultOption, options.tree);
        this.options.text = $.extend(textDefaultOption, options.text);
        for (var i = 0; i < options.cols.length; i++) {
            // 列默认参数
            var colDefaultOption = {
                field: undefined,   // 字段名
                title: undefined,   // 标题
                align: undefined,  // 对齐方式
                templet: undefined,  // 自定义模板
                toolbar: undefined,  // 工具列
                width: undefined,   // 宽度
                minWidth: undefined,  // 最小宽度
                type: undefined,    // 列类型
                style: undefined,   // 单元格样式
                class: '',  // 单元格class
                singleLine: true,  // 一行显示
                fixed: undefined,    // 固定列
                unresize: false   // 关闭拖拽列宽
            };
            this.options.cols[i] = $.extend(colDefaultOption, options.cols[i]);
        }
        this.init();  // 初始化表格
        this.bindEvents();  // 绑定事件
    };
    /** 初始化表格 */
    TreeTable.prototype.init = function () {
        var options = this.options;
        var tbFilter = options.elem.substring(1);  // 树表格的filter
        var $elem = $(options.elem);  // 原始表格
        // 生成树表格dom
        $elem.removeAttr('lay-filter');
        $elem.next('.ew-tree-table').remove();
        var viewHtml = '<div class="layui-form ew-tree-table" style="' + (options.style || '') + '">';
        viewHtml += '      <div class="ew-tree-table-group">';
        viewHtml += '         <div class="ew-tree-table-head">';
        viewHtml += '            <table class="layui-table"></table>';
        viewHtml += '            <div class="ew-tree-table-border bottom"></div>';
        viewHtml += '         </div>';
        viewHtml += '         <div class="ew-tree-table-box">';
        viewHtml += '            <table class="layui-table"></table>';
        viewHtml += '            <div class="ew-tree-table-loading"><i class="layui-icon layui-anim layui-anim-rotate layui-anim-loop">&#xe63d;</i></div>';
        viewHtml += '            <div class="ew-tree-table-empty" style="display: none;">' + (options.text.none || '') + '</div>';
        viewHtml += '         </div>';
        viewHtml += '      </div>';
        viewHtml += '      <div class="ew-tree-table-border top"></div><div class="ew-tree-table-border left"></div>';
        viewHtml += '      <div class="ew-tree-table-border right"></div><div class="ew-tree-table-border bottom"></div>';
        viewHtml += '   </div>';
        $elem.after(viewHtml);
        // 获取各个组件
        var components = this.getComponents();
        var $view = components.$view;   // 容器
        $view.attr('lay-filter', tbFilter);
        var $group = components.$group;  // 表格容器
        var $tbBox = components.$tbBox;  // 表格主体部分容器
        var $table = components.$table;  // 主体表格
        var $headTb = components.$headTb;  // 表头表格
        var $tbEmpty = components.$tbEmpty;  // 空视图
        var $tbLoading = components.$tbLoading;  // 空视图
        // 基础参数设置
        options.skin && $table.attr('lay-skin', options.skin);
        options.size && $table.attr('lay-size', options.size);
        options.even && $table.attr('lay-even', options.even);
        // 容器边框调整
        if (device.ie) {
            $view.find('.ew-tree-table-border.bottom').css('height', '1px');
            $view.find('.ew-tree-table-border.right').css('width', '1px');
        }
        // 固定宽度
        if (options.width) {
            $view.css('width', options.width);
            $headTb.parent().css('width', options.width);
            $tbBox.css('width', options.width);
        }
        // col最小宽度
        var tbWidth = options.getTbWidth();
        if (tbWidth.setWidth) {
            $table.css('width', tbWidth.minWidth);
            $headTb.css('width', tbWidth.minWidth);
        } else {
            $table.css('min-width', tbWidth.minWidth);
            $headTb.css('min-width', tbWidth.minWidth);
        }
        // 渲染表结构及表头
        var colgroupHtmlStr = options.getColgroup();
        var headHtmlStr = colgroupHtmlStr + '<thead>' + options.getThead() + '</thead>';
        if (options.height) {  // 固定表头
            $table.html(colgroupHtmlStr + '<tbody></tbody>');
            $headTb.html(headHtmlStr);
            $table.css('margin-top', '-1px');
            if (options.height.indexOf('full-') == 0) {  // 差值高度
                var h = parseFloat(options.height.substring(5));
                var cssStr = '<style>.ew-tree-table > .ew-tree-table-group > .ew-tree-table-box {';
                cssStr += '      height: ' + (getPageHeight() - h) + 'px;';
                cssStr += '      height: -moz-calc(100vh - ' + h + 'px);';
                cssStr += '      height: -webkit-calc(100vh - ' + h + 'px);';
                cssStr += '      height: calc(100vh - ' + h + 'px);';
                cssStr += '   }</style>';
                $tbBox.after(cssStr);
                $tbBox.attr('ew-tree-full', h);
            } else {  // 固定高度
                $tbBox.css('height', options.height);
            }
        } else {
            $table.html(headHtmlStr + '<tbody></tbody>');
        }
        form.render('checkbox', tbFilter);  // 渲染表头的表单元素
        // 渲染数据
        if (options.reqData) {  // 异步加载
            this.renderBodyAsync();
        } else {  // 一次性渲染
            if (options.data && options.data.length > 0) {
                // 处理数据
                if (options.tree.isPidData) {  // pid形式数据
                    options.data = treeTb.pidToChildren(options.data, options.tree.idName, options.tree.pidName, options.tree.childName);
                } else {  // children形式数据
                    addPidField(options.data, options.tree);
                }
                $table.children('tbody').html(this.renderBody(options.data));
                $tbLoading.hide();
                this.renderNumberCol();  // 渲染序号列
                form.render(null, tbFilter);  // 渲染表单元素
                this.checkChooseAllCB();  // 联动全选框
                updateFixedTbHead($view);
            } else {
                $tbLoading.hide();
                $tbEmpty.show();
            }
        }
    };
    /** 绑定各项事件 */
    TreeTable.prototype.bindEvents = function () {
        var that = this;
        var options = this.options;
        var components = this.getComponents();
        var $view = components.$view;
        var $table = components.$table;
        var $tbEmpty = components.$tbEmpty;
        var tbFilter = components.tbFilter;
        var checkboxFilter = components.checkboxFilter;
        var radioFilter = components.radioFilter;
        var cbAllFilter = components.cbAllFilter;
        var $tbody = $table.children('tbody');
        /** 行事件公共返回对象 */
        var commonMember = function (ext) {
            var $tr = $(this);
            if (!$tr.is('tr')) {
                var $td_tr = $tr.parent('tr[data-id]');
                if ($td_tr.length > 0) {
                    $tr = $td_tr;
                } else {
                    $tr = $tr.parentsUntil('tr[data-id]').last().parent();
                }
            }
            var id = $tr.data('id');
            var data = getDataById(options.data, id, options.tree);
            var obj = {
                tr: $tr,  // 当前行
                data: data, //当前行数据
                del: function () { // 删除行
                    var indent = parseInt(this.tr.data('indent'));
                    this.tr.nextAll('tr').each(function () {
                        if (parseInt($(this).data('indent')) <= indent) {
                            return false;
                        }
                        $(this).remove();
                    });
                    var $parentTr = this.tr.prevAll('tr');
                    this.tr.remove();
                    delDataById(options.data, id, options.tree);
                    if (!options.data || options.data.length <= 0) {
                        $tbEmpty.show();
                    }
                    that.renderNumberCol();  // 渲染序号列
                    // 联动父级
                    $parentTr.each(function () {
                        var tInd = parseInt($(this).data('indent'));
                        if (tInd < indent) {
                            that.checkParentCB($(this));
                            indent = tInd;
                        }
                    });
                    that.checkChooseAllCB();  // 联动全选框
                },
                update: function (fields) {  // 修改行
                    data = $.extend(data, fields);
                    var indent = parseInt(this.tr.data('indent'));
                    that.renderBodyTr(data, indent, undefined, this.tr);
                    form.render(null, tbFilter);  // 渲染表单元素
                    that.checkIndeterminateCB();  // 恢复半选框状态
                    that.checkChooseAllCB();  // 联动全选框
                }
            };
            return $.extend(obj, ext);
        };
        // 绑定折叠展开事件
        $tbody.off('click.fold').on('click.fold', '.ew-tree-pack', function (e) {
            layui.stope(e);
            var $tr = $(this).parentsUntil('tr').last().parent();
            if ($tr.hasClass('ew-tree-table-loading')) {  // 已是加载中
                return;
            }
            var haveChild = $tr.data('have-child');
            if (haveChild != true && haveChild != 'true') {  // 子节点
                return;
            }
            var id = $tr.data('id');
            var isOpen = $tr.hasClass('ew-tree-table-open');
            var data = getDataById(options.data, id, options.tree);
            if (!isOpen && (!data[options.tree.childName] || data[options.tree.childName].length <= 0)) {
                that.renderBodyAsync(data, $tr);
            } else {
                toggleRow($tr);
            }
        });
        // 绑定lay-event事件
        $tbody.off('click.tool').on('click.tool', '*[lay-event]', function (e) {
            layui.stope(e);
            var $this = $(this);
            layui.event.call(this, MOD_NAME, 'tool(' + tbFilter + ')', commonMember.call(this, {
                event: $this.attr('lay-event')
            }));
        });
        // 绑定单选框事件
        form.on('radio(' + radioFilter + ')', function (data) {
            var d = getDataById(options.data, data.value, options.tree);
            that.removeAllChecked();
            d.LAY_CHECKED = true;  // 同时更新数据
            layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', {checked: true, data: d, type: 'one'});
        });
        // 绑定复选框事件
        form.on('checkbox(' + checkboxFilter + ')', function (data) {
            var checked = data.elem.checked;
            var $cb = $(data.elem);
            var $layCb = $cb.next('.layui-form-checkbox');
            // 如果是半选状态,点击全选
            if (!checked && $layCb.hasClass('ew-form-indeterminate')) {
                checked = true;
                $cb.prop('checked', checked);
                $cb.data('indeterminate', 'false');
                $layCb.addClass('layui-form-checked');
                $layCb.removeClass('ew-form-indeterminate');
            }
            var d = getDataById(options.data, data.value, options.tree);
            d.LAY_CHECKED = checked;  // 同时更新数据
            // 联动操作
            var $tr = $cb.parentsUntil('tr').last().parent();
            if (d[options.tree.childName] && d[options.tree.childName].length > 0) {
                that.checkSubCB($tr, checked);  // 联动子级
            }
            var indent = parseInt($tr.data('indent'));
            $tr.prevAll('tr').each(function () {
                var tInd = parseInt($(this).data('indent'));
                if (tInd < indent) {
                    that.checkParentCB($(this));  // 联动父级
                    indent = tInd;
                }
            });
            that.checkChooseAllCB();  // 联动全选框
            // 回调事件
            layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', {
                checked: checked,
                data: d,
                type: 'one'
            });
        });
        // 绑定全选复选框事件
        form.on('checkbox(' + cbAllFilter + ')', function (data) {
            var checked = data.elem.checked;
            var $cb = $(data.elem);
            var $layCb = $cb.next('.layui-form-checkbox');
            if (!options.data || options.data.length <= 0) {  // 如果数据为空
                $cb.prop('checked', false);
                $cb.data('indeterminate', 'false');
                $layCb.removeClass('layui-form-checked ew-form-indeterminate');
                return;
            }
            // 如果是半选状态,点击全选
            if (!checked && $layCb.hasClass('ew-form-indeterminate')) {
                checked = true;
                $cb.prop('checked', checked);
                $cb.data('indeterminate', 'false');
                $layCb.addClass('layui-form-checked');
                $layCb.removeClass('ew-form-indeterminate');
            }
            layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', {
                checked: checked,
                data: undefined,
                type: 'all'
            });
            that.checkSubCB($table.children('tbody'), checked);  // 联动操作
        });
        // 绑定行单击事件
        $tbody.off('click.row').on('click.row', 'tr', function () {
            layui.event.call(this, MOD_NAME, 'row(' + tbFilter + ')', commonMember.call(this, {}));
        });
        // 绑定行双击事件
        $tbody.off('dblclick.rowDouble').on('dblclick.rowDouble', 'tr', function () {
            layui.event.call(this, MOD_NAME, 'rowDouble(' + tbFilter + ')', commonMember.call(this, {}));
        });
        // 绑定单元格点击事件
        $tbody.off('click.cell').on('click.cell', 'td', function (e) {
            var $td = $(this);
            var type = $td.data('type');
            // 判断是否是复选框、单选框列
            if (type == 'checkbox' || type == 'radio') {
                layui.stope(e);
                return;
            }
            var edit = $td.data('edit');
            var field = $td.data('field');
            if (edit) {  // 开启了单元格编辑
                layui.stope(e);
                if ($tbody.find('.ew-tree-table-edit').length > 0) {
                    return;
                }
                var index = $td.data('index');
                var indentSize = $td.children('.ew-tree-table-indent').length;
                var id = $td.parent().data('id');
                var d = getDataById(options.data, id, options.tree);
                if ('text' == edit || 'number' == edit) {  // 文本框
                    var $input = $('<input type="' + edit + '" class="layui-input ew-tree-table-edit"/>');
                    $input[0].value = d[field];
                    $td.append($input);
                    $input.focus();
                    $input.blur(function () {
                        var value = $(this).val();
                        if (value == d[field]) {
                            $(this).remove();
                            return;
                        }
                        var rs = layui.event.call(this, MOD_NAME, 'edit(' + tbFilter + ')', commonMember.call(this, {
                            value: value,
                            field: field
                        }));
                        if (rs == false) {
                            $(this).addClass('layui-form-danger');
                            $(this).focus();
                        } else {
                            d[field] = value;  // 同步更新数据
                            that.renderBodyTd(d, indentSize, index, $td);  // 更新单元格
                        }
                    });
                } else {
                    console.error('不支持的单元格编辑类型:' + edit);
                }
            } else {  // 回调单元格点击事件
                var rs = layui.event.call(this, MOD_NAME, 'cell(' + tbFilter + ')', commonMember.call(this, {
                    td: $td,
                    field: field
                }));
                if (rs == false) {
                    layui.stope(e);
                }
            }
        });
        // 绑定单元格双击事件
        $tbody.off('dblclick.cellDouble').on('dblclick.cellDouble', 'td', function (e) {
            var $td = $(this);
            var type = $td.data('type');
            // 判断是否是复选框、单选框列
            if (type == 'checkbox' || type == 'radio') {
                layui.stope(e);
                return;
            }
            var edit = $td.data('edit');
            var field = $td.data('field');
            if (edit) {  // 开启了单元格编辑
                layui.stope(e);
            } else {  // 回调单元格双击事件
                var rs = layui.event.call(this, MOD_NAME, 'cellDouble(' + tbFilter + ')', commonMember.call(this, {
                    td: $td,
                    field: field
                }));
                if (rs == false) {
                    layui.stope(e);
                }
            }
        });
        // 同步滚动条
        components.$tbBox.on('scroll', function () {
            var $this = $(this);
            var scrollLeft = $this.scrollLeft();
            var scrollTop = $this.scrollTop();
            components.$headTb.parent().scrollLeft(scrollLeft);
            // $headGroup.scrollTop(scrollTop);
        });
        // 列宽拖拽调整
        /*$view.off('mousedown.resize').on('mousedown.resize', '.ew-tb-resize', function (e) {
            layui.stope(e);
            var index = $(this).parent().data('index');
            $(this).data('move', 'true');
            $(this).data('x', e.clientX);
            var w = $(this).parent().parent().parent().parent().children('colgroup').children('col').eq(index).attr('width');
            $(this).data('width', w);
        });
        $view.off('mousemove.resize').on('mousemove.resize', '.ew-tb-resize', function (e) {
            layui.stope(e);
            var move = $(this).data('move');
            if ('true' == move) {
                var x = $(this).data('x');
                var w = $(this).data('width');
                var index = $(this).parent().data('index');
                var nw = parseFloat(w) + e.clientX - parseFloat(x);
                $(this).parent().parent().parent().parent().children('colgroup').children('col').eq(index).attr('width', nw);
            }
        });
        $view.off('mouseup.resize').on('mouseup.resize', '.ew-tb-resize', function (e) {
            layui.stope(e);
            $(this).data('move', 'false');
        });
        $view.off('mouseleave.resize').on('mouseleave.resize', '.ew-tb-resize', function (e) {
            layui.stope(e);
            $(this).data('move', 'false');
        });*/
    };
    /** 获取各个组件 */
    TreeTable.prototype.getComponents = function () {
        var $view = $(this.options.elem).next();   // 容器
        var $group = $view.children('.ew-tree-table-group');  // 表格容器
        var $tbBox = $group.children('.ew-tree-table-box');  // 表格主体部分容器
        var $table = $tbBox.children('.layui-table');  // 主体表格
        var $headTb = $group.children('.ew-tree-table-head').children('.layui-table');  // 表头表格
        var $tbEmpty = $tbBox.children('.ew-tree-table-empty');  // 空视图
        var $tbLoading = $tbBox.children('.ew-tree-table-loading');  // 加载视图
        var tbFilter = $view.attr('lay-filter');  // 容器filter
        var checkboxFilter = 'ew_tb_checkbox_' + tbFilter;  // 复选框filter
        var radioFilter = 'ew_tb_radio_' + tbFilter;  // 单选框filter
        var cbAllFilter = 'ew_tb_choose_all_' + tbFilter;  // 全选按钮filter
        return {
            $view: $view,
            $group: $group,
            $tbBox: $tbBox,
            $table: $table,
            $headTb: $headTb,
            $tbEmpty: $tbEmpty,
            $tbLoading: $tbLoading,
            tbFilter: tbFilter,
            checkboxFilter: checkboxFilter,
            radioFilter: radioFilter,
            cbAllFilter: cbAllFilter
        };
    };
    /**
     * 递归渲染表格主体部分
     * @param data 数据列表
     * @param indentSize 缩进大小
     * @param isHide 是否默认隐藏
     * @returns {string}
     */
    TreeTable.prototype.renderBody = function (data, indentSize, isHide) {
        var options = this.options;
        var treeOption = options.tree;
        indentSize || (indentSize = 0);
        var htmlStr = '';
        for (var i = 0; i < data.length; i++) {
            var d = data[i];
            htmlStr += this.renderBodyTr(d, indentSize, isHide);
            // 递归渲染子集
            var children = d[treeOption.childName];
            if (children && children.length > 0) {
                htmlStr += this.renderBody(children, indentSize + 1, !d[treeOption.openName]);
            }
        }
        return htmlStr;
    };
    /**
     * 渲染一行数据
     * @param d 行数据
     * @param option 配置
     * @param indentSize 缩进大小
     * @param isHide 是否隐藏
     * @param $tr
     * @returns {string}
     */
    TreeTable.prototype.renderBodyTr = function (d, indentSize, isHide, $tr) {
        var options = this.options;
        var cols = options.cols;
        var treeOption = options.tree;
        indentSize || (indentSize = 0);
        var htmlStr = '';
        var haveChild = getHaveChild(d, treeOption);
        if ($tr) {
            $tr.data('pid', d[treeOption.pidName] || '');
            $tr.data('have-child', haveChild);
            $tr.data('indent', indentSize);
            $tr.removeClass('ew-tree-table-loading');
        } else {
            var classNames = '';
            if (haveChild && d[treeOption.openName]) {
                classNames += 'ew-tree-table-open';
            }
            if (isHide) {
                classNames += 'ew-tree-tb-hide';
            }
            htmlStr += '<tr class="' + classNames + '" data-id="' + d[treeOption.idName] + '"';
            htmlStr += ' data-pid="' + (d[treeOption.pidName] || '') + '" data-have-child="' + haveChild + '"';
            htmlStr += ' data-indent="' + indentSize + '">';
        }
        for (var j = 0; j < cols.length; j++) {
            var $td;
            if ($tr) {
                $td = $tr.children('td').eq(j);
            }
            htmlStr += this.renderBodyTd(d, indentSize, j, $td);
        }
        htmlStr += '</tr>';
        return htmlStr;
    };
    /**
     * 渲染每一个单元格数据
     * @param d 行数据
     * @param indentSize 缩进大小
     * @param index 第几列
     * @param $td
     * @returns {string}
     */
    TreeTable.prototype.renderBodyTd = function (d, indentSize, index, $td) {
        var options = this.options;
        var col = options.cols[index];
        var treeOption = options.tree;
        var components = this.getComponents();
        var checkboxFilter = components.checkboxFilter;
        var radioFilter = components.radioFilter;
        indentSize || (indentSize = 0);
        // 内容填充
        var fieldStr = '';
        if (col.type == 'numbers') {  // 序号列
            fieldStr += '<span class="ew-tree-table-numbers"></span>';
            col.singleLine = false;
        } else if (col.type == 'checkbox') {  // 复选框列
            var attrStr = 'name="' + checkboxFilter + '" lay-filter="' + checkboxFilter + '" value="' + d[treeOption.idName] + '"';
            attrStr += d.LAY_CHECKED ? ' checked="checked"' : '';
            fieldStr += '<input type="checkbox" lay-skin="primary" ' + attrStr + ' class="ew-tree-table-checkbox" />';
            col.singleLine = false;
        } else if (col.type == 'radio') {  // 单选框列
            var attrStr = 'name="' + radioFilter + '" lay-filter="' + radioFilter + '" value="' + d[treeOption.idName] + '"';
            attrStr += d.LAY_CHECKED ? ' checked="checked"' : '';
            fieldStr += '<input type="radio" ' + attrStr + ' class="ew-tree-table-radio" />';
            col.singleLine = false;
        } else if (col.templet) {  // 自定义模板
            if (typeof col.templet == 'function') {
                fieldStr += col.templet(d);
            } else if (typeof col.templet == 'string') {
                laytpl($(col.templet).html()).render(d, function (html) {
                    fieldStr += html;
                });
            }
        } else if (col.toolbar) {  // 工具列
            laytpl($(col.toolbar).html()).render(d, function (html) {
                fieldStr += html;
            });
        } else if (col.field && d[col.field] != undefined && d[col.field] != null) {  // 普通字段
            fieldStr += d[col.field];
        }
        var tdStr = '';
        // 图标列处理
        if (index == treeOption.iconIndex) {
            // 缩进
            for (var k = 0; k < indentSize; k++) {
                tdStr += '<span class="ew-tree-table-indent"></span>';
            }
            tdStr += '<span class="ew-tree-pack">';
            // 加箭头
            var haveChild = getHaveChild(d, treeOption);
            tdStr += ('<i class="layui-icon ew-tree-table-arrow ' + (haveChild ? '' : 'ew-tree-table-arrow-hide') + ' ' + (options.tree.arrowType || '') + '"></i>');
            // 加图标
            tdStr += treeOption.getIcon(d);
            if (options.tree.onlyIconControl) {
                tdStr += '</span>';
                tdStr += ('<span>' + fieldStr + '</span>');
            } else {
                tdStr += ('<span>' + fieldStr + '</span>');
                tdStr += '</span>';
            }
        } else {
            tdStr += fieldStr;
        }
        if ($td && col.type != 'numbers') {
            $td.html(tdStr);
        }
        var htmlStr = '<td data-index="' + index + '" ';
        col.field && (htmlStr += (' data-field="' + col.field + '"'));
        col.edit && (htmlStr += (' data-edit="' + col.edit + '"'));
        col.type && (htmlStr += (' data-type="' + col.type + '"'));
        col.align && (htmlStr += (' align="' + col.align + '"'));  // 对齐方式
        col.style && (htmlStr += (' style="' + col.style + '"'));  // 单元格样式
        col.class && (htmlStr += (' class="' + col.class + '"'));  // 单元格样式
        htmlStr += '>';
        if (col.singleLine) {
            htmlStr += ('<div class="ew-tree-table-td-single"><i class="layui-icon layui-icon-close ew-tree-tips-c"></i><div class="ew-tree-tips">' + tdStr + '</div></div>');
        } else {
            htmlStr += tdStr;
        }
        htmlStr += '</td>';
        return htmlStr;
    };
    /**
     * 异步加载渲染
     * @param data 父级数据
     * @param $tr 父级dom
     */
    TreeTable.prototype.renderBodyAsync = function (d, $tr) {
        var that = this;
        var options = this.options;
        var components = this.getComponents();
        var $tbEmpty = components.$tbEmpty;
        var $tbLoading = components.$tbLoading;
        // 显示loading
        if ($tr) {
            $tr.addClass('ew-tree-table-loading');
            $tr.children('td').find('.ew-tree-pack').children('.ew-tree-table-arrow').addClass('layui-anim layui-anim-rotate layui-anim-loop');
        } else {
            if (options.data && options.data.length > 0) {
                $tbLoading.addClass('ew-loading-float');
            }
            $tbLoading.show();
            $tbEmpty.hide();
        }
        // 请求数据
        options.reqData(d, function (res) {
            if (options.tree.isPidData) {
                res = treeTb.pidToChildren(res, options.tree.idName, options.tree.pidName, options.tree.childName);
            }
            that.renderBodyData(res, d, $tr);  // 渲染内容
            // 移除loading
            if ($tr) {
                $tr.removeClass('ew-tree-table-loading');
                $tr.children('td').find('.ew-tree-pack').children('.ew-tree-table-arrow').removeClass('layui-anim layui-anim-rotate layui-anim-loop');
            } else {
                $tbLoading.hide();
                $tbLoading.removeClass('ew-loading-float');
                // 是否为空
                if (!res || res.length == 0) {
                    $tbEmpty.show();
                } else {
                    $tbEmpty.hide();
                }
            }
        });
    };
    /**
     * 根据数据渲染body
     * @param data  数据集合
     * @param option 配置项
     * @param d 父级数据
     * @param $tr 父级dom
     */
    TreeTable.prototype.renderBodyData = function (data, d, $tr) {
        var that = this;
        var options = this.options;
        var components = this.getComponents();
        var $view = components.$view;
        var $table = components.$table;
        var tbFilter = components.tbFilter;
        addPidField(data, options.tree, d);  // 补充pid字段
        // 更新到数据
        if (d == undefined) {
            options.data = data;
        } else {
            d[options.tree.childName] = data;
        }
        var indent;
        if ($tr) {
            indent = parseInt($tr.data('indent')) + 1;
        }
        var htmlStr = this.renderBody(data, indent);
        if ($tr) {
            // 移除旧dom
            $tr.nextAll('tr').each(function () {
                if (parseInt($(this).data('indent')) <= (indent - 1)) {
                    return false;
                }
                $(this).remove();
            });
            // 渲染新dom
            $tr.after(htmlStr);
            $tr.addClass('ew-tree-table-open');
        } else {
            $table.children('tbody').html(htmlStr);
        }
        form.render(null, tbFilter);  // 渲染表单元素
        this.renderNumberCol();  // 渲染序号列
        this.checkIndeterminateCB();  // 恢复复选框半选状态
        if ($tr) {
            // 更新父级复选框状态
            this.checkParentCB($tr);
            $tr.prevAll('tr').each(function () {
                var tInd = parseInt($(this).data('indent'));
                if (tInd < (indent - 1)) {
                    that.checkParentCB($(this));
                    indent = tInd + 1;
                }
            });
        }
        this.checkChooseAllCB();  // 联动全选框
        updateFixedTbHead($view);
    };
    /**
     * 联动子级复选框状态
     * @param $tr 当前tr的dom
     * @param checked
     */
    TreeTable.prototype.checkSubCB = function ($tr, checked) {
        var that = this;
        var components = this.getComponents();
        var cbFilter = components.checkboxFilter;
        var indent = -1, $trList;
        if ($tr.is('tbody')) {
            $trList = $tr.children('tr');
        } else {
            indent = parseInt($tr.data('indent'));
            $trList = $tr.nextAll('tr')
        }
        $trList.each(function () {
            if (parseInt($(this).data('indent')) <= indent) {
                return false;
            }
            var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]');
            $cb.prop('checked', checked);
            if (checked) {
                $cb.data('indeterminate', 'false');
                $cb.next('.layui-form-checkbox').addClass('layui-form-checked');
                $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate');
            } else {
                $cb.data('indeterminate', 'false');
                $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate');
            }
            that.update($(this).data('id'), {LAY_CHECKED: checked});  // 同步更新数据
        });
    };
    /**
     * 联动父级复选框状态
     * @param $tr 父级的dom
     */
    TreeTable.prototype.checkParentCB = function ($tr) {
        var that = this;
        var components = this.getComponents();
        var cbFilter = components.checkboxFilter;
        var indent = parseInt($tr.data('indent'));
        var ckNum = 0, unCkNum = 0;
        $tr.nextAll('tr').each(function () {
            if (parseInt($(this).data('indent')) <= indent) {
                return false;
            }
            var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]');
            if ($cb.prop('checked')) {
                ckNum++;
            } else {
                unCkNum++;
            }
        });
        var $cb = $tr.children('td').find('input[name="' + cbFilter + '"]');
        if (ckNum > 0 && unCkNum == 0) {  // 全选
            $cb.prop('checked', true);
            $cb.data('indeterminate', 'false');
            $cb.next('.layui-form-checkbox').addClass('layui-form-checked');
            $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate');
            that.update($tr.data('id'), {LAY_CHECKED: true});  // 同步更新数据
        } else if (ckNum == 0 && unCkNum > 0) {  // 全不选
            $cb.prop('checked', false);
            $cb.data('indeterminate', 'false');
            $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate');
            that.update($tr.data('id'), {LAY_CHECKED: false});  // 同步更新数据
        } else if (ckNum > 0 && unCkNum > 0) {  // 半选
            $cb.prop('checked', true);
            $cb.data('indeterminate', 'true');
            $cb.next('.layui-form-checkbox').addClass('layui-form-checked ew-form-indeterminate');
            that.update($tr.data('id'), {LAY_CHECKED: true});  // 同步更新数据
        }
    };
    /** 联动全选复选框 */
    TreeTable.prototype.checkChooseAllCB = function () {
        var components = this.getComponents();
        var cbAllFilter = components.cbAllFilter;
        var cbFilter = components.checkboxFilter;
        var $tbody = components.$table.children('tbody');
        var ckNum = 0, unCkNum = 0;
        $tbody.children('tr').each(function () {
            var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]');
            if ($cb.prop('checked')) {
                ckNum++;
            } else {
                unCkNum++;
            }
        });
        var $cb = $('input[lay-filter="' + cbAllFilter + '"]');
        if (ckNum > 0 && unCkNum == 0) {  // 全选
            $cb.prop('checked', true);
            $cb.data('indeterminate', 'false');
            $cb.next('.layui-form-checkbox').addClass('layui-form-checked');
            $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate');
        } else if ((ckNum == 0 && unCkNum > 0) || (ckNum == 0 && unCkNum == 0)) {  // 全不选
            $cb.prop('checked', false);
            $cb.data('indeterminate', 'false');
            $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate');
        } else if (ckNum > 0 && unCkNum > 0) {  // 半选
            $cb.prop('checked', true);
            $cb.data('indeterminate', 'true');
            $cb.next('.layui-form-checkbox').addClass('layui-form-checked ew-form-indeterminate');
        }
    };
    /** 填充序号列 */
    TreeTable.prototype.renderNumberCol = function () {
        var components = this.getComponents();
        var $tbody = components.$table.children('tbody');
        $tbody.children('tr').each(function (index) {
            $(this).children('td').find('.ew-tree-table-numbers').text(index + 1);
        });
    };
    /* 解决form.render之后半选框被重置的问题 */
    TreeTable.prototype.checkIndeterminateCB = function () {
        var components = this.getComponents();
        var cbFilter = components.checkboxFilter;
        $('input[lay-filter="' + cbFilter + '"]').each(function () {
            var $cb = $(this);
            if ($cb.data('indeterminate') == 'true' && $cb.prop('checked')) {
                $cb.next('.layui-form-checkbox').addClass('ew-form-indeterminate');
            }
        });
    };
    /**
     * 搜索数据
     * @param ids 关键字或数据id集合
     */
    TreeTable.prototype.filterData = function (ids) {
        var components = this.getComponents();
        var $trList = components.$table.children('tbody').children('tr');
        if (typeof ids == 'string') {  // 关键字
            var keyword = ids;
            ids = [];
            $trList.each(function () {
                var id = $(this).data('id');
                $(this).children('td').each(function () {
                    if ($(this).text().indexOf(keyword) != -1) {
                        ids.push(id);
                        return false;
                    }
                });
            });
        }
        $trList.addClass('ew-tree-table-filter-hide');
        for (var i = 0; i < ids.length; i++) {
            var $tr = $trList.filter('[data-id="' + ids[i] + '"]');
            $tr.removeClass('ew-tree-table-filter-hide');
            // 联动父级
            var indent = parseInt($tr.data('indent'));
            $tr.prevAll('tr').each(function () {
                var tInd = parseInt($(this).data('indent'));
                if (tInd < indent) {
                    $(this).removeClass('ew-tree-table-filter-hide');  // 联动父级
                    if (!$(this).hasClass('ew-tree-table-open')) {
                        toggleRow($(this));
                    }
                    indent = tInd;
                }
            });
        }
    };
    /** 重置搜索 */
    TreeTable.prototype.clearFilter = function () {
        var components = this.getComponents();
        var $trList = components.$table.children('tbody').children('tr');
        $trList.removeClass('ew-tree-table-filter-hide');
    };
    /** 展开指定行 */
    TreeTable.prototype.expand = function (id, cascade) {
        var components = this.getComponents();
        var $tr = components.$table.children('tbody').children('tr[data-id="' + id + '"]');
        if (!$tr.hasClass('ew-tree-table-open')) {
            $tr.children('td').find('.ew-tree-pack').trigger('click');
        }
        if (cascade == false) {
            return;
        }
        // 联动父级
        var indent = parseInt($tr.data('indent'));
        $tr.prevAll('tr').each(function () {
            var tInd = parseInt($(this).data('indent'));
            if (tInd < indent) {
                if (!$(this).hasClass('ew-tree-table-open')) {
                    $(this).children('td').find('.ew-tree-pack').trigger('click');
                }
                indent = tInd;
            }
        });
    };
    /** 折叠指定行 */
    TreeTable.prototype.fold = function (id, cascade) {
        var components = this.getComponents();
        var $tr = components.$table.children('tbody').children('tr[data-id="' + id + '"]');
        if ($tr.hasClass('ew-tree-table-open')) {
            $tr.children('td').find('.ew-tree-pack').trigger('click');
        }
        if (cascade == false) {
            return;
        }
        // 联动父级
        var indent = parseInt($tr.data('indent'));
        $tr.prevAll('tr').each(function () {
            var tInd = parseInt($(this).data('indent'));
            if (tInd < indent) {
                if ($(this).hasClass('ew-tree-table-open')) {
                    $(this).children('td').find('.ew-tree-pack').trigger('click');
                }
                indent = tInd;
            }
        });
    };
    /** 全部展开 */
    TreeTable.prototype.expandAll = function () {
        var that = this;
        var components = this.getComponents();
        var $trList = components.$table.children('tbody').children('tr');
        $trList.each(function () {
            that.expand($(this).data('id'), false);
        });
    };
    /** 全部折叠 */
    TreeTable.prototype.foldAll = function () {
        var that = this;
        var components = this.getComponents();
        var $trList = components.$table.children('tbody').children('tr');
        $trList.each(function () {
            that.fold($(this).data('id'), false);
        });
    };
    /** 获取当前数据 */
    TreeTable.prototype.getData = function () {
        return this.options.data;
    };
    /** 重载表格 */
    TreeTable.prototype.reload = function (opt) {
        treeTb.render($.extend(this.options, opt));
    };
    /** 根据id更新数据 */
    TreeTable.prototype.update = function (id, fields) {
        var data = getDataById(this.getData(), id, this.options.tree);
        $.extend(data, fields);
    };
    /** 根据id删除数据 */
    TreeTable.prototype.del = function (id) {
        delDataById(this.getData(), id, this.options.tree);
    };
    /** 获取当前选中行 */
    TreeTable.prototype.checkStatus = function (needIndeterminate) {
        (needIndeterminate == undefined) && (needIndeterminate = true);
        var that = this;
        var components = this.getComponents();
        var $table = components.$table;
        var checkboxFilter = components.checkboxFilter;
        var radioFilter = components.radioFilter;
        var list = [];
        // 获取单选框选中数据
        var $radio = $table.find('input[name="' + radioFilter + '"]');
        if ($radio.length > 0) {
            var id = $radio.filter(':checked').val();
            var d = getDataById(this.getData(), id, this.options.tree);
            if (d) {
                list.push(d);
            }
        } else {  // 获取复选框数据
            $table.find('input[name="' + checkboxFilter + '"]:checked').each(function () {
                var id = $(this).val();
                var isIndeterminate = $(this).next('.layui-form-checkbox').hasClass('ew-form-indeterminate');
                if (needIndeterminate || !isIndeterminate) {
                    var d = getDataById(that.getData(), id, that.options.tree);
                    if (d) {
                        d.isIndeterminate = isIndeterminate;
                        list.push(d);
                    }
                }
            });
        }
        return list;
    };
    /** 设置复/单选框选中 */
    TreeTable.prototype.setChecked = function (ids) {
        var components = this.getComponents();
        var $table = components.$table;
        var checkboxFilter = components.checkboxFilter;
        var radioFilter = components.radioFilter;
        var $radio = $table.find('input[name="' + radioFilter + '"]');
        if ($radio.length > 0) {  // 开启了单选框
            $radio.each(function () {
                if (ids[ids.length - 1] == $(this).val()) {
                    $(this).next('.layui-form-radio').trigger('click');
                    return false;
                }
            });
        } else {  // 开启了复选框
            $table.find('input[name="' + checkboxFilter + '"]').each(function () {
                var $cb = $(this);
                var value = $cb.val();
                var $layCb = $cb.next('.layui-form-checkbox');
                for (var i = 0; i < ids.length; i++) {
                    if (value == ids[i]) {
                        var checked = $cb.prop('checked');
                        var indeterminate = $layCb.hasClass('ew-form-indeterminate');
                        if (!checked || indeterminate) {
                            $layCb.trigger('click');
                        }
                    }
                }
            });
        }
    };
    /** 移除全部选中 */
    TreeTable.prototype.removeAllChecked = function () {
        var components = this.getComponents();
        var $table = components.$table;
        var checkboxFilter = components.checkboxFilter;
        this.checkSubCB($table.children('tbody'), false);
    };
    /**
     * 刷新指定父级下的节点
     * @param id 父级id,空则全部刷新
     * @param data 非异步模式替换的数据
     */
    TreeTable.prototype.refresh = function (id, data) {
        if (isClass(id) == 'Array') {
            data = id;
            id = undefined;
        }
        var components = this.getComponents();
        var $table = components.$table;
        var d, $tr;
        if (id != undefined) {
            d = getDataById(this.getData(), id, this.options.tree);
            $tr = $table.children('tbody').children('tr[data-id="' + id + '"]');
        }
        if (data) {  // 数据模式
            components.$tbLoading.addClass('ew-loading-float');
            components.$tbLoading.show();
            this.renderBodyData(data, d, $tr);
            components.$tbLoading.hide();
            components.$tbLoading.removeClass('ew-loading-float');
            if (data && data.length > 0) {
                components.$tbEmpty.hide();
            } else {
                components.$tbEmpty.show();
            }
        } else {  // 异步模式
            this.renderBodyAsync(d, $tr);
        }
    };
    /** 生成表头 */
    function getThead(options) {
        var htmlStr = '<tr>';
        for (var i = 0; i < options.cols.length; i++) {
            var col = options.cols[i];
            htmlStr += '<td data-index="' + i + '" ';
            col.align && (htmlStr += ' align="' + col.align + '"');  // 对齐方式
            htmlStr += ' >';
            if (col.singleLine && col.type != 'checkbox') {  // 单行显示
                htmlStr += '<div class="ew-tree-table-td-single"><i class="layui-icon layui-icon-close ew-tree-tips-c"></i><div class="ew-tree-tips">';
            }
            // 标题
            if (col.type == 'checkbox') {
                htmlStr += options.getAllChooseBox();
            } else {
                htmlStr += (col.title || '');
            }
            // 列宽拖拽
            if (!col.unresize && 'checkbox' != col.type && 'radio' != col.type && 'numbers' != col.type && 'space' != col.type) {
                htmlStr += '<span class="ew-tb-resize"></span>';
            }
            if (col.singleLine) {  // 单行显示
                htmlStr += '</div></div>';
            }
            htmlStr += '</td>';
        }
        htmlStr += '</tr>';
        return htmlStr;
    }
    /** 生成colgroup */
    function getColgroup(options) {
        var htmlStr = '<colgroup>';
        for (var i = 0; i < options.cols.length; i++) {
            var col = options.cols[i];
            htmlStr += '<col ';
            // 设置宽度
            if (col.width) {
                htmlStr += 'width="' + col.width + '"'
            } else if (col.type == 'space') {  // 空列
                htmlStr += 'width="15"'
            } else if (col.type == 'numbers') {  // 序号列
                htmlStr += 'width="40"'
            } else if (col.type == 'checkbox' || col.type == 'radio') {  // 复/单选框列
                htmlStr += 'width="48"'
            }
            htmlStr += ' />';
        }
        htmlStr += '</colgroup>';
        return htmlStr;
    }
    /** 计算table宽度 */
    function getTbWidth(options) {
        var minWidth = 0, setWidth = true;
        for (var i = 0; i < options.cols.length; i++) {
            var col = options.cols[i];
            if (col.type == 'space') {  // 空列
                minWidth += 15;
            } else if (col.type == 'numbers') {  // 序号列
                minWidth += 40;
            } else if (col.type == 'checkbox' || col.type == 'radio') {  // 复/单选框列
                minWidth += 48;
            } else if (!col.width || /\d+%$/.test(col.width)) {  // 列未固定宽度
                setWidth = false;
                if (col.minWidth) {
                    minWidth += col.minWidth;
                } else if (options.cellMinWidth) {
                    minWidth += options.cellMinWidth;
                }
            } else {  // 列固定宽度
                minWidth += col.width;
            }
        }
        return {minWidth: minWidth, setWidth: setWidth};
    }
    /** 生成全选按钮 */
    function getAllChooseBox(options) {
        var tbFilter = $(options.elem).next().attr('lay-filter');
        var cbAllFilter = 'ew_tb_choose_all_' + tbFilter;
        return '<input type="checkbox" lay-filter="' + cbAllFilter + '" lay-skin="primary" class="ew-tree-table-checkbox"/>';
    }
    /** 获取列图标 */
    function getIcon(d, treeOption) {
        if (getHaveChild(d, treeOption)) {
            return '<i class="ew-tree-icon layui-icon layui-icon-layer"></i>';
        } else {
            return '<i class="ew-tree-icon layui-icon layui-icon-file"></i>';
        }
    }
    /** 折叠/展开行 */
    function toggleRow($tr) {
        var indent = parseInt($tr.data('indent'));
        var isOpen = $tr.hasClass('ew-tree-table-open');
        if (isOpen) {  // 折叠
            $tr.removeClass('ew-tree-table-open');
            $tr.nextAll('tr').each(function () {
                if (parseInt($(this).data('indent')) <= indent) {
                    return false;
                }
                $(this).addClass('ew-tree-tb-hide');
            });
        } else {  // 展开
            $tr.addClass('ew-tree-table-open');
            var hideInd;
            $tr.nextAll('tr').each(function () {
                var ind = parseInt($(this).data('indent'));
                if (ind <= indent) {
                    return false;
                }
                if (hideInd != undefined && ind > hideInd) {
                    return true;
                }
                $(this).removeClass('ew-tree-tb-hide');
                if (!$(this).hasClass('ew-tree-table-open')) {
                    hideInd = parseInt($(this).data('indent'));
                } else {
                    hideInd = undefined;
                }
            });
        }
        updateFixedTbHead($tr.parent().parent().parent().parent().parent());
    }
    /** 固定表头滚动条补丁 */
    function updateFixedTbHead($view) {
        var $group = $view.children('.ew-tree-table-group');
        var $headBox = $group.children('.ew-tree-table-head');
        var $tbBox = $group.children('.ew-tree-table-box');
        var sWidth = $tbBox.width() - $tbBox.prop('clientWidth');
        if (sWidth > 0) {
            $headBox.css('border-right', sWidth + 'px solid #f2f2f2');
        } else {
            $headBox.css('border-right', 'none');
        }
    }
    // 监听窗口大小改变
    $(window).resize(function () {
        $('.ew-tree-table').each(function () {
            updateFixedTbHead($(this));
            var $tbBox = $(this).children('.ew-tree-table-group').children('.ew-tree-table-box');
            var full = $tbBox.attr('ew-tree-full');
            if (full && device.ie && device.ie < 10) {
                $tbBox.css('height', getPageHeight() - full);
            }
        });
    });
    // 表格溢出点击展开功能
    $(document).on('mouseenter', '.ew-tree-table td', function () {
        var $tdSingle = $(this).children('.ew-tree-table-td-single');
        var $content = $tdSingle.children('.ew-tree-tips');
        if ($tdSingle.length > 0 && $content.prop('scrollWidth') > $content.outerWidth()) {
            $(this).append('<div class="layui-table-grid-down"><i class="layui-icon layui-icon-down"></i></div>');
        }
    }).on('mouseleave', '.ew-tree-table td', function () {
        $(this).children('.layui-table-grid-down').remove();
    });
    // 点击箭头展开
    $(document).on('click', '.ew-tree-table td>.layui-table-grid-down', function (e) {
        hideAllTdTips();
        var $tdSingle = $(this).parent().children('.ew-tree-table-td-single');
        $tdSingle.addClass('ew-tree-tips-open');
        var $box = $tdSingle.parents().filter('.ew-tree-table-box');
        if ($box.length <= 0) {
            $box = $tdSingle.parents().filter('.ew-tree-table-head');
        }
        if (($tdSingle.outerWidth() + $tdSingle.parent().offset().left) > $box.offset().left + $box.outerWidth()) {
            $tdSingle.addClass('ew-show-left');
        }
        if (($tdSingle.outerHeight() + $tdSingle.parent().offset().top) > $box.offset().top + $box.outerHeight()) {
            $tdSingle.addClass('ew-show-bottom');
        }
        e.stopPropagation();
    });
    // 点击关闭按钮关闭
    $(document).on('click', '.ew-tree-table .ew-tree-tips-c', function (e) {
        hideAllTdTips();
    });
    // 点击空白部分关闭
    $(document).on('click', function () {
        hideAllTdTips();
    });
    $(document).on('click', '.ew-tree-table-td-single.ew-tree-tips-open', function (e) {
        e.stopPropagation();
    });
    /* 关闭所有单元格溢出提示框 */
    function hideAllTdTips() {
        var $single = $('.ew-tree-table-td-single');
        $single.removeClass('ew-tree-tips-open');
        $single.removeClass('ew-show-left');
    }
    /** 判断是否还有子节点 */
    function getHaveChild(d, treeOption) {
        var haveChild = false;
        if (d[treeOption.haveChildName] != undefined) {
            haveChild = d[treeOption.haveChildName];
            haveChild = haveChild == true || haveChild == 'true';
        } else if (d[treeOption.childName]) {
            haveChild = d[treeOption.childName].length > 0;
        }
        return haveChild;
    }
    /** 补充pid字段 */
    function addPidField(data, treeOption, parent) {
        for (var i = 0; i < data.length; i++) {
            if (parent) {
                data[i][treeOption.pidName] = parent[treeOption.idName];
            }
            if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) {
                addPidField(data[i][treeOption.childName], treeOption, data[i]);
            }
        }
    }
    /** 根据id获取数据 */
    function getDataById(data, id, treeOption) {
        for (var i = 0; i < data.length; i++) {
            if (data[i][treeOption.idName] == id) {
                return data[i];
            }
            if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) {
                var d = getDataById(data[i][treeOption.childName], id, treeOption);
                if (d != undefined) {
                    return d;
                }
            }
        }
    }
    /** 根据id删除数据 */
    function delDataById(data, id, treeOption) {
        for (var i = 0; i < data.length; i++) {
            if (data[i][treeOption.idName] == id) {
                data.splice(i, 1);
                return true;
            }
            if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) {
                var rs = delDataById(data[i][treeOption.childName], id, treeOption);
                if (rs) {
                    return true;
                }
            }
        }
    }
    /** 获取顶级的pId */
    function getPids(list, idName, pidName) {
        var pids = [];
        for (var i = 0; i < list.length; i++) {
            var hasPid = false;
            for (var j = 0; j < list.length; j++) {
                if (i != j && list[j][idName] == list[i][pidName]) {
                    hasPid = true;
                }
            }
            if (!hasPid) {
                pids.push(list[i][pidName]);
            }
        }
        return pids;
    }
    /** 判断pId是否相等 */
    function pidEquals(pId, pIds) {
        if (isClass(pIds) == 'Array') {
            for (var i = 0; i < pIds.length; i++) {
                if (pId == pIds[i]) {
                    return true;
                }
            }
        } else {
            return pId == pIds;
        }
        return false;
    }
    /** 获取变量类型 */
    function isClass(o) {
        if (o === null)
            return 'Null';
        if (o === undefined)
            return 'Undefined';
        return Object.prototype.toString.call(o).slice(8, -1);
    }
    /* 获取浏览器高度 */
    function getPageHeight() {
        return document.documentElement.clientHeight || document.body.clientHeight;
    }
    /* 获取浏览器宽度 */
    function getPageWidth() {
        return document.documentElement.clientWidth || document.body.clientWidth;
    }
    /** 对外提供的方法 */
    var treeTb = {
        /* 渲染 */
        render: function (options) {
            return new TreeTable(options);
        },
        /* 事件监听 */
        on: function (events, callback) {
            return layui.onevent.call(this, MOD_NAME, events, callback);
        },
        /* pid转children形式 */
        pidToChildren: function (data, idName, pidName, childName, pId) {
            childName || (childName = 'children');
            var newList = [];
            for (var i = 0; i < data.length; i++) {
                (pId == undefined) && (pId = getPids(data, idName, pidName));
                if (pidEquals(data[i][pidName], pId)) {
                    var children = this.pidToChildren(data, idName, pidName, childName, data[i][idName]);
                    (children.length > 0) && (data[i][childName] = children);
                    newList.push(data[i]);
                }
            }
            return newList;
        }
    };
    exports('treeTable', treeTb);
});
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/opration/feedback.html
@@ -51,7 +51,7 @@
            elem: '#dateend'
        });
        // 渲染表格
        table.render({
        var tableLoad=table.render({
            elem: '#feedback-table',
            url: config.base_server + 'api-opration/sysfeedback',
            method: 'GET',
@@ -95,7 +95,9 @@
                layer.load(2);
                admin.req('api-opration/sysfeedback/'+obj.data.id, {}, function (data) {
                    layer.closeAll('loading');
                    layer.msg('成功', {icon: 1, time: 500});
                    layer.msg(data.msg, {icon: 1, time: 500},function(){
                        tableLoad();
                    });
                    obj.del();
                }, 'DELETE');
            });
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/system/sysArea.html
New file
@@ -0,0 +1,183 @@
<div class="layui-card">
    <div class="layui-card-header">
        <h2 class="header-title">地区管理</h2>
        <span class="layui-breadcrumb pull-right">
          <a href="#!console">首页</a>
          <a><cite>地区管理</cite></a>
        </span>
    </div>
    <div class="layui-card-body">
        <div class="layui-form toolbar">&emsp;
            <input id="area-search-value" class="layui-input search-input" type="text" placeholder="输入地区名称"/>&emsp;
            <button id="area-btn-search" class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜索</button>
            <button id="area-btn-add" class="layui-btn icon-btn"><i class="layui-icon">&#xe654;</i>添加</button>
            <button id="area-btn-expand" class="layui-btn">全部展开</button>
            <button id="area-btn-fold" class="layui-btn">全部折叠</button>
        </div>
        <table class="layui-table" id="area-table" lay-filter="area-table"></table>
    </div>
</div>
<!-- 表格操作列 -->
<script type="text/html" id="area-table-bar">
    <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">编辑</a>
    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<!-- 表格状态列 -->
<script type="text/html" id="area-tpl-state">
    <input type="checkbox" lay-filter="area-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用"
           {{d.enabled==true?'checked':''}}/>
</script>
<script>
    layui.use(['form', 'table', 'util', 'config', 'admin', 'formSelects', 'treetable'],function () {
        let table = layui.table;
        let layer = layui.layer;
        let admin = layui.admin;
        let treetable = layui.treetable;
        let config = layui.config;
        let form = layui.form;
        // 渲染表格
        var renderTable = function (param) {
            if (param) {
                param.access_token = config.getToken().access_token;
            } else {
                param = {
                    access_token: config.getToken().access_token
                };
            }
            treetable.render({
                treeColIndex: 0,
                treeSpid: -1,
                treeIdName: 'id',
                treePidName: 'areaParentId',
                elem: '#area-table',
                url: config.base_server + 'api-user/sysarea/findAlls',
                where: param,
                page: false,
                cols: [[
                    {field: 'areaName', minWidth: 200, title: '区域名称'},
                    {field: 'areaCh',  align: 'center', title: '拼音'},
                    {field: 'areaShortname', minWidth: 80, title: '简称'},
                    {field: 'areaCitycode', title: '区号'},
                    {field: 'areaZipcode', title: '邮编'},
                    {field: 'sort', width: 80, align: 'center', title: '排序号'},
                    {
                        field: 'areaLeveltype', width: 80, align: 'center', templet: function (d) {
                            switch(d.areaLeveltype){
                                case 0:
                                return '<span class="layui-badge layui-bg-red">国家</span>';
                                break;
                                case 1:
                                return '<span class="layui-badge layui-bg-blue">省/行政区</span>';
                                break;
                                case 2:
                                return '<span class="layui-badge layui-bg-gray">市</span>';
                                break;
                                case 3:
                                return '<span class="layui-badge layui-bg-green">区/县</span>';
                                break;
                            }
                        }, title: '级别'
                    },
                    {field: 'enabled', width: 100,sort: true, templet: '#area-tpl-state', title: '状态'},
                    {templet: '#area-table-bar', width: 120, align: 'center', title: '操作'}
                ]]
            });
        };
        renderTable();
        // 修改状态
        form.on('switch(area-tpl-state)', function (obj) {
        layer.load(2);
        admin.req('api-user/sysarea/updateEnabled', {
            id: obj.elem.value,
            enabled: obj.elem.checked ? true : false
        }, function (data) {
            layer.closeAll('loading');
            if (data.code == 0) {
                layer.msg(data.msg, {icon: 1, time: 500});
            } else {
                layer.msg(data.msg, {icon: 2, time: 500});
                $(obj.elem).prop('checked', !obj.elem.checked);
                form.render('checkbox');
            }
        }, 'GET');
        });
        // 工具条点击事件
        table.on('tool(area-table)', function (obj) {
            if (obj.event === 'del') { // 删除
                layer.confirm('确定要删除吗?', function (i) {
                layer.close(i);
                layer.load(2);
                admin.req('api-user/sysarea/'+obj.data.id, {}, function (data) {
                    layer.closeAll('loading');
                    layer.msg(data.msg, {icon: 1, time: 800},function(){
                        renderTable();
                    });
                    obj.del();
                }, 'DELETE');
            });
            }
            else if(obj.event=='edit')
            {
                showEditModel(obj.data);
            }
        });
        // 显示编辑弹窗
        var showEditModel = function (data) {
            let title = data ? '修改区域' : '添加区域';
            if (!data){
                data = {};
            }
            admin.putTempData('t_area', data);
            admin.popupCenter({
                title: title,
                path: 'pages/system/sysarea_form.html',
                finish: function () {
                    renderTable();
                }
            });
        };
        // 搜索按钮点击事件
        $('#area-btn-search').click(function () {
            var keyword = $('#area-search-value').val();
            var searchCount = 0;
            $('#area-table').next('.treeTable').find('.layui-table-body tbody tr td').each(function () {
                $(this).css('background-color', 'transparent');
                var text = $(this).text();
                if (keyword !== '' && text.indexOf(keyword) >= 0) {
                    $(this).css('background-color', 'rgba(250,230,160,0.5)');
                    if (searchCount === 0) {
                        $('.layui-tab-item.layui-show').stop(true);
                        $('.layui-tab-item.layui-show').animate({scrollTop: $(this).offset().top - 150}, 500);
                    }
                    searchCount++;
                }
            });
            if (keyword !== '' && searchCount === 0) {
                layer.msg("没有匹配结果", {icon: 5, time: 500});
            } else {
                treetable.expandAll('#area-table');
            }
        });
        $('#area-btn-expand').click(function () {
            treetable.expandAll('#area-table');
        });
        $('#area-btn-fold').click(function () {
            treetable.foldAll('#area-table');
        });
        // 添加按钮点击事件
        $('#area-btn-add').click(function () {
            showEditModel();
        });
    });
</script>
kidgrow-web/kidgrow-web-manager/src/main/resources/static/pages/system/sysArea_form.html
New file
@@ -0,0 +1,108 @@
<!-- 菜单弹框 -->
<form id="area-form" lay-filter="area-form" class="layui-form model-form" method="POST">
    <div class="layui-form-item">
        <label class="layui-form-label">区域级别</label>
        <div class="layui-input-block">
            <select name="areaLeveltype" id="areaLeveltype">
                <option value="">请选择</option>
                <option value="0">国家</option>
                <option value="1">省/行政区</option>
                <option value="2">市</option>
                <option value="3">区县</option>
            </select>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">区域编号</label>
        <div class="layui-input-block">
            <input id="id" name="id" placeholder="请输入区域编号" type="text" class="layui-input" maxlength="20"
                   lay-verify="required" required/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">区域名称</label>
        <div class="layui-input-block">
            <input name="areaName" placeholder="请输入区域名称" type="text" class="layui-input" maxlength="50"
                   lay-verify="required" required/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">简称</label>
        <div class="layui-input-block">
            <input name="areaShortname"  type="text" class="layui-input" maxlength="50"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">拼音名称</label>
        <div class="layui-input-block">
            <input name="areaCh"  type="text" class="layui-input" maxlength="50"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">父级编号</label>
        <div class="layui-input-block">
            <input name="areaParentId"  type="text" class="layui-input" maxlength="20"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">区号</label>
        <div class="layui-input-block">
            <input name="areaCitycode"  type="text" class="layui-input"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">邮编</label>
        <div class="layui-input-block">
            <input name="areaZipcode"  type="text" class="layui-input"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">纬度</label>
        <div class="layui-input-block">
            <input name="areaLng"  type="text" class="layui-input"/>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">经度</label>
        <div class="layui-input-block">
            <input name="areaLat"  type="text" class="layui-input"/>
        </div>
    </div>
    <div class="layui-form-item model-form-footer">
        <button class="layui-btn layui-btn-primary" ew-event="closeDialog" type="button">取消</button>
        <button class="layui-btn" lay-filter="area-form-submit" lay-submit>保存</button>
    </div>
</form>
<script>
    layui.use(['layer', 'admin', 'form'],function () {
        var layer = layui.layer;
        var admin = layui.admin;
        var form = layui.form;
        // 回显menu数据
        let area = admin.getTempData('t_area');
        if(area){
        form.val('area-form', area);
        $("#Id").attr("enabled","false");
    }
        // 表单提交事件
        form.on('submit(area-form-submit)', function (data) {
            layer.load(2);
            admin.req('api-user/sysarea', JSON.stringify(data.field), function (data) {
                if (data.code === 0) {
                    layer.closeAll('loading');
                    layer.msg(data.msg, {icon: 1, time: 500});
                    admin.finishPopupCenter();
                } else {
                    layer.closeAll('loading');
                    layer.msg(data.msg, {icon: 2, time: 500});
                }
            }, $('#area-form').attr('method'));
            return false;
        });
    });
</script>