摘要:本文针对致远表单绘制工具中时间计算功能的不足,通过自定义函数提供了两种实用解决方案:一是校验明细表中同一员工的日期时间段是否重叠,避免重复上报;二是精确计算两个日期时间之间的小时差,满足特殊业务规则。文章详细说明了参数类型识别、Groovy代码实现、函数调用方法及实际效果验证,为开发者提供了可直接复用的代码示例。
在表单绘制工具中,对于时间的计算公式致远只提供了日期差和日期时间差,可以算出两个时间中间的差额。但对于时间,需要校验的场景和计算的情况很多,会存在系统校验无法满足的情况。那我们怎么在自定义函数中来做校验呢?


首先要用函数来做校验,得先知道参数类型是什么,小编之前一直以为时间控件的类型是Date类型,写完函数上了系统一直无效。后面才在去去了类型看,结果是字符串类型。。。我们可以使用getClass()方法,去取控件里数据的类型查看。
def timeType = param[0]
return timeType.getClass().name

一、校验明细表中日期是否重叠
现在有调休申请单,需要客户输入员工的加班开始日期和加班结束日期,要求同一个员工的加班时间不能报重叠(比如第一行第二行都是张三上报的加班信息,一行加班日期 8-13 — > 8-15 ,第二行8-14 — > 8-15,则重复上报加班)这种情况咋给校验呢?



首先一定得明确参数类型,如果要校验全部的明细表数据就得取明细全量数据。如果我把明细字段传入自定义函数的参数列表,得到的是什么类型的参数?我们依旧用getClass()方法看看。


可以看出明细参数是个List列表,并且开始时间、结束时间、员工编号三列都是单独的,等长的三组列表。并且根据索引一一对应。找到对应关系那这校验就好做了。
def startStrList = param[0]
def endStrList = param[1]
def personCodeList = param[2]
def parseDay = { str ->
Date.parse("yyyy-MM-dd", str).time
}
try {
def ranges = []
startStrList.eachWithIndex { s, idx ->
long sTime = parseDay(s)
long eTime = parseDay(endStrList[idx])
String userCode = personCodeList[idx]
ranges.add([
index: idx,
person: userCode,
start: sTime,
end: eTime
])
}
def overlapIndexArr = []
int len = ranges.size()
for (int i = 0; i < len; i++) {
def a = ranges[i]
for (int j = i + 1; j < len; j++) {
def b = ranges[j]
if (a.person == b.person && a.start < b.end && b.start < a.end) {
overlapIndexArr.add("(${a.person}:${a.index+1}行与${b.index+1}行)")
}
}
}
return overlapIndexArr.isEmpty() ? "0" : "请检查以下行中存在重叠日期:" + overlapIndexArr.join(" ")
} catch (Exception err) {
return err.getMessage()
}
参数:

如果要直接复制代码使用,参数顺序一定不能写错。
如果要直接复制代码使用,参数顺序一定不能写错。
日期控件传来的参数是字符串类型,如果算时间差首先得转成Date类型。Groovy 为 java.util.Date 添加了静态扩展方法:Date.parse(pattern, 字符串),这个方法等价于 new SimpleDateFormat("yyyy-MM-dd").parse(str) 方法。我们可以把它封装到一个内部闭包中方便后续调用(闭包是一段可以单独打包、可以随时调用的可执行代码块,相当于 Java 的方法,但它是变量,可以定义在方法里面,也就是内部闭包)。接收三组下标对应的数组(开始日期、结束日期、人员编码);先将日期字符串转为毫秒时间戳,封装成时间段对象;采用双层循环两两比对所有时间段,只校验同一人员,依靠区间重叠公式判断时间冲突,记录冲突行号;无重叠返回 0,存在重叠输出提示信息。
返回结果
正常填写情况:

存在重叠数据时:

二、计算两个日期时间相差多少小时
现在有这么个需求,客户公司要求出差补助规则:结束时间-开始时间满24小时算一天,按一天来报,48小时算两天且不满24小时不报。(虽然规则很不合理,但得按客户要求来做😂)
现在小编使用的版本没有小时差的公式,且日期时间差算出来结果如下

如果算成天还得再转为小时,就更麻烦了。那有函数能算出小时差吗?
有的兄弟有的 。但可能是小编技术有限或是系统限制,我只能算到一个文本控件上,再把文本控件转为数字,所以这个函数仅供参考蛤
首先加一个文本控件,函数如下:
def startStr = param[0]
def endStr = param[1]
try {
long sTime = Date.parse ("yyyy-MM-dd HH:mm",startStr).time
long eTime = Date.parse ("yyyy-MM-dd HH:mm",endStr).time
long ms = Math.abs (eTime – sTime)
def hourNum = Math.floor (ms / (1000 * 60 * 60d))
return "${hourNum} 小时"
} catch (Exception err) {
return err.getMessage ()
}

接收起止时间(yyyy‑MM‑dd HH:mm),解析成毫秒时间戳,求取时间差绝对值;换算小时之后向下取整,返回整数小时文本;不足一小时会直接舍弃,例如相差 59 分钟返回 0小时。
结果:
再加一个数字控件,用来把文本的408.0小时转为数字408
def str = param[0]
try{
if(!str) return BigDecimal.ZERO
def matcher = (str =~ /([0-9]+\\.?[0-9]*)/)
if(matcher.find()){
String numStr = matcher.group(1)
return new BigDecimal(numStr)
}
return BigDecimal.ZERO
}catch (Exception e){
return BigDecimal.ZERO
}


然后就能根据时间差来算天数了



