TSS 报表开发指南

一个传统的报表制作过程可能是这样的:

  • 1、报表制作人员(通常是熟悉业务的人员)提需求;
  • 2、熟悉数据库的人员打开数据库客户端(比如Oracle的客户端PLSQL),编写查询SQL语句,执行查询,导出数据到Excel文件,再交给业务人员;
  • 3、业务人员通过Excel完成数据加工分析,做成可供观看的报表,再邮件发送给管理人员;
  • 4、循环往复,日报、周报、月报、季报、年报。。。。。。

在TSS中,过程是这样:

  • 1、登录BI,新建一个报表,选定数据源,填入查询数据的SQL,生成一个数据服务;
  • 2、编写一个HTML网页,专门用做对第一步查询到的数据进行可视化展示;
  • 3、上传该网页到BI服务器,结合第一步创建的数据服务完成调试;
  • 4、为报表设置访问权限,对外开放;
  • 5、业务管理人员定期登录BI访问报表。

两相对比,第一种比较原始,需要多人参与,用到多种工具,过程多次重复,实时性、准确性、安全性等缺乏保障;第二种方式只需一个浏览器,和一个懂业务、会写SQL和做网页的数据分析员,且一次开发完成,长期可用,对管理人员来说也更方便,数据实时可见,查询方便且更安全,准确性也更有保障。 当然这只是有BI工具和没有BI工具的简单对比,市面上有众多的BI工具,下面看TSS的报表具体有哪些特色。

TSS报表可以以以下多种形式存在:

  • 是一个数据服务,由SQL语句加一组查询条件组成,可单独执行,以表格形式展现查询结果;也可作为定时邮件推送;还可作为一个数据API服务;
  • 是一个展现页面,维护一个HTML页面的链接,链接里的HTML页可调用一个或多个数据服务,读取数据后生成图表展示;
  • 是一个可编辑数据表,指向一个数据表,可打开此数据表进行数据录入、修改、删除等操作。数据表的详细介绍参考下一章《数据表》。


新建报表

报表分组

报表分组的作用是对多个报表进行分类,方便查找,避免单一目录下报表数量过多。

  • 1、进入'报表管理’,鼠标右键点击“全部”节点或已经存在的分组,选择【新建分组】,填写分组名称(必填)、描述;
  • 2、点击[完成],系统提示操作成功,此时可以在左边树上看到新增的分组节点
属于同一分组的报表,操作组的时候会作用到其下的所有报表及子组,便于统一管理,比如启用/停用、导入/导出、权限设置、移动删除等。

基本信息

右键点击报表分组,选择【新增报表(服务)】。

  • 报表名称:为必填字段;报入表ID:保存时自动生成,无需填写。
  • 数据源:选择报表访问数据所在的数据源。数据源维护操作参照《管理数据源》,点击【管理数据源】可以打开数据源管理界面。
  • 记录访问日志:选择是,报表里SQL每一次执行都会记录日志,日志信息包括访问人信息、访问时间、运行时长等,对于有需要统计访问量的报表,应该记录日志。可以对报表进行分析,比如:访问人员分布、访问时段分布、报表执行性能等,参考《量能监控》

查询脚本

查询脚本可以是一个可运行的SELECT SQL语句,但也不只是SQL,其内容格式支持Freemarker模板引擎,可以根据传递过来的不同查询条件及当前登录的用户、组织、角色等信息,来动态的解析生成最终可被执行的SQL语句,起到控制查询逻辑,及过滤数据(即控制数据行级权限)的作用。

通常,直接把通过测试运行的SQL复制过来即可,需注意select出来字段的别名不能有重名,否则在分页查询时会出错。查询脚本可以和查询条件有机组合使用,以满足不同的查询需求。
下面以具体例子来演示,先看看可以用做过滤数据用户信息(更多参考:登录用户会话信息)有哪些:假设某用户账号为XX00123,所属组织架构为:X物流公司/ 浙江分公司/ 杭州分拨,拥有角色:分拨经理。

名称               类型         值         说明
userCode          String      XX00123     用户账号
userName          String      金石        用户名称
userRoles         List        [12]        用户拥有的角色ID列表; _userRoles 逗号分隔的字符串
userRoleNames     List        [分拨经理]   用户拥有的角色ID列表; _userRoleNames 逗号分隔字符串
userGroup         String      杭州分拨     用户所在组 

现在假设有一张表(tbl_kq),记录了所有分拨层级员工的考勤信息,字段包括:
staff(考勤员工), group(所属组织), worktime(工作时长) , workday(工作日), creator(录入人)
1、统计每天的考勤人数
Select t.workday 工作日, count(distinct t.staff) 考勤人数 from tbl_kq t  group by t.workday
2、分拨经理查看本分拨员工考勤日报
Select t.workday 工作日, count(distinct t.staff) 考勤人数
  from tbl_kq t 
  where t.group = '${userGroup}'          -- 数据只看本分拨
    and <#if 分拨经理??> 1=1 <#else> 1=0 </#if>  -- 要求查询人拥有【分拨经理】角色,没有则无法查看
  group by t.workday
3、总公司的薪资人员可以按不同查询条件查询考勤数据,具体查询条件有:param1(日期从) 、param2(日期到)、param3(员工)
<#if param3??>  -- 如果查询条件param3(员工)不为空,则查该员工考勤明细
  Select  t.staff 员工, t.workday 工作日,  sum(t.worktime) 工作时长
  from tbl_kq t 
  where t.staff = '${ param3}' and t.workday >= ${param1} and t.workday <= ${param2}
  group by t.workday
<#else> -- 查汇总数据
  Select t.workday 工作日,  t.group 分拨, count(distinct t.staff) 考勤人数,  sum(worktime) 工作时长
  from tbl_kq t 
  where  t.workday >= ${param1} and t.workday <= ${param2}
  group by t.workday, t.group
</#if>
4、匹配条件直接用通配符: ?
Select t.workday 工作日,  t.group 分拨, count(distinct t.staff) 考勤人数,  sum(worktime) 工作时长
  from tbl_kq t 
  where t.workday >= ? and t.workday <= ? and t.staff = ?    --  ?号的顺序与param1(日期从) 、param2(日期到)、param3(员工)编号一致
  group by t.workday, t.group
Freemarker模板引擎参考Freemarker常用写法,更多请谷歌百度。

查询条件配置

报表通常要支持不同的查询条件,以查询不同时间空间范围里数据。TSS支持在线配置参数,配置好的参数可以和报表查询脚本无缝组合,联合起来查询各种报表。为能更方便的配置参数,TSS设计了以下参数定义编辑器: 点击“报表参数”下方的【配置】按钮,即可弹出上面编辑器,右键点击“查询参数列表”,选【新建参数】即可开始开始定义新参数,完成后“参数参数列表”下方的列表里会多出一个节点项,如需要修改,直接鼠标单击要修改的节点。下表将逐个解释参数定义编辑器里属性的作用:

属性 说明 备注
参数名称 显示在网页表格或表单的标签位置
参数编码 支持自定义查询编码,默认为param1、param2……
参数类型 目前支持的类型有:字符串、数字、日期、日期时间、隐藏,隐藏字段用来存放一些固定的条件。默认为“字符串。 日期和日期时间,界面输入框为时间选择器。其中日期类型的默认值支持相对写法,today-n,n为数字,表示今天往前n天。
是否必填 选是,则参数要求必填,参数输入框后面会出现一个红色的星号
默认值 打开查询表单查询时,参数输入框默认显示该值 建议:对于必填的参数,设置一个默认值,可以引导使用者如何正确填写参数。
校验正则 对输入参数值有要求的字段,可以通过定制一个JS的正则表达式,对值进行校验,比如电子邮件等;校验不通过的,输入框下方将会出现提示气泡,提醒用户改正
出错提示 结合上面的正则校验,在提示气泡显示个性化的内容
宽度、高度 定义查询参数输入框的高和宽,如右边效果图显示,每个条件输入框,都可以有不同的宽度和高度。注:通常只正对字段类型为“字符串”的字段。
下拉列表 输入固定字段信息时,需要从列表中选择。列表的选项如果是固定的,可以直接在定义里输入,格式如:1|2,A|B,显示的是A、B选项,选中的值为1、2; 如果列表选项非固定,而是来自某种数据配置表,则需要通过数据服务从数据库里把列表数据取出来,需要事先在报表模块里建立一个数据服务。注:select字段的别名要求为id|value|code、name|text
是否多选 上面下拉列表默认是单选,如果需要多选,则此处打勾,效果见右边截图。
联动方法 当下拉选择是多级时,比如省、市、区,此时需要在不同的下拉列表间进行联动,这里的联动方法,是指当前下拉列表选择完成后,自动触发方法加载下一级联动下拉列表,联动方法可以自行在页面控制脚本里定义,也可以使用通用的联动方法getNextLevelOption getNextLevelOption(^param2^,718,^param1^) loc:下一级联动的参数编码 718:下一级联动对应的数据服务ID param1:该数据服务需要接受一个名为param1的参数,此参数值即为上一级值

最后,所有参数定义完成后,不要忘记点编辑器左下角的【完成编辑】,点完成后定义内容才会输出到“报表参数”这个编辑框,参数定义编辑器也自动关闭。可以反复点“报表参数”下方的【配置】按钮,来打开参数定义编辑器进行编辑。 删除参数用右键点击要删除的参数,然后点【删除】。也可以直接在“报表参数”的文本内容里直接删除该参数对应的配置行。

访问权限设置

报表(或分组)创建完成正式启用后,还需要把权限开放给特定的角色。右键选中新建的报表节点,点击【授予角色】,打开把报表授给角色的界面,出来一个二维授权矩阵图,左侧列表是系统的角色列表,矩阵的顶部维度是“报表”资源的“权限操作项”,如果需要把当前数据表的部分操作权限授给特定角色,在它们交汇的勾选框里打上勾即可,如果要取消授权,则在已勾选的框再次点击一下,即可去掉勾,完成后点击【保存授权】,界面会刷新出最新的授权结果。 注:因报表是和报表分组组成的一个树形组织结构,为了保证树结构的完整性,对报表分组也同样需要进行授予角色操作,报表分组的“查看报表”权限授给和报表一样的角色。 如授权比较混乱,需要重新梳理,可以点【清除已授权限】,即可清除该报表资源的所有授权信息,然后重新开始勾选授权。

报表权限项分为: 查看报表、维护报表、删除报表、停用|启用:

  • 拥有“查看报表”权限的,可以打开报表进行数据查询,对于普通用户,只开放此项权限即可;
  • 拥有”维护报表“权限的,可以编辑报表的定义、移动报表至其它分组、授予角色;
  • 拥有“删除报表”权限的,可以删除报表(分组);
  • 拥有“停用|启用”权限的,可以对报表进行停用或启用操作;

报表维护

停用|启用报表(组)

停用后的报表将从用户的可见报表清单里消失,但如果报表是一个数据服务,仍可继续被第三方访问。另外报表的开发维护人员可以继续编辑并调试报表。
  • 停用分组时,其所有子组也同时被停用,包括组下的报表;
  • 启用报表(组)时,其所在分组也同时被启用(如果所在分组也是停用状态的话);
  • 在停用状态的分组下新增子分组或新增报表时,新增节点也是停用状态;
  • 在启用状态的分组下新增子分组或新增报表时,新增节点也是启用状态;
  • 停用后的报表将无法在用户的报表树上不显示,但在“报表管理”页面里显示,但颜色图标和字体的颜色表灰色;

移动报表(组)

报表及分组可以进行移动,移动到其它分组下。
注:如果目标组是被停用的组,移动过去的子组或报表也将被停用。如果目标组是启用状态,则被移动的节点保持移动前的状态不变。

删除报表(组)

右键点击需要删除的节点,选择【删除】;系统将提示是否删除,选择[是],提示删除成功后节点从树上消失,如节点是分组,则组下所有子组及报表将一起被删除。
注:删除操作不可逆,千万小心,优先使用【停用】功能替代。停用后移动到“回收站”目录。

报表定义的导出与导入

报表和数据表,都支持导入导出,这样可以方便将开发好的报表从一个环境复制到另一个环境(比如从开发测试环境复制到正式环境)。导出时,可以单个报表导出,也可以导出整个分组下的所有报表。

  • 1、右键点击需要导出的报表或分组,选择【导出报表定义】;
  • 2、下载导出文件到本地;
  • 3、在目标环境右键点击分组(或“全部”节点),选择【导入报表定义】;
  • 4、系统弹出一个“数据源”选择界面,选择一个,然后点“确定”;
  • 5、系统提示导入成功,刷新左侧资源树,可以看到新导入进来的报表。
注:如果导入的是报表分组,则要求分组下的所有报表对应的数据源是同一个。如有不相同的,则需要在导入成功后将数据源不正确的报表逐个修改成正确的数据源。

设置数据缓存策略

数据服务的查询请求发送到BI服务器后,会被转发到数据库端运行,完成后返回结果给应用服务器,应用服务器再把数据发布成功JSON格式传递给报表页面。这其中有些服务的数据很多报表都可能用到,而且频次很高,如果反复被发送到数据库去查询,造成资源浪费。针对这类情况,可以在应用服务器端对数据进行缓存。

报表数据通常对实时性要求不高,延后几分钟一般感觉不出来。TSS设置了多档时长的数据缓存策略,默认对数据采取3分钟缓存策略(以数据服务的地址及查询条件做Key进行缓存),即一份数据被查询到应用服务器后,它会在应用服务器的缓存里上存活3分钟,这3分钟内如果再有相同查询条件的请求过来,则直接从缓存里获取该数据,不用再从数据库里查询一边。而3分钟后,数据被销毁,此后再有新请求过来,会重新获取一份最新的数据,继续缓存3分钟,循环往复。如此可以为数据库挡掉很多查询请求,而用户也能更快的从缓存中获取到数据。可以通过查看系统《缓存管理》模块里数据缓存池的命中率来评估缓存策略是否有效,及如何调整。

数据缓存后被后面请求命中需要满足条件:它们查询的是同一个数据服务且参数条件完全一致。如果参数有不一样,那就是两份不同的数据。所以BI对每个数据服务默认是针对参数条件进行缓存。但有些情形下,就算条件一致,不同的人查询出来的结果却可能不一样。这种情形下,需要对数据按【用户+参数】进行缓存,这类数据服务在发送请求时,需要多传递一个参数uCache='true'。第三种情形是对数据有实时性要求,希望每次获取的数据都是最新的,这种情况就不宜再使用缓存了。请求时,需要多传递一个参数noCache='true'。


数据服务&可视化

默认展示

新建好一个带报表脚本的报表后,它就已经具备获取数据的能力,TSS提供了一个默认的Grid表格展示页,双击报表节点,打开查询条件框,输入条件点击【查询】,显示如下图。数据是分页显示的,一页50行,滚动条滚动到底部时,会自动加载下一页,也可以使用右上角的翻页按钮逐页查看,可以导出查询结果到Excel。

数据服务

一个带报表脚本的报表,其数据可以查询展示成Grid表格,也可以导出成Excel,同时它也是一个独立的数据服务(或者叫API接口,报表节点右键菜单里【测试数据服务】专门用测数据服务),在BI系统里的HTML页面、BI外其它系统,被授权后,即可以通过访问报表数据服务获取数据。

HTML页面通过JS AJAX访问报表数据服务的方式有两种JSON和JSONP,前者JSON用在单一BI系统访问,后者JSONP可用在多个BI系统并存时,相互之间的跨域访问。跨域访问,除了JSONP之外,也可以使用后台语言(JAVA等)发请求到BI系统,进行访问。

数据服务调用更多详细的说明参考: TSS API接口

定制HTML5展示模板

除了上面默认展示及导出两种查看数据方式外,TSS还支持自定义基于HTML5编写的展示模板。HTML5网页里可以方便的通过AJAX请求获取一个或多个数据服务的数据,然后进行集中加工处理分析,最终结果在图表控件(Echarts、EasyUI等任选)里展示出来。TSS默认集成了Echarts(2、3版本)、EasyUI(1.5.2)等可视化组件,如果需要使用其它的组件,直接把组件包上传到BI环境下,然后即可引用。

定制好的展示HTML5页面及其额外所需的组件包(JS、CSS、图片等),都可以通过【TSS资源上传模块】上传到BI服务器。点击【上传附件】, 弹出资源上传界面完成上传后,再点【选择页面】,将刚上传的展示模板页面选中。设置完展示页面后,再次查询报表展现的将是设定的定制页面。

当定制页面只需要访问一个数据服务时,可直接把SQL和HTML5页放在一个报表里,打开报表前会先去执行SQL查询,获取到的数据放在框架页(reporter.html或report_portlet.html)的全局变量里globalValiable.data,定制页面且嵌在框架页的iframe里,可以通过parent.globalValiable.data的方式获取到已查询到的数据。查询参数同时存在globalValiable.queryParams里,定制页里可以获取这些参数,然后发送新的查询请求。可在定制页里这么写:

var globalValiable = window.parent.globalValiable, data,  params;
if(globalValiable && globalValiable.queryParams) {
    params = globalValiable.queryParams;
    data = globalValiable.data;
}
当定制页面需要访问多个数据服务,此时,定制页面所在的报表只能写一个报表脚本,这种情形可以考虑把数据服务和定制页面分离开,即先创建多个数据服务,再由定制页面自主发送请求去获取各个数据服务的数据。页面里如何获取数据参考如下:
var data1, data2, data3, data4, params = {};

URL_DATA_1 = '/tss/api/json/100';
URL_DATA_2 = '/tss/api/json/101';
URL_DATA_3 = '/tss/api/json/102'; 
URL_DATA_4 = '/tss/api/json/103'; 

// 发送数据请求一
$.getJSON(URL_DATA_1, params, function(data) {
        data1 = data;
        params = data1[0];

        /* 发送数据请求二 (注意: 请求二是在请求一响应成功并返回数据后才发送)
         * 这种场景适合:当请求二需要以请求一的返回数据作为其参数条件时
         */
        $.getJSON(URL_DATA_2, params, function(data) {
          data2 = data;
          show2(data1, data2);
        });  
    }
});

// 发送数据请求三 
$.getJSON(URL_DATA_3, params, function(data) {
  data3 = data;
  data3 && data4 && show34(); // show34方法需要等请求三和请求四都成功返回数据后才执行
}); 
// 发送数据请求四(注意: 请求三是和请求四并行发送)
$.getJSON(URL_DATA_4, params, function(data) {
  data4 = data;
  data3 && data4 && show34(); // show34方法需要等请求三和请求四都成功返回数据后才执行
});  

不同于市面上很多报表BI类软件强调的拖拽式开发报表,TSS侧重于为开发者提供服务,允许开发者完全自主去定制任意形式的可视化效果,开发者使用合适的图表控件(Echarts、D3、HighCharts、EasyUI等),结合TSS的后端能力,可以做出不受任何限制的报表,只需要开发者有一定JS代码基础。我们的案例库里也提供了多种模板供开发者借鉴参考。

通用查询条件

通常用户访问报表的方式是找到相应的功能报表目录,打开输入查询条件然后查询,然后再打开下一个报表再输入条件查询,当报表个数不多且各自查询条件迥异时,这种从功能打开报表的行为比较合理。

当有很多类似查询条件的报表,分别查询各个不同的指标分析(比如一个物流公司有货量指标、营收指标、质量指标等),此时如果还用上面方式就很痛苦了:当希望横向对比一下某几个指标的趋势时,需要多次打开多个报表,逐个输入相同的查询条件。这时如果可以先设定条件,然后再逐个打开各个指标报表,这些报表自动复用开始设定的查询条件,这样指标间来回切换则会很方便。而且各个报表页始终共享一份参数条件,参数条件发生改变,刷新各个页面即自动更新数据。

我们姑且称第一种为纵向打开,第二种为横向打开,横向打开要求各个报表页从一个统一的查询界面获取查询条件。TSS里,通过报表框架页report_portlet.html打开报表时,每个报表可以设置是否需要使用通用查询条件(默认使用 more/bi_condition.html),且可以单独指定通用查询条件页面地址。通用查询条件界面效果如下图: 右边为固定的时间条件,比较通用,左侧为具体业务所需的空间分布类查询条件,最多支持六个维度。通用查询条件里的条件不是越多越好,相对生僻不通用的条件可以单独放在报表页内,然后组合通用条件及自身特有的条件完成数据查询。

单个报表如需引用通用查询条件框里的值,则需要在设置报表自身的“参数配置”时引入,写法如: 此处表示“开始日期”这个查询条件,优先使用通用查询框里的“日期从”的值,即_day1,如果_day1没有值,则默认使用 today-30。_day2是“日期到”的值。周、月、季度、年的从和到的值写法分别为 _week1|_week2、_month1|_month2、_season|_season2、_year1|_year2,左侧空间组织类从上到下分别为 _g1、_g2、_g3、_g4……。也可以在发起AJAX请求时,直接读取通用查询框里的条件值(存在Cookie里),如:tssJS.Cookie.getValue(“_day1”)。

移动端展示

TSS支持在移动端录入和展示数据,开发好的数据报表可直接在移动端展示(目前支持HTML5和微信小程序)。将配置项【移动端浏览】设置为“支持”,则报表自动在移动端(小程序或H5)的报表目录里展示。
如需定制开发移动端,基本开发方式和开发一个PC端展示的报表定制页类似,具体示例参考 mobile 目录下的例子。

集成到其它模块(系统)

通过页面report_portlet.html,TSS的报表支持从邮件、文章、菜单链接、第三方系统等各类入口快速打开,且可设置默认打开的查询条件,示例如下:
http://www.boubei.com/tss/modules/dm/report_portlet.html?id=501& param1=today-10
其中id为报表的ID,param1为打开初始参数。考虑到系统迁移,报表ID可能会变化,可使用报表的编码替代ID来打开:
http://www.boubei.com/tss/modules/dm/report_portlet.html?rpcode=reportxxx& param1=today-10

可选参数refresh,如果打开的报表是个看板,此参数可支持自动刷新看板,单位(分钟)
http://www.boubei.com/tss/modules/dm/report_portlet.html?rpName=报表名称& param1=today-10&refresh=3

数据表兼顾展示和录入功能,某种程度上也是一个报表(录入型报表),所以在组织报表的目录结构时,可以考虑把录入型报表也放在报表的目录里展示,实现目录的统一。右键点击报表分组,选择按钮【新增录入表链接】,选择相应的数据表。这样当这个报表菜单被打开时,会自动切换到数据录入页。
注:需要额外多做一次授权,把录入页的链接的查看权限授予相应角色。


数据分发共享

报表开发完成后,除了用户主动登陆BI进行访问外,也可以由系统或用户主动把数据推送给其它用户。TSS目前支持多种数据分发和共享方式。

邮件推送

  • 1、右键点击报表,选择【定时邮件推送】,弹出定时邮件配置界面;
  • 2、输入定时规则,可以按小时/天/周/月触发,默认是每天12点推送;
  • 3、输入收件人(可以是Email地址、BI账号、角色、用户组,后三个要求用户信息里已经维护了Email信息),
    示例:boubei@163.com,XL00618,12@tssRole,13@tssGroup。12为角色ID,13为组ID。
  • 4、输入参数,时间类的条件通常输入一个相对时间,比如today-30到today-0 表示时间范围为今日0点往前30天时间;
  • 5、点【保存推送】,提示操作成功,邮件推送设置完成;
  • 6、需要取消,点【取消推送】,提示取消成功。
设置了邮件推送的报表,可以被用户主动订阅,订阅操作参考下一节《报表订阅》。 注:要开启邮件推送,需要自行准备邮件服务器,参考《邮件服务器设置》

报表订阅

  • 1、在报表框架页的右侧竖条工具栏里,选择点击【订阅报表】,弹出订阅界面
  • 2、输入定时规则、收件人(可以为别人订阅)、参数信息等
  • 3、点【订阅】,提示订阅成功
  • 4、如要退订,从新打开订阅界面后,点【退订】,提示退订成功

分享报表到数据门户

  • 1、在报表框架页的右侧竖条工具栏里,选择点击【分享数据】图标,弹出分享提示;
  • 2、点【确认】,系统跳转到到“文章栏目”管理页面;
  • 3、新建一篇分享文章,并发布到门户里,具体操作参考《TSS管理员手册》之《新建文章》及《发布文章》。
当报表数据以及发布者的观点在文章里被发布到门户里后,其它人登陆BI时,将可以直接浏览到,并可以留言发表观点,在线进行讨论。

收藏报表

对于访问频次高的报表,可以加入到收藏夹,后续使用直接从收藏夹打开报表。操作如下:

  • 1、 在报表框架页的右侧竖条工具栏里,选择点击【+】号,提示收藏成功;
  • 2、 在收藏列表里可以看到当前已经收藏的报表列表;
  • 3、 取消收藏,点【-】号,提示取消成功;报表从收藏列表里移除。

点赞/差评报表、反馈异常

可以点击右侧工具栏里的点赞/差评按钮对某个功能进行评价。
当使用者在浏览报表的过程中发现报表数据有异常、或者有更好的改进建议,可以进行异常反馈。管理员可以看到使用者对当前报表的反馈意见,进而完善报表。