<main id="js-page-content" role="main" class="page-content"> <div class="row"> <div class="col-sm-12 col-xl-12"> <h1 class="p-2 mb-0">報表管理</h1> <div class="row"> <div class="col-sm-12 col-xl-2"> <div class="rounded border border-white"> <!-- nav-menu-reset will reset the font colors --> <ul class="nav-menu nav-menu-reset nav-menu-compact mb-sm-4 mb-md-0 rounded border border-white" data-nav-accordion="true" > <li class="active"> <a name="reportTypeRadio" href="javascript:;" data-value="day"> <span class="nav-link-text"> 電錶 - 日報表 </span> </a> </li> <li> <a name="reportTypeRadio" href="javascript:;" data-value="month" > <span class="nav-link-text"> 電錶 - 月報表 </span> </a> </li> <li> <a name="reportTypeRadio" href="javascript:;" data-value="year"> <span class="nav-link-text"> 電錶 - 年報表 </span> </a> </li> <li> <a name="reportTypeRadio" href="javascript:;" data-value="compare" > <span class="nav-link-text"> 電錶 - 同期比較 </span> </a> </li> </ul> <div class="filter-message js-filter-message m-0 text-left pl-4 py-3 fw-500" ></div> </div> </div> <div class="col-12 col-xl-10"> <div class="panel-hdr" style="min-height: auto"> <h2 class="py-2" id="xx"> <div class="col-auto"> <span class="report-type-name"></span>費每度單價 </div> <input type="text" id="elecPriceDegree" class="form-control col-1" /> <div id="compareTypeBtnsDiv" class="item btn-group btn-group-toggle offset-1" data-toggle="buttons" style="display: none" > <label class="btn btn-outline-success waves-effect active waves-themed" > <input type="radio" name="compareTypeRadio" id="compareMonth" value="month" checked /> 年度同月比較 </label> <label class="btn btn-outline-success waves-effect waves-themed" > <input type="radio" name="compareTypeRadio" id="compareDay" value="day" /> 月份同日比較 </label> </div> <div class="col-auto offset-1"> 選擇<span id="elecTimeText">單一月份</span> </div> <input type="text" id="elecMonthDate" class="form-control col-2" /> <input type="text" id="elecYearDate" class="form-control col-2" style="display: none" /> <div id="elecStartEndDiv" class="row m-0 align-items-center" style="display: none" > <input type="text" id="elecSYearDate" class="form-control col-4" /> <span class="px-2">~</span> <input type="text" id="elecEYearDate" class="form-control col-4" /> </div> <div id="elecCompareDiv" class="row m-0 align-items-center" style="display: none" > <div id="elecComYearDiv" class="row m-0 align-items-center"> <input type="text" id="elecCom1YearDate" class="form-control col-4" /> <span class="px-2">、</span> <input type="text" id="elecCom2YearDate" class="form-control col-4" /> </div> <div id="elecComMonthDiv" class="row m-0 align-items-center" style="display: none" > <input type="text" id="elecCom1MonthDate" class="form-control col-4" /> <span class="px-2">、</span> <input type="text" id="elecCom2MonthDate" class="form-control col-4" /> </div> </div> </h2> </div> <div class="panel-hdr" style="min-height: auto"> <h2 class="py-2 col-12" id="building"> <div class="col-1">棟別</div> <div class="item btn-group btn-group-toggle" data-toggle="buttons" ></div> </h2> </div> <div class="panel-hdr" style="min-height: auto"> <h2 class="py-2 col-12" id="floors"> <div class="col-1">樓層</div> <button type="button" class="btn btn-secondary float-right allbtn mr-2 col-auto align-self-center" onclick="allFloor()" style="display: none" > 全選 </button> <div class="item btn-group btn-group-toggle row m-0" data-toggle="buttons" style="row-gap: 5px" ></div> <span class="text-notice notice-noSelectedBuilding" style="display: none" >請選擇棟別</span > <span class="text-notice notice-noBuilding" style="display: none" >該棟別沒有樓層</span > </h2> </div> <div class="d-flex my-2"> <button type="button" class="btn btn-primary" onclick="getMeterData()" > 查詢 </button> <button type="button" class="btn btn-danger ml-2" onclick="setExportList()" > 匯出 </button> <div id="tableLoading" class="row m-0 align-items-center" style="display: none" > <div class="spinner-border text-info mx-2" role="status" style="width: 1.2rem; height: 1.2rem" > <span class="sr-only">Loading...</span> </div> <span id="tableLoadingText">列表讀取中</span> </div> <!-- <button type="button" class="btn btn-primary" onclick="SaveRealTimeCombination()">儲存常用組合</button> <button type="button" class="btn btn-danger ml-2" onclick="CleanAll()">全部清除</button> <button type="button" class="btn btn-info allbtn ml-2" onclick="LookRealTime()">查看即時資訊</button> --> </div> <table id="report_table" class="table table-bordered table-striped text-center m-0" ></table> </div> </div> </div> </div> </main> <script> var default_building = localStorage.getItem("default_building"); var Building; //取得所有棟別 var SelectBuildings = new Array(0); //選擇的區域 var datatable; var datepickerOptions = { autoclose: true, minViewMode: 1, language: "zh-TW", format: "yyyy-mm", }; var reportTypeDict = { RWater: { name: "Water", chiName: "水", listApiUrl: "WaterList", exportListApiUrl: "ExportWaterList", }, RElec: { name: "Electric", chiName: "電", listApiUrl: "ElectricList", exportListApiUrl: { day:"ExportElectricList", month:"ExportElectricList", year:"ExportElectricList", compare:"ExportElectricCompareList", } }, }; var token = cookies.get("JWT-Authorization"); $(function () { console.log("即時趨勢進入點"); setNameByType(); initDatePicker(); eventsInit(); getPrice(); setReportTable([]); $("#elecSYearDate") .val(moment().subtract(5, "years").format("YYYY")) .trigger("change"); $("#elecEYearDate").val(moment().format("YYYY")).trigger("change"); $("#elecCom1YearDate").val(moment().subtract(1, "years").format("YYYY")); $("#elecCom2YearDate").val(moment().format("YYYY")); $("#elecCom1MonthDate").val( moment().subtract(1, "months").format("YYYY-MM") ); $("#elecCom2MonthDate").val(moment().format("YYYY-MM")); //調整畫面 $("#js-page-content").removeClass("mt-0"); var html = ""; for (let building of pageAct.buildList) { html += `<label class="btn btn-outline-success waves-effect waves-themed"> <input type="radio" name="buildingRadio" id="radio_${building.building_tag}" value="${building.building_tag}" onChange="SelectBuild(this,'${building.building_tag}')"> ${building.full_name} </label>`; } $("#building").find(".item").empty(); $("#building").find(".item").append(html); checkIsSelectedBuilding(); }); function setNameByType() { $(".report-type-name").text(reportTypeDict["RElec"]["chiName"]); } function initDatePicker(name = null, otherParam = {}) { const datepickerMonthOptions = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 1, format: "yyyy-mm", }, otherParam ) ); const datepickerYearOptions = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 2, format: "yyyy", }, otherParam ) ); const datepickerSYearOptions = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 2, format: "yyyy", }, otherParam ) ); const datepickerEYearOptions = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 2, format: "yyyy", }, otherParam ) ); const datepickerComYear1Options = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 2, format: "yyyy", }, otherParam ) ); const datepickerComYear2Options = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 2, format: "yyyy", }, otherParam ) ); const datepickerComMonth1Options = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 1, format: "yyyy-mm", }, otherParam ) ); const datepickerComMonth2Options = Object.assign( {}, datepickerOptions, Object.assign( { minViewMode: 1, format: "yyyy-mm", }, otherParam ) ); if (name == null || name == "Month") { $("#elecMonthDate") .datepicker("destroy") .datepicker(datepickerMonthOptions) .focus(function () { $(this).datepicker("show"); }) .datepicker("update", new Date()); } if (name == null || name == "Year") { $("#elecYearDate") .datepicker("destroy") .datepicker(datepickerYearOptions) .focus(function () { $(this).datepicker("show"); }) .datepicker("update", new Date()); } if (name == null || name == "SYear") { $("#elecSYearDate") .datepicker("destroy") .datepicker(datepickerSYearOptions) .focus(function () { $(this).datepicker("show"); }); } if (name == null || name == "EYear") { $("#elecEYearDate") .datepicker("destroy") .datepicker(datepickerEYearOptions) .focus(function () { $(this).datepicker("show"); }); } if (name == null || name == "ComYear1") { $("#elecCom1YearDate") .datepicker("destroy") .datepicker(datepickerComYear1Options) .focus(function () { $(this).datepicker("show"); }); } if (name == null || name == "ComYear2") { $("#elecCom2YearDate") .datepicker("destroy") .datepicker(datepickerComYear2Options) .focus(function () { $(this).datepicker("show"); }); } if (name == null || name == "ComMonth1") { $("#elecCom1MonthDate") .datepicker("destroy") .datepicker(datepickerComMonth1Options) .focus(function () { $(this).datepicker("show"); }); } if (name == null || name == "ComMonth2") { $("#elecCom2MonthDate") .datepicker("destroy") .datepicker(datepickerComMonth2Options) .focus(function () { $(this).datepicker("show"); }); } } function eventsInit() { $("body").on("change", "[name=reportTypeRadio]", function () { $( "#elecMonthDate, #elecYearDate, #elecStartEndDiv, #elecCompareDiv" ).hide(); $("#compareTypeBtnsDiv").hide(); const value = $(this).data("value"); const curDate = $("#elecDate").val(); if (value === "day") { $("#elecTimeText").text("月份"); $("#elecMonthDate").show(); } else if (value == "month") { $("#elecTimeText").text("年份"); $("#elecYearDate").show(); } else if (value == "year") { $("#elecTimeText").text("年份範圍"); $("#elecStartEndDiv").show(); } else if (value == "compare") { $("#elecTimeText").text("年份"); $("#elecCompareDiv").show(); $("#compareTypeBtnsDiv").show(); } }); $("body").on("change", "[name=compareTypeRadio]", function () { $("#elecComYearDiv, #elecComMonthDiv").hide(); const value = $(this).val(); if (value === "month") { $("#elecTimeText").text("年份"); $("#elecComYearDiv").show(); } else if (value == "day") { $("#elecTimeText").text("月份"); $("#elecComMonthDiv").show(); } }); $("[name=reportTypeRadio]") .parent("li") .on("click", function () { $("[name=reportTypeRadio]").parent("li").removeClass("active"); const oldVal = $("li.active [name=reportTypeRadio]").data("value"); $(this).addClass("active"); const newVal = $("li.active [name=reportTypeRadio]").data("value"); if (oldVal !== newVal) { $("li.active [name=reportTypeRadio]").trigger("change"); } }); $("[name=compareTypeRadio]") .parent("label") .on("click", function () { debugger; $("[name=compareTypeRadio]").parent("label").removeClass("active"); const oldVal = $("label.active [name=compareTypeRadio]").val(); $(this).addClass("active"); const newVal = $("label.active [name=compareTypeRadio]").val(); if (oldVal !== newVal) { $("label.active [name=compareTypeRadio]").trigger("change"); } }); $("[name=floorCheckbox]") .parent(".btn") .off("click") .on("click", function () { const oldVal = $("[name=floorCheckbox]:checked").val(); $(this).find("input[name=floorCheckbox]").prop("checked", true); const newVal = $("[name=floorCheckbox]:checked").val(); if (oldVal !== newVal) { $("[name=floorCheckbox]:checked").trigger("change"); } }); $("body").on("change", "#elecSYearDate", function () { initDatePicker("EYear", { startDate: moment($(this).val()).startOf("year").toDate(), }); }); $("body").on("change", "#elecEYearDate", function () { initDatePicker("SYear", { endDate: moment($(this).val()).endOf("year").toDate(), }); }); } function getListSendData() { const tableType = $("li.active [name=reportTypeRadio]").data("value"); const compareType = $("label.active [name=compareTypeRadio]").val(); const startTime = tableType == "day" ? $("#elecMonthDate").val() : tableType == "month" ? $("#elecYearDate").val() : tableType == "year" ? $("#elecSYearDate").val() : tableType == "compare" ? compareType == "month" ? !$("#elecCom1YearDate").val() || !$("#elecCom2YearDate").val() ? null : [$("#elecCom1YearDate").val(), $("#elecCom2YearDate").val()] : compareType == "day" ? !$("#elecCom1MonthDate").val() || !$("#elecCom2MonthDate").val() ? null : [$("#elecCom1MonthDate").val(), $("#elecCom2MonthDate").val()] : null : null; if (!startTime) { toast_error("請選擇日期"); return; } if (Array.isArray(startTime) && startTime.length < 2) { toast_error("請選擇比較日期"); return; } const endTime = tableType == "year" ? $("#elecEYearDate").val() : null; if (!endTime && tableType == "year") { toast_error("請選擇結束日期"); return; } let sent_data = { tableType: $("li.active [name=reportTypeRadio]").data("value") == "compare" ? $("[name=compareTypeRadio]:checked").val() : $("li.active [name=reportTypeRadio]").data("value"), building_tag: $("[name=buildingRadio]:checked").val(), floor_tag: $("[name=floorCheckbox]:checked") .map((i, e) => $(e).val()) .toArray(), startTime: startTime, endTime: endTime, price: $("#elecPriceDegree").val() ? parseFloat($("#elecPriceDegree").val()) : null, }; if (Array.isArray(startTime)) { sent_data = [Object.assign({}, sent_data), Object.assign({}, sent_data)]; startTime.forEach((sTime, i) => { const compareType = $("[name=compareTypeRadio]:checked").val(); sent_data[i].startTime = sTime; sent_data[i].endTime = null; }); } return sent_data; } function getMeterData() { let result = []; var sent_data = getListSendData(); if (!Array.isArray(sent_data)) { sent_data = [sent_data]; } if (!sent_data.some((s) => s.building_tag)) { toast_error("請選擇棟別"); return; } if (!sent_data.some((s) => s.floor_tag)) { toast_error("請選擇樓層"); return; } var url = baseApiUrl + "/api/" + reportTypeDict["RElec"]["listApiUrl"]; setLoading(true); sent_data.forEach((sdata, i) => { $.ajax({ type: "POST", headers: { Authorization: "Bearer " + token, }, url: url, async: false, data: JSON.stringify(sdata), contentType: "application/json; charset=utf-8", success: function (rel) { if (rel.code != "0000") { if (rel.code == "9999") { toast_error(rel.msg); } else { toast_warning(rel.msg); } return; } if (i == 0) { result = result.concat(rel.data); result.forEach(r => { r._compare_price = null; r._compare_total = null; r._compare_total_price = null; }) } else { rel.data.forEach((r) => { let target = result.find( (d) => d.building_tag == r.building_tag && d.device_serial_tag == r.device_serial_tag && d.floor_tag == r.floor_tag ) ?? null; let _target = {}; // if(!target){ // result.push(target); // target = {}; // } _target.rawData = (target?.rawData ?? []).concat(r.rawData); _target._compare_price = r.price; _target._compare_total = r.total; _target._compare_total_price = r.total_price; if (!target) { _target = Object.assign(_target, r); _target.price = null; _target.total = null; _target.total_price = null; result.push(_target); return; } target = Object.assign(target, _target); }); } }, complete: () => { if (sent_data.length - 1 == i) { setLoading(false); } }, }); }); debugger; setReportTable(result); } function getPrice() { debugger; var sentdata = { type: reportTypeDict["RElec"]["name"], }; var url = baseApiUrl + "/api/HydroMeterPrice"; $.ajax({ type: "POST", url: url, headers: { Authorization: "Bearer " + token, }, data: JSON.stringify(sentdata), contentType: "application/json; charset=UTF-8;", success: function (rel) { if (rel.code != "0000") { if (rel.code == "9999") { toast_error(rel.msg); } else { toast_warning(rel.msg); } return; } $("#elecPriceDegree").val(rel.data); }, }); } function getDayByMonth(month) { const firstDayOfMonth = moment(month).startOf("month"); const lastDayOfMonth = moment(month).endOf("month"); const datesOfMonth = []; let currentDay = moment(firstDayOfMonth); while (currentDay.isSameOrBefore(lastDayOfMonth)) { datesOfMonth.push(currentDay.format("YYYY-MM-DD")); currentDay = currentDay.add(1, "day"); } return datesOfMonth; } function getMonthByYear(year) { const firstMonthOfYear = moment(year).startOf("year").month(); const lastMonthOfYear = moment(year).endOf("year").month(); const monthOfYear = []; for (let i = firstMonthOfYear; i <= lastMonthOfYear; i++) { monthOfYear.push(moment(year).month(i).format("YYYY-MM")); } return monthOfYear; } function getStartEndYear(sYear, eYear) { const years = []; for (let i = sYear; i <= eYear; i++) { years.push(moment().year(i).format("YYYY")); } return years; } function setTableColumns() { const tableType = $("li.active [name=reportTypeRadio]").data("value"); const compareType = $("label.active [name=compareTypeRadio]").val(); let columns = []; switch (tableType) { case "day": columns = getDayByMonth($("#elecMonthDate").val()).map((dc) => { return { title: dc, data: dc }; }); break; case "month": columns = getMonthByYear($("#elecYearDate").val()).map((dc) => { return { title: dc, data: dc }; }); break; case "year": columns = getStartEndYear( $("#elecSYearDate").val(), $("#elecEYearDate").val() ).map((dc) => { return { title: dc, data: dc }; }); break; case "compare": let compareResult = []; switch (compareType) { case "month": columns1 = getMonthByYear($("#elecCom1YearDate").val()); columns2 = getMonthByYear($("#elecCom2YearDate").val()); columns1.forEach((c1, index) => { compareResult.push(c1); if (columns2[index]) { compareResult.push({ value: columns2[index], _isCompared: true, }); } }); break; case "day": columns1 = getDayByMonth($("#elecCom1MonthDate").val()); columns2 = getDayByMonth($("#elecCom2MonthDate").val()); columns1.forEach((c1, index) => { compareResult.push(c1); if (columns2[index]) { compareResult.push({ value: columns2[index], _isCompared: true, }); } }); break; } return compareResult.map((dc) => { if (dc._isCompared) { return { title: dc.value, data: dc.value, sClass: "compare" }; } return { title: dc, data: dc }; }); break; } return columns; } function setReportTable(datas = []) { if (datatable) { datatable.clear().draw(); datatable.destroy(); $("#report_table").empty(); } datesColumns = setTableColumns(); const compareType = $("label.active [name=compareTypeRadio]").val(); datas.forEach((td) => { td.rawData.forEach((rd) => { td[rd.timeStamp] = rd.avg_rawdata; }); datesColumns.forEach((dc) => { td[dc.data] = td[dc.data] === undefined ? null : td[dc.data]; }); }); let totalColumns = [ { title: "小計", data: "total", }, { title: "單價", data: "price", }, { title: "金額總計", data: "total_price", }, ]; const tableType = $("li.active [name=reportTypeRadio]").data("value"); if (tableType == "compare") { const com1Time = compareType == "month" ? $("#elecCom1YearDate").val() : $("#elecCom1MonthDate").val(); const com2Time = compareType == "month" ? $("#elecCom2YearDate").val() : $("#elecCom2MonthDate").val(); for (var i = 0; i < totalColumns.length; i++) { let c = totalColumns[i]; if (["total", "price", "total_price"].includes(c.data)) { totalColumns.splice(i + 1, 0, { title: com2Time + c.title, data: "_compare_" + c.data, sWidth: "60px", sClass: "compare", }); c.title = com1Time + c.title; c.sWidth = "60px"; } } } console.log("datas",datas) console.log("totalColumns",totalColumns) datatable = $("#report_table").DataTable({ data: datas, destroy: true, sDom: '<"toolbar">tipl', fixedColumns: { left: 3, right: tableType == "compare" ? 2 : 3 }, scrollX: "auto", scrollCollapse: true, autoWidth: true, language: { url: "/file/BajascriptTest/js/dataTables/zh-HANT.json" }, columns: [ { title: "棟別", data: "building_name", className: "text-nowrap", }, { title: "樓層", data: "floor_tag", width: "8%", }, { title: "設備", data: "device_serial_tag", width: "8%", }, ...datesColumns, ...totalColumns, ], }); } function setExportList() { const tableType = $("li.active [name=reportTypeRadio]").data("value"); var sent_data = getListSendData(); if (!Array.isArray(sent_data)) { sent_data = [sent_data]; } if (!sent_data.some((s) => s.building_tag)) { toast_error("請選擇棟別"); return; } if (!sent_data.some((s) => s.floor_tag)) { toast_error("請選擇樓層"); return; } debugger var url = baseApiUrl + "/api/" + reportTypeDict["RElec"]["exportListApiUrl"][tableType]; setLoading(true, "匯出中"); $.ajax({ type: "POST", url: url, data: tableType == "compare" ? JSON.stringify(sent_data) : JSON.stringify(sent_data[0]), headers: { Authorization: "Bearer " + token, }, contentType: "application/json; charset=utf-8", xhrFields: { responseType: "blob", // to avoid binary data being mangled on charset conversion }, success: function (rel, text, xhr) { if (rel) { downloadByBlob(xhr, rel); } }, complete: (xhr) => { setLoading(false); }, }); } function setLoading(type = true, text = "列表讀取中") { if (type) { $("#tableLoading").fadeIn(200); $("#tableLoadingText").html(text); } else { $("#tableLoading").fadeOut(200); } } //選擇棟別 function SelectBuild(e, building_tag) { checkIsSelectedBuilding(); GetFloors(building_tag); } //取得樓層 function GetFloors(building_tag) { var sentdata = { building_tag: building_tag, }; var url = baseApiUrl + "/api/GetAllfloor"; $.ajax({ type: "POST", url: url, headers: { Authorization: "Bearer " + token, }, data: sentdata, success: function (rel) { if (rel.code != "0000") { if (rel.code == "9999") { toast_error(rel.msg); } else { toast_warning(rel.msg); } return; } if (rel.data && rel.data.length > 0) { $(".allbtn").show(); } drawFloorsBtn(rel.data); checkIsHasFloorByBuilding(); // JudgeCurrentDeviceData(); // RedrawDataTable(); }, }); } function allFloor() { $("[name=floorCheckbox]").prop("checked", true); $("[name=floorCheckbox]").parent(".btn").addClass("active"); } function checkIsSelectedBuilding() { let result = false; let buildingRadios = $("[name=buildingRadio]:checked"); if (buildingRadios && buildingRadios.length > 0) { $("#floors .text-notice.notice-noSelectedBuilding").hide(); result = true; } else { $("#floors .text-notice.notice-noSelectedBuilding").show(); $(".allbtn").hide(); } return result; } function checkIsHasFloorByBuilding() { let result = false; let floorCheckboxs = $("[name=floorCheckbox]"); if (!checkIsSelectedBuilding()) { return null; } if (floorCheckboxs && floorCheckboxs.length > 0) { $("#floors .text-notice.notice-noBuilding").hide(); result = true; } else { $("#floors .text-notice.notice-noBuilding").show(); $(".allbtn").hide(); } return result; } function drawFloorsBtn(floors) { var html = ""; for (let floor of floors) { html += `<label class="btn btn-outline-success waves-effect waves-themed" style="flex:0 0 auto"> <input type="checkbox" name="floorCheckbox" onChange="SelectFloor(this,'${floor.floor_guid}')" value="${floor.full_name}" id="${floor.floor_guid}"> ${floor.full_name} </label>`; } $("#floors").find(".item").empty(); $("#floors").find(".item").append(html); } function SelectFloor(e, floor_guid) { // getMeterData(); } </script>