JSFiddle - React, Tailwind, and code Playground
HTML
<link rel="stylesheet" href="//cdn.datatables.net/1.10.0/css/jquery.dataTables.css">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//cdn.datatables.net/1.10.0/js/jquery.dataTables.js"></script>
<table id="mediciones" width="100%">
<thead>
<tr>
<th>Via</th>
<th>Grupo</th>
<th>Coste</th>
<th>Operación</th>
<th>Fecha</th>
<th>Cant.</th>
<th>Ud.</th>
<th>Precio ud. (€)</th>
<th>Coste med. (€)</th>
</tr>
</thead>
<tbody id="tabla3">
<tr height= "50px">
<td>CO-6218 De Lucena a la Ermita de Nuestra Señora de Araceli</td>
<td>Grupo I Vialidad</td>
<td>1758.69</td>
<td>12512 Despeje de vegetación y retirada de productos</td>
<td>13/08/2017</td>
<td>55</td>
<td>m2</td>
<td>0.11</td>
<td>6.05</td>
</tr>
<tr height= "50px">
<td>CO-6218 De Lucena a la Ermita de Nuestra Señora de Araceli</td>
<td>Grupo I Vialidad</td>
<td>2218.90</td>
<td>12512 Despeje de vegetación y retirada de productos</td>
<td>10/08/2017</td>
<td>10000</td>
<td>m2</td>
<td>0.11</td>
<td>1100</td>
</tr>
<tr height= "50px">
<td>CO-6218 De Lucena a la Ermita de Nuestra Señora de Araceli</td>
<td>Grupo II Conservación ordinaria</td>
<td>27.88</td>
<td>12411 Limpieza-reparación de cunetas de la plataforma</td>
<td>08/08/2017</td>
<td>34</td>
<td>m</td>
<td>0.82</td>
<td>27.88</td>
</tr>
<tr height= "50px">
<td>CO-6218 De Lucena a la Ermita de Nuestra Señora de Araceli</td>
<td>Grupo II Conservación ordinaria</td>
<td>1758.69</td>
<td>12414 Limpieza-reparación de...
CSS
/* Estilo para los subgrupos de ta tabla de mediciones totales */
tr.subgroup,
tr.subgroup:hover {
background-color: #F2F2F2 !important;
/* color: blue; */
font-weight: bold;
}
.group{
background-color:#333!important;
font-size:15px;
color:#fff!important;
opacity:0.7;
}
JavaScript
$(document).ready(function() {
var table = $('#mediciones').DataTable({
"language": {
//"decimal": ",",
//"thousands": ".",
"lengthMenu": "Mostrar _MENU_ registros",
"zeroRecords": "Ningún registro encontrado",
"info": "Mostrando del _START_ al _END_ de _TOTAL_ registros",
"infoFiltered": "(filtrado de un total de _MAX_ registros)",
"search": "Buscar:",
"paginate": {
"next": "Siguiente",
"previous": "Anterior"
}
},
"columnDefs": [
{ "targets": [0, 1, 2], "visible": false },
],
"order": [[ 0, 'asc' ], [ 1, 'asc' ], [ 3, 'asc' ], [ 4, 'asc' ]],
"displayLength": 10,
"drawCallback": function ( settings ) {
var api = this.api();
var rows = api.rows( {page:'all'} ).nodes();
var last = null;
var sublast = null;
var grupo;
var total = null;
var subtotal = null;
var a_origen = null;
var intVal = function ( i ) {
return typeof i === 'string' ? i.replace(/[\$,]/g, '_')*1 :
typeof i === 'number' ? i : 0;
};
api.column(0, {} ).data().each( function ( ctra, i ) {
ctra_assoc = ctra.substring(0, 6);
if (last !== ctra) {
$(rows).eq( i ).before(
'<tr class="group" height= "50px"><td colspan="5">'+ctra.toUpperCase()+'</td><td colspan="2" class="'+ctra_assoc+'"></td></tr>'
);
total = intVal(api.column(8).data()[i]);
last = ctra;
} else {
total += intVal(api.column(8).data()[i]);
}
$("."+ctra_assoc).html(total.toFixed(2));
a_origen += intVal(api.column(8).data()[i]);
grupo = api.column(1).data()[i];
grupo_assoc = grupo.replace(/\s/g, "_");
if (sublast !== grupo) {
$(rows).eq( i ).before(
'<tr class="subgroup" height= "50px"><td colspan="5">'+grupo+'</td><td colspan="2" class="'+ctra_assoc+'_'+grupo_assoc+'"></td></tr>'
...