html table 分组合并 与导出分组后的数据

HTML:

html 复制代码
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <script src="~/Scripts/jquery-1.6.4.min.js"></script>
    <script src="~/Scripts/jquery.table2excel.js?a=@DateTime.Now.ToString("yyyyMMddHHmmssff")"></script>
</head>
<body hidden>
    <table id="table" border="1" width="100%">
        <thead>
            <tr>
                <th colspan="14">客户基础信息</th>
                <th colspan="10">跟踪维护信息</th>
            </tr>
            <tr>
                <th>客户名称</th>
                <th>联系人</th>
                <th>联系电话</th>
                <th>客户喜好</th>
                <th>纪念日/生日</th>

                <th>项目标题</th>
                <th>项目信息</th>
                <th>项目状态</th>
                <th>项目等级</th>

                <th>核心诉求</th>
                <th>诉求应答</th>
                <th>预成交金额(万元)</th>
                <th>需要的支持</th>
                <th>备注</th>

                <th>首次维护时间</th>
                <th>最近维护时间</th>
                <th>未跟进时间(天)</th>
                <th>维护日期</th>
                <th>维护方式</th>
                <th>维护类型</th>
                <th>内容/跟进重点</th>
                <th>下次跟进时间</th>
                <th>销售人员</th>
                <th>本记录时间</th>
            </tr>
        </thead>
        <tbody id="tbody">
            @if (ViewBag.TrackExport != null)
            {
                for (int i = 0; i < ViewBag.TrackExport.Count; i++)
                {
                    <tr>
                        <td>@ViewBag.TrackExport[i].CUSTOMER_NAME </td>
                        <td>@ViewBag.TrackExport[i].CONTACT_LINK </td>
                        <td>@ViewBag.TrackExport[i].CONTACT_PHONE </td>
                        <td>@ViewBag.TrackExport[i].HOBBIES </td>
                        <td>@ViewBag.TrackExport[i].BIRTHDAY </td>
                        @* 利用<b>标签包含不同内容进行二次分组,分组后移除<b>标签 *@
                        <td>@ViewBag.TrackExport[i].PROJECT_TITLE <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].PROJECT_INFO <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].PROJECT_STATUS_NAME <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].PROJECT_LEVEL_NAME <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].NEEDS <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].RESPONSE <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].EST_AMOUNT <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].NEED_SUPPORT <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>
                        <td>@ViewBag.TrackExport[i].REMARKS <b>@ViewBag.TrackExport[i].SALES_OPPORTUNITY_PROJECT_SID</b></td>

                        <td>@ViewBag.TrackExport[i].FIRST_MANAGE_DATE </td>
                        <td>@ViewBag.TrackExport[i].LAST_MANAGE_DATE </td>
                        <td>@ViewBag.TrackExport[i].SINCE_DAYS </td>

                        <td>@ViewBag.TrackExport[i].MANAGE_DATE.ToString("yyyy-MM-dd") </td>
                        <td>@ViewBag.TrackExport[i].MANAGE_TYPE_NAME </td>
                        <td>@ViewBag.TrackExport[i].MANAGE_CONTENT_NAME </td>
                        <td>@ViewBag.TrackExport[i].FOLLOW_FOCUS </td>
                        <td>@ViewBag.TrackExport[i].NEXT_DATETIME </td>
                        <td>@ViewBag.TrackExport[i].SALES_MAN </td>
                        <td>@ViewBag.TrackExport[i].CREATED_TIME.ToString("yyyy-MM-dd HH:mm:ss") </td>
                    </tr>
                }
            }
        </tbody>
    </table>

    <script>
        //合并相同行
        function mergeFunc(tableId, maxCol, groupColumn) {
            var tab = document.getElementById(tableId);
            if (!tab) return;
            groupColumn = groupColumn === undefined ? 0 : groupColumn;

            for (var col = maxCol - 1; col >= 0; col--) {
                var count = 1;
                for (var i = 0; i < tab.rows.length; i++) {
                    if (i > 0) {
                        var groupSame = tab.rows[i].cells[groupColumn].innerHTML == tab.rows[i - 1].cells[groupColumn].innerHTML;
                        var colSame = tab.rows[i].cells[col].innerHTML == tab.rows[i - 1].cells[col].innerHTML;
                        if (groupSame && colSame) {
                            count++;
                        } else {
                            if (count > 1) {
                                var start = i - count;
                                tab.rows[start].cells[col].rowSpan = count;
                                for (var j = start + 1; j < i; j++) {
                                    tab.rows[j].removeChild(tab.rows[j].cells[col]);
                                }
                                count = 1;
                            }
                        }
                    }
                }
                if (count > 1) {
                    start = i - count;
                    tab.rows[start].cells[col].rowSpan = count;
                    for (var j = start + 1; j < i; j++) {
                        tab.rows[j].removeChild(tab.rows[j].cells[col]);
                    }
                }
            }
            $('#' + tableId +' td b').remove();//移除<td>内的<b>标签
        }

        //初始化加载
        $(function () {
            //合并相同行
            mergeFunc("tbody", 17, 0);

            //导出excel弹窗
            setTimeout(() => {
                Export();
            }, 1000);
        });

        //导出Excel
        function Export() {
            $('#table').table2excel({
                filename: 'CRM_' + new Date().getTime(), //文件名称
            });

            // 导出后延迟 3000ms 再关闭页面
            setTimeout(() => {
                window.close();
            }, 3000);
        }
    </script>

</body>
</html>

jquery.table2excel.js

javascript 复制代码
/*  调用方法:
 *   $('#test_table').table2excel({//'#test_table' table的id
 *       subtotal: 1,//可选参数(可删除此行),默认值:0
 *       width:200,//导出excel表格的宽度百分比的值(不含%号),可删除此行(默认100%)
 *       filename: 'excel_' + new Date().getTime() + '.xls', //excel文件名称,扩展名:.xlsx 或者.xls
 *   });
 */
(function ($, window, document, undefined) {
    var pluginName = "table2excel",
        defaults = {
            exclude: ".noExl",
            name: "Table2Excel",
            filename: "table2excel",
            fileext: ".xls",
            exclude_img: true,
            exclude_links: true,
            exclude_inputs: true,
            preserveColors: false,
            subtotal: 0,//"合计"行所在的行号(不包括标题行),0表示没有合计行...
            width: 100,//表格宽度百分比,默认100%
        };
    //插件配置
    function Plugin(element, options) {
        this.element = element;
        this.settings = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }
    Plugin.prototype = {
        init: function () {
            var e = this;
            var w = getWidth(e.settings);//导出EXCEL表格的宽度,默认100%
            var utf8Heading = "<meta http-equiv=\"content-type\" content=\"application/vnd.ms-excel; charset=UTF-8\">";
            e.template = {
                head: "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns=\"http://www.w3.org/TR/REC-html40\">" + utf8Heading + "<head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets>",
                sheet: {
                    head: "<x:ExcelWorksheet><x:Name>",
                    tail: "</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>"
                },
                mid: "</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>",
                table: {
                    head: " <table border='1' style='width:" + w + "%;'>",//<table>的边框&宽度
                    tail: " </table>"
                },
                foot: "</body></html>"
            };
            e.tableRows = [];

            //读取原始表
            var rowNumber = 0;//行号
            $(e.element).each(function (i, o) {
                var tempRows = "";//table的html
                $(o).find("tr").not(e.settings.exclude).each(function (i, p) {
                    //<tr>的样式
                    var trStyles = "";//整行样式
                    //开始创建一行表格
                    if (trStyles) {
                        tempRows += "<tr align='center' style='" + trStyles + "'>";//内容居中:align='center'
                    }
                    else {
                        tempRows += "<tr align='center'>";//内容居中:align='center'
                    }
                    //读取原始<table>的<th>表头行(表头必须是<th>!表头如果是<td>的话则会当做普通数据行处理...)
                    $(p).find("th").not(e.settings.exclude).each(function (i, q) {
                        //<th>的样式:
                        var thStyles = "";//background-color: cornflowerblue; color:white;
                        var rc = {
                            rows: $(this).attr("rowspan"),
                            cols: $(this).attr("colspan"),
                            flag: $(q).find(e.settings.exclude)
                        };
                        if (rc.flag.length > 0) {
                            tempRows += "<td> </td>"; //空格!
                        } else {
                            tempRows += "<td";
                            if (rc.rows > 0) {
                                tempRows += " rowspan='" + rc.rows + "' ";//跨行
                            }
                            if (rc.cols > 0) {
                                tempRows += " colspan='" + rc.cols + "' ";//跨列
                            }
                            if (thStyles) {
                                tempRows += " style='" + thStyles + "'";//样式
                            }
                            tempRows += ">" + $(q).html() + "</td>";//内容
                        }
                    });

                    //读取原始<table>的<td>数据行
                    $(p).find("td").not(e.settings.exclude).each(function (i, q) {
                        //<td>的样式
                        var tdStyles = "background-color:yellow;";//合计行的样式
                        var rc = {
                            rows: $(this).attr("rowspan"),
                            cols: $(this).attr("colspan"),
                            flag: $(q).find(e.settings.exclude)
                        };
                        if (rc.flag.length > 0) {
                            tempRows += "<td> </td>"; //空格!                       
                        } else {
                            tempRows += "<td ";
                            if (rc.rows > 0) {
                                tempRows += " rowspan='" + rc.rows + "' ";//跨行
                            }
                            if (rc.cols > 0) {
                                tempRows += " colspan='" + rc.cols + "' ";//跨列
                            }
                            var subtotal = getSubtotal(e.settings);//获取"合计"行所在的行号(不包括标题行)
                            if (rowNumber == subtotal) {//if(当前行行号 == 合计行行号)
                                if (tdStyles) {
                                    tempRows += " style='mso-number-format:\"\@\"; " + tdStyles + "' ";//样式
                                }
                                else {
                                    tempRows += " style='mso-number-format:\"\@\";' ";//纯文本
                                }
                            }
                            else {
                                tempRows += " style='mso-number-format:\"\@\";' ";//纯文本
                            }
                            tempRows += ">" + $(q).html() + "</td>";
                        }
                    });
                    tempRows += "</tr>";//生成一行结束
                    rowNumber++;//行号+1
                });
                // exclude img tags
                if (e.settings.exclude_img) {
                    tempRows = exclude_img(tempRows);
                }
                // exclude link tags
                if (e.settings.exclude_links) {
                    tempRows = exclude_links(tempRows);
                }
                // exclude input tags
                if (e.settings.exclude_inputs) {
                    tempRows = exclude_inputs(tempRows);
                }
                e.tableRows.push(tempRows);
            });
            e.tableToExcel(e.tableRows, e.settings.name, e.settings.sheetName);
        },
        tableToExcel: function (table, name, sheetName) {
            var e = this, fullTemplate = "", i, link, a;
            e.format = function (s, c) {
                return s.replace(/{(\w+)}/g, function (m, p) {
                    return c[p];
                });
            };
            sheetName = typeof sheetName === "undefined" ? "Sheet" : sheetName;
            e.ctx = {
                worksheet: name || "Worksheet",
                table: table,
                sheetName: sheetName
            };
            fullTemplate = e.template.head;
            if ($.isArray(table)) {
                Object.keys(table).forEach(function (i) {
                    //fullTemplate += e.template.sheet.head + "{worksheet" + i + "}" + e.template.sheet.tail;
                    fullTemplate += e.template.sheet.head + sheetName + i + e.template.sheet.tail;
                });
            }
            fullTemplate += e.template.mid;
            if ($.isArray(table)) {
                Object.keys(table).forEach(function (i) {
                    fullTemplate += e.template.table.head + "{table" + i + "}" + e.template.table.tail;
                });
            }
            fullTemplate += e.template.foot;
            for (i in table) {
                e.ctx["table" + i] = table[i];
            }
            delete e.ctx.table;
            var isIE = navigator.appVersion.indexOf("MSIE 10") !== -1 || (navigator.userAgent.indexOf("Trident") !== -1 && navigator.userAgent.indexOf("rv:11") !== -1); // this works with IE10 and IE11 both :)
            //if (typeof msie !== "undefined" && msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))      // this works ONLY with IE 11!!!
            if (isIE) {
                if (typeof Blob !== "undefined") {
                    //use blobs if we can
                    fullTemplate = e.format(fullTemplate, e.ctx); // with this, works with IE
                    fullTemplate = [fullTemplate];
                    //convert to array
                    var blob1 = new Blob(fullTemplate, { type: "text/html" });
                    window.navigator.msSaveBlob(blob1, getFileName(e.settings));
                } else {
                    //otherwise use the iframe and save
                    //requires a blank iframe on page called txtArea1
                    txtArea1.document.open("text/html", "replace");
                    txtArea1.document.write(e.format(fullTemplate, e.ctx));
                    txtArea1.document.close();
                    txtArea1.focus();
                    sa = txtArea1.document.execCommand("SaveAs", true, getFileName(e.settings));
                }

            } else {
                var blob = new Blob([e.format(fullTemplate, e.ctx)], { type: "application/vnd.ms-excel" });
                window.URL = window.URL || window.webkitURL;
                link = window.URL.createObjectURL(blob);
                a = document.createElement("a");
                a.download = getFileName(e.settings);
                a.href = link;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
            }
            return true;
        }
    };
    //获取excel文件名
    function getFileName(settings) {
        return (settings.filename ? settings.filename : "table2excel");
    }
    //获取"合计"行所在的行号(不包括标题行)
    function getSubtotal(settings) {
        return (settings.subtotal ? settings.subtotal : 0);//默认值0
    }
    //导出Excel的表格宽度百分比的值(不含%号),默认100%
    function getWidth(settings) {
        return (settings.width ? settings.width : 100);
    }
    // Removes all img tags
    function exclude_img(string) {
        var _patt = /(\s+alt\s*=\s*"([^"]*)"|\s+alt\s*=\s*'([^']*)')/i;
        return string.replace(/<img[^>]*>/gi, function myFunction(x) {
            var res = _patt.exec(x);
            if (res !== null && res.length >= 2) {
                return res[2];
            } else {
                return "";
            }
        });
    }
    // Removes all link tags
    function exclude_links(string) {
        return string.replace(/<a[^>]*>|<\/a>/gi, "");
    }
    // Removes input params
    function exclude_inputs(string) {
        var _patt = /(\s+value\s*=\s*"([^"]*)"|\s+value\s*=\s*'([^']*)')/i;
        return string.replace(/<input[^>]*>|<\/input>/gi, function myFunction(x) {
            var res = _patt.exec(x);
            if (res !== null && res.length >= 2) {
                return res[2];
            } else {
                return "";
            }
        });
    }
    $.fn[pluginName] = function (options) {
        var e = this;
        e.each(function () {
            if (!$.data(e, "plugin_" + pluginName)) {
                $.data(e, "plugin_" + pluginName, new Plugin(this, options));
            }
        });
        // chain jQuery functions
        return e;
    };
})(jQuery, window, document);

图示:


Layui-table 参考:

javascript 复制代码
        <script type="text/javascript">
            //初始化
            $(function () {
                PageList();
            });
            //重置
            function Reset() {
                window.location.reload();
            }
            //查询
            function PageList() {
                var START_DATE = $("#START_DATE").val();
                var END_DATE = $("#END_DATE").val();
                var CUSTOMER_NAME = $("#TXT_CUSTOMER_NAME").val();
                var CONTACT_LINK = $("#TXT_CONTACT_LINK").val();
                var PROJECT_STATUS = $("#TXT_PROJECT_STATUS").val();
                var PROJECT_LEVEL = $("#TXT_PROJECT_LEVEL").val();

                layui.use(['table'], function () {
                    var table = layui.table;

                    table.render({
                        elem: '#table'//对应着Table的ID
                        //, width: '100%'
                        , method: 'POST'
                        , url: '/SalesOpportunity/SalesOpportunityTrackPage'//URL为数据接口的地址
                        , where: { //where就是ajax的data,但不包括分页条件
                            "START_DATE": START_DATE,
                            "END_DATE": END_DATE,
                            "CUSTOMER_NAME": CUSTOMER_NAME,
                            "CONTACT_LINK": CONTACT_LINK,
                            "PROJECT_STATUS": PROJECT_STATUS,
                            "PROJECT_LEVEL": PROJECT_LEVEL,
                        }
                        , request: {  //分页条件: page  limit
                            pageName: 'page',    //页码的参数名称,默认:page 或者 index、pageIndex
                            limitName: 'size'  //每页数据量的参数名,默认:limit 或者 size、pageSize
                        }
                        , parseData: function (res) {
                            return {
                                "code": 0,//数据类型,必须的
                                "count": res.total,//总记录数,用于分页
                                "data": res.data,//必须的
                            }
                        }
                        , cols: [
                            [
                                /* { title: '操作', toolbar: '#barDemo', width: 80, align: 'center', rowspan: 2 },*/
                                {
                                    field: 'SALES_OPPORTUNITY_SID', title: '操作', width: 80, align: 'center', rowspan: 2
                                    , templet: function (d) {
                                        //return d.SALES_OPPORTUNITY_SID;
                                        return `<button class="layui-btn layui-btn-xs layui-btn-radius layui-form-button-blue" onclick="OpenEdit(` + d.SALES_OPPORTUNITY_SID + `)">详情<span hidden>` + d.SALES_OPPORTUNITY_SID + `</span></button>`;
                                    }
                                },
                                { title: '客户基础信息', colspan: 14, align: 'center' },
                                { title: '跟踪维护信息', colspan: 10, align: 'center' },
                            ],
                            [
                                { field: 'CUSTOMER_NAME', title: '客户名称', width: 200, align: 'center' },
                                { field: 'CONTACT_LINK', title: '联系人', width: 100, align: 'center' },
                                { field: 'CONTACT_PHONE', title: '联系电话', width: 150, align: 'center' },
                                { field: 'HOBBIES', title: '客户喜好', width: 150, align: 'center' },
                                {
                                    field: 'BIRTHDAY', title: '纪念日/生日', width: 200, align: 'center'
                                    , templet: function (d) {
                                        if (d.BIRTHDAY) {
                                            return d.BIRTHDAY.replace(",", ",<br>");
                                        }
                                        else {
                                            return "";
                                        }
                                    }
                                },

                                { field: 'PROJECT_TITLE', title: '项目标题', width: 250, align: 'center' },
                                { field: 'PROJECT_INFO', title: '项目信息', width: 250, align: 'center' },
                                {
                                    field: 'PROJECT_STATUS', title: '项目状态', width: 100, align: 'center'
                                    , templet: function (d) {
                                        if (d.PROJECT_STATUS == 0) return "进行中<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else if (d.PROJECT_STATUS == 1) return "<font color='green'>完成</font><span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else if (d.PROJECT_STATUS == 2) return "<font color='red'>中止</font><span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else return "<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                    }
                                },
                                {
                                    field: 'PROJECT_LEVEL', title: '项目等级', width: 100, align: 'center'
                                    , templet: function (d) {
                                        if (d.PROJECT_LEVEL == 0) return "D<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else if (d.PROJECT_LEVEL == 1) return "C<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else if (d.PROJECT_LEVEL == 2) return "B<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else if (d.PROJECT_LEVEL == 3) return "A<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                        else return "<span hidden>" + d.SALES_OPPORTUNITY_PROJECT_SID + "</span>";
                                    }
                                },

                              
                                { field: 'NEEDS', title: '核心诉求', width: 250, align: 'center' },
                                { field: 'RESPONSE', title: '诉求应答', width: 250, align: 'center' },
                                { field: 'EST_AMOUNT', title: '预成交金额(万元)', width: 150, align: 'center' },
                                { field: 'NEED_SUPPORT', title: '需要的支持', width: 250, align: 'center' },
                                { field: 'REMARKS', title: '备注', width: 250, align: 'center' },
                                {
                                    field: 'FIRST_MANAGE_DATE', title: '首次维护时间', width: 150, align: 'center'
                                    , templet: function (d) {
                                        if (d.FIRST_MANAGE_DATE) {
                                            return dateToDateString(d.FIRST_MANAGE_DATE);
                                        }
                                        else {
                                            return '';
                                        }
                                    }
                                },
                                {
                                    field: 'LAST_MANAGE_DATE', title: '最近维护时间', width: 150, align: 'center'
                                    , templet: function (d) {
                                        if (d.LAST_MANAGE_DATE) {
                                            return dateToDateString(d.LAST_MANAGE_DATE);
                                        }
                                        else {
                                            return '';
                                        }
                                    }
                                },
                                { field: 'SINCE_DAYS', title: '未跟进时间(天)', width: 150, align: 'center' },
                                {
                                    field: 'MANAGE_DATE', title: '维护日期', width: 150, align: 'center'
                                    , templet: function (d) {
                                        if (d.MANAGE_DATE) {
                                            return timestampToDateString(d.MANAGE_DATE);
                                        } else {
                                            return '';
                                        }
                                    }
                                },
                                {
                                    field: 'MANAGE_TYPE', title: '维护方式', width: 100, align: 'center'
                                    , templet: function (d) {
                                        if (d.MANAGE_TYPE == 0) return "电话";
                                        else if (d.MANAGE_TYPE == 1) return "微信";
                                        else if (d.MANAGE_TYPE == 2) return "面谈";
                                        else if (d.MANAGE_TYPE == 3) return "邮件";
                                        else if (d.MANAGE_TYPE == 4) return "其他";
                                        else return "";
                                    }
                                },
                                {
                                    field: 'MANAGE_CONTENT', title: '维护类型', width: 100, align: 'center'
                                    , templet: function (d) {
                                        if (d.MANAGE_CONTENT == 0) return "需求";
                                        else if (d.MANAGE_CONTENT == 1) return "反馈";
                                        else if (d.MANAGE_CONTENT == 2) return "问候";
                                        else if (d.MANAGE_CONTENT == 3) return "其他";
                                        else return "";
                                    }
                                },
                                { field: 'FOLLOW_FOCUS', title: '内容/跟进重点', width: 250, align: 'center' },
                                { field: 'NEXT_DATETIME', title: '下次跟进时间', width: 150, align: 'center' },

                                { field: 'SALES_MAN', title: '销售人员', width: 100, align: 'center' },
                                {
                                    field: 'CREATED_TIME', title: '本记录时间', width: 180, align: 'center', templet: function (d) {
                                        if (d.CREATED_TIME) {
                                            return timestampToTimeString(d.CREATED_TIME);
                                        } else {
                                            return '';
                                        }
                                    }
                                },
                            ]],
                        page: true,//开启分页功能
                        limit: 25,//当前每页条数
                        limits: [25, 50, 100],//每页条数集合
                        done: function (res, curr, count) {
                            $('.layui-table-cell').css('height', 'auto'); // 暴力刷新

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_SID'], 'SALES_OPPORTUNITY_SID');

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'CUSTOMER_NAME');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'CONTACT_LINK');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'CONTACT_PHONE');

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'PROJECT_TITLE');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'PROJECT_INFO');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'PROJECT_STATUS');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'PROJECT_LEVEL');

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'HOBBIES');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'BIRTHDAY');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'NEEDS');

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'RESPONSE');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'EST_AMOUNT');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'NEED_SUPPORT');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'REMARKS');

                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'FIRST_MANAGE_DATE');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'LAST_MANAGE_DATE');
                            mergeCell('table', ['SALES_OPPORTUNITY_SID', 'SALES_OPPORTUNITY_PROJECT_SID'], 'SINCE_DAYS');
                        },
                    });
                });
            }

            // 合并规则:N个主列 + 副列 都相同 → 才合并【副列】
            // tableId:表格ID
            // mainFields:主字段数组(支持多个,如 ['SALES_OPPORTUNITY_SID','SALES_OPPORTUNITY_PROJECT_SID'])
            // subField:要合并的字段(联系人)
            function mergeCell(tableId, groupFields, mergeField) {
                const $tbody = $('#' + tableId + ' + div .layui-table-body tbody');
                const $trs = $tbody.find('tr');

                if ($trs.length <= 1) return;

                let startRow = 0;
                let spanCount = 1;

                for (let i = 1; i < $trs.length; i++) {
                    const $prevTr = $trs.eq(startRow);
                    const $currTr = $trs.eq(i);

                    // ======================================
                    // 【关键】判断所有分组列是否完全一样
                    // ======================================
                    let groupSame = true;
                    for (const field of groupFields) {
                        const t1 = $prevTr.find('td[data-field="' + field + '"]').text().trim();
                        const t2 = $currTr.find('td[data-field="' + field + '"]').text().trim();
                        if (t1 !== t2) {
                            groupSame = false;
                            break;
                        }
                    }

                    // 判断要合并的列是否一样
                    const m1 = $prevTr.find('td[data-field="' + mergeField + '"]').text().trim();
                    const m2 = $currTr.find('td[data-field="' + mergeField + '"]').text().trim();
                    const mergeSame = m1 === m2;

                    // 分组相同 + 合并列相同 → 合并
                    if (groupSame && mergeSame) {
                        spanCount++;
                        $currTr.find('td[data-field="' + mergeField + '"]').hide();
                    } else {
                        // 设置合并
                        $prevTr.find('td[data-field="' + mergeField + '"]').attr('rowspan', spanCount);
                        startRow = i;
                        spanCount = 1;
                    }
                }

                // 最后一行处理
                $trs.eq(startRow).find('td[data-field="' + mergeField + '"]').attr('rowspan', spanCount);
            }


            //时间戳转日期
            function timestampToDateString(dateTime) {
                if (!dateTime) return "";

                // 提取时间戳
                var timestampStr = dateTime.replace("/Date(", "").replace(")/", "");
                var timestamp = parseInt(timestampStr);
                const date = new Date(timestamp);

                // 获取 年/月/日
                var year = date.getFullYear();
                var month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月补0
                var day = date.getDate().toString().padStart(2, '0');         // 日补0

                // 返回标准格式:2025-04-05
                return year + "-" + month + "-" + day;
            }

            //时间戳转时间
            function timestampToTimeString(dateTime) {
                if (!dateTime) return "";

                // 提取时间戳(兼容 /Date(xxx)/ 格式)
                var timestampStr = dateTime.replace("/Date(", "").replace(")/", "");
                var timestamp = parseInt(timestampStr);
                const date = new Date(timestamp);

                // 获取 年/月/日
                var year = date.getFullYear();
                var month = (date.getMonth() + 1).toString().padStart(2, '0');
                var day = date.getDate().toString().padStart(2, '0');

                // 获取 时/分/秒 + 自动补0
                var hour = date.getHours().toString().padStart(2, '0');
                var minute = date.getMinutes().toString().padStart(2, '0');
                var second = date.getSeconds().toString().padStart(2, '0');

                // 返回格式:2025-04-05 14:05:09
                return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
            }

            //日期转日期
            function dateToDateString(dateTime) {
                if (!dateTime) return "";

                const date = new Date(dateTime);

                // 获取 年/月/日
                var year = date.getFullYear();
                var month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月补0
                var day = date.getDate().toString().padStart(2, '0');         // 日补0

                // 返回标准格式:2025-04-05
                return year + "-" + month + "-" + day;
            }

        </script>
相关推荐
张风捷特烈1 小时前
状态管理大乱斗#04 | Riverpod 源码评析 (上) - 核心架构
android·前端·flutter
FlyWIHTSKY1 小时前
router-viiew没有滚动条,如何修复
前端·vue.js·elementui
jinanwuhuaguo1 小时前
暗黑演化——记忆投毒、认知篡改与“数字精神分裂症”的安全悖论(第十四篇)
前端·人工智能·安全·重构·openclaw
靳向阳2 小时前
【无标题】
前端·javascript·vue.js
存在的五月雨2 小时前
uniapp 一些组件的使用
java·前端·uni-app
涵涵(互关)2 小时前
GoView各项目文件中的相关语法
前端·vue.js·typescript
佳xuan2 小时前
QA与RAG检索
java·服务器·前端
z19408920662 小时前
微软语音识别失败原因排查:从上传到获取文本的完整指南
前端·经验分享·语音识别
M ? A2 小时前
Vue 转 React:toRaw(),VuReact 怎么处理?
前端·javascript·vue.js·经验分享·react.js·面试·vureact