Saiku设置展示table数据不隐藏空的行数据信息

saiku有个 非空的字段 按钮,点击这个后,会自动的把空的行数据信息给隐藏掉,这里我们来设置一下让其行数据不隐藏,为空的就为空。

主要更改两个文件

1. Query.js    文件路径: /saiku-ui/js/saiku/models/Query.js  (如果是编译好的saiku,请找到 saiku-server\tomcat\webapps\ROOT\js\saiku\models\Query.js  )

2. SaikuTableRenderer.js             文件路径: /saiku-ui/js/saiku/render/SaikuTableRenderer.js  (如果是编译好的saiku,请找到 saiku-server\tomcat\webapps\ROOT\js\saiku\render\SaikuTableRenderer.js  )

这里我们是在做KPI汇总信息的是遇到这样的需求,具体还是看用户需求去改动哦哈哈哈~ 我们这边是要求为空的数据列信息也要展示空的数据信息。

1.首先我们为了保证后台能传回完整的数据,需要在Query.js 的 run 方法中设定参数信息 行数据非空也展示  (ps: 为了避免影响到其他数据的展示,我们将需要行数据为空也展示的数据单独拿出来判断,通过cube名来判断!)

var exModel = this.helper.model();  // 这条是run 方法里面原有的数据哦

主要代码:  exModel.queryModel.axes.ROWS.nonEmpty=false;//設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data  这是新加的

//針對Summary數據做出更改 當行數據為空的時候 也需要展示出來
var cubename = exModel.cube.name ;
if(cubename == "SummaryKPI_2018_ext" ||cubename == "SummaryKPI_2019_ext" ||cubename == "SummaryKPI_2019_Dynamic" ) {exModel.queryModel.axes.ROWS.nonEmpty=false;//設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data
}else{exModel.queryModel.axes.ROWS.nonEmpty=true;
}

  

2.然后我们再在table渲染页面设定数据项为空也展示就可以啦!!!  SaikuTableRenderer.js 的 internalRender 方法

更改rowWithOnlyEmptyCells 的默认值为 false ,  (ps: 为了避免影响到其他数据的展示,我们将需要行数据为空也展示的数据单独拿出来判断,通过cube名来判断!)

//rowWithOnlyEmptyCells = true; //默认行数据为空时不展展示,如果需要不展示改回来 将此条值置为true即可
主要代码: rowWithOnlyEmptyCells = false; //設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data

 rowWithOnlyEmptyCells = true; //默认行数据为空时不展展示,如果改回来 将此条值置为true即可if(cubename == "SummaryKPI_2018_ext" ||cubename == "SummaryKPI_2019_ext" ||cubename == "SummaryKPI_2019_Dynamic"){rowWithOnlyEmptyCells = false; //設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data
}

这样就可以了哦。

 >>> 下面提供完整的js文件

Query.js

/**   Copyright 2012 OSBI Ltd**   Licensed under the Apache License, Version 2.0 (the "License");*   you may not use this file except in compliance with the License.*   You may obtain a copy of the License at**       http://www.apache.org/licenses/LICENSE-2.0**   Unless required by applicable law or agreed to in writing, software*   distributed under the License is distributed on an "AS IS" BASIS,*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*   See the License for the specific language governing permissions and*   limitations under the License.*//*** Workspace query*/
var Query = Backbone.Model.extend({formatter: Settings.CELLSET_FORMATTER,properties: null,/*初始化方法*/initialize: function(args, options) {if(args != null && args != undefined && args != "" && args.flag == "resultForstatisdate"){this.get_all_statisdate(args);}else{// Save cube_.extend(this, options);// Bind `this`_.bindAll(this, "run");// Generate a unique query idthis.uuid = 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function (c) {var r = Math.random() * 16 | 0,v = c == 'x' ? r : (r & 0x3 | 0x8);return v.toString(16);}).toUpperCase();this.model = _.extend({ name: this.uuid }, SaikuOlapQueryTemplate);if (args.cube) {this.model.cube = args.cube;}this.helper = new SaikuOlapQueryHelper(this);// Initialize properties, action handler, and result handlerthis.action = new QueryAction({}, { query: this });this.result = new Result({ limit: Settings.RESULT_LIMIT }, { query: this });this.scenario = new QueryScenario({}, { query: this });// A flag to tell who changed selection membersthis.updatedSelectionFromModal = false;}},parse: function(response) {// Assign id so Backbone knows to PUT instead of POSTthis.id = this.uuid;if (response.name) {this.id = response.name;this.uuid = response.name;}this.model = _.extend(this.model, response);this.model.properties = _.extend({}, Settings.QUERY_PROPERTIES, this.model.properties);},setProperty: function(key, value) {this.model.properties[key] = value;},getProperty: function(key) {return this.model.properties[key];},syncSelectionsModalAndUpdateParameters: function() {if (this.updatedSelectionFromModal) {var mParameters = this.helper.model().parameters;for (var mKey in mParameters) {var mVal       = mParameters[mKey];var selections = this.helper.getSelectionsForParameter(mKey);mVal = selections.map(function(sel) { return sel.caption; }).join();mParameters[mKey] = mVal;}} else {var mParameters = this.helper.model().parameters;for (var mKey in mParameters) {var mVal       = mParameters[mKey];var mLevel     = this.helper.getLevelForParameter(mKey);var selections = this.helper.getSelectionsForParameter(mKey);if (mVal !== null && mVal !== undefined) {this.helper.setSelectionsForParameter(mKey, _.filter(selections, function(sel) {var containsParam = false;_.each(mVal.split(','), function (v) {if (sel.caption === v) {containsParam = true;return false;}});return containsParam;}));}}}this.updatedSelectionFromModal = false;},/*执行查询的方法*/run: function(force, mdx) {this.syncSelectionsModalAndUpdateParameters();var self = this;// Check for automatic executionSaiku.ui.unblock();if (typeof this.model.properties != "undefined" && this.model.properties['saiku.olap.query.automatic_execution'] === false &&(force === false || force === undefined || force === null)) {return;}this.workspace.unblock();$(this.workspace.el).find(".workspace_results_info").empty();this.workspace.trigger('query:run');this.result.result = null;var validated = false;var errorMessage = '<span class="i18n">Query Validation failed!</span>';var exModel = this.helper.model();//針對Summary數據做出更改 當行數據為空的時候 也需要展示出來var cubename = exModel.cube.name ;if(cubename == "SummaryKPI_2018_ext" ||cubename == "SummaryKPI_2019_ext" ||cubename == "SummaryKPI_2019_Dynamic" ) {exModel.queryModel.axes.ROWS.nonEmpty=false;//設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data}else{exModel.queryModel.axes.ROWS.nonEmpty=true;}for(var k in this.attributes) {var att = this.attributes[k];if(k.substring(0,5)==="PARAM"){var p = k.substring(5, k.length);exModel.parameters[p] = att;}}if (exModel.queryType == "OLAP") {if (exModel.type == "QUERYMODEL") {var columnsOk = Object.keys(exModel.queryModel.axes.COLUMNS.hierarchies).length > 0;var rowsOk = Object.keys(exModel.queryModel.axes.ROWS.hierarchies).length > 0;var detailsOk = exModel.queryModel.details.axis == 'COLUMNS' && exModel.queryModel.details.measures.length > 0;if (!rowsOk || !columnsOk || !detailsOk) {errorMessage = "";}if (!columnsOk && !detailsOk) {errorMessage += '<span class="i18n">You need to include at least one measure or a level on columns for a valid query.</span>';}if(!rowsOk) {errorMessage += '<span class="i18n">You need to include at least one level on rows for a valid query.</span>';}if ( (columnsOk || detailsOk) && rowsOk) {validated = true;}} else if (exModel.type == "MDX") {validated = (exModel.mdx && exModel.mdx.length > 0);if (!validated) {errorMessage = '<span class="i18n">You need to enter some MDX statement to execute.</span>';}}}if (!validated) {this.workspace.table.clearOut();$(this.workspace.processing).html(errorMessage).show();this.workspace.adjust();Saiku.i18n.translate();return;}// Run itthis.workspace.table.clearOut();$(this.workspace.processing).html('<span class="processing_image">  </span> <span class="i18n">Running query...</span> [ <a class="cancel i18n" href="#cancel">Cancel</a> ]').show();this.workspace.adjust();this.workspace.trigger('query:fetch');Saiku.i18n.translate();var message = '<span class="processing_image">  </span> <span class="i18n">Running query...</span> [ <a class="cancel i18n" href="#cancel">Cancel</a> ]';this.workspace.block(message);
/*TODO: i wonder if we should clean up the model (name and captions etc.)delete this.model.queryModel.axes['FILTER'].name;
*//**根据ROWS中的statisdate字段过滤!*///根據用戶輸入的開始日期與結束日期查詢範圍數據/*var dimensionArr = exModel.queryModel.axes.ROWS.hierarchies; //取出行信息中的所有维度信息 dimension,用一个数组接收var statisdateFlag = "no";for(var i=0;i<dimensionArr.length;i++){//判断维度信息中是否有statisdate这个时间维度(这是固定的)if(dimensionArr[i]!=null && ((dimensionArr[i].dimension == "statisdate")||(dimensionArr[i].levels.statisdate != null)) ){var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url//判断参数是否为空if(paramsURI.startdate != null && paramsURI.startdate != undefined && paramsURI.startdate != ""&&paramsURI.enddate != null && paramsURI.enddate != undefined && paramsURI.enddate != ""){statisdateFlag = "yes";   this.startdateThis=null;this.enddateThis=null;var key="statisdateSpec";(new SelectionsModal({key: key,exModel: exModel,result: this.result,workspace: this.workspace}));}}}*//**根据Fliter中的statisdate字段过滤!*/var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies; //取出FILTER信息中的所有维度信息 dimension,用一个数组接收var statisdateFlag = "no";for(var i=0;i<dimensionArr.length;i++){//判断维度信息中是否有statisdate这个时间维度(这是固定的)if(dimensionArr[i]!=null && ((dimensionArr[i].dimension == "statisdate")||(dimensionArr[i].levels.statisdate != null)) ){var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url//判断参数是否为空if(paramsURI.startdate != null && paramsURI.startdate != undefined && paramsURI.startdate != ""&&paramsURI.enddate != null && paramsURI.enddate != undefined && paramsURI.enddate != ""){statisdateFlag = "yes";    this.startdateThis=null;this.enddateThis=null;var key="statisdateSpec";(new SelectionsModal({key: key,exModel: exModel,result: this.result,workspace: this.workspace}));}}}//根据入参是否有statisdate字段来判断是否执行以下查询if(statisdateFlag == 'no'){this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {Saiku.ui.unblock();var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';self.workspace.table.clearOut();$(self.workspace.processing).html(errorMessage).show();self.workspace.adjust();Saiku.i18n.translate();} });}},//得到返回的所有statisdate參數信息get_all_statisdate: function(args){var response = args.response;this.result = args.result;//var exModel = args.exModel;var statisdateArr= new Array();for(var i=0;i<response.length;i++){statisdateArr[i]=response[i].name;}//this.helper = new SaikuOlapQueryHelper(this);var exModel = args.exModel;var paramsURI = Saiku.URLParams.paramsURI(); //get the param from urlvar startdate=null;var enddate=null;if(this.startdateThis != null){startdate=this.dateToStr(this.startdateThis); //获取修正后的开始日期}else{startdate=paramsURI.startdate;//开始日期(参数中的)}if(this.enddateThis != null){enddate=this.dateToStr(this.enddateThis); //获取修正后的结束日期}else{enddate=paramsURI.enddate;//结束日期(参数中的)}//startdate = this.dateToStr(startdate); // 日期格式化//enddate = this.dateToStr(enddate); // 日期格式化if(statisdateArr.indexOf(startdate) > -1){// 这里是判断开始日期是否属于statisdateArrif(statisdateArr.indexOf(enddate) > -1){// 这里是判断结束日期是否属于statisdateArr//var dimensionArr = exModel.queryModel.axes.ROWS.hierarchies; //根据ROWSvar dimensionArr = exModel.queryModel.axes.FILTER.hierarchies; //根据Filterfor(var i=0;i<dimensionArr.length;i++){if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+startdate+"]:[statisdate].[statisdate].[statisdate].["+enddate+"]";//需要清除之前默認展示本週數據的過濾腳本信息//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式}}this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {Saiku.ui.unblock();var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';self.workspace.table.clearOut();$(self.workspace.processing).html(errorMessage).show();self.workspace.adjust();Saiku.i18n.translate();} });}else{//结束日期不存在时:如果结束日期大于开始日期,将结束日期往前减一天var tmpStartdate = this.strToDate(startdate);//StringToDate方法不存在var tmpEnddate = this.strToDate(enddate);if(tmpEnddate>=tmpStartdate){tmpEnddate = tmpEnddate.valueOf();tmpEnddate = tmpEnddate - 1*24*60*60*1000;tmpEnddate = new Date(tmpEnddate);//这里改变paramURL中的结束日期参数值,然后回调当前函数 get_all_statisdatethis.enddateThis=tmpEnddate;this.get_all_statisdate(args);}else{ //否则的话直接执行查询,直接无数据返回var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies;for(var i=0;i<dimensionArr.length;i++){if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){enddate = this.dateToStr(tmpStartdate)//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+enddate+"]:[statisdate].[statisdate].[statisdate].["+enddate+"]";//需要清除之前默認展示本週數據的過濾腳本信息//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式}}this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {Saiku.ui.unblock();var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';self.workspace.table.clearOut();$(self.workspace.processing).html(errorMessage).show();self.workspace.adjust();Saiku.i18n.translate();} });}}}else{ //开始日期不存在时: 如果开始日期小于结束日期,将开始日期往后加一天var tmpStartdate = this.strToDate(startdate);var tmpEnddate = this.strToDate(enddate);if(tmpStartdate<=tmpEnddate){tmpStartdate = tmpStartdate.valueOf();tmpStartdate = tmpStartdate + 1*24*60*60*1000;tmpStartdate = new Date(tmpStartdate);//这里改变paramURL中的结束日期参数值,然后回调当前函数get_all_statisdatethis.startdateThis=tmpStartdate;this.get_all_statisdate(args);}else{ //否则的话直接执行查询,直接无数据返回var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies;for(var i=0;i<dimensionArr.length;i++){if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){startdate = this.dateToStr(tmpEnddate)//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+startdate+"]:[statisdate].[statisdate].[statisdate].["+startdate+"]";//需要清除之前默認展示本週數據的過濾腳本信息//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式   }}this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {Saiku.ui.unblock();var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';self.workspace.table.clearOut();$(self.workspace.processing).html(errorMessage).show();self.workspace.adjust();Saiku.i18n.translate();} });}}},/*將string類型的數據轉換為date類型*/strToDate: function(strDate){strDate = strDate.toLocaleString();strDate = strDate.substring(-1,10);var convert = Date.parse(strDate);var tmpdate = new Date(convert);return tmpdate;},/*将Date类型转换为String类型 格式为:2019-03-03*/dateToStr: function(dateStr){//dateStr = this.strToDate(dateStr);var tmpYear= dateStr.getFullYear();var tmpMonth = dateStr.getMonth()+1;var tmpDay = dateStr.getDate();if(tmpMonth < 10){ tmpMonth = "0"+tmpMonth;}if(tmpDay < 10){ tmpDay = "0"+tmpDay;}var tmpdate = tmpYear+"-"+tmpMonth+"-"+tmpDay;return tmpdate;    },enrich: function() {var self = this;this.workspace.query.action.post("/../enrich", {contentType: "application/json",data: JSON.stringify(self.model),async: false,success: function(response, model) {self.model = model;}});},url: function() {return "api/query/" + encodeURI(this.uuid);}/**get_statisdate_members: function() {var path = "/result/metadata/hierarchies/%5Bstatisdate%5D.%5Bstatisdate%5D/levels/statisdate";* gett isn't a typo, although someone should probably rename that method to avoid confusion.this.workspace.query.action.gett(path, {success: this.fetch_statisdate_members,error: function() {alert("error");},data: {result: true, searchlimit: 30000 }});},得到獲取statisdate字段的結果信息然後處理fetch_statisdate_members: function(model, response) {if (response && response.length > 0) {alert("Fetch_statisdate_member++++++++++++"+response);}},*/
});

  

SaikuTableRenderer.js

function SaikuTableRenderer(data, options) {this._data = data;this._options = _.extend({}, SaikuRendererOptions, options);
}function getAxisLevelsName(data, axisName) {var queryData = data.query.queryModel.axes[axisName].hierarchies;var len = queryData.length;var arrLevels = [];for (var i = 0; i < len; i++) {for (var level in queryData[i].levels) {if (queryData[i].levels.hasOwnProperty(level)) {if (Settings.COLUMN_TITLE_TABLE_USE_LEVEL_CAPTION_NAME) {arrLevels.push(queryData[i].levels[level].caption);}else {arrLevels.push(level);}}}}return arrLevels;
}function setStyleNegativeNumber(value) {var className = '';if (Settings.STYLE_NEGATIVE_NUMBER && parseFloat(value) < 0) {className = ' style_negative_number ';}return className;
}function getAxisSize(data, axisName) {var queryData = data.query.queryModel.axes[axisName].hierarchies;var len = queryData.length;var axisSize = 0;for (var i = 0; i < len; i++) {axisSize += _.size(queryData[i].levels);}return axisSize;
}function getDomColumnsLevelsName(htmlObject) {var $htmlObject = $(htmlObject.closest('.workspace').find('.workspace_fields').find('.columns.axis_fields').find('.hierarchy').find('.d_level'));var arrLevels = [];$.each($htmlObject, function(key, level) {if ($(level).attr('style') === 'display: list-item;') {if (Settings.COLUMN_TITLE_TABLE_USE_LEVEL_CAPTION_NAME) {arrLevels.push($(level).find('.level').attr('title'));}else {arrLevels.push($(level).find('.level').attr('level'));}}});return arrLevels;
}/*table render method*/
SaikuTableRenderer.prototype.render = function(data, options) {var self = this;if (data) {this._data = data;}if (options) {this._options = _.extend({}, SaikuRendererOptions, options);}if (typeof this._data == "undefined") {return;}if (this._data != null && this._data.error != null) {return;}if (this._data == null || (this._data.cellset && this._data.cellset.length === 0)) {return;}this.hideEmpty = this._options.hideEmpty;if (this._options.htmlObject) {
//            $(this._options.htmlObject).stickyTableHeaders("destroy");// in case we have some left over scrollersif (self._options.hasOwnProperty('batch')) {$(self._options.htmlObject).parent().parent().unbind('scroll');}_.defer(function(that) {if (self._options.hasOwnProperty('batch') && !self._options.hasOwnProperty('batchSize')) {self._options['batchSize'] = 1000;}// the key method to render data by table form. 20190423var html =  self.internalRender(self._data, self._options);$(self._options.htmlObject).html(html);// Render the totals summary$('#totals_summary').remove(); // Remove one previous totals div, if present$(self._options.htmlObject).after(self.renderSummary(data)); // Render the new summary//                $(self._options.htmlObject).stickyTableHeaders( { container: self._options.htmlObject.parent().parent(), fixedOffset: self._options.htmlObject.parent().parent().offset().top });_.defer(function(that) {if (self._options.hasOwnProperty('batch') && self._options.hasBatchResult) {var batchRow = 0;var batchIsRunning = false;var batchIntervalSize = self._options.hasOwnProperty('batchIntervalSize') ? self._options.batchIntervalSize : 20;var batchIntervalTime = self._options.hasOwnProperty('batchIntervalTime') ? self._options.batchIntervalTime : 20;var len = self._options.batchResult.length;var batchInsert = function() {// maybe add check for reach table bottom - ($('.workspace_results').scrollTop() , $('.workspace_results table').height()if (!batchIsRunning && len > 0 && batchRow < len) {batchIsRunning = true;var batchContent = "";var startb = batchRow;for (var i = 0;  batchRow < len && i < batchIntervalSize ; i++, batchRow++) {batchContent += self._options.batchResult[batchRow];}if (batchRow > startb) {$(self._options.htmlObject).append( $(batchContent));}batchIsRunning = false;}if (batchRow >= len) {$(self._options.htmlObject).parent().parent().unbind('scroll');}};var lazyBatchInsert = _.debounce(batchInsert, batchIntervalTime);$(self._options.htmlObject).parent().parent().scroll(function () {lazyBatchInsert();});}});return html;});} else {var html =  this.internalRender(this._data, self._options);return html;}};SaikuTableRenderer.prototype.clear = function(data, options) {var self = this;if (this._options && this._options.htmlObject && this._options.hasOwnProperty('batch')) {$(self._options.htmlObject).parent().parent().unbind('scroll');}};SaikuTableRenderer.prototype.processData = function(data, options) {this._hasProcessed = true;
};function genTotalDataCells(currentIndex, cellIndex, scanSums, scanIndexes, lists) {var contents = '';var lists = lists[ROWS];for (var i = scanSums.length - 1; i >= 0; i--) {if (currentIndex == scanSums[i]) {var currentListNode = lists[i][scanIndexes[i]];for (var m = 0; m < currentListNode.cells.length; m++) {contents += '<td class="data total">' + currentListNode.cells[m][cellIndex].value + '</td>';}scanIndexes[i]++;if (scanIndexes[i] < lists[i].length)scanSums[i] += lists[i][scanIndexes[i]].width;}}return contents;
}function genTotalHeaderCells(currentIndex, bottom, scanSums, scanIndexes, lists, wrapContent) {var contents = '';for (var i = bottom; i >= 0; i--) {if (currentIndex == scanSums[i]) {var currentListNode = lists[i][scanIndexes[i]];var cssClass;if (i == 0 && bottom == 1)cssClass = "col";else if (i == bottom)cssClass = "col_total_corner";else if (i == bottom - 1 && currentListNode.captions)cssClass = "col_total_first";else cssClass = "col_null";for (var m = 0; m < currentListNode.cells.length; m++) {var text = ' ';if (bottom == lists.length - 1) {if (currentListNode.captions) {text = lists[i][scanIndexes[i]].captions[m];}if (i == 0 && scanIndexes[i] == 0) {if (currentListNode.captions)text += " ";else text = "";text += (wrapContent ? "<span class='i18n'>Grand Total</span>" :  "Grand Total");}}contents += '<th class="' + cssClass + '">'+ (wrapContent ? '<div>' + text + '</div>' : text ) + '</th>';}scanIndexes[i]++;if (scanIndexes[i] < lists[i].length)scanSums[i] += lists[i][scanIndexes[i]].width;}}return contents;
}function totalIntersectionCells(currentIndex, bottom, scanSums, scanIndexes, lists) {var contents = '';for (var i = bottom; i >= 0; i--) {if (currentIndex == scanSums[i]) {var currentListNode = lists[i][scanIndexes[i]];var cssClass = "data total";for (var m = 0; m < currentListNode.cells.length; m++) {var text = ' ';contents += '<td class="' + cssClass + '">' + text + '</td>';}scanIndexes[i]++;if (scanIndexes[i] < lists[i].length)scanSums[i] += lists[i][scanIndexes[i]].width;}}return contents;
}function isNextTotalsRow(currentIndex, scanSums, scanIndexes, totalsLists, wrapContent) {var colLists = totalsLists[COLUMNS];var colScanSums = scanSums[COLUMNS];var colScanIndexes = scanIndexes[COLUMNS];var bottom = colLists.length - 2;var contents = -1;for (var i = bottom; i >= 0; i--) {if (currentIndex == colScanSums[i]) {for (var m = 0; m < colLists[i][colScanIndexes[i]].cells.length; m++) {contents += '<tr>';for (var j = 0; j <= bottom; j++) {var cssClass;var text = ' ';if (i == 0 && j == 0)cssClass = 'row';else if (i == j + 1){cssClass = 'row_total_corner';return j;}else if (i == j && colLists[i][colScanIndexes[i]].captions) {cssClass = 'row_total_first';} else if (i < j + 1)cssClass = 'row_total';elsecssClass = 'row_null';if (j == bottom ) {if (colLists[i][colScanIndexes[i]].captions) {text = colLists[i][colScanIndexes[i]].captions[m];}if (i == 0 && colScanIndexes[i] == 0) {if (colLists[i][colScanIndexes[i]].captions)text += " ";else text = "";text += (wrapContent ? "<span class='i18n'>Grand Total</span>" :  "Grand Total");}}}}}}return -1;
}function genTotalHeaderRowCells(currentIndex, scanSums, scanIndexes, totalsLists, wrapContent) {var colLists = totalsLists[COLUMNS];var colScanSums = scanSums[COLUMNS];var colScanIndexes = scanIndexes[COLUMNS];var bottom = colLists.length - 2;var contents = '';for (var i = bottom; i >= 0; i--) {if (currentIndex == colScanSums[i]) {for (var m = 0; m < colLists[i][colScanIndexes[i]].cells.length; m++) {contents += '<tr>';for (var j = 0; j <= bottom; j++) {var cssClass;var text = ' ';if (i == 0 && j == 0)cssClass = 'row';else if (i == j + 1)cssClass = 'row_total_corner';else if (i == j && colLists[i][colScanIndexes[i]].captions) {cssClass = 'row_total_first';} else if (i < j + 1)cssClass = 'row_total';elsecssClass = 'row_null';if (j == bottom ) {if (colLists[i][colScanIndexes[i]].captions) {text = colLists[i][colScanIndexes[i]].captions[m];}if (i == 0 && colScanIndexes[i] == 0) {if (colLists[i][colScanIndexes[i]].captions)text += " ";else text = "";text += (wrapContent ? "<span class='i18n'>Grand Total</span>" :  "Grand Total");}}contents += '<th class="' + cssClass + '">'+ (wrapContent ? '<div>' + text + '</div>' : text ) + '</th>';}var scanIndexes = {};var scanSums = {};if (totalsLists[ROWS]) {for (var z = 0; z < totalsLists[ROWS].length; z++) {scanIndexes[z] = 0;scanSums[z] = totalsLists[ROWS][z][scanIndexes[z]].width;}}for (var k = 0; k < colLists[i][colScanIndexes[i]].cells[m].length; k++) {contents += '<td class="data total">' + colLists[i][colScanIndexes[i]].cells[m][k].value + '</td>';if (totalsLists[ROWS]) {contents += totalIntersectionCells(k + 1, totalsLists[ROWS].length - 1, scanSums, scanIndexes, totalsLists[ROWS]);}}contents += '</tr>';}colScanIndexes[i]++;if (colScanIndexes[i] < colLists[i].length) {colScanSums[i] += colLists[i][colScanIndexes[i]].width;}}}return contents;
}var ROWS = "ROWS";
var COLUMNS = "COLUMNS";function nextParentsDiffer(data, row, col) {while (row-- > 0) {if (data[row][col].properties.uniquename != data[row][col + 1].properties.uniquename)return true;}return false;
}function topParentsDiffer(data, row, col) {while (col-- > 0)if (data[row][col].properties.uniquename != data[row - 1][col].properties.uniquename)return true;return false;
}/*** This function is intended to traverse the totals arrays and cleanup empty* totals. This will optimize the query result on screen, displaying just the* needed cells.* @param dirs The direction array ['ROWS', 'COLUMNS']* @param totalsLists The totals from allData.rowTotalsLists and allData.colTotalsLists.*/
function cleanupTotals(dirs, totalsLists) {// For each direction (ROWS/COLUMNS)for (var dirIndex = 0; dirIndex < dirs.length; dirIndex++) {var dir = dirs[dirIndex];// If there are defined totalsif (totalsLists[dir]) {var isEmpty = true; // A flag to indicate if this total is emptyfor (var row = 0; row < totalsLists[dir].length; row++) {var totalsInfoArray = totalsLists[dir][row];for (var totalIndex = 0; totalIndex < totalsInfoArray.length; totalIndex++) {var cells = totalsLists[dir][row][totalIndex].cells;for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {var cellArray = cells[cellIndex];// For each total cellfor (var i = 0; i < cellArray.length; i++) {var cell = cellArray[i];// If it contains a value different from emptyif (cell.value !== '-') {isEmpty = false; // So, this total is not empty}}}}}if (isEmpty) { // If this total is emptytotalsLists[dir] = null; // Remove it}}}
}/*the main method to render data by table form. 20190423*/
SaikuTableRenderer.prototype.internalRender = function(allData, options) {var tableContent = "";var rowContent = "";var data = allData.cellset;var newRowContent = '';var arrRowData = [];var objRowData = [];var table = data ? data : [];var colSpan;var colValue;var isHeaderLowestLvl;var isBody = false;var firstColumn;var isLastColumn, isLastRow;var nextHeader;var processedRowHeader = false;var lowestRowLvl = 0;var rowGroups = [];var batchSize = null;var batchStarted = false;var isColHeader = false, isColHeaderDone = false;var resultRows = [];var wrapContent = true;if (options) {batchSize = options.hasOwnProperty('batchSize') ? options.batchSize : null;wrapContent = options.hasOwnProperty('wrapContent') ? options.wrapContent : true;}var totalsLists = {};totalsLists[COLUMNS] = allData.rowTotalsLists;totalsLists[ROWS] = allData.colTotalsLists;var scanSums = {};var scanIndexes = {};var dirs = [ROWS, COLUMNS];var hasMeasures = allData.query && allData.query.queryModel && allData.query.queryModel.details? allData.query.queryModel.details.measures.length: 0;if (typeof this._options.htmlObject === 'object' &&Settings.ALLOW_AXIS_COLUMN_TITLE_TABLE &&hasMeasures > 0 &&allData.query.type === 'QUERYMODEL' &&allData.query.queryModel.details.axis === 'COLUMNS' &&allData.query.queryModel.details.location === 'BOTTOM') {var arrColumnTitleTable = getAxisLevelsName(allData, COLUMNS);var arrDomColumnTitleTable = getDomColumnsLevelsName(this._options.htmlObject);var colspanColumnTitleTable = getAxisSize(allData, ROWS);var auxColumnTitleTable = 0;if (arrColumnTitleTable.length === arrDomColumnTitleTable.length) {arrColumnTitleTable = arrDomColumnTitleTable;}else {arrColumnTitleTable = _.intersection(arrDomColumnTitleTable, arrColumnTitleTable);}}for (var i = 0; i < dirs.length; i++) {scanSums[dirs[i]] = new Array();scanIndexes[dirs[i]] = new Array();}// Here we cleaup the empty totalscleanupTotals(dirs, totalsLists);if (totalsLists[COLUMNS]) {for (var i = 0; i < totalsLists[COLUMNS].length; i++) {scanIndexes[COLUMNS][i] = 0;scanSums[COLUMNS][i] = totalsLists[COLUMNS][i][scanIndexes[COLUMNS][i]].width;}}var headerFlag=true;// add this flag to solve the bug when same data to merge。 20190423var cubename = allData.query.cube.name;for (var row = 0, rowLen = table.length; row < rowLen; row++) {var rowShifted = row - allData.topOffset;colSpan = 1;colValue = "";isHeaderLowestLvl = false;isLastColumn = false;isLastRow = false;isColHeader = false;var headerSame = false;if (totalsLists[ROWS]) {for (var i = 0; i < totalsLists[ROWS].length; i++) {scanIndexes[ROWS][i] = 0;scanSums[ROWS][i] = totalsLists[ROWS][i][scanIndexes[ROWS][i]].width;}}rowWithOnlyEmptyCells = true; //默认行数据为空时不展展示,如果改回来 将此条值置为true即可if(cubename == "SummaryKPI_2018_ext" ||cubename == "SummaryKPI_2019_ext" ||cubename == "SummaryKPI_2019_Dynamic"){rowWithOnlyEmptyCells = false; //設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data}rowContent = "<tr>";var header = null;if (row === 0) {rowContent = "<thead>" + rowContent;}if (typeof this._options.htmlObject === 'object' &&Settings.ALLOW_AXIS_COLUMN_TITLE_TABLE &&hasMeasures > 0 &&allData.query.type === 'QUERYMODEL' &&allData.query.queryModel.details.axis === 'COLUMNS' &&allData.query.queryModel.details.location === 'BOTTOM' &&auxColumnTitleTable < arrColumnTitleTable.length) {rowContent += '<th class="row_header" style="text-align: right;" colspan="' + colspanColumnTitleTable + '" title="' + arrColumnTitleTable[auxColumnTitleTable] + '">'+ (wrapContent ? '<div>' + arrColumnTitleTable[auxColumnTitleTable] + '</div>' : arrColumnTitleTable[auxColumnTitleTable])+ '</th>';auxColumnTitleTable += 1;}for (var col = 0, colLen = table[row].length; col < colLen; col++) {var colShifted = col - allData.leftOffset;header = data[row][col];if (header.type === "COLUMN_HEADER") {isColHeader = true;}// If the cell is a column header and is null (top left of table)if (header.type === "COLUMN_HEADER" && header.value === "null" && (firstColumn == null || col < firstColumn)) {if (((!Settings.ALLOW_AXIS_COLUMN_TITLE_TABLE || (Settings.ALLOW_AXIS_COLUMN_TITLE_TABLE && allData.query.queryModel.details.location !== 'BOTTOM')) || hasMeasures === 0) ||allData.query.type === 'MDX') {rowContent += '<th class="all_null"> </th>';}} // If the cell is a column header and isn't null (column header of table)else if (header.type === "COLUMN_HEADER") {if (firstColumn == null) {firstColumn = col;}if (table[row].length == col+1)isLastColumn = true;elsenextHeader = data[row][col+1];if (isLastColumn) {// Last column in a row...if (header.value == "null") {rowContent += '<th class="col_null"> </th>';} else {if (totalsLists[ROWS])colSpan = totalsLists[ROWS][row + 1][scanIndexes[ROWS][row + 1]].span;rowContent += '<th class="col" style="text-align: center;" colspan="' + colSpan + '" title="' + header.value + '">'+ (wrapContent ? '<div rel="' + row + ":" + col +'">' + header.value + '</div>' : header.value)+ '</th>';}} else {// All the rest...var groupChange = (col > 1 && row > 1 && !isHeaderLowestLvl && col > firstColumn) ?data[row-1][col+1].value != data[row-1][col].value || data[row-1][col+1].properties.uniquename != data[row-1][col].properties.uniquename: false;var maxColspan = colSpan > 999 ? true : false;if (header.value != nextHeader.value || nextParentsDiffer(data, row, col) || isHeaderLowestLvl || groupChange || maxColspan) {if (header.value == "null") {rowContent += '<th class="col_null" colspan="' + colSpan + '"> </th>';} else {if (totalsLists[ROWS])colSpan = totalsLists[ROWS][row + 1][scanIndexes[ROWS][row + 1]].span;rowContent += '<th class="col" style="text-align: center;" colspan="' + (colSpan == 0 ? 1 : colSpan) + '" title="' + header.value + '">'+ (wrapContent ? '<div rel="' + row + ":" + col +'">' + header.value + '</div>' : header.value)+ '</th>';}colSpan = 1;} else {colSpan++;}}if (totalsLists[ROWS])rowContent += genTotalHeaderCells(col - allData.leftOffset + 1, row + 1, scanSums[ROWS], scanIndexes[ROWS], totalsLists[ROWS], wrapContent);} // If the cell is a row header and is null (grouped row header)else if (header.type === "ROW_HEADER" && header.value === "null") {rowContent += '<th class="row_null"> </th>';} // If the cell is a row header and isn't null (last row header)else if (header.type === "ROW_HEADER") {if (lowestRowLvl == col)isHeaderLowestLvl = true;elsenextHeader = data[row][col+1];var previousRow = data[row - 1];var nextRow = data[row + 1];// when  same set fixed value is false ,It means the same data will not merge。table data will  show row by row.20190423//var same=false; /*judge the current value and previousRow value,if equals ,all set comeback,set the headerFlag is true, we can judge the data as usual. 20190423*/if(header.value !== previousRow[col].value){headerFlag =true;}/*judge the tableContent include value or not, if include ,set the headerFlag value is true to avoid repeat datas showed in table.20190423*/if(tableContent.indexOf(header.value) > -1 ){headerFlag =true;}/*add headerFlag to judge the data is same ,then control the data merge wheather or not.20190423 */var same = !headerSame && !isHeaderLowestLvl && (col == 0 || !topParentsDiffer(data, row, col)) && header.value === previousRow[col].value && headerFlag;headerSame = !same;var sameAsPrevValue = false;if(Settings.ALLOW_TABLE_DATA_COLLAPSE){if (row > 0 && row < rowLen - 1) {if (totalsLists[ROWS] == null || (col <= colLen - totalsLists[ROWS].length - 1)) {var checkOther = true;if (totalsLists[COLUMNS] && rowShifted >= 0 && col <= isNextTotalsRow(rowShifted + 1, scanSums, scanIndexes, totalsLists, wrapContent)) {sameAsPrevValue = true;checkOther = false;}if (checkOther && nextRow[col].value == header.value) {if (col > 0) {for (var j = 0; j < col; j++) {if (nextRow[j].value == data[row][j].value) {sameAsPrevValue = true;} else {sameAsPrevValue = false;break;}}} else {sameAsPrevValue = true;}}}} else if(row > 0 && row == rowLen - 1) {if (totalsLists[COLUMNS] && rowShifted >= 0 && col <= isNextTotalsRow(rowShifted + 1, scanSums, scanIndexes, totalsLists, wrapContent)) {sameAsPrevValue = true;}}}var value = (same ? "<div> </div>" : '<div rel="' + row + ":" + col + '">'+ (sameAsPrevValue && Settings.ALLOW_TABLE_DATA_COLLAPSE ? '<span class="expander expanded" style="cursor: pointer;">▼</span>' : '' ) + header.value + '</div>');if (!wrapContent) {value = (same ? " " : header.value );}var tipsy = "";/* var tipsy = ' original-title="';if (!same && header.metaproperties) {for (key in header.metaproperties) {if (key.substring(0,1) != "$" && key.substring(1,2).toUpperCase() != key.substring(1,2)) {tipsy += "<b>" + safe_tags_replace(key) + "</b> : " + safe_tags_replace(header.metaproperties[key]) + "<br>";}}}tipsy += '"';*/var cssclass = (same ? "row_null" : "row");var colspan = 0;if (!isHeaderLowestLvl && (typeof nextHeader == "undefined" || nextHeader.value === "null")) {colspan = 1;var group = header.properties.dimension;var level = header.properties.level;var groupWidth = (group in rowGroups ? rowGroups[group].length - rowGroups[group].indexOf(level) : 1);for (var k = col + 1; colspan < groupWidth && k <= (lowestRowLvl+1) && data[row][k] !== "null"; k++) {colspan = k - col;}col = col + colspan -1;}/*when the content is to long ,we will set new line to show it.*/// eg value: <div rel="3:0">新業務及保單行政部</div>if(cssclass == "row" && value.length>0){var startPos = value.indexOf('>'); //find  start position of the tag. eg: <div rel="3:0">var endPos = value.lastIndexOf('<'); //find  end position of the tag. eg: </div>var tmpValue = value.substr( startPos+1 ,endPos-startPos-1); // get the content value. eg: 新業務及保單行政部//将value值每隔40个字自动加上换行符//each 40 character add one <br> tag to get new line. if(tmpValue.length>120){ tmpValue = tmpValue.substr(0,40)+"<br/>"+tmpValue.substr(40,40)+"<br/>"+tmpValue.substr(80,40)+"<br/>"+tmpValue.substr(120,tmpValue.length-120);}else if(tmpValue.length>80){ tmpValue = tmpValue.substr(0,40)+"<br/>"+tmpValue.substr(40,40)+"<br/>"+tmpValue.substr(80,tmpValue.length-80);}else if(tmpValue.length>40){tmpValue = tmpValue.substr(0,40)+"<br/>"+tmpValue.substr(40,tmpValue.length-40);}// compared with old value, this value only add <br> tag for show data in table more beautiful.value = value.substr(0,startPos+1) + tmpValue + value.substr(endPos,value.length-endPos);}rowContent += '<th class="' + cssclass + '" ' + (colspan > 0 ? ' colspan="' + colspan + '"' : "") + tipsy + '>' + value + '</th>';}else if (header.type === "ROW_HEADER_HEADER") {var hierName = function(data) {var hier = data.properties.hierarchy;var name = hier.replace(/[\[\]]/gi, '').split('.')[1]? hier.replace(/[\[\]]/gi, '').split('.')[1]: hier.replace(/[\[\]]/gi, '').split('.')[0];return name;};var arrPosRowData = [];if (_.contains(arrRowData, header.value)) {for (var i = 0; i < arrRowData.length; i++) {if (arrRowData[i] === header.value) {arrPosRowData.push(i);}}arrPosRowData.push(col);}rowContent += '<th class="row_header">' + (wrapContent ? '<div>' + header.value + '</div>' : header.value) + '</th>';arrRowData.push(header.value);objRowData.push({name: header.value,hierName: hierName(header) + '/' + header.value});isHeaderLowestLvl = true;processedRowHeader = true;lowestRowLvl = col;if (header.properties.hasOwnProperty("dimension")) {var group = header.properties.dimension;if (!(group in rowGroups)) {rowGroups[group] = [];}rowGroups[group].push(header.properties.level);}if (arrPosRowData.length > 0) {var aux = 0;rowContent = '<tr>';if (row === 0) {rowContent = '<thead>' + rowContent;}for (var i = 0; i < objRowData.length; i++) {if (arrPosRowData[aux] === i) {newRowContent += '<th class="row_header">' + (wrapContent ? '<div>' + objRowData[i].hierName + '</div>' : objRowData[i].hierName) + '</th>';aux += 1;}else {newRowContent += '<th class="row_header">' + (wrapContent ? '<div>' + objRowData[i].name + '</div>' : objRowData[i].name) + '</th>';}}rowContent += newRowContent;}} // If the cell is a normal data cellelse if (header.type === "DATA_CELL") {batchStarted = true;var color = "";var val = _.isEmpty(header.value) ? Settings.EMPTY_VALUE_CHARACTER : header.value;var arrow = "";if (header.properties.hasOwnProperty('image')) {var img_height = header.properties.hasOwnProperty('image_height') ? " height='" + header.properties.image_height + "'" : "";var img_width = header.properties.hasOwnProperty('image_width') ? " width='" + header.properties.image_width + "'" : "";val = "<img " + img_height + " " + img_width + " style='padding-left: 5px' src='" + header.properties.image + "' border='0'>";}// Just apply formatting to non-empty cellsif (val !== '-' && val !== '' && header.properties.hasOwnProperty('style')) {color = " style='background-color: " + header.properties.style + "' ";}if (header.properties.hasOwnProperty('link')) {val = "<a target='__blank' href='" + header.properties.link + "'>" + val + "</a>";}if (header.properties.hasOwnProperty('arrow')) {arrow = "<img height='10' width='10' style='padding-left: 5px' src='./images/arrow-" + header.properties.arrow + ".gif' border='0'>";}if (val !== '-' && val !== '') {rowWithOnlyEmptyCells = false;}rowContent += '<td class="data" ' + color + '>'+ (wrapContent ? '<div class="datadiv '+ setStyleNegativeNumber(header.properties.raw) + '" alt="' + header.properties.raw + '" rel="' + header.properties.position + '">' : "")+ val + arrow+ (wrapContent ? '</div>' : '') + '</td>';if (totalsLists[ROWS])rowContent += genTotalDataCells(colShifted + 1, rowShifted, scanSums[ROWS], scanIndexes[ROWS], totalsLists, wrapContent);}}rowContent += "</tr>";// Change it to let hideEmpty true by defaultif (options.hideEmpty && header.type === "DATA_CELL" && rowWithOnlyEmptyCells) {/*when data_cell is null,set the headerFlag is false ,to fix the problem data merge inccrrect.*/headerFlag=false;rowContent = '';}var totals = "";if (totalsLists[COLUMNS] && rowShifted >= 0) {totals += genTotalHeaderRowCells(rowShifted + 1, scanSums, scanIndexes, totalsLists, wrapContent);}if (batchStarted && batchSize) {if (row <= batchSize) {if (!isColHeader && !isColHeaderDone) {tableContent += "</thead><tbody>";isColHeaderDone = true;}tableContent += rowContent;if (totals.length > 0) {tableContent += totals;}} else {resultRows.push(rowContent);if (totals.length > 0) {resultRows.push(totals);}}} else {if (!isColHeader && !isColHeaderDone) {tableContent += "</thead><tbody>";isColHeaderDone = true;}tableContent += rowContent;if (totals.length > 0) {tableContent += totals;}}}if (options) {options['batchResult'] = resultRows;options['hasBatchResult'] = resultRows.length > 0;}return "<table>" + tableContent + "</tbody></table>";
};SaikuTableRenderer.prototype.renderSummary = function(data) {if (data && data.query) {var hasSomethingToRender = false;var measures = data.query.queryModel.details? data.query.queryModel.details.measures: [];var summaryData = {};for (var i = 0; i < measures.length; i++) {var m = measures[i];if (m.aggregators) {for (var j = 0; j < m.aggregators.length; j++) {var a = m.aggregators[j];if (a.indexOf('_') > 0) {var tokens = a.split('_');var aggregator = tokens[0];var axis = tokens[1];if (aggregator !== 'nil' && aggregator !== 'not') {hasSomethingToRender = true;aggregator = aggregator.capitalizeFirstLetter();if (!(axis in summaryData)) summaryData[axis] = [];summaryData[axis].push(m.name + ": " + aggregator);}}}}}if (hasSomethingToRender) {var summary = "<div id='totals_summary'><br/>";$.each(summaryData, function(key, aggregators) {summary += "<h3>" + key.capitalizeFirstLetter();for (var i = 0; i < aggregators.length; i++) {summary += "<br/> " + aggregators[i];}summary += "</h3>";});return summary + "</div>";}}return "";
};String.prototype.capitalizeFirstLetter = function() {return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
}

  

=====================二次更新=显示空的行数据========start================

最近又遇到了需要不隐藏的空的行数据的报表,笔者想了想用参数去处理此类问题会更好些吧

所以我们就在请求上URL添加参数  showEmptyRows=yes

之前判断具体cubename的部分 用参数来判定!!!

var paramsURI = Saiku.URLParams.paramsURI();if( paramsURI .showEmptyRows=='yes') {exModel.queryModel.axes.ROWS.nonEmpty=false;//設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data}

视图渲染也根据入参如判断即可

var paramsURI = Saiku.URLParams.paramsURI();if( paramsURI .showEmptyRows=='yes') {
  rowWithOnlyEmptyCells = false; //設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data }

  

ps: 请求url上记得添加参数 showEmptyRows=yes

感觉用参数会更加方便些,以后有添加其它报表的时候添加参数即可!!!(建议不直接判断cubename哦,哈哈哈哈哈哈 用此方式会更好些~)
=====================二次更新=显示空的行数据=======end=================

 

转载于:https://www.cnblogs.com/DFX339/p/10768039.html

Saiku设置展示table数据不隐藏空的行数据信息(二十六)相关推荐

  1. linux内核网络协议栈--数据包的skb桥转发蓝图(二十六)

    话不多说,先看一张桥转发时函数调用的一个基本蓝图. 这张图中,简单的展示了,数据的接收和发送,其中还包括netfilet的钩子点所处的位置. 需要说明的是: 1.我们先暂时忽略数据包从一开始是怎么从驱 ...

  2. excel WPS批量删除表格中某一列为空的行数据

    面试一点通丨模拟面试 模拟笔试,跳槽.升职.加薪.换更好工作必备微信小程序神器. 如下截图Excel,我们想删除E列为空的行数据(即黄颜色的行数据),如何批量操作呢: 1.鼠标左键选中E列. 2.键盘 ...

  3. 2021年大数据Hadoop(二十六):YARN三大组件介绍

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 Yarn三大组件介绍 ResourceManager No ...

  4. 从零开始学java(二十六)--多维数组,多维数组存储表格数据

    从零开始学java(二十六)--多维数组 多维数组 多维数组存储表格数据 多维数组 多维数组可以看成以数组为元素的数组.可以有二维.三维.甚至更多维数组,但是实际开发中用的非常少.最多到二维数组(学习 ...

  5. VMware vSphere 5.1 群集深入解析(二十六)- 数据存储维护模式汇总

    VMware vSphere 5.1 Clustering Deepdive HA.DRS.Storage DRS.Stretched Clusters Duncan Epping &Fran ...

  6. openlayers6【二十六】业务交互:Cluster 聚合标注控制,显示隐藏聚合标注

    文章目录 1. 聚合标注常见业务需求交互 2. 实现效果 3. 核心代码 4. 完整代码 1. 聚合标注常见业务需求交互 业务需求:在地图场景中,通常是多种业务场景(点位图标,边界图层,热力图层等)在 ...

  7. 数据与广告系列二十六:知识迁移的Embedding应用,智能化定向的解药

    作者·黄崇远 『数据虫巢』 全文共4348字 题图ssyer.com " 效果广告后定向时代,虽有千般万难,我们一样还得解决定向智能的问题." 需要提前说明的是,这一篇会涉及到本系 ...

  8. mysql大量数据合并_mysql中将多行数据合并成一行数据

    一个字段可能对应多条数据,用mysql实现将多行数据合并成一行数据 例如:一个活动id(activeId)对应多个模块名(modelName),按照一般的sql语句: 1 SELECT am.acti ...

  9. mysql循环查询一个表中的数据并进行修改_JavaScript学习笔记(二十四)-- MYSQL基础操作...

    MYSQL mysql 是一个数据库的名字 和 php 合作的比较好的数据库 之前我们说过一个问题,前端向后端索要数据,后端就是去数据库中查询数据,返回给前端 接下来就聊聊使用 php 操作数据库 M ...

最新文章

  1. LIVE 预告 | 华为诺亚韩凯:Transformer in Transformer
  2. fork()子进程与父进程之间的文件描述符问题
  3. extern quot;Cquot; 的含义:实现C++与C及其他语言的混合编程
  4. 17.深浅拷贝和写时拷贝
  5. Node响应中文时解决乱码问题
  6. 科大星云诗社动态20210131
  7. .NET Core 2.0 特性介绍和使用指南
  8. 广西 启动计算机教案,广西版六年级下册信息技术教案.docx
  9. 给定数组,去掉0元素后将剩下的元素赋给新的数组
  10. 从中煤陕西公司看政企移动信息化应用
  11. 《啊哈算法》学习笔记(三)——最短路径
  12. flutter 手机定位
  13. 利用Cookies实现ASP.NET跨域单点登录
  14. java 逃逸分析_JVM之逃逸分析
  15. HEVC中变换(Transform)过程中的scaling操作的理解
  16. 【论文笔记】Learning to Count in the Crowd from Limited Labeled Data
  17. 简单定义一个RMB类
  18. untu复制粘贴快捷键
  19. VBA提取PPT中的文字
  20. 中兴软件编程规范C/C++

热门文章

  1. PHP compact() 函数,好用!
  2. 内部管理类软件基础架构思想(思路图解 + 配套免费视频)
  3. 服务器看门狗芯片电路图,看门狗芯片MAX708的工作原理及数 - 电源设计应用 - 电子发烧友网...
  4. 港服优势何在?游戏公司为什么选择香港服务器?
  5. Linux服务器安装git
  6. 爬取携程和蚂蜂窝的景点评论数据\携程评论数据爬取\旅游网站数据爬取
  7. Java中的equals()方法
  8. 【Hive】hive 微博案例
  9. Deep learning based segmentation for automated training of apple trees on trellis wires
  10. 3904三极管是什么功能_光敏二极管与发光二极管有什么区别