<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>layui table 组件综合演示</title>
  <meta name="renderer" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="../../../res/layui/css/layui.css" rel="stylesheet">
  <link href="../../../res/adminui/dist/css/admin.css" rel="stylesheet">
</head>
<body>
  <script id="addPlan" type="text/html">
    <style>
.layui-form-select dl{max-height: 160px}
.top-0 {top: 0!important}
td[handler] {cursor: move}
</style>
    <div class="layui-form" style="margin:10px 15px" id="editPlanForm" lay-filter="editPlanForm">
        <div class="layui-form-item">
            <input type="hidden" name="id"/>
            <label class="layui-form-label">计划名称<span>*</span></label>
            <div class="layui-input-block">
                <input type="text" lay-verify="required" name="name" placeholder="" autocomplete="off" class="layui-input"/>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">计划表达式<span>*</span></label>
            <div class="layui-input-block">
                <input type="text" lay-verify="required" name="cronExpr" placeholder="" autocomplete="off" class="layui-input"/>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">更新方法<span>*</span></label>
            <div class="layui-input-block">
                <table id="table-methods" lay-filter="table-methods"></table>
            </div>
        </div>
        
        <div id="params">
        </div>
        <div id="periods">
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">启用<span>*</span></label>
            <div class="layui-input-block">
                <input type="checkbox"
                       name="enabled" lay-skin="switch" lay-filter="enabled" lay-text="ON|OFF">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">交易日校验<span>*</span></label>
            <div class="layui-input-block">
                <input type="checkbox"
                       name="openDayCheck" lay-skin="switch" lay-filter="openDayCheck" lay-text="ON|OFF">
            </div>
        </div>
        <div style="display:none" class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit="*" lay-filter="submitPlan">提交</button>
            </div>
        </div>
    </div>
</script>
  <div class="layui-card layadmin-header">
    <div class="layui-breadcrumb" lay-filter="breadcrumb">
      <a lay-href="">主页</a>
      <a><cite>应用</cite></a>
      <a><cite>任务</cite></a>
      <a><cite>计划列表</cite></a>
    </div>
  </div>
  
  <div class="layui-fluid">
    <div class="layui-row layui-col-space15">
      <div class="layui-col-md12">
        <div class="layui-card">
          <div class="layui-card-header">综合演示</div>
          <div class="layui-card-body">
            <table class="layui-hide" id="plan-table" lay-filter="plan-table"></table>
            <script type="text/html" id="toolbarDemo">
              <div class="layui-btn-container">
                <button class="layui-btn layui-btn-sm" lay-event="new">新增</button>
                <button class="layui-btn layui-btn-sm layui-bg-blue" id="reloadTest">
                  重载测试 
                  <i class="layui-icon layui-icon-down layui-font-12"></i>
                </button>
              </div>
            </script>
            <script type="text/html" id="enabled-switchTpl">
              <input type="checkbox" name="enabled" title="" lay-text="启用|停用" lay-skin="switch" lay-filter="table-switch" 
               value="{{d.id}}" {{ d.enabled ? 'checked' : ''}}>
            </script>
            <script type="text/html" id="openDayCheck-switchTpl">
              <input type="checkbox" name="openDayCheck" title="" lay-text="开启|关闭" lay-skin="switch" lay-filter="table-switch" 
               value="{{d.id}}" {{ d.openDayCheck ? 'checked' : ''}}>
            </script>
            <script type="text/html" id="barDemo">
              <a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
              <a class="layui-btn layui-btn-xs" lay-event="trigger">触发</a>
              <a class="layui-btn layui-btn-xs" lay-event="interrupt">停止</a>
              <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
            </script>  
          </div>
        </div>
      </div>
    </div>
  </div>
  
  <script src="../../../res/layui/layui.js"></script>  
  <script>
  layui
  .config({
    base: '../../../res/' // 静态资源所在路径
  }).use(['index', 'table', 'dropdown', 'cron'], function(){
    var table = layui.table, dropdown = layui.dropdown, form = layui.form, $ = layui.$;
    var methods;
    var sortableInstance = null;
    
    $.ajax({
      method: 'GET',
      url: '/admin/manage/reviews/update-methods/method-list-resp',
      success: res => methods = res
    })
    
    // 创建渲染实例
    table.render({
      elem: '#plan-table'
      ,url: '/admin/manage/reviews/plans/list' // 此处为静态模拟数据，实际使用时需换成真实接口
      ,toolbar: '#toolbarDemo'
      ,defaultToolbar: ['filter', 'exports', 'print', {
        title: '帮助'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,height: 'full-100' // 最大高度减去其他容器已占有的高度差
      ,cellMinWidth: 80
      ,totalRow: true // 开启合计行
      ,page: true
      ,cols: [ [
        {type: 'checkbox', fixed: 'left'}
        ,{field:'id', fixed: 'left', width:80, title: 'ID', sort: true, totalRowText: '合计：'}
        ,{field:'name', width:200, title: '名称'}
        ,{field:'cronExpr', title:'计划任务表达式', hide: 0, width:150}
        ,{field:'enabled', width:90, title: '启用', templet: '#enabled-switchTpl'}
        ,{field:'openDayCheck', width:90, title: '交易日验证', templet: '#openDayCheck-switchTpl'}
        ,{field:'valid', title: '有效', width: 80, templet: d => {
          return '<span title="当值为无效时，请检查方法参数等是否有效">' +
          d.valid ? '<font color="green">有效</font>' : '<font color="red">无效</font>' +
              '</span>';
        }}
        ,{fixed: 'right', title:'操作', minWidth: 125, toolbar: '#barDemo'}
      ]]
      ,done: function(){
        var id = this.id;
      }
      ,error: function(res, msg){
        console.log(res, msg)
      }
    });
    
    // 表单提交事件
    form.on('submit(submitPlan)', function (obj) {
      console.log(obj);
      
      let form = obj.elem.closest('.layui-form');
      // 查找其下所有表单
      form.querySelectorAll('input').forEach(input => {
        if (input.name)
          obj.field[input.name] = input.value;
      })
      
      // 主要是清洗 methods
      const tbodies = document.querySelectorAll('#table-methods tbody');
      const selectedMethods = [];
      for (let i = 0; i < tbodies.length; i++) {
        const tbody = tbodies[i];
        const checkbox = tbody.querySelector('input[type="checkbox"]');
        if (!checkbox?.checked) continue;
        const methodId = tbody.dataset.id;
        // 查找选择的参数
        const selects = tbody.querySelectorAll('select');
        const params = [];
        selects.forEach(select => {
          params.push({name: select.getAttribute('name'), value: select.value})
        })
        selectedMethods.push({
          id: methodId, params: params
        })
      }
      obj.field.methods = selectedMethods;
       
      
      console.log(obj.field);
      
      const load = layui.layer.load(4);
      
      $.ajax({
        method: 'POST',
        url: '/admin/manage/reviews/plans/save',
        contentType: 'application/json',
        data: JSON.stringify(obj.field),
        success: res => {
          // POST 
          layer.msg('操作成功', {icon: 1, time: 1000}, function() {
            // TABLE RELOAD
            layui.table.reload('plan-table')
          });
        },
        error: res => {
          layer.alert(res.responseJSON.message || '发生错误', {
            icon: 2,
            shadeClose: true
          });
        },
        complete: () => layui.layer.close(load)
      })
    });
    
    async function openNewForm(id) {
      const load = layui.layer.load(4);
      const json = await (await fetch((() => {
        const url = '/admin/manage/reviews/plans/get';
        if (id) return url + '?id=' + id;
        return url
      })())).json();
      if (json.ok) { 
        layui.layer.close(load);
        openPlanForm(json.data)
      }
      else {
        layui.layer.close(load);
        layer.alert(json.message || '发生错误', {
          icon: 2,
          shadeClose: true
        });
      }
    }
    
    function openPlanForm(plan) {
      layer.open({
        type: 1,
        title: `${plan.id ? '编辑':'新建'}任务`,
        yes: (index, layero) => {
          layero.find('[lay-filter="submitPlan"]').click()
        },
        skin: 'top-0 layui-anim layui-anim-rl layui-layer-adminRight',
        area: '50%', anim: -1, shadeClose: !0, clostBtn: !1, move: !1,
        offset: 'r', content: $('#addPlan').html(),
        btn: ['提交', '关闭'],
        success: async (layero, layerIndex) => {
          const el = $(layero);
          console.log(plan);
          ['id', 'name', 'cronExpr'].forEach(x => {
            const fieldEl = el[0].querySelector(`[name="${x}"]`);
            if (!fieldEl) return;
            fieldEl.value = plan[x];
          });
          // 开关控件值绑定
          ['enabled', 'openDayCheck'].forEach(x => {
            const fieldEl = el[0].querySelector(`[name="${x}"]`);
            if (!fieldEl) return;
            fieldEl.checked = !!plan[x];
            fieldEl.value = !!plan[x];
            layui.form.on('switch(' + x + ')', obj => {
              obj.elem.value = obj.elem.checked;
              console.log('name', x, 'checked', obj.elem.checked, 'value', obj.elem.value)
            })
          });
          
          // 渲染方法表格
          const table = $('#table-methods');
          table.addClass('layui-table');
          table.html('');
          table.append(`
              <thead>
              <tr>
              <th>选择</th>
              <th>方法名</th>
              <th>参数</th>
              <th>值</th>
              </tr>
              </thead>`);
          // 每一层都是一样的 field, name...只是 rowspan 根据 params 个数而变
          // 每个方法 rowspan = params.length
          
          // 去重合并：
          // 去除传回 plan 中不合法的 method, 并打上 checked: true
          // 保留 potentialMethods 中未在 plan 中启用的 method, 并打上 checked: false
          // 合并两个 array
          const potentialIds = new Set(methods.map(x => x.id));
          const currentMethodsValid = plan.methods.filter(x => potentialIds.has(x.id)).map(x => ({ ...x, checked: true }));
          
          const currentMethodsIds = new Set(currentMethodsValid.map(x => x.id));
          const potentialUncheckedMethods = methods.filter(x => !currentMethodsIds.has(x.id)).map(x => ({ ...x, checked: false }));
          
          const result = [...currentMethodsValid, ...potentialUncheckedMethods];
          
          result.forEach(m => {
            const tbody = $(`<tbody data-id="${m.id}"></tbody>`);
            let paramLength =  m.params && Array.isArray(m.params) && m.params.length || 0;
            if (paramLength) {
              m.params.forEach((p, pIdx) => {
                const tr = [];
                if (pIdx === 0) {
                  tr.push(`<td rowspan="${paramLength}">
                      <input ${m.checked ? 'checked':''} type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-type="layTableCheckbox" title="">
                  </td>`);
                  tr.push(`<td handler rowspan="${paramLength}">${m.name}</td>`);
                }
                tr.push(`<td>${p.name}</td>`);
                // 渲染参数选择
                const select = $(`<select name="${p.name}" class="layui-border" lay-ignore></select>`);
                if (Array.isArray(p.allowedEnumValues) && p.allowedEnumValues.length) {
                  const value = p.value || p.allowedEnumValues[0] || null;
                  p.allowedEnumValues.forEach(e => {
                    let option = `<option value="${e}" ${e == value ? 'selected' : ''}>${e}</option>`;
                    select.append(option)
                  })
                }
                tr.push(`<td>${select[0].outerHTML}</td>`);
                tbody.append(`<tr>${tr.join('')}</tr>`);
              })
            }
            else {
              const tr = [];  
              tr.push(`<td>
                  <input ${m.checked ? 'checked':''} type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-type="layTableCheckbox" title="">
              </td>`);
              tr.push(`<td colspan="3" handler>${m.name}</td>`);
              tbody.append(`<tr>${tr.join('')}</tr>`);
            }
            table.append(tbody);
          })
          $.each(table.find('td'), (_, td) => {
            $(td).addClass("layui-table-col-special");
          });
          if (sortableInstance) sortableInstance.destroy();

          let currentGroup = null;
          let groupRows = [];
          
          sortableInstance = new Sortable(
            document.querySelector('#table-methods'), {
            animation: 150,
            handle: 'td[handler]'
          });
          layui.cron.render({
            elem: '[name="cronExpr"]',
            btns: ['confirm']
          });
          layui.form.render();
        }
      })
    }
    
    // 工具栏事件
    table.on('toolbar(plan-table)', async function(obj){
      var id = obj.config.id;
      var checkStatus = table.checkStatus(id);
      var othis = lay(this);
      switch(obj.event){
        case 'new':
          openNewForm();
        break;
      };
    });
   
    //触发单元格工具事件
    table.on('tool(plan-table)', function(obj){ // 双击 toolDouble
      var data = obj.data;
      //console.log(obj)
      if(obj.event === 'edit'){
        openNewForm(obj.data.id)
      }
      else if(obj.event === 'del'){
        layer.confirm('真的删除行么', function(index){
          obj.del();
          layer.close(index);
        });
      }
      else if(obj.event === 'trigger'){
        var load = layui.layer.load(4);
        $.ajax({
          method: 'POST',
          url: '/admin/manage/reviews/plans/manualTrigger',
          data: {id: obj.data.id},
          success: res => {
            layer.msg('操作成功', {time: 1000});
          },
          error: res => {
            layer.msg(res.responseJSON.message || '操作失败', {time: 2000});
          },
          complete: () => {if (load) layui.layer.close(load)}
        })
      }
    });
    
    function updateSwitch(elem, load) {
      var id = elem.value;
      var name = elem.name;
      $.ajax({
        method: 'POST',
        url: '/admin/manage/reviews/plans/updateBool',
        data: {
          id: id,
          name: name,
          value: elem.checked
        },
        success: res => {
          layer.msg('操作成功', {time: 1000});
        },
        error: res => {
          // 恢复开关状态
          elem.checked = !elem.checked;
          layui.form.render();
          layer.msg(res.responseJSON.message || '操作失败', {time: 2000});
        },
        complete: () => {if (load) layui.layer.close(load)}
      })
    }
    
    form.on('switch(table-switch)', function (obj) {
      updateSwitch(obj.elem, layui.layer.load(4));
      
    })
   
    //触发表格复选框选择
    table.on('checkbox(plan-table)', function(obj){
      console.log(obj)
    });
   
    //触发表格单选框选择
    table.on('radio(plan-table)', function(obj){
      console.log(obj)
    });
    
    // 行单击事件
    table.on('row(plan-table)', function(obj){
      //console.log(obj);
      //layer.closeAll('tips');
    });
    // 行双击事件
    table.on('rowDouble(plan-table)', function(obj){
      console.log(obj);
    });
   
    // 单元格编辑事件
    table.on('edit(plan-table)', function(obj){
      var field = obj.field //得到字段
      ,value = obj.value //得到修改后的值
      ,data = obj.data; //得到所在行所有键值
   
      var update = {};
      update[field] = value;
      obj.update(update);
    });
  });
  </script>
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
</body>
</html>