当前位置: 首页 > article >正文

【layui】table 样式实现合并单元格

版本 :layui -2.4.5

背景:由于不支持合并单元格,故需要自己实现。将项目上自己封装的合并行、合并列的工具忒上来,作为记录。

直接上案例代码

html:

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<link rel="stylesheet" href="../../libs/layui/layui-2.4.5/dist/css/layui.css">

	<script src="../../libs/jquery-easyui-1.8.5/jquery.min.js"></script>
	<script src="../../libs/layui/layui-2.4.5/dist/layui.js"></script>
	<script src="./js/compoments.js"></script>
	<style>


	</style>
</head>

<body style="margin: 50px;">

	<div>
		<table id="table1"></table>
	</div>


	<script>

		
		layui.use('table', function () {
			var table = layui.table;
			var $ = layui.jquery;


			var tableId = "table1";
			// console.log(res);
			//合并单元格
			table.render({
				elem: '#' + tableId
				, url: '../assets/table/data4.json' //数据接口
				// , data: res
				, cols: [
					[ //标题栏
						, { field: 'unit', title: '单位', width: 100, rowspan: 2, align: "center" } //rowspan即纵向跨越的单元格数
						, { field: 'type', title: '型号', width: 100, rowspan: 2, align: "center" }
						, { field: 'num', title: '现有人数', width: 100, rowspan: 2, align: "center" }
						, { field: 'isManager', title: '管理/人员', colspan: 2, align: "center" } //colspan即横跨的单元格数,这种情况下不用设置field和width
						, { field: 'age', title: '年龄', width: 100, rowspan: 2, align: "center" }
						, { field: 'degree', title: '文化程度', width: 100, rowspan: 2, align: "center" }
						, { field: 'ageLayer', title: '年龄结构', colspan: 5, align: "center" }
						, { field: 'degreeLayer', title: '文化层次', colspan: 6, align: "center" }
					], [
						{ field: 'username', title: '姓名', width: 100, align: "center" }
						, { field: 'work', title: '职务', width: 100, align: "center" }
						, { field: 'lte50', title: '>=50', width: 80 }
						, { field: 'in40', title: '40-49', width: 80 }
						, { field: 'in30', title: '30-39', width: 80 }
						, { field: 'in20', title: '<=29', width: 80 }
						, { field: 'average', title: '平均', width: 80 }
						, { field: 'xx', title: '小学', width: 80 }
						, { field: 'cz', title: '初中', width: 80 }
						, { field: 'gz', title: '高中', width: 80 }
						, { field: 'zz', title: '中专', width: 80 }
						, { field: 'dz', title: '大专', width: 80 }
						, { field: 'bk', title: '本科', width: 80 }


					]
				]

				
				, parseData: function (res) { //这个函数用于处理 接收数据和规定格式不符合时,可以在这里进行数据转换
					res.data.push({
						"id": 92, "unit": "总计","degree":" " ,"mergeRows":1

					});
					res.data.push({
						"id": 92, "unit": "比例","degree":" " ,"mergeRows":2
					});
					res.data.push({
						"id": 93, "unit": "备注","degree":" ", "type": "共计59人,其中管理干部4人,工人55人,平均年龄为51.76。" ,"mergeRows":2
					});
					res.count = res.data.length;
					console.log(res);
					return {
						"code": res.code, //解析接口状态
						"msg": res.msg, //解析提示文本
						"count": res.count, //解析数据长度
						"data": res.data //解析数据列表
					};
				}

				, done: function (res, curr, count) {
					 		//基础数据(不包括最后三行):计算当地机务段内的救援列车分类,这决定垂直合并的行数
                            // 从 第 0行开始检查,
                            if (count <= 3) {
                                return;
                            }

                            var rows = res.data;
                            //获取第一个垂直合并数

                            //c0(第1列) 合并所有行
                            JxLayuiUtil.mergeRowsVertically(tableId, 0, 0, count - 4);

                            //先找到第一列标题
                            var title00 = JxLayuiUtil.findTitleCell4JQuery(tableId,0,0);
                            //对第一列 第一行的单元格必须做特殊处理
                            var cell00= JxLayuiUtil.findDataCell4JQuery(tableId,0,0);

							//显示的第1列恰好如图所示(本列需要全部合并),需要加入这个代码,不然合并样式会有问题
                            var dataKey = title00.attr("data-key");
                            cell00.attr("data-key",dataKey);
                            cell00.find("div").removeClass("laytable-cell-undefined").addClass("laytable-cell-"+dataKey);

							//这个合并列函数,需要借助每行数据中包含 mergeRows 字段来控制合并的行数,如果没有这个属性,则合并忽略
                            //c1,c2,c7-c17
                            JxLayuiUtil.mergeRowsByMergeRows(tableId,[1, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],res.data,count - 3)


							//自动检测指定列 的值,如果相同,就合并。(存在bug:如果与合并行混合使用,样式会乱,请规避
							JxLayuiUtil.mergeRowsByColName(tableId,6,'degree',res.data,res.data.length-4)

                            //汇总数据(最后三行)
                            if (count >= 3) {
                                //倒数第三行(合并水平方向的 两个单元格(col=3  and col=4))
                                JxLayuiUtil.mergeRowsHorizontally(tableId, count - 3, 3, 4);

                                //倒数第二行(合并水平方向的 两个单元格(col=3  and col=4))
                                JxLayuiUtil.mergeRowsHorizontally(tableId, count - 2, 3, 4);

                                //倒数第一行(处理col=0,其他全部合并)
                                JxLayuiUtil.mergeRowsHorizontally(tableId, count - 1, 1);

                                // //修改最后一行 的合并的tr->td->div{width:1000px}
                                JxLayuiUtil.findDataCell4JQuery(tableId, count - 1, 1).find("div").css({width: "100%","text-align": "left" });

                            }
							
							//如果使用前端插件导出 html 为Excel 时,需要将 合并样式时的 隐藏的 html剔除掉,不然不会影响导出效果。
                            JxLayuiUtil.clearHideCellClassAfterMergeTable();
					
				}

			});





		});



	</script>





</body>

</html>

合并单元格的方法文件: compoments.js:

/**
 * @note 可编辑下拉框
 * @author jiangxu
 */
class EditableCombobox {

    constructor(layuiId, $) {

        this.layuiId = layuiId;
        this._$ = $;
        this.invaildTagNameOfDD = "id_" + this.layuiId + "_dd";
        this.invaildTagNameOfOption = "id_" + this.layuiId + "_option";

        this.invalidValue_DataKey = "data-" + this.layuiId;

        this.defaultValue4InvalidTag = "#"

        this.textObj = this._$(this._$("#" + this.layuiId).next()[0].children[0]);
        this.selectObj = this._$(this._$("#" + this.layuiId).next()[0].children[1]);

        this.defaultValueObj = this._$("#" + this.layuiId + "_default");

        this.init();

        this.putDefaultValue();

    }

    /**
     * 用于编辑时回填信息
     */
    putDefaultValue() {
        /**
         * 处于编辑界面时,下拉框会被预填入值的。此时需要处理显示【非法值的问题】
         * 在页面加载完毕时触发
         */
        //获取实际值
        if (!this.defaultValueObj) {
            return;
        }
        var value_default = this.defaultValueObj.val();
        if (value_default == undefined || value_default == '' || value_default == null) {
            return;
        }
        //如果是已知的值,就忽略;如果不是,需要追加 非法信息
        var arrValue = this.getValidValues();
        if (arrValue.indexOf(value_default) >= 0) {
            return;
        }

        console.warn(value_default, arrValue);
        this._$("#" + this.layuiId).val(value_default);
        this.textObj.find('input').val(value_default);


    }

    init() {

        // var inputStr = "";
        var that = this;

        this.textObj.on('keyup', function (v) {

            that.appendInfoTag4InvalidValue();

        });

        /**
         * 对已有的下拉框值 提前绑定 click 事件。
         * 如果点击了已有值,则需要提前清楚【非法值】
         */
        this.selectObj.find("dd").on('click', function (v) {

            //清除预存 非法值
            that._$("#" + that.layuiId).data(that.invalidValue_DataKey, "");

            //清除非法值的 dom
            // console.log($("#"+layuiId).data("jylc-data"));
            // console.log($(this).html())
            // 删除之前的 非法的option 的dom
            if (that._$("#" + that.invaildTagNameOfOption)) {
                that._$("#" + that.invaildTagNameOfOption).remove();
                that._$("#" + that.invaildTagNameOfDD).remove();
            }

        });


    }

    /**
     * 获取有效值集合
     */
    getValidValues() {
        var values = [];
        var that = this;
        this._$("#" + this.layuiId).find("option").each(function (index) {
            // console.log(that._$(this));
            var v = that._$(this).attr("value");
            if (v != undefined && v != null && v != '') {
                values.push(v);
            }
        })

        return values;
    }

    /**
     * 根据【非法值】追加标签信息
     */
    appendInfoTag4InvalidValue() {

        var inputStr = this.textObj.find('input').val();

        this._$("#" + this.layuiId).data(this.invalidValue_DataKey, inputStr);

        // 删除之前的 非法的option 的dom
        if (this._$("#" + this.invaildTagNameOfOption)) {
            this._$("#" + this.invaildTagNameOfOption).remove();
            this._$("#" + this.invaildTagNameOfDD).remove();
        }
        this._$("#" + this.layuiId).append('<option id="' + this.invaildTagNameOfOption + '" value="' + this.defaultValue4InvalidTag + '" selected>' + inputStr + '</option>')

        //先移除内部的 class="layui-this"
        this.selectObj.find(".layui-this").removeClass("layui-this");

        this.selectObj.append('<dd id="' + this.invaildTagNameOfDD + '" class="layui-this" lay-value="' + this.defaultValue4InvalidTag + '" >' + inputStr + '(未定义)</dd>');

        this.textObj.val(this.defaultValue4InvalidTag);

    }

    getValue() {
        var name = this._$("#" + this.layuiId).attr('name');
        var value = this._$("#" + this.layuiId).val();
        if (value == this.defaultValue4InvalidTag) {
            value = this._$("#" + this.layuiId).data(this.invalidValue_DataKey);
        }
        // var formData = {};
        // formData[name] = value;
        return value;
    }
}


/**
 * 和 Layui 相关的工具包
 */
var JxLayuiUtil = {

    /**
     * @dependence layui-table
     * @description 获取数据部分的单元格
     * @return jquery对象
     */
    findDataCell4JQuery: function (tableId, rowIndex, colIndex) {
        if (!tableId) {
            console.log("tableId is invalid!")
            return null;
        }

        var table = $("div[lay-id='" + tableId + "']");
        var tbody = table.find("tbody");
        // console.log(tbody.html())
        var rows = tbody.find("tr");

        var cols = $(rows[rowIndex]).find("td");

        return $(cols[colIndex]);
    },
    /**
     * @dependence layui-table
     * @description 获取标题部分的单元格
     * @return jquery对象
     */
    findTitleCell4JQuery: function (tableId, rowIndex, colIndex) {
        if (!tableId) {
            console.log("tableId is invalid!")
            return null;
        }

        var table = $("div[lay-id='" + tableId + "']");
        var tbody = table.find("thead");
        // console.log(tbody.html())
        var rows = tbody.find("tr");
        if (!rows || !rows[rowIndex]) {
            return null;
        }
        var cols = $(rows[rowIndex]).find("th");

        return $(cols[colIndex]);
    }
    ,

    /**
     * @dependence layui-table
     * @description 垂直方向上合并单元格
     * @param rootColIndex 需要排序的列号(start from 0)  or Array[rootColIndex...]
     * @param startRowIndex 排序的起始行号(start from 0)
     * @param endRowIndex 排序的结尾行号(start from 0)
     */
    mergeRowsVertically: function (tableId, rootColIndex, startRowIndex, endRowIndex) {
        if (!tableId) {
            console.log("tableId is invalid!")
            return;
        }

        var table = $("div[lay-id='" + tableId + "']");
        var tbody = table.find("tbody");
        // console.log(tbody.html())
        var rows = tbody.find("tr");

        if (startRowIndex === undefined) {
            startRowIndex = 0;
        }
        if (endRowIndex === undefined) {
            endRowIndex = rows.length - 1;
        }


        if (startRowIndex < 0 || endRowIndex < 0 || startRowIndex >= endRowIndex) {
            console.log("error:[rootColIndex<0||startRowIndex<0||endRowIndex<0||startRowIndex>=endRowIndex]")
            return;
        }

        var table = $("div[lay-id='" + tableId + "']");
        var tbody = table.find("tbody");

        var rows = tbody.find("tr");
        // console.log(rows.length)
        //
        var startRow = $(rows[startRowIndex]).find("td");
        if (rootColIndex instanceof Array) {
            rootColIndex.forEach(e => {
                $(startRow[e]).attr("rowspan", endRowIndex - startRowIndex + 1)
            });
        } else {
            $(startRow[rootColIndex]).attr("rowspan", endRowIndex - startRowIndex + 1)
        }

        for (var i = startRowIndex + 1; i < rows.length; i++) {

            var cols = $(rows[i]).find("td");
            if (i > endRowIndex) {
                continue;
            }

            if (rootColIndex instanceof Array) {
                rootColIndex.forEach(e => {
                    // $(cols[e]).css("display", "none");
                    // $(cols[e]).remove();
                    this.eatElement2MergeCell($(cols[e]));
                });
            } else {
                //display:none 会影响 Html 导出Excel 功能,故改为 remove
                // $(cols[rootColIndex]).css("display", "none");
                // $(cols[rootColIndex]).remove();
                this.eatElement2MergeCell($(cols[rootColIndex]))
            }


        }
    },

    /**
     *
     * mergeRowsVertically 的改进版
     * 通过 每行数据的 mergeRows( or MERGEROWS )属性 来动态识别需要合并的行数
     * 需要注意的是:处于同一合并内的不同行的 mergeRows 需要是相同值
     * @param tableId
     * @param<Array or int> rootColIndexs single or array (列号从 0 开始)
     * @param<Array> dataRows 所有的数据行
     * @param<int (not required)> rowTotal 总行数 如果不指定,默认从 dataRows 读取
     * @dependence dataRows 中每条数据中必须包含 mergeRows 字段
     */
    mergeRowsByMergeRows: function (tableId, rootColIndexs, dataRows, rowTotal) {


        var invalidArr = dataRows.filter(e => {
            var currentMergeRows = e.mergeRows ? e.mergeRows : e["MERGEROWS"];
            if (!currentMergeRows) {
                return true;
            }
            return false;
        });
        if (invalidArr.length > 0) {
            console.warn("it don't contains mergeRows property in [dataRows] ")
            return;
        }
        ;

        var count = rowTotal ? rowTotal : dataRows.length;

        var rootColIndexArray = [];
        if (typeof rootColIndexs == 'number') {
            rootColIndexArray.push(rootColIndexs);
        } else {
            rootColIndexArray = rootColIndexs
        }

        for (var i = 0; i < count;) {

            var row = dataRows[i];
            var currentMergeRows = row.mergeRows ? row.mergeRows : row["MERGEROWS"];

            currentMergeRows = parseInt(currentMergeRows);
            this.mergeRowsVertically(tableId, rootColIndexArray, i, i + currentMergeRows - 1);

            i += currentMergeRows;

        }
    },

    /**
     * 在 mergeRowsVertically 的改性版
     * @param colIndex 实际 datagrid 中 columns 中的列号,从 0 开始
     * 通过已经排好序的数据中的指定列名 来自动计算该列需要合并的行数
     * @limit 只支持 单列
     */
    mergeRowsByColName: function (tableId, colIndex, colName, dataRows, rowTotal) {

        //检查字段是否存在
        var invalidArr = dataRows.filter(e => {
            var currentMergeRows = e[colName];
            if (!currentMergeRows) {
                return true;
            }
            return false;
        });
        if (invalidArr.length > 0) {
            console.warn("the row  don't contains [" + colName + "] property in [dataRows] ")
            return;
        }

        /**
         * 第一步 需要计算数据中【colName】列 的相同数据的合并行数,即 mergeRows
         * @type {number}
         */
        var mergeRows = new Map()
        dataRows.forEach(r => {
            var total = mergeRows.get(r[colName]);
            if (!total) {
                mergeRows.set(r[colName], 1);
            } else {
                mergeRows.set(r[colName], ++total);
            }
        })

        var count = rowTotal ? rowTotal : dataRows.length;


        for (var i = 0; i < count;) {

            var row = dataRows[i];

            var currentMergeRows = mergeRows.get(row[colName]);

            currentMergeRows = parseInt(currentMergeRows);
            this.mergeRowsVertically(tableId, colIndex, i, i + currentMergeRows - 1);

            i += currentMergeRows;

        }
    }
    ,
    /**
     * @dependence layui-table
     * @description 水平方向上合并单元格
     * @param rootColIndex 需要排序的行号(start from 0)
     * @param startColIndex 排序的起始列号(start from 0)
     * @param endColIndex 排序的结尾列号(start from 0)
     */
    mergeRowsHorizontally: function (tableId, rootRowIndex, startColIndex, endColIndex) {
        if (!tableId) {
            console.warn("tableId is invalid!")
            return;
        }
        var table = $("div[lay-id='" + tableId + "']");
        var tbody = table.find("tbody");
        // console.log(tbody.html())
        var rows = tbody.find("tr");
        //随便取第一行
        var cols = $(rows[0]).find("td");

        if (startColIndex == undefined) {
            startColIndex = 0;
        }
        if (endColIndex === undefined) {
            endColIndex = cols.length - 1;
        }
        if (rootRowIndex < 0 || startColIndex < 0 || endColIndex < 0 || startColIndex >= endColIndex) {
            console.warn("error:[rootRowIndex < 0 || startColIndex < 0 || endColIndex < 0 || startColIndex >= endColIndex]")
            return;
        }


        var cols = $(rows[rootRowIndex]).find("td");

        $(cols[startColIndex]).attr("colspan", endColIndex - startColIndex + 1)

        for (var i = startColIndex + 1; i <= endColIndex; i++) {
            // $(cols[i]).css("display", "none");
            // $(cols[i]).remove();
            this.eatElement2MergeCell($(cols[i]));
        }

    }
    ,
    /**
     * 吃掉元素
     * @param jqueryObj
     */
    eatElement2MergeCell: function (jqueryObj) {
        if (!jqueryObj) {
            return;
        }
        //display:none 会影响 Html 导出Excel 功能,故改为 remove
        jqueryObj.empty().addClass("hideCellClass").css("display", "none");
        // jqueryObj.remove();
    },
    /**
     * @description 在合并完 table 所有单元格后,需要清除隐藏的元素
     * 不然导出时候,会把隐藏的单元格凸显出来
     * @note 如果不需要导出,则可忽略
     */
    clearHideCellClassAfterMergeTable: function () {
        $('.hideCellClass').remove();
    },


    /**
     * 将form表单转换为json格式
     * @param formSelector form标签的id
     * @returns {string}
     */
    clearForm: function (formSelector, hiddenTagSaving, filterList) {
        var flag = false;
        $('#' + formSelector).find(':input[name]').each(function () {
            var tagName = this.tagName.toLowerCase();
            var name = $(this).attr('name');
            var hidden = $(this).attr('hidden');

            // console.log("--",hidden);

            if (tagName === 'input' || tagName === 'textarea') {
                if (filterList) {
                    for (let e in filterList) {
                        if (filterList[e] != name) {
                            $(this).val("");
                        }
                    }
                } else {
                    //将隐藏的值不能剔除
                    if (hidden && hiddenTagSaving) {

                    } else {
                        $(this).val("");
                    }

                }

            } else if (tagName === 'select') {
                if (filterList) {
                    for (let e in filterList) {
                        if (filterList[e] != name) {
                            $(this).val("");
                            layui.form.render('select'); // 重新渲染 select 组件
                        }
                    }
                } else {
                    $(this).val("");
                    layui.form.render('select'); // 重新渲染 select 组件
                }

            }
        });


    },

    /**
     * 打开一个窗口
     */
    openWindowByUrl: function (layer, url, options) {

        /**
         * 默认值
         * @type {
  
  {area: string[], maxmin: boolean, fix: boolean, id: string, type: number, title: (title|*|string), content}}
         */
        var defaultOptions = {
            id: 'detailDialog',
            type: 2,
            title: "数据详情",
            share: 0.8,
            area: ['1600px', '750px'], //宽高
            fix: false, //不固定
            maxmin: false,
            content: url,

        }
        //默认值和用户值进行合并
        var settings = $.extend({}, defaultOptions, options);

        //打开一个 panel
        layer.open(settings);
    }
    ,

    /**
     * @author jiangxu
     * 初始化通用下拉框
     * @dependence 形如 <select id="cjcode" name="cjcode" ></select>
     * @param layer layui
     * @param elId 元素id
     * @param url 路由
     * @param value2Key 名称 对 键值
     * @param defaultVal 默认值
     */
    initCommonSelect: function (layui, elId, url, value2Key, defaultVal, callback) {

        var keyValName = ["TEXT", "VALUE"];
        if (value2Key && value2Key.length === 2) {
            keyValName = value2Key
        }
        var ajax = new layui.HussarAjax(url, function (res) {
            // console.log(res);
            var select = layui.$('#' + elId);
            if (res.data) {
                select.html('<option value = "">请选择</option>');
                $.each(res.data, function (index, item) {
                    if (defaultVal && item[keyValName[1]].trim() == defaultVal) {
                        select.append("<option selected value=" + item[keyValName[1]].trim() + ">" + item[keyValName[0]].trim() + "</option>");
                        // select.attr("disabled", true);
                    } else {
                        select.append("<option value=" + item[keyValName[1]].trim() + ">" + item[keyValName[0]].trim() + "</option>");
                    }
                })
            } else {
                select.append(new Option("暂无数据", ""));
                layui.Hussar.error("请求失败!");
            }
            layui.form.render("select");

            //触发回调
            if (callback) {
                callback();
            }
        }, function (data) {
            layui.Hussar.error("请求失败!");
        });
        ajax.async = false;
        ajax.realStart();
    }

}

/**
 * 常用工具类
 * @type {
  
  {a: ToolUtil.a}}
 * jquery --> $ 是必须的
 */
var JxToolUtil = {

    /**
     * 获取当前 YYYYMMDD 格式的 日期
     * @param offDays 距离当前时间的天数偏移量
     */
    getCurrentDateByYYYYMMDD: function (offDays) {
        if (!offDays) {
            offDays = 0;
        }
        // 获取当前日期的年月部分
        var currentDate = new Date();
        currentDate.setDate(currentDate.getDate() + offDays)
        var year = currentDate.getFullYear();
        var month = currentDate.getMonth() + 1; // 月份从0开始,需要加1
        var day = currentDate.getDate();
        // 格式化为"yyyy-mm-dd"的字符串
        var formattedDate = year + '-' + (month < 10 ? '0' + month : month)
            + '-' + (day < 10 ? '0' + day : day);

        // 将格式化后的字符串设置为日期框的值
        return formattedDate
    },
    /**
     * 获取当前 YYYYMMDD 格式的 日期
     * @param offDays 距离当前时间的天数偏移量
     */
    getDateByYYYYMMDD: function (myDate, offDays) {
        // 获取当前日期的年月部分
        var currentDate = new Date();
        if (myDate) {
            currentDate = myDate;
        }
        if (!offDays) {
            offDays = 0;
        }

        currentDate.setDate(currentDate.getDate() + offDays)
        var year = currentDate.getFullYear();
        var month = currentDate.getMonth() + 1; // 月份从0开始,需要加1
        var day = currentDate.getDate();
        // 格式化为"yyyy-mm-dd"的字符串
        var formattedDate = year + '-' + (month < 10 ? '0' + month : month)
            + '-' + (day < 10 ? '0' + day : day);

        // 将格式化后的字符串设置为日期框的值
        return formattedDate
    },
    /**
     * 获取当前 YYYYMMDD 格式的 日期
     * @param offDays 距离当前时间的天数偏移量
     */
    getCurrentFirtDayOfMonthByYYYYMMDD: function () {

        // 获取当前日期的年月部分
        var currentDate = new Date();
        // currentDate.setDate(currentDate.getDate() + offDays)
        var year = currentDate.getFullYear();
        var month = currentDate.getMonth() + 1; // 月份从0开始,需要加1
        var day = 1;
        // 格式化为"yyyy-mm"的字符串
        var formattedDate = year + '-' + (month < 10 ? '0' + month : month)
            + '-' + (day < 10 ? '0' + day : day);

        // 将格式化后的字符串设置为日期框的值
        return formattedDate
    },
    /**
     * 获取当前年月字符串日期
     * @returns {string} yyyy-mm
     */
    getCurrentDateOfYYYYMM: function (offSet) {
        if (!offSet) {
            offSet = 0;
        }
        // 获取当前日期
        var currentDate = new Date();
        var currentYear = currentDate.getFullYear();
        var currentMonth = currentDate.getMonth() + 1; // 月份从0开始,所以加1

        // 手动计算新的月份和年份
        var newMonth = currentMonth + offSet;

        // 处理月份的正负溢出,跨年
        while (newMonth <= 0) {
            currentYear--;  // 年份减1
            newMonth += 12; // 月份加12
        }
        while (newMonth > 12) {
            currentYear++;  // 年份加1
            newMonth -= 12; // 月份减12
        }

        // 格式化月份
        var formattedMonth = newMonth < 10 ? '0' + newMonth : newMonth;

        // 返回格式化的"yyyy-mm"字符串
        return currentYear + '-' + formattedMonth;
    },
    /**
     * 获取当前时间(YYYYMMDD HHMMSS)
     * 适配于 Layui 的日期控件
     * @param offset 当前日期的偏差(单位:天)
     * @returns {string}
     */
    getCurrentDateOfYYYYMMDDHHMMSS: function (offset, type) {
        if (!offset) {
            offset = 0;
        }


        // 获取当前日期
        var currentDate = new Date();

        // 手动计算新的日期
        currentDate.setDate(currentDate.getDate() + offset);

        // 获取年份、月份、日期
        var year = currentDate.getFullYear();
        var month = currentDate.getMonth() + 1; // 月份从0开始,需要加1
        var day = currentDate.getDate();

        // 格式化"yyyy-mm-dd"
        var formattedDate = year + '-' + (month < 10 ? '0' + month : month)
            + '-' + (day < 10 ? '0' + day : day);

        // 获取小时、分钟、秒钟
        var h = (currentDate.getHours() < 10 ? "0" + currentDate.getHours() : currentDate.getHours()) + ":";
        var m = (currentDate.getMinutes() < 10 ? "0" + currentDate.getMinutes() : currentDate.getMinutes()) + ":";
        var s = (currentDate.getSeconds() < 10 ? "0" + currentDate.getSeconds() : currentDate.getSeconds());

        if (type == 'S') { //初始时间
            return formattedDate + (" 00:00:00");
        } else if (type == 'E') { //终止时间
            return formattedDate + (" 23:59:59");
        } else {
            return formattedDate + (" " + h + m + s);
        }

    },


    /**
     * 获取当前的时间范围
     * @returns {string}
     */
    getCurrentDateRange: function (separator) {
        if (!separator) {
            separator = " ~ ";
        }
        return this.getCurrentDateByYYYYMMDD(-7) + separator + this.getCurrentDateByYYYYMMDD();
    },
    /**
     * 将form表单转换为json格式
     * @param formId form标签的id
     * @param mergeNames 合并name  例:['age'], 作用,会自动将重复的age进行递增 后缀会+1,提交到后台就是age=xx,age1=xx,age2=xx
     // * @param ts 特殊输入框获取值,自己第三方使用的输入框,自己塞数据到这里即可 ,这是数组 [{name:xx,value:'xx'}]
     * @returns {string}
     */
    serializeFormToJson: function (formId, mergeNames) {

        var formObject = formId;
        if (typeof formId == 'string') {
            formObject = $('#' + formId);
        }

        mergeNames = mergeNames || [];  // 如果未提供 mergeNames,则默认为空数组

        var formData = formObject.find(':input[name]').toArray().reduce(function (obj, element) {
            var $element = $(element);
            var name = $element.attr('name');
            var value;
            if ($element.is('select')) {
                value = $element.find('option:selected').val();
            } else if ($element.is(':checkbox, :radio')) {
                if ($element.is(':checked')) {
                    value = $element.val();
                } else {
                    return obj; // 跳过未选中的复选框或单选按钮
                }
            } else {
                value = $element.val();
            }

            if (obj.hasOwnProperty(name)) {
                if (mergeNames.includes(name)) {
                    // 合并成数组
                    if (!Array.isArray(obj[name])) {
                        obj[name] = [obj[name]]; // 将现有值转换为数组
                    }
                    obj[name].push(value);
                } else {
                    // name 已存在,但不需要合并,按计数器方式处理
                    var counter = 1;
                    while (obj.hasOwnProperty(name + counter)) {
                        counter++;
                    }
                    obj[name + counter] = value;
                }
            } else {
                obj[name] = value;
            }

            return obj;
        }, {});

        return formData;
    },
    /**
     * 收集 form 参数 并转为 url 的参数格式
     */
    collectFormParam2Url: function (formId) {
        var paramObj = this.serializeFormToJson(formId);
        return this.collectObjectParam2Url(paramObj);
    },

    /**
     * 收集 form 参数 并转为 url 的参数格式
     */
    collectObjectParam2Url: function (paramObj) {
        if (!paramObj) {
            return "";
        }
        var paramUrl = "";

        for (let key in paramObj) {
            paramUrl += ('&' + key + '=' + paramObj[key]);
        }
        if (paramUrl) {
            paramUrl = paramUrl.substring(1);
        }

        return paramUrl;
    },
    /**
     * 初始化 单位 的下拉框
     * @dependence <script src="${ctxPath}/static/js/plugins/xm-select-v1.2.4/dist/xm-select.js"></script>
     * @param arrId id 数组,显然支持多个控件同时渲染
     * @waringInfo 每个 ID 需要再 html 内存在对应的  <div id="dw" class="xm-select-demo"></div>
     *
     * 默认使用参数中的 id 作为 name ,进行重写 div 的 name,故原标签的 name 是无效的。
     */
    initTreeCombox4DW: function (id, options) {
        if (!id) {
            return;
        }

        // var defaultRequestParams = {"type":"zrdw"};
        var defaultRequestParams = {};
        if (options && options.requestParams) {
            defaultRequestParams = $.extend({}, defaultRequestParams, options.requestParams)
        }
        var p = JxToolUtil.collectObjectParam2Url(defaultRequestParams)


        $.ajaxSettings.async = false;
        $.get(ydzb_apiPath + "/szjwCommon/treeAqjxBmxx?" + p, function (response) {

            var defaultSelectOptions = { initValue: [] };
            if (options) {
                defaultSelectOptions = $.extend({}, defaultSelectOptions, options)
            }
            /**
             * 控件的手柄
             * @type {*[]}
             */
            // 初始化单位树
            var dwSelect = xmSelect.render({
                el: '#' + id,
                name: id,
                model: { label: { type: 'text' } },
                radio: true,
                clickClose: true,
                filterable: true,

                delay: 100,
                data: response.data,
                tree: {
                    show: true,
                    strict: false,
                    expandedKeys: ['G00232'],
                },
                // initValue: ['G00232'],
                initValue: defaultSelectOptions.initValue,
                height: '200px',
            });


            /**
             * 函数回调,返回 控件的手柄
             */
            if (options && options.callback) {
                options.callback(dwSelect);
            }

        });
    }
    ,
    // /**
    //  * 打开一个窗口
    //  * @deprecated
    //  */
    // openWindowByUrl: function (layer, url, options) {
    //
    //     /**
    //      * 默认值
    //      * @type {
  
  {area: string[], maxmin: boolean, fix: boolean, id: string, type: number, title: (title|*|string), content}}
    //      */
    //     var defaultOptions = {
    //         id: 'detailDialog',
    //         type: 2,
    //         title: "数据详情",
    //         share: 0.8,
    //         area: ['1600px', '750px'], //宽高
    //         fix: false, //不固定
    //         maxmin: false,
    //         content: url,
    //
    //     }
    //     //默认值和用户值进行合并
    //     var settings = $.extend({}, defaultOptions, options);
    //
    //     //打开一个 panel
    //     layer.open(settings);
    // }
    // ,


}


http://www.kler.cn/a/513016.html

相关文章:

  • 分布式多卡训练(DDP)踩坑
  • 数学基础 --线性代数之理解矩阵乘法
  • VS Code AI开发之Copilot配置和使用详解
  • 【计算机视觉】人脸识别
  • Dockerfile另一种使用普通用户启动的方式
  • OneFlow的简单介绍
  • Unsafe
  • MySQL指定表使用的存储引擎
  • AI大模型-提示工程学习笔记10-链式提示
  • Web小练习01
  • 将AWS S3设置为类SFTP服务用于数据上传
  • 从零搭建一个Vue3 + Typescript的脚手架——day2
  • Linux——入门基本指令汇总
  • ubuntu22.04编译多个版本OpenCV
  • Linux高并发服务器开发 第十五天(fork函数)
  • 领域算法 - 大数据处理
  • Git 详细安装教程以及gitlab添加SSH密钥
  • 微头条业务流程
  • 实战演示:利用ChatGPT高效撰写论文
  • 【C/C++实现】直接插入排序(图例--超详细解析,小白一看就会!)
  • 【单片机通过蜂鸣器模拟警号 救护车 警车 等声音 】
  • node.js+npm的环境配置以及添加镜像(保姆级教程)
  • [LeetCode] 哈希表 I — 242#有效的字母异位词 | 349#两个数组的交集 | 202#快乐数 | 1#两数之和
  • 【Rust自学】13.10. 性能对比:循环 vs. 迭代器
  • Excel 技巧12 - 如何在Excel中输入对号叉号(★),字体Wingdings2
  • 鸿蒙Harmony json转对象(1)