日历类报表可以这样实现

【摘要】

在出勤考核、生产系统的排班等业务中,日历格式的报表是最为直观呈现给使用人员的形式,以日历形式按月份展现数据、通过月份参数可动态更换月份、日期中显示相应的信息,使得这类报表展现更加灵活、直观,详情查看:日历类报表可以这样实现

数据一般都具有天然的时间属性,在很多业务中,以自然月为周期进行数据统计、分析和展示非常普遍。例如,在人事系统中查看某个月的考勤信息、销售人员查看自己或者部门的日程安排等。这些情况下,将报表以日历形式进行展示,往往具有更加直观的展示效果。

下面,我们将通过一个常见的考勤报表的制作,说明如何制作这些日历形式的报表。先看一下报表应有的展示效果:

1jpg

该报表以日历形式清晰、直观地展示了 3 月份的人员出勤情况。下面介绍下该报表的制作方法。

在润乾报表中,制作日历类报表主要的操作是通过 to 函数实现一个交叉报表扩展出对应的行列,然后在想办法找到该月第一天是周几,这样后边的日期就能依次获取,至于日历最终用于考勤还是其他业务,只需要将实际业务中的日期字段和日历中的日期对应即可,下面看下详细的操作步骤。

一、日历格式制作

实际应用中需要动态传入月份,从而实现动态日历的设置,因此先在报表中增加一个参数 rq,值表达式默认为 2018-03

2jpg

在一个自然月中,日期最多会跨六周,因此只需在单元格 A2 输入 =to(0,5),B1 单元格输入 =to(1,7),并且将 B1 单元格的扩展方向设置成横向扩展,然后将 A 列隐藏。

3jpg

这样报表展现时就会纵向扩展出 6 行,横向扩展出 7 列。

在 B2 单元格表达式中写入 =A2*7+B1, 此时报表预览结果如下:

4jpg

大家知道,每个月的第一天有可能是一周中的任何一天,以 2018-03-01 为例,该日为周四,所以日历展示时,1 号要展示在周四处,也就是上图红框中的“5”的位置(国际日历中,第一列为周日),简单来看就是将上图中的日期 -4 即可,接下来看下这个 4 是怎么动态获取的。

润乾函数中有个时间日期函数 day,通过该函数可以获取某个日期在该月中是几号,使用时可以增加 w 参数,即 day@w,可以获取某个日期是一个星期中的第几天,先用 rq+”-01”字符串拼接成一个日期格式字符串,再用 date 函数对其进行日期格式转换 date(rq+“-01”),这样 day@w(date(rq+“-01”)) 就能够获取该月 1 号是一个星期中的第几天,因为是国际日历,如果是周日则返回 1,周一则返回 2,所以如果是周四的话,day@w(date(rq+“-01”)) 返回的值是 5,要取得想要的 4 则在该值的基础上减 1 即可。

还有一种可能,如果 1 号恰好是周日的话,之前纵向扩展时是 0 到 5 扩展出了 6 行,日历中通常 1 号为周日的话是放在日历的第二行,所以要进行 1 号是否是周日的判断,如果是则在第二行显示(值 -7),最终 B2 单元格表达式为:

=A2*7+B1-if(day@w(date(rq+“-01”))==1,7,day@w(date(rq+“-01”))-1)

也就是在原有生成连续日期的基础上减去当月第一天处于该周中第几天,预览结果如下:

5jpg

可以看到 1 号目前显示在了周四的位置。

ps:day@w 函数返回日期所在该周的第几天,周日返回 1.

做为日历,第一行展示时要显示成中文,并且是从周日开始显示,在 B1 单元格显示值表达式写入:map(to(1,7),list(“星期日”,“星期一”,“星期二”,“星期三”,“星期四”,“星期五”,“星期六”))

另外,由于交叉区域扩展出来 6*7(42)个单元格,而一个月为 30 天左右,所以会有负数(上个月)以及大于当前月最大值的数。这些值在展示时是不需要的,可以通过表达式将不需要数据隐藏掉,在 B2 单元格显示值表达式中写入:if(value()<1||value()>days((date(rq+“-01”))),"",value())

A2 中扩展出 6 行数据,实际中该月可能会横跨四周到 5 周,所以同样要将不需要数据给隐藏掉,判断规则:

如果在第五行第一天的日期超过了该月天数,那么其他几天肯定也超过最大天数了,这行数据就需要隐藏,或者如果日期在扩展的第一行中,并且该行最后那天日期 <1 的话,那么该行也需要隐藏,所以在 B2 单元格隐藏行表达式中写入:if(A2>=4 and B1==1 and value()>days((date(rq+“-01”))),true,if(A2==0 and B1==7 and value()<1,true,false))

这样报表就展示成如下日历格式:

6jpg

二、考勤数据如何结合日历报表

接下来看一下考勤数据如何放到日历中显示。

考勤数据通常会有两个字段,一个为考勤日期,另一个为出勤情况,如下述数据集:

7jpg

数据集中有两列数据,rq 为考核日期,sfcq:是否出勤,1:出勤,0:缺勤

在上述制作好的报表基础上将 A2 和 A3 单元格合并,在 B3 单元格中输入表达式:=ds1.select(sfcq,day(rq)==B2)

B2 单元格为日历的天,day(rq) 含义取 rq 字段的日,这样将这个做为过滤条件就能从 ds1 数据集中取出该天的出勤情况。

展示时要展示成中文,在 B3 单元格显示值表达式中写入:if(value()==“1”,“出勤”,if(B1==1 or B1==7,"",“缺勤”)),当数据库中字段的值为 1 时代表出勤,并且当 B1 等于 1 或者 7 时,表示周末,不参与考勤评定,其余日期为空的同样算缺勤。

再调整边框样式,主要 B2、B3 单元格展示时,要将日期和出勤情况展示成一个单元格内,所以 B2 和 B3 单元格中间的边框设成不显示。

8jpg

报表展现时,为了更加醒目的显示哪些日期没有出勤,可以设置成如果缺勤则字体变成橙色展示,在 B3 单元格的前景色表达式中写入:if(value()!=“1”,-32768,-16777216),通常情况下,周末的日期以红色展示,所以在 B2 单元格前景色表达式中写入:if(B1==1 or B1==7,-65536,-16777216)。

在之前 B2 单元格隐藏行表达式中动态控制哪些行隐藏,因为报表增加了 B3 单元格,所以要在 B3 中要做同样控制,在 B3 单元格隐藏行表达式中写入:

if(A2>=4 and B1==1 and B2>days((date(rq+“-01”))),true,if(A2==0 and B1==7 and B2<1,true,false))。

报表中可增加一行用于展示当前月份信息,在报表上方插入行,将 A1、B1 合并,单元格中写入表达式:=string(date(rq+“-01”),“yyyy 年 MM”)+“月份出勤统计”

剩余进行样式调整,根据实际需要设置报表前景色、背景色、边框样式等,这样考勤报表就制作完成了。

最终报表展现结果如下:

9jpg

总结:本例中通过单元格扩展以及日期函数的使用,实现了报表的灵活定制,使之以日历形式展示,并且能够在日历中显示考勤等信息。实际应用中同样可显示其他信息,只需要将日期字段和日历中的日期做关联即可,并且该报表还可和其他报表或业务系统联动,比如日历中可显示技术部门每天处理的任务数,结合报表的超链接功能,点击任务数就能够跳转到任务列表中查看具体的任务信息,等等。
更多报表样式类问题请看:报表样式分类导航
* 按段分组报表制作
* 如何开发主从报表
* 报告式报表的制作
* 报表中如何实现不规则布局
* 报表工具轻松搞定卡片式报表