1.服务端宏-图片列无图片时默认显示一条斜线

因为客户端宏只影响在浏览器中的显示,导出的文件是不受影响的。如果实际需求是导出的文件中也要求无图片的单元格默认填充上斜线的话,就可以使用下面的方法了。

(1).首先添加一个服务端宏

名称:自己取一个就成
类型:ServerSide
对象:spreadsheetReport
事件:onBeforeOutput

(2).在宏代码中,main方法外添加如下自定义方法

// 检测如果没有图片就画一个斜线出来
function handlePictureCells(cellAddress) {var sheet = spreadsheetReport.sheets[0]; //获取sheet[0]对象//根据cellAddress单元格获取"数据"字段扩展出的所有数据var positions = sheet.getExpandedPositions(cellAddress);var worksheet = spreadsheetReport.workbook.worksheets.get(0);var cells = worksheet.cells;for (var i = 0; i < positions.length; i++) {var pos = positions[i];// 所有扩展出来的图片默认都是有一个名称的:SSR_Image_行号_列号// 其中行号从0开始,这个例子中行列号都是从对象中取的,所以不影响var imgName = "SSR_Image_"+(pos.row)+"_"+pos.column;// 通过这个方法可以获取到图片对象var shp = worksheet.shapes.get(imgName);// 获得cell对象,以设置值cell = cells.get(pos.row, pos.column);// 如果没有图片的话,就把值设置成斜线if(!shp){cell.value='/';}}
}

(3).在main方法中调用该方法

这里以安全咨询问题整改的季报报表为例,在表格中可以看到图片的原始单元格有F4J4

所以在main方法中调用方法,并传入这两个单元格

function main(spreadsheetReport) {handlePictureCells("F4");handlePictureCells("J4");
}

看下网页端已经生效了

导出的excel中也是

2.服务端宏-在当前分页中对指定列的相同值的单元格进行合并

不分页的情况下只需要将扩展属性由“列表”设置为“分组”即可。但是如果报表使用了分页,即 xx 条就分成一页,比如安全咨询问题整改的季报,因为一个报表中图片数量太多,且比较大,因此不分页的话,可能会导致报表需要下载几十上百M的数据才能展示,甚至可能直接报错。但是分页后分组这种扩展方式就不太适合了,如果仍然直接使用分组的话,大概会显示成如下的样子

目前使用的解决办法就是取消扩展属性里面的分组,转为使用服务端宏的形式对当前页面的指定列进行相同值单元格合并的操作,官方文档中有一个横向合并单元格的,可以到下面的连接里面去看
参考官方文档:https://wiki.smartbi.com.cn/pages/viewpage.action?pageId=52625784

(1).首先还是添加服务端宏

名称:自己取一个就成
类型:ServerSide
对象:spreadsheetReport
事件:onBeforeOutput

(2).在宏代码中,main方法外添加如下自定义方法

//  spreadsheetReport 是全局对象
// cellAddress 是指需要合并单元格的、会扩展成列的那个单元格。比如
function myMergeCells(cellAddress) {var sheet = spreadsheetReport.sheets[0]; //获取sheet[0]对象// var sheet =  spreadsheetReport.workbook.worksheets.get(0); //获取sheet[0]对象//根据C4单元格获取"数据"字段扩展出的所有数据var positions = sheet.getExpandedPositions(cellAddress);var worksheet = spreadsheetReport.workbook.worksheets.get(0);var cells = worksheet.cells;var cell = undefined,row1 = 0,row2 = 0;for (var i = 0; i < positions.length; i++) {var pos = positions[i];//判断当前行的值和下一行的值是否一样,如果一样则合并,否则不处理if (!cell) {cell = cells.get(pos.row, pos.column);row1 = pos.row;}var nextCell = cells.get(pos.row + 1, pos.column);if (nextCell && cell && cell.value == nextCell.value) {row2 = pos.row + 1;var value = cell.value;try {cells.merge(row1, pos.column, row2 - row1 + 1, 1);} catch (exception) {// 只是为了防止报错影响数据展示,也可以在这里加处理方法}} else {cell = null;}// var value = cell.value;// cells.get(pos.row, pos.column - 2).value = value;// cells.merge(pos.row, pos.column - 2, 1, 3);}
}

(3).在main方法中调用该方法

这里以安全咨询问题整改的季报报表为例,在表格中可以看到需要纵向合并相同值的原始单元格有C4D4

所以在main方法中执行调用方法

function main(spreadsheetReport) {myMergeCells("C4");myMergeCells("D4");
}

看效果,合并单元格已经不再会跨页了

3 服务端宏-添加空单元格填充默认值

3.1 按单元格来指定

(1).首先还是添加服务端宏

名称:自己取一个就成
类型:ServerSide
对象:spreadsheetReport
事件:onBeforeOutput
(2).在宏代码中,main方法外添加如下自定义方法

/*** 指定的cell及其扩展出来的单元格里面如果值为"" 则填充 “-”* @param cellAddress 需要填充“-”的、有着数据源定义的单元格* @param sheetIndex 第几个sheet,从0开始,默认0,也就是第一个sheet* @param notEmeptyCell 用来表示是否是空表的单元格,如果传入了该参数,且对应单元格里面有值则不填充,否则填充* @param fillText 为空时填充的内容,默认 "-"*/
function fillEmptyCell(cellAddress,sheetIndex,notEmeptyCell,fillText) {// 设置默认值,如果不传则默认处理第一个sheetif(!sheetIndex){sheetIndex = 0;}// 设置默认填充内容为"-"if(!fillText){fillText = "-";}// 获取sheet[0]对象var sheet = spreadsheetReport.sheets[sheetIndex]; // 获得整个sheet对象var worksheet = spreadsheetReport.workbook.worksheets.get(sheetIndex);// 获得sheet对象中所有的单元格对象,下面会根据位置获得对应的具体的单元格var cells = worksheet.cells;// 如果有传notEmptyCell参数,且单元格里面值为空,则说明是空表,不再填充对应内容if(notEmeptyCell){// 用来表示是否需要填充var isEmptyGrid = true;// 根据指定单元格获取到所有扩展出来的单元格的位置的数组var emptyCellPostions = sheet.getExpandedPositions(notEmeptyCell);// 遍历该位置数组for(var j = 0;j < emptyCellPostions.length; j++){// 获得当前位置var emptyCellPos = emptyCellPostions[j];// 根据位置得到具体的单元格对象var emptyCell = cells.get(emptyCellPos.row,emptyCellPos.column);// 如果该单元格不为空,则说明不是空表if(emptyCell.value){isEmptyGrid = false;break;}}// 如果是空表的话,就不再填充内容了if(isEmptyGrid){return;}}// 如果不是空表,则进行填充// 根据指定单元格获取到所有扩展出来的单元格的位置的数组var positions = sheet.getExpandedPositions(cellAddress);    for (var i = 0; i < positions.length; i++) {var pos = positions[i];//合并单元格并设置合并后的单元格的值var cell = cells.get(pos.row, pos.column);if (!cell.value || cell.value == "") { //判断值是否为空cell.value = fillText;}}
}

(3).在main方法中调用该方法,以下(每一行都是B13单元格)为调用示例,实际使用时对应的单元格只需要调用一次即可

function main(spreadsheetReport) {// 第一个sheet中的B13单元格及其扩展出来的单元格值为空时填充“-”fillEmptyCell("B13")// 第一个sheet中的B13单元格及其扩展出来的单元格值为空时填充“-”fillEmptyCell("B13",0)// 第二个sheet中的B13单元格及其扩展出来的单元格值为空时填充“-”fillEmptyCell("B13",1)// 第一个sheet中的B13单元格及其扩展出来的单元格值为空,且O1单元格(一般是样品ID,用于判断是否空表)里面有值时,则说明不是空表,填充“-”,否则不填充fillEmptyCell("B13",null,"O1")// 第一个sheet中的B13单元格及其扩展出来的单元格值为空时填充“/”fillEmptyCell("B13",0,null,"/")
}

3.2 优化-按区域指定

上面的是针对单个单元格来进行填充的,如果需要配置的单元格比较多,那么使用和维护都是一个比较麻烦的过程,如果可以直接指定区域,那就更加灵活一些了,所以下面改成了可以传入单元格区域的
(1). 同上
(2).在宏代码中,main方法外添加如下自定义方法

/*** 指定的区里面有绑定数据源的cell及其扩展出来的单元格里面如果值为空串(即"") 则填充 “-”* @param range 需要填充“-”的、有着数据源定义的单元格区域,只会对里面有绑定数据源的单元格做处理* @param sheetIndex 第几个sheet,从0开始,默认0,也就是第一个sheet* @param notEmeptyCell 用来表示是否是空表的单元格,如果传入了该参数,且对应单元格里面有值则不填充,否则填充* @param fillText 为空时填充的内容,默认 "-"*/
function fillEmptyRange(range,sheetIndex,notEmeptyCell,fillText) {if(range.indexOf(":")>-1){var re = /([a-zA-Z]+)([0-9]+):([a-zA-Z]+)([0-9]+)/;var oarr = re.exec(range);if(oarr.length>4){var columnStart = oarr[1];var columnEnd = oarr[3];var rowStart = parseInt(oarr[2]);var rowEnd = parseInt(oarr[4]);var columnStartValue = parseRangeToInt(columnStart);var columnEndValue = parseRangeToInt(columnEnd);for(var i = columnStartValue;i<= columnEndValue;i++){var columnName = parseIntToRange(i);for(var j = rowStart;j<=rowEnd;j++){fillEmptyCell(columnName+j,sheetIndex,notEmeptyCell,fillText);}}}}
}/*** 指定的cell及其扩展出来的单元格里面如果值为"" 则填充 “-”* @param cellAddress 需要填充“-”的、有着数据源定义的单元格* @param sheetIndex 第几个sheet,从0开始,默认0,也就是第一个sheet* @param notEmeptyCell 用来表示是否是空表的单元格,如果传入了该参数,且对应单元格里面有值则不填充,否则填充* @param fillText 为空时填充的内容,默认 "-"*/
function fillEmptyCell(cellAddress,sheetIndex,notEmeptyCell,fillText) {// 设置默认值,如果不传则默认处理第一个sheetif(!sheetIndex){sheetIndex = 0;}// 设置默认填充内容为"-"if(!fillText){fillText = "-";}// 获取sheet[0]对象var sheet = spreadsheetReport.sheets[sheetIndex]; // 获得整个sheet对象var worksheet = spreadsheetReport.workbook.worksheets.get(sheetIndex);// 获得sheet对象中所有的单元格对象,下面会根据位置获得对应的具体的单元格var cells = worksheet.cells;// 如果有传notEmptyCell参数,且单元格里面值为空,则说明是空表,不再填充对应内容if(notEmeptyCell){// 用来表示是否需要填充var isEmptyGrid = true;// 根据指定单元格获取到所有扩展出来的单元格的位置的数组var emptyCellPostions = null;try{emptyCellPostions = sheet.getExpandedPositions(notEmeptyCell);    }catch(e){return;}if(!emptyCellPostions){return;}// 遍历该位置数组for(var j = 0;j < emptyCellPostions.length; j++){// 获得当前位置var emptyCellPos = emptyCellPostions[j];// 根据位置得到具体的单元格对象var emptyCell = cells.get(emptyCellPos.row,emptyCellPos.column);// 如果该单元格不为空,则说明不是空表if(emptyCell.value){isEmptyGrid = false;break;}}// 如果是空表的话,就不再填充内容了if(isEmptyGrid){return;}}// 如果不是空表,则进行填充// 根据指定单元格获取到所有扩展出来的单元格的位置的数组var positions = sheet.getExpandedPositions(cellAddress);    for (var i = 0; i < positions.length; i++) {var pos = positions[i];//合并单元格并设置合并后的单元格的值var cell = cells.get(pos.row, pos.column);logger.debug("cell: "+cell)logger.debug("cell.value: "+cell.value)if (!cell.value || cell.value == "" || Number(cell.value) == 0) { //判断值是否为空logger.info("set")cell.value = fillText;}}
}// 做AA=>26,AB=> 27的转换
function parseRangeToInt(rangeString){var arr = getLetterArray();var result = 0;var brr = rangeString.toUpperCase().split('');for(var j = 0;j<brr.length;j++){var code = brr[brr.length-j-1];var jindex = arr.indexOf(code);if(j>0){jindex +=1;}if(jindex>-1){result += jindex * Math.pow(26,j);}}return result;
}// 获得一个从A到Z的数组,用来做索引
function getLetterArray(){var arr = [];for(var i = 1;i<27;i++){arr.push(String.fromCharCode(i+64));}return arr;
}
// 做26=>AA,27=>AB的转换
function parseIntToRange(val){var arr = getLetterArray();var str = val.toString(26);var srr = str.split('');var result = '';for(var i = 0;i < srr.length;i++){var letter = srr[i];var nv = parseInt(letter,26);if(i<srr.length-1){result+=arr[nv-1];}else{result+=arr[nv];}}return result;
}

(3).在main方法中调用该方法,这次只需要传入区域就可以了。当然了后面三个参数的用法还是和3中的用法是一样的

function main(spreadsheetReport) {// 第一个sheet中的A1:M24区域中的、有绑定数据源的单元格及其扩展出来的单元格值为空时填充“-”fillEmptyRange("A1:M24");
}

4 服务端宏 解决自动换行不会在单词中间换行的问题

  1. 服务端宏
function main(spreadsheetReport) {// 将A2单元格里面的长字符串格式化成每19个字符就插入一个硬回车符formatStringToWrapedLine("A19", 92)
}/*** 根据给定的一行可容纳字符数,来插入硬回车* @param cell 要进行格式化的单元格* @param wordsLimit 一行可以容纳的字符数,excel中就是列宽,默认1000个字符* @param sheetIndex 当前工作薄的第几个sheet,默认0,即第一个sheet*/
function formatStringToWrapedLine(cell, wordsLimit, sheetIndex) {// 用于存储for循环中每一行已累计的字符数var count = 0;// 用于拼接结果字符串var resultArr = [];// 第几个sheet,默认0,即第一个sheet页if (!sheetIndex) {sheetIndex = 0}// 每行可容纳字符数限制,默认给1000个if (!wordsLimit) {wordsLimit = 1000;}// 获得sheet页对象var sheet = spreadsheetReport.sheets[sheetIndex]// 获得指定单元格对象var cell = sheet.getCell(cell);// 单元格的值var str = cell.value;// 把原文拆成char数组var arr = str.split('');// 用于判断是否是中文的正则var reg = /[\u4e00-\u9fff]/for (var i = 0; i < arr.length; i++) {// 当前char字符var curStr = arr[i];// 当前字符个数var curLen = 1;// 一个汉字占2个字符,其他的按1个算if (reg.test(curStr)) {curLen = 2;}// 如果当前行已累计的字符数 再加上2个字符长度后 >= 每行的字符限制,则插入Excel里面的硬换行符if (count + 2 >= wordsLimit) {// 插入换行符resultArr.push(String.fromCharCode(10));resultArr.push(String.fromCharCode(13));// 拼接上本轮的字符resultArr.push(curStr);// 重置计数count = 1;} else {// 不需要换行的话就直接拼接即可resultArr.push(curStr);count += curLen;}}// 指定单元格的位置var loc = cell.cellPosition;// 向指定单元格回写格式化后的字符串sheet.setCellValue(loc.row, loc.column, resultArr.join(''));
}

SmartBI常用报表宏代码相关推荐

  1. Smartbi数据报表系统,国内性价比最高的报表工具

    ​在报表软件的实际应了通过报表展现数据,用户还经常需要利用报表来填报录入各种业务数据.例如通过销售合同表来录入新签合同,通过员工信息表来录入新进员工信息. Smartbi数据报表系统是企业报表平台的解 ...

  2. EXCEL宏代码大全

    本文件部分文章来源于网络,文章版权归原作者所有,如果本站转载的文章侵犯了您的权益请及时联系我们,我们将尽快妥善处理.本站除部分特别声明禁止转载的专稿外,其他文章可以自由转载,但请务必注明原出处和作者. ...

  3. 来,看看这20个常用的宏定义!

    关注.星标公众号,直达精彩内容 ID:技术让梦想更伟大 作者:李肖遥 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等.下面列举一些成熟软件中常用的宏定义. 1 ...

  4. NetSuite 中国财务常用报表功能包

    目录 1.致谢 2.功能说明 2.1 概述 2.2 报表说明 3.安装 4.操作指南 4.1 CLR_资产负债表 4.2 CLR_资产负债表(期初/发生/结余) 4.3 CLR_利润表 4.4 CLR ...

  5. vba代码编程800例_VBA编程常用“积木”过程代码Address的含义

    蓝字关注,加微信NZ9668获资料信息  VBA解决方案   系列丛书作者  头条百家平台 VBA资深创作者 _______________________________ 大家好,今日继续和大家分享 ...

  6. 初学者怎样看懂python代码_新手入门必看,最常用的Python代码片段

    对于编程开发人员来讲,Python语法一开始可能看起来很奇怪.如果我们看到Python使用其他编程语言(例如Java)完成常见的工作,那会不会很意思?我们常见的代码片段称为"代码惯用法&qu ...

  7. Maven 配置文件 POM 的常用插件配置代码

    Maven 配置文件 POM 的常用插件配置代码 普通 将 Maven 多模块依赖集成打进一个 JAR 包(方法 1) 将 Maven 多模块依赖集成打进一个 JAR 包(方法 2) 生成单入口类 J ...

  8. Maven 配置文件 POM 的常用依赖配置代码

    Maven 配置文件 POM 的常用依赖配置代码 Lombok 测试 Junit 5 日志 Log4j2 & SLF4J & Lombok Spring Bean Spring Boo ...

  9. 软文推荐:常用 Java 静态代码分析工具的分析与比较

    http://www.uml.org.cn/j2ee/201107114.asp 常用 Java 静态代码分析工具的分析与比较 作者:赵卓 , 发布于2011-07-11 , IBM 简介: 本文首先 ...

  10. .NET常用功能和代码[总结与收藏] (转)

    .NET常用功能和代码[总结与收藏] 1. 打开新的窗口并传送参数: 传送参数: response.write("<script>window.open('*.aspx?id=& ...

最新文章

  1. 【自然框架】稳定版的Demo——看点二:权限,权限过滤与验证。
  2. Xilinx FPGA全局时钟和第二全局时钟资源的使用方法
  3. Java的Exception和Error面试题10问10答
  4. SourceTree -- Installation has failed
  5. jyphon 环境变量配置
  6. C# VS本地Sqlserver 操作笔记
  7. java的继承实例_Java继承和多态实例
  8. ffmpeg解码器优化
  9. php论坛系统教程,国内php原创论坛
  10. rotateleft_Java Integer类rotateLeft()方法与示例
  11. 【排列组合】ZSC1076: 数学、不容易系列之三——考新郎
  12. nginx部署前端代码 负载均衡
  13. c语言大作业超市系统设计,超市管理系统(C语言课程设计报告)
  14. 射频电路设计实录前言与第一章,目标市场分析
  15. 基于python的爬虫毕业论文_基于python网络爬虫及数据处理毕业论文 相关实例(示例源码)下载 - 好例子网...
  16. Java实现对数函数图像增强
  17. 防灾科技学院考研计算机,防灾科技学院考研难吗
  18. c语言倒直角梯形,请问一下大佬们这段代码问题在哪里?
  19. VUE Element-ui 图标加载失败问题 Failed to decode downloaded font : woff ttf
  20. 绝地求生6月23号服务器维护到几点,绝地求生6月23日更新到几点 绝地求生6月23日更新内容介绍...

热门文章

  1. wordpress启动_使用Wumblr在WordPress中启动微博
  2. 基于javaweb+mysql的超市进销存管理系统(java+SpringBoot+Html+Layui+echarts+mysql)
  3. C/C++ 反编译工具开源软件
  4. 3 Idiots ——谢 阿米尔·汗
  5. 做360度评估引发员工不满?
  6. 维和医疗分队患者信息管理系统的开发与研究
  7. SSL单向认证和双向认证
  8. 搜索引擎类网站调查报告
  9. 全面解读“数字孪生”
  10. 生成条形码二维码DataMatrix条码.EAN码.39码.交叉25码.UPC码.128码.93码.ISBN码.Codabar等...