如何用报表工具实现树状层级结构的填报表

简介: 数据填报中,表头项如果是科目或者地区等有层级关系的维度数据,常常会希望表头能以树状形式展示,以便用户能更直观的理解填报业务,方便录入数据,点击 <a href="http://c.raqsoft.com.

需求说明
对于带有层级结构的数据中,用户为了能够更加清晰直观地查看,往往需要在数据展示时将层级展示出来,比如常见的省、市、县结构,或者一些科目中也会带有层级。通常,我们管这种形式叫做树状报表。在查询统计类报表中可以使用报表的左主格来实现,但是由于填报模型更加侧重于数据处理,格式设计上有别于查询统计报表,往往较难实现树状报表。
下面,我们通过一个层级科目的例子介绍一下在填报表中如何实现这个需求。首先,我们看一下报表展示的结果:
1

这个报表是一个按照科目录入数据的填报表,科目分不同等级,比如 1001 为第一层,下属 100101、100102,然后下边又有不同科目。展示时要求能够按层级展示。
解决方案
此类报表根据数据库中数据层级要求不同,有不同的解决方案:
一:科目固定不变
比如省、市、县,行政区域极少发生变动,针对这种固定不变的,可以制作固定的报表格式,如下图:
2

报表设计时的格式和展现格式完全一致,因此技术门槛低,但是工作量大,如果是几十个科目,就需要设计几十行,如果更多,需要耗费的时间也就更多了。并且如果万一科目发生变化,后续的维护工作也会十分不便。
二:数据库中数据已经按层级存储好
在数据库中,科目顺序以及层级等都已经按照要求存储好了,此时填报表只需要按照正常的清单格式制作即可,如下图:
3

这种方式报表开发量小,但对数据库数据有特定要求。如果数据库中新增了科目,那么数据库中的数据顺序及格式都需要调整,以满足严格要求,才能达到效果,例如不同层级的前方有相应的缩进。这时往往需要人工对数据进行维护,因此实际应用中有一定的限制性。
三:数据库中数据灵活存储,有相应层级关联关系
上述两种方式对数据自身的要求都比较严格,而且都不利于系统维护。下面这个例子应该才是大家真正关心的,也就是在对数据库数据无特殊要求的情况下,如何实现一个带层级结构的树状填报表。
当然,如果要实现层级,数据格式不能是完全杂乱无章的,比如以下数据:
4

CODE 字段存储的是科目,科目中的层级关系是:1001 这种四位的为第一层级,然后六位为第二层级,并且第二层级通过 CODE 的前四位来确定属于哪个第一层科目,第三层同样规律。这也就是说,要想实现层级结构,数据中是必须要有相应规律的。
需求实现
数据结构和层次规则确定了,接下来看看如何在填报表中实现该需求。这个需求的难点主要是如何设置层级,由于层级是动态的,单写 sql 很难实现,所以就需要借助数据处理利器:集算器。在集算器中,可以根据规律生成想要的数据格式,具体脚本如下:
5

A1:连接数据源
B1:执行 sql,从数据库中取出需要的数据
C1:按照 B1 的结果,生成一个空序表,用于存放生成的数据,该序表中有四个字段:CODE、NAME、QCYE、QMYE
A2:=B1.select(len(CODE)==4),从 B1 中取出 CODE 长度为 4 位的数据,即第一层数据。
A3:for A2,按照 A2 做循环,本例的思路就是按不同层级依次循环,然后取出下级数据拼接进去。
B4:>C1=C1|A3,C1 是之前定义的空序表,这里将 A3 的内容插入到 C1 中,A3 为每次循环的单条记录,此例中是第一层级数据
C4:=B1.select(len(CODE)==6 && left(CODE,4)==A3.CODE).run(if(CODE!=null," "+CODE):CODE),该表达式可以拆分成两步操作,select 是按照条件从 B1 中取出 CODE 长度为 6 位,并且前四位和第一层级相同的数据,即第二层。由于报表展示时,第二层前方需要缩进几个空格,所以此处在通过 run 函数,在科目前增加几个空格,并且可以增加判断,当 CODE 不为空时,也就是有子层级时再操作。这样就在 C4 里按照 A2 做循环取出了第二层。
C5:for C4,按照第二层再次做循环,要取第三层数据
D6:>C1=C1|C5,在 C1 的基础上再将 C5(第二层)插入进去,这样 C5 中就有两层数据了。
D7:=B1.select(len(CODE)==8 && left(CODE,6)==trim(C5.CODE)).run(if(CODE!=null," "+CODE):CODE)
该表达式同 C4,从 B1 中取出 CODE 长度为 8 位并且左六位为第二层 CODE 的值,也就是取出第三层数据,注意,由于第二层要设置缩进,在 C4 单元格中在 CODE 前插入了空格,所以此处条件关联时用 trim 函数去掉空格,再通过 run 函数在 CODE 前增加相应空格,具体缩进多少,增加几个空格即可。
D8:>C1=C1|D7,再将 D7 取出来的数据追加到 C1 中。
这样通过两个循环,就能够实现层级格式,此时 C1 中的结果如下:
6

NAME 字段在原数据库中已经有相应空格了,所以集算器中并没有对其做处理,如果数据库中数据没有空格,也想做缩进的话,通过 run 函数在循环中一并处理即可。
A9:>taizhang=C1.new(CODE:CODE,NAME:NAME,QCYE:QCYE,QMYE:QMYE),C1 中数据是个序列,此处通过 new 取出相应数据生成序表设置给对象 taizhang,在填报表中使用。
A10:通过 close() 函数关闭数据库连接。
将该集算器文件保存为 get.dfx 供填报表使用。
数据来源
在填报表中,设置:数据处理——数据来源,采用 DFX 文件,选择刚才保存的 get.dfx 文件:
7

填报表制作
数据都已在取数 dfx 文件中处理完毕,所以报表格式设计起来就方便很多,如下图:
8

标题、表头按照需求设置。
A3 单元格类型设置成维度格,表达式设置成:=taizhang.(CODE),字段名称设置成:taizhang.CODE
B3、C3、D3 单元格类型设置成数值格,字段名称为别设置为:NAME、QCYE、QMYE
这样报表就能够取出相应的数据进行展示,展示结果如下图:
9

数据去向
要想将数据保存回数据库,需要在数据去向中进行回写设置,此处同样可以使用 dfx 文件,脚本如下:
10

A1:连接数据源
A2:>A1.update@k(taizhang:taizhang_old,TAIZHANG,CODE:trim(CODE),NAME,QCYE,QMYE;CODE),NAME,QCYE,QMYE;CODE)),通过 update 函数向数据库中 taizhang 表回写数据,具体可参看 update 函数说明,注意:之前取出时在 CODE 前加了空格做数据缩进,所以回写时要通过 trim 函数去掉空格。
A3:=A1.error@m(),看保存过程中是否有错误
A4:>if(A3==null,A1.commit(),A1.rollback()),如果错误(A3)为空,则提交,否则回滚事务
A5:关闭数据链接。
另外,还需要在保存对象的旧对象中设置:
11

这样,就能够完成填报表的树状层级结构。
后记
通过此例可以看到,如果在集算器中对数据进行处理,事先形成层级树状结构数据,那么在报表中只需要直接使用集算器处理后的数据就行了。本例中通过科目的 CODE 位数确定层级,而在其它不同的数据结构中可能会有不同的形式,但必然会有相应的规律可循,只需要在集算器中按照相应规律整合数据。
小遗憾:这种方式灵活方便,但是报表数据扩展前在设计器中都在同一个单元格内,如果需要页面端按照层级自动计算,比如第三级数据更改后相应的第二级数据需要自动变化,这样就很难写对应的自动计算公式,but,报表展现后是可以通过 javascript 对页面中数据做处理的,所以可以在 js 中根据层级规律设置自动计算公式来实现。

目录
相关文章
|
监控 关系型数据库 Linux
|
前端开发
若依(ruoyi)前端Vue3 Element Plus Vite版样式修改
若依(ruoyi)前端Vue3 Element Plus Vite版样式修改
3143 0
|
编解码 前端开发
Element el-row el-col 布局组件详解
本文目录 1. 背景 2. 分栏布局 3. 分栏间隔 4. 分栏偏移 4. 对齐方式 5. 响应式布局 6. 小结
7593 0
Element el-row el-col 布局组件详解
|
机器学习/深度学习 缓存 NoSQL
Redis高级客户端Lettuce详解(上)
Lettuce是一个Redis的Java驱动包,初识她的时候是使用RedisTemplate的时候遇到点问题Debug到底层的一些源码,发现spring-data-redis的驱动包在某个版本之后替换为Lettuce。既然能被Spring生态所认可,Lettuce想必有过人之处,于是笔者花时间阅读她的官方文档,整理测试示例,写下这篇文章。
1830 0
Redis高级客户端Lettuce详解(上)
|
Java 数据库连接 Spring
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could
这个错误通常出现在使用Spring Boot进行数据库连接时。错误信息表明Spring Boot未能配置一个DataSource,因为没有指定'url'属性,并且没有发现默认的数据库连接。
6204 0
|
Java 关系型数据库 MySQL
数据库的连接用Java
本文介绍了如何使用Java连接MySQL数据库,包括注册JDBC驱动、创建数据库连接URL、设置数据库用户和密码、建立连接以及关闭连接的完整代码示例。
399 0
数据库的连接用Java
|
API
Vue3组件通信全解析:利用props、emit、provide/inject跨层级传递数据,expose与ref实现父子组件方法调用
Vue3组件通信全解析:利用props、emit、provide/inject跨层级传递数据,expose与ref实现父子组件方法调用
4422 0
|
JavaScript 开发者
Element UI & Element Plus之改变表格单元格颜色
这篇文章展示了如何在Element UI和Element Plus框架中使用`:cell-style`属性来根据条件改变表格单元格的颜色。
1875 0
Element UI & Element Plus之改变表格单元格颜色
|
监控 Java 调度
若依修改定时任务,定时任务在系统监控的定时任务当中,宕机情况都不会去管,涉及到定时任务
若依修改定时任务,定时任务在系统监控的定时任务当中,宕机情况都不会去管,涉及到定时任务
|
JavaScript
Vue子组件调用父组件方法并传参的5种方式:$emit触发、传入子组件function、访问父组件$parent.function、用inject关联父组件provide的方法、用window.fun
Vue子组件调用父组件方法并传参的5种方式:$emit触发、传入子组件function、访问父组件$parent.function、用inject关联父组件provide的方法、用window.fun