JSFiddle - React, Tailwind, and code Playground

by Denis Tverdokhlebov

HTML

<button onclick="SwapAll(false);">Свернуть все</button></a>
<button onclick="SwapAll(true);">Развернуть все</button></a>
<br><br>
<table class="treetable">
  <thead>
    <tr>
      <th>ФИО</th>
      <th>Проект</th>
      <th>Задача</th>
      <th>План</th>
      <th>Факт</th>
    </tr>
  </thead>
  <tr class="lev1">
    <td><label><input type="checkbox"><a onclick="sh(this)">Иванов</a></label></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev2">
    <td></td>
    <td><label><input type="checkbox"><a onclick="sh(this)">Проект 1</a></label></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev3">
    <td></td>
    <td></td>
    <td><label><input type="checkbox"><a onclick="sh(this)">Задача 1_1</a></label></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>10</td>
    <td>20</td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>20</td>
    <td>40</td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>30</td>
    <td>60</td>
  </tr>
  <tr class="lev3">
    <td></td>
    <td></td>
    <td><label><input type="checkbox"><a onclick="sh(this)">Задача 1_2</a></label></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>90</td>
    <td>99</td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>80</td>
    <td>88</td>
  </tr>
  <tr class="lev2">
    <td></td>
    <td><label><input type="checkbox"><a onclick="sh(this)">Проект 2</a></label></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev3">
    <td></td>
    <td></td>
    <td><label><input type="checkbox"><a onclick="sh(this)">Задача 2_1</a></label></td>
    <td></td>
    <td></td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
    <td>12</td>
    <td>12</td>
  </tr>
  <tr class="lev4">
    <td></td>
    <td></td>
    <td></td>
...

CSS

.treetable {
  border-collapse: collapse;
}

.treetable th {
  background: #4682B4;
  color: #FFFFFF;
}

.treetable td,
th {
  padding: 3px;
  border: 1px solid #D3D3D3;
  width: 200px;
}

.treetable label a {
  cursor: pointer;
  color: #FFFFFF;
  font-weight: bold;
  padding-left: 16px;
}

.treetable tr {
  display: none;
}

.treetable thead tr {
  display: table-row;
}

.treetable .lev1 {
  background: #6E9ECA;
  display: table-row;
}

.lev2 {
  background: #708090;
}

.lev3 {
  background: #8FA0B0;
}

input[type="checkbox"] {
  display: none;
}

input+a {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAIAAAAmzuBxAAAACXBIWXMAAAsSAAALEgHS3X78AAAAkElEQVQYlXWOvRWDQAyDv/DYK2wQSro8OkpGuRFcUjJCRmEE0TldCpsjPy9qzj7Jki62Pgh4vnqbbbEWuN+use/PlArwHccWGg780psENGFY6W4YgxZIAM339WmT3m397YYxxn6aASslFfVotYLTT3NwcuTKlFpNR2sdEak4acdKeafPlE2SZ7sw/1BEtX94AXYTVmyR94mPAAAAAElFTkSuQmCC) no-repeat 0px 5px;
}

input:checked+a {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAIAAAAmzuBxAAAACXBIWXMAAAsSAAALEgHS3X78AAAAeklEQVQYlX2PsRGDMAxFX3zeK9mAlHRcupSM4hFUUjJCRpI70VHIJr7D8BtJ977+SQ9Zf7isVG16WSQC0/D0OW/FqoBlDFkIVJ2xAhA8sI/NHbcYiFrPfI0fGklKagDx2F4ltdtaM0J9L3dxcVxi+zv62E+MwPs7c60dClRP6iug7wUAAAAASUVORK5CYII=) no-repeat 0px 5px;
}

td+td+td+td {
  text-align: right;
}

JavaScript

function ResetAll() {
  var cs = document.getElementsByTagName('input');
  for (i = 0; i < cs.length; i++) {
    if (cs[i].type == 'checkbox') {
      cs[i].checked = false;
    }
  }
}

function ShowLevel(row, lv) {
  var tBody = row.parentNode;
  var i = row.rowIndex;
  row = tBody.rows[i]; // Попытка перейти к следующей строке
  while (row && row.className.substring(3) * 1 > lv) {
    if (row.className.substring(3) * 1 == lv + 1) {
      row.style.display = 'table-row';
      if ((row.querySelector('td input')) && row.querySelector('td input').checked) {
        ShowLevel(row, lv + 1);
      }
    }
    i += 1;
    row = tBody.rows[i];
  }
}

function HideLevel(row, lv) {
  var i = row.rowIndex;
  var tBody = row.parentNode;
  row = tBody.rows[i]; // Попытка перейти к следующей строке
  while (row && row.className.substring(3) * 1 > lv) {
    row.style.display = 'none';
    i += 1;
    row = tBody.rows[i];
  }
}

function sh(el) {
  var row = el.parentNode.parentNode.parentNode;
  var lv = row.className.substring(3) * 1; // Уровень строки, циферка после 'lev'
  if (row.querySelector('td input').checked) {
    HideLevel(row, lv);
  } else {
    ShowLevel(row, lv);
  }
}

function SwapAll(b) {
  var tbl = document.getElementsByClassName('treetable')[0];
  for (i = 1; i < tbl.rows.length; i++) {
    if (tbl.rows[i].className != 'lev1') {
      if (b) {
        tbl.rows[i].style.display = 'table-row';
      } else {
        tbl.rows[i].style.display = 'none';
      }
    }

    if (tbl.rows[i].querySelector('td input')) {
      tbl.rows[i].querySelector('td input').checked = b;
    }
  }
}