Javascript 如何对数据表中的子行进行分组

Javascript 如何对数据表中的子行进行分组,javascript,jquery,ajax,datatables,Javascript,Jquery,Ajax,Datatables,我有一个表,它使用子行,其中每一行都是可展开/可折叠的,但父行将有重复的数据 我想对我的子行或子行进行分组,因为它们在正式文档中被调用,我有下表,其中父行中有采购订单、采购订单日期、货币和状态列 如果您看一下,我有3个采购订单,它们对应于本例中相同的标识符is258,但每个采购订单包含一个具有不同信息的第二行,该信息是接收日期、发票号、项目代码和说明 +-----------------------------------------------------------------------+

我有一个表,它使用子行,其中每一行都是可展开/可折叠的,但父行将有重复的数据

我想对我的子行或子行进行分组,因为它们在正式文档中被调用,我有下表,其中父行中有采购订单、采购订单日期、货币和状态列

如果您看一下,我有3个采购订单,它们对应于本例中相同的标识符is258,但每个采购订单包含一个具有不同信息的第二行,该信息是接收日期、发票号、项目代码和说明

+-----------------------------------------------------------------------+
|    | Purchase Order   |    Purchase Order Date   |Currency|   Status  |
+----+------------------+--------------------------+--------+-----------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |                                
+------+---------+------------+--------------------+-------------+------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+------+---------+-----------+---------------------+-------------+------+
|       07/01/2020      |     617     |      CA0033     |       CT      |
+-----------------------------------------------------------------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       14/01/2020      |     620     |      CA0036     |      CTR      |
+-----------------------+-------------+-----------------+---------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|      Receipt Date     | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       16/01/2020      |     626     |      CC0048     |      CTY      |
+-----------------------+-------------+-----------------+---------------+
在不重复采购订单的情况下,我想要实现的是将第二行分组如下

+-----------------------------------------------------------------------+
|    | Purchase Order   |    Purchase Order Date   |Currency|   Status  |
+----+------------------+--------------------------+--------+-----------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |                                
+------+---------+------------+-------------------+-------------+-------+
|      Receipt Date     | No. Invoice |    Code Item    |  Description  |
+------+---------+-----------+--------------------+-------------+-------+
|       07/01/2020      |     617     |      CA0033     |       CT      |
+-----------------------+-------------+-----------------+---------------+
|       14/01/2020      |     620     |      CA0036     |      CTR      |
+-----------------------+-------------+-----------------+---------------+
|       16/01/2020      |     626     |      CC0048     |      CTY      |
+-----------------------+-------------+-----------------+---------------+
如果您现在查看采购订单,它包含分组在一起的相同3个订单的信息,这就是我想要了解的内容

下面是我用来构建表的AJAX调用代码

/* Formatting function for row details - modify as you need */
function format(d) {
    // `d` is the original data object for the row
    console.log(d);
    
    return '<table cellpadding="5" cellspacing="0" style="border-collapse: separate; border-spacing: 40px 5px;">' +
        '<tr>' +      
        '<td><strong>Receipt Date: </strong></td>' + '<td><strong>No. Invoice:<strong></td>' +  '<td><strong>Code Item:<strong></td>' +  '<td><strong>Description:</strong></td>' +
        '</tr>' +
        '<tr>' +
        '<td>' + d.ReceiptDate + '</td>' + '<td>' + d.Invoice+ '</td>' + '<td>' + d.CodeItem+ '</td>' +  '<td>' + d.Description + '</td>' +
        '</tr>' +    
        '</table>';     
}


$(document).ready(function () {
    $('#example').dataTable( {
        responsive : true,
         ajax : {
             "type": 'POST',
             "url" : './test.php',  
             "dataType": 'JSON',             
             "cache": false,
             "data": {
                 'param' : 1,                           
             },
         },
         language : {
            "lengthMenu": "Mostrar _MENU_ registros",
            "zeroRecords": "No se encontró nada",
            "info": "Mostrando del _START_ al _END_ de un total de _TOTAL_",
            "infoEmpty": "No hay registros",
            "emptyTable": "No hay datos para mostrar",
            "loadingRecords": "Cargando...",
            "processing": "Procesando...",
            "search": "Buscar:",
            "infoFiltered": "(filtrado de un total de _MAX_ registros)",
            "paginate": {
                "first": "Primera",
                "last": "Última",
                "next": "Siguiente",
                "previous": "Anterior"
            }
         },    
         columns: [          
             {
                 "className":      'details-control',
                 "orderable":      false,
                 "data":           null,
                 "defaultContent": ''
             },
             { "data" : "PurchaseOrder" },
             { "data" : "PurcharOrderDate" },
             { "data" : "Currency" },
             { "data" : "Status" }                 
        ],
         order : [[1, 'desc']]
    } );

    
    // Add event listener for opening and closing details
    $('#example').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = $('#example').DataTable().row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        }
    });

});
重要的是要记住,作为父行,我需要采购订单、采购订单日期、货币和状态,作为子行,我需要找到收货日期、发票号、代码项和说明

+-----------------------------------------------------------------------+
|    | Purchase Order   |    Purchase Order Date   |Currency|   Status  |
+----+------------------+--------------------------+--------+-----------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |                                
+------+---------+------------+--------------------+-------------+------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+------+---------+-----------+---------------------+-------------+------+
|       07/01/2020      |     617     |      CA0033     |       CT      |
+-----------------------------------------------------------------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       14/01/2020      |     620     |      CA0036     |      CTR      |
+-----------------------+-------------+-----------------+---------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|      Receipt Date     | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       16/01/2020      |     626     |      CC0048     |      CTY      |
+-----------------------+-------------+-----------------+---------------+
更新2:

我添加了php代码,为我的问题提供了更多的指导

Test.php

<?php
    header('Content-Type: text/html; charset=utf-8');
    
    $param = $_POST['param'];   
    switch($param) {
        case '1': 
                $query = array();
                include './db/conecct.php';
                $sql = "select PURCHID as 'PurchaseOrder',
                CREATEDDATETIME as 'PurchaseOrderDate',
                MONEDA as 'Currency',
                INVOICEDATE as 'ReceiptDate',
                ITEMID  as 'CodeItem',
                FACTURA as 'No. Invoice',
                NAMEALIAS as 'Description',
                PURCHSTATUS as 'Status'         
                FROM PP_FACTURAS
                $stmt = sqlsrv_query($conn, $sql, $params);
                if ( $stmt === false) {
                    die( print_r( sqlsrv_errors(), true) );
                }   
                while( $row = sqlsrv_fetch_array($stmt) ) {
                    //print_r($row);
                    $record = array(
                       "PurchaseOrder"       => $row['PurchaseOrder'],
                       "PurchaseOrderDate"  => $row['PurchaseOrderDate']->format('d/m/Y'),
                       "Currency"        => $row['Currency'],
                       "Status"            => $row['Status'],
                       "PurchaseOrderDate"      => $row['PurchaseOrderDate'] != null ? $row['PurchaseOrderDate']->format('d/m/Y'):"",
                       "No. Invoice"           => utf8_encode ($row['No. Invoice']),
                       "CodeItem"          => utf8_encode ($row['CodeItem']), 
                       "Description"        => utf8_encode ($row['Description']),           
                    );
                    array_push($query, $record);
                }

                sqlsrv_free_stmt( $stmt);       
                sqlsrv_close($conn);

                $json = array(
                    "success"=> count($query) > 0 ? true : false,
                    "data"=>$query
                );

                echo json_encode($json);
            break;
我根据答案附上我支持自己的代码:

/* Formatting function for row details - modify as you need */
function format(d) {
    // `d` is the original data object for the row
    console.log(d);

    var tableHtml = '<table><thead><tr><th>Receipt Date</th><th>Invoice No.</th><th>Item Code</th><th>Description</th></tr></thead>';

       tableHtml = tableHtml + '<tbody>';

        var rowHtml = '';
        for (const rowData of d.details){
            rowHtml = rowHtml + '<tr><td>' + rowData.ReceiptDate + '</td><td>' + rowData.Invoice + '</td><td>' + rowData.CodeItem + '</td><td>' + rowData.Description + '</td></tr>';
        }
        tableHtml = tableHtml + rowHtml + '</tbody></table>';
        return tableHtml;
}


function denormalize(originalJson) {
    let denormalizedMap = new Map();

    for (const element of originalJson) {
        let headerInfo = (({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }) => ({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }))(element);
        headerInfo.details = [];

        let detailLine = (({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description

        }) => ({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description
        }))(element);

        if (! denormalizedMap.has(element.PurchaseOrder)) {
            denormalizedMap.set(element.PurchaseOrder, headerInfo);
        }
        denormalizedMap.get(element.PurchaseOrder).details.push(detailLine);
    }

    let denormalizeSource = Array.from(denormalizedMap.values());

    return denormalizeSource;
}

$(document).ready(function () {
    $('#example').dataTable( {
        responsive : true,
         ajax : {
             "type": 'POST',
             "url" : './test.php',  
             "dataType": 'JSON',             
             "cache": false,
             "dataSrc" : function (json){
                 console.log(json);
                 return denormalize(json);
             },
         },    
         columns: [          
             {
                 "className":      'details-control',
                 "orderable":      false,
                 "data":           null,
                 "defaultContent": ''
             },
             { "data" : "PurchaseOrder" },
             { "data" : "PurcharOrderDate" },
             { "data" : "Currency" },
             { "data" : "Status" }                
     
        ],
         order : [[1, 'desc']],
    } );

    
    // Add event listener for opening and closing details
    $('#example').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = $('#example').DataTable().row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        }
    });

});
/*行详细信息的格式化功能-根据需要进行修改*/
函数格式(d){
//`d`是该行的原始数据对象
控制台日志(d);
var tableHtml='收货日期发票编号项目代码说明';
tableHtml=tableHtml+“”;
var rowHtml='';
用于(d.详细信息的常量行数据){
rowHtml=rowHtml+''+rowData.ReceiptDate+''+rowData.Invoice+''+rowData.CodeItem+''+rowData.Description+'';
}
tableHtml=tableHtml+rowHtml+“”;
返回表格html;
}
函数反规范化(原始JSON){
让denormalizedMap=new Map();
for(原始JSON的常量元素){
让headerInfo=(({
采购订单,
PurcharOrderDate,
货币,
地位
}) => ({
采购订单,
PurcharOrderDate,
货币,
地位
}))(要素);
headerInfo.details=[];
设detailLine=(({
收到日期,
发票,
代码项,
描述
}) => ({
收到日期,
发票,
代码项,
描述
}))(要素);
如果(!denormalizedMap.has(element.PurchaseOrder)){
反规范化映射集(element.PurchaseOrder,headerInfo);
}
非规范化的map.get(element.PurchaseOrder).details.push(detailLine);
}
让denormalizeSource=Array.from(denormalizedMap.values());
返回非规范化源;
}
$(文档).ready(函数(){
$('#示例')。数据表({
回答:是的,
阿贾克斯:{
“类型”:“职位”,
“url”:“../test.php”,
“数据类型”:“JSON”,
“缓存”:false,
“dataSrc”:函数(json){
log(json);
返回非规范化(json);
},
},    
列:[
{
“className”:“详细信息控制”,
“可订购”:错误,
“数据”:空,
“defaultContent”:”
},
{“数据”:“采购订单”},
{“数据”:“PurcharOrderDate”},
{“数据”:“货币”},
{“数据”:“状态”}
],
订单:[[1,'说明']],
} );
//为打开和关闭详细信息添加事件侦听器
$('#示例')。在('click','td.details control',函数(){
var tr=$(this.nexist('tr');
var row=$('#示例').DataTable().row(tr);
if(row.child.isShown()){
//此行已打开-关闭它
row.child.hide();
tr.removeClass(“显示”);
}
否则{
//打开这一排
row.child(格式(row.data()).show();
tr.addClass(“显示”);
}
});
});

基于最初的问题,我假设ajax调用提供的JSON如下所示:

[
{“采购订单”:258,
“PurcharOrderDate”:“2020年1月6日”,
“货币”:“美元”,
“状态”:“已交付”,
“接收日期”:“2020年1月7日”,
“发票”:617,
“代码项”:“CA0033”,
“说明”:“CT”
},
{“采购订单”:258,
“PurcharOrderDate”:“2020年1月6日”,
“货币”:“美元”,
“状态”:“已交付”,
“接收日期”:“2020年1月4日”,
“发票”:620,
“代码项”:“CA0036”,
“说明”:“CTR”
},
{“采购订单”:258,
“PurcharOrderDate”:“2020年1月6日”,
“货币”:“美元”,
“状态”:“已交付”,
“接收日期”:“2020年1月16日”,
“发票”:626,
“代码项”:“CA0048”,
“说明”:“CTY”
},
{“采购订单”:261,
“PurcharOrderDate”:“2020年2月22日”,
“货币”:“美元”,
“状态”:“已交付”,
“接收日期”:“2020年3月3日”,
“发票”:679,
“代码项”:“CA0062”,
“说明”:“CTZ”
}
];
我为订单号261增加了一行,只是为了使数据更加多样化

您希望将其重新构造为一个新数组,其中每个唯一的PO编号只有一个对象(但该对象还包含相关发票记录的多个项目)

以下数据表明:

[
{
“采购订单”:258,
“PurcharOrderDate”:“2020年1月6日”,
“货币”:“美元”,
“状态”:“已交付”,
“详情”:[{
“接收日期”:“2020年1月7日”,
“发票”:617,
“代码项”:“CA0033”,
“描述
/* Formatting function for row details - modify as you need */
function format(d) {
    // `d` is the original data object for the row
    console.log(d);

    var tableHtml = '<table><thead><tr><th>Receipt Date</th><th>Invoice No.</th><th>Item Code</th><th>Description</th></tr></thead>';

       tableHtml = tableHtml + '<tbody>';

        var rowHtml = '';
        for (const rowData of d.details){
            rowHtml = rowHtml + '<tr><td>' + rowData.ReceiptDate + '</td><td>' + rowData.Invoice + '</td><td>' + rowData.CodeItem + '</td><td>' + rowData.Description + '</td></tr>';
        }
        tableHtml = tableHtml + rowHtml + '</tbody></table>';
        return tableHtml;
}


function denormalize(originalJson) {
    let denormalizedMap = new Map();

    for (const element of originalJson) {
        let headerInfo = (({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }) => ({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }))(element);
        headerInfo.details = [];

        let detailLine = (({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description

        }) => ({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description
        }))(element);

        if (! denormalizedMap.has(element.PurchaseOrder)) {
            denormalizedMap.set(element.PurchaseOrder, headerInfo);
        }
        denormalizedMap.get(element.PurchaseOrder).details.push(detailLine);
    }

    let denormalizeSource = Array.from(denormalizedMap.values());

    return denormalizeSource;
}

$(document).ready(function () {
    $('#example').dataTable( {
        responsive : true,
         ajax : {
             "type": 'POST',
             "url" : './test.php',  
             "dataType": 'JSON',             
             "cache": false,
             "dataSrc" : function (json){
                 console.log(json);
                 return denormalize(json);
             },
         },    
         columns: [          
             {
                 "className":      'details-control',
                 "orderable":      false,
                 "data":           null,
                 "defaultContent": ''
             },
             { "data" : "PurchaseOrder" },
             { "data" : "PurcharOrderDate" },
             { "data" : "Currency" },
             { "data" : "Status" }                
     
        ],
         order : [[1, 'desc']],
    } );

    
    // Add event listener for opening and closing details
    $('#example').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = $('#example').DataTable().row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        }
    });

});
ajax: {
  method: "GET",
  url: // your URL goes here!,
  dataSrc: function ( json ) { 
    //console.log( json );
    return restructure(json);
  },
},