E9利用layui实现流程超时表格
效果图:
使用:
● 引入layui
● 引入后端代码(在后面,两个类)
● 引入页面(在后面,要修改引入JS、CSS路径)
● 页面放在服务eclogy下,直接:ip:端口/页面名称.html即可访问
1、 后端,用泛微的原生JAR实现。
2、 页面,HTML+layui+jQuery
1、 后端逻辑:
■ 接收参数:page(当前页)、limit(每页显示数)、workflowid(动态ID,可匹配任意流程); 目前只有这三个参数,后期如要增加根据日期,人员,部分等条件搜索,需自行实现。
■ 获取分页数据逻辑,先找出requestid ,再根据requestid找出所有审批意见,然后根据requestid分组,因为一个requestid就是一个流程,下面有很多审批意见(包含提交、转办、提交等状态);然后办理人就是这些节点经手人的汇总,停留天数就是这些状态节点最长的哪一个(剔除周末)
后端接口返回json示例:
2、 页面逻辑
目前页面还不能根据wfid适配,只能根据特定wfid去做自定义。
主要是改
url
,where: {workflowid:"2869"}
以及,cols: [[
这三处需要自己修改。
后端代码:
ReportAction
package com.api.http.web; import com.alibaba.fastjson.JSONObject; import com.engine.u9integration.util.LogUtil; import org.apache.commons.lang3.StringUtils; import weaver.conn.RecordSet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import java.io.IOException; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import weaver.hrm.HrmUserVarify; import weaver.hrm.User; import static com.HttpUtils.FormatUtils.getJsonStringFromRequest; @Path("/http/ ") public class ReportAction { @POST @Path("/getWFOvertimeData") @Produces({"application/json"}) public String getWFOvertimeData(@Context HttpServletRequest var1, @Context HttpServletResponse var2) throws IOException { User user = HrmUserVarify.getUser (var1 , var2) ; if (user==null){ return toResponseInfo("-1", "0", "没有登录", "失败","").toString(); } var2.setContentType("application/json; charset=utf-8"); String workflowInfo = getJsonStringFromRequest(var1); LogUtil.log("sap","sap").info("ReportAction:"+workflowInfo.toString()); JSONObject datas = JSONObject.parseObject(workflowInfo); String workflowid = datas.getString("workflowid"); String currentPage = datas.getString("page"); String pageSize = datas.getString("limit"); if (StringUtils.isBlank(workflowid) || StringUtils.isBlank(currentPage) || StringUtils.isBlank(pageSize)){ return toResponseInfo("-1", "0", "分页参数为空", "失败","").toString(); } Integer pageNum = (Integer.parseInt(currentPage)-1) * Integer.parseInt(pageSize); RecordSet rs = new RecordSet(); String pagingsql = "select top "+pageSize+" * from (select DISTINCT a.requestid from workflow_currentoperator a ,workflow_nodebase b, hrmresource c where a.nodeid = b.id and a.userid = c.id and a.workflowid = " +workflowid+ ") a where a.requestid not in (select top "+pageNum+" requestid from (select DISTINCT a.requestid from workflow_currentoperator a ,workflow_nodebase b, hrmresource c where a.nodeid = b.id and a.userid = c.id and a.workflowid = " +workflowid+ ") b ) ORDER BY a.requestid"; rs.execute(pagingsql); StringBuffer stringBuffer = new StringBuffer(); while (rs.next()) { stringBuffer.append(rs.getString("requestid")+","); } stringBuffer.deleteCharAt(stringBuffer.length()-1); String searchCurrentoperatorByWFid = "select a.isremark,a.requestid,a.userid,c.lastname,a.workflowid,a.nodeid,b.nodename,a.receivedate,a.receivetime,a.islasttimes,a.operatedate,a.operatetime from workflow_currentoperator a ," + "workflow_nodebase b, hrmresource c where a.nodeid = b.id and a.userid = c.id and a.workflowid = "+workflowid+" and a.requestid in ("+stringBuffer.toString()+")"; rs.execute(searchCurrentoperatorByWFid); List<Map> list = new ArrayList<Map>(); while (rs.next()) { HashMap<Object, Object> map = new HashMap<>(); map.put("isremark",rs.getString("isremark")); map.put("requestid",rs.getString("requestid")); map.put("userid",rs.getString("userid")); map.put("lastname",rs.getString("lastname")); map.put("workflowid",rs.getString("workflowid")); map.put("nodeid",rs.getString("nodeid")); map.put("nodename",rs.getString("nodename")); map.put("receivedate",rs.getString("receivedate")); map.put("receivetime",rs.getString("receivetime")); map.put("islasttimes",rs.getString("islasttimes")); map.put("operatedate",rs.getString("operatedate")); map.put("operatetime",rs.getString("operatetime")); list.add(map); } Map<String, List<Map>> map = list.stream().collect(Collectors.groupingBy(item -> { return (String) item.get("requestid"); })); //2- 根据wfid找到对应的节点 //找出所有的nodeid ,根据nodeid 大小排序。 workflow_flownode a , workflow_nodebase b String searchDetailNodeByWFid = "select nodeorder,b.nodename,nodeid,b.isstart from workflow_flownode a , workflow_nodebase b where workflowid = "+workflowid+" and a.nodeid=b.id"; rs.execute(searchDetailNodeByWFid); List<Map> detailNode = new ArrayList<Map>(); while (rs.next()) { HashMap<Object, Object> map1 = new HashMap<>(); map1.put("nodeorder",rs.getString("nodeorder")); map1.put("nodename",rs.getString("nodename")); map1.put("nodeid",rs.getString("nodeid")); map1.put("isstart",rs.getString("isstart")); detailNode.add(map1); } ArrayList<Map> objects = new ArrayList<>(); for(String requestid:map.keySet()){ HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("requestid",requestid); List<Map> lists = map.get(requestid); for (Map map1 : detailNode){ String map1nodeid = (String)map1.get("nodeid"); String map1nodename = (String)map1.get("nodename"); objectObjectHashMap.put("nodeid-"+map1nodeid,map1nodeid); objectObjectHashMap.put("nodename-"+map1nodeid,map1nodename); String blr = ""; long diff = 0; for (Map map2 : lists){ String map2nodeid = (String)map2.get("nodeid"); String map2lastname = (String)map2.get("lastname"); String map2receivedate = (String)map2.get("receivedate"); String map2operatedate = (String)map2.get("operatedate"); if(map1nodeid.equals(map2nodeid)){ blr=blr+(map2lastname+";"); if(StringUtils.isNotBlank(map2receivedate) && StringUtils.isNotBlank(map2operatedate)){ LocalDate parse1_ = LocalDate.parse(map2receivedate); LocalDate parse2_ = LocalDate.parse(map2operatedate); // long between_ = ChronoUnit.DAYS.between(parse1_, parse2_); long between_ = getWorkDayDiff(parse1_,parse2_); if(between_>diff){ diff = between_; } } if(StringUtils.isNotBlank(map2receivedate) && StringUtils.isBlank(map2operatedate)){ LocalDate parse1_ = LocalDate.parse(map2receivedate); String map2operatedate_ = (String) LocalDate.now().toString(); LocalDate parse2_ = LocalDate.parse(map2operatedate_); // long between_ = ChronoUnit.DAYS.between(parse1_, parse2_); long between_ = getWorkDayDiff(parse1_,parse2_); if(between_>diff){ diff = between_; } } } } objectObjectHashMap.put("nodeblr-"+map1nodeid,blr); objectObjectHashMap.put("nodediff-"+map1nodeid,diff); } objects.add(objectObjectHashMap); } String conutsql = "select count(DISTINCT a.requestid) as ct from workflow_currentoperator a ,workflow_nodebase b, hrmresource c where a.nodeid = b.id and a.userid = c.id and a.workflowid = "+workflowid; rs.execute(conutsql); rs.next(); String count = rs.getString("ct"); return toResponseInfo(count, "0", "修改流程成功!", "成功",objects).toJSONString(); } //接口返回信息 指定为SAP返回构造 private JSONObject toResponseInfo(String count, String code, String errNo, String Msg,Object data) { JSONObject ResponseInfo = new JSONObject(); ResponseInfo.put("count", count); ResponseInfo.put("code", code); ResponseInfo.put("errNo", errNo); ResponseInfo.put("Msg", Msg); ResponseInfo.put("data", data); return ResponseInfo; } private static int getWorkDayDiff(LocalDate startDate, LocalDate endDate){ int workingDays = 0; while (!startDate.isAfter(endDate)) { if (startDate.getDayOfWeek() != DayOfWeek.SATURDAY && startDate.getDayOfWeek() != DayOfWeek.SUNDAY) { // 排除周末 workingDays++; } startDate = startDate.plus(1, ChronoUnit.DAYS); // 日期加1天 } return workingDays; } public static void main(String[] args) { LocalDate parse1 = LocalDate.parse("2023-09-01"); LocalDate parse2 = LocalDate.parse("2023-09-01"); getWorkDayDiff(parse1,parse2); System.out.println(getWorkDayDiff(parse1,parse2)); } }
FormatUtils
package com.HttpUtils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; public class FormatUtils { public static String getJsonStringFromRequest(HttpServletRequest request) throws IOException { StringBuffer sb = new StringBuffer(); InputStream is = request.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "UTF-8"); BufferedReader br = new BufferedReader(isr); String s = ""; while ((s = br.readLine()) != null) { sb.append(s); } String str = sb.toString(); return str; } public String Replacestr(String str) { boolean status = str.contains("<p>"); if (status) { try { String str1 = str.replace("<p>", ""); return str1.replace("</p>", ""); } catch (Exception E) { return str; } } return str; } public Map<String, String> getAllRequestParam(HttpServletRequest request) { Map<String, String> res = new HashMap(); Enumeration<?> temp = request.getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String)temp.nextElement(); String value = request.getParameter(en); res.put(en, value); } } return res; } }
页面代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Layui</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta http-equiv="Access-Control-Allow-Origin" content="*"> <link rel="stylesheet" href="/js/layui-v2.8.13/layui/css/layui.css" media="all"> <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 --> </head> <body> <table class="layui-hide" id="test"></table> <script src="/js/layui-v2.8.13/layui/layui.js" charset="utf-8"></script> <script src="/js/jquery/jquery-1.4.2.min_wev8.js" charset="utf-8"></script> <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 --> <script> layui.use(['table', 'laydate'], function(){ var table = layui.table ,laydate = layui.laydate; //监听行工具事件 table.on('toolbar(test)', function(obj){ var data = obj.data; //console.log(obj) if(obj.event === 'del'){ layer.confirm('真的删除行么', function(index){ }); } else if(obj.event === 'query'){ console.log("1233") }else if(obj.event === 'export'){ /*alert('2333') $("#btnExport").click(function () { $.ajax({ type: "POST", url: "http://ip:8090/api/http/report/getWFOvertimeData", data: JSON.stringify({page:1,limit:10000, workflowid:"2869" }), contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { table.exportFile(data.data, 'xls'); //默认导出 csv,也可以为:xls }, error: function() { console.log("error"); } }); alert("123213") }) */ alert("123213") } }); table.render({ elem: '#test' ,id: 'idTest' ,toolbar: '#toolbarDemo' ,url: 'http://ip:8090/api/http/report/getWFOvertimeData' ,where: {workflowid:"2869"} ,method: 'post' ,contentType: 'application/json' ,parseData: function(res){ //res 即为原始返回的数据 return { "code": 0, //解析接口状态 "msg": res.Msg, //解析提示文本 "count": res.count, //解析数据长度 "data": res.data //解析数据列表 }; } ,cols: [[ {field:'requestid', width:120, title: 'requestid', sort: true} ,{field:'nodename-12713', width:120, title: '节点名称'} ,{field:'nodeblr-12713', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12713', width:120, title: '节点停留天数'} ,{field:'nodename-12714', width:120, title: '节点名称'} ,{field:'nodeblr-12714', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12714', width:120, title: '节点停留天数'} ,{field:'nodename-12716', width:120, title: '节点名称'} ,{field:'nodeblr-12716', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12716', width:120, title: '节点停留天数'} ,{field:'nodename-12717', width:120, title: '节点名称'} ,{field:'nodeblr-12717', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12717', width:120, title: '节点停留天数'} ,{field:'nodename-12718', width:120, title: '节点名称'} ,{field:'nodeblr-12718', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12718', width:120, title: '节点停留天数'} ,{field:'nodename-12719', width:120, title: '节点名称'} ,{field:'nodeblr-12719', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12719', width:120, title: '节点停留天数'} ,{field:'nodename-12720', width:120, title: '节点名称'} ,{field:'nodeblr-12720', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12720', width:120, title: '节点停留天数'} ,{field:'nodename-12721', width:120, title: '节点名称'} ,{field:'nodeblr-12721', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12721', width:120, title: '节点停留天数'} ,{field:'nodename-12722', width:120, title: '节点名称'} ,{field:'nodeblr-12722', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12722', width:120, title: '节点停留天数'} ,{field:'nodename-12723', width:120, title: '节点名称'} ,{field:'nodeblr-12723', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12723', width:120, title: '节点停留天数'} ,{field:'nodename-12724', width:120, title: '节点名称'} ,{field:'nodeblr-12724', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12724', width:120, title: '节点停留天数'} ,{field:'nodename-12725', width:120, title: '节点名称'} ,{field:'nodeblr-12725', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12725', width:120, title: '节点停留天数'} ,{field:'nodename-12726', width:120, title: '节点名称'} ,{field:'nodeblr-12726', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12726', width:120, title: '节点停留天数'} ,{field:'nodename-12715', width:120, title: '节点名称'} ,{field:'nodeblr-12715', width:120, title: '节点办理人', sort: true} ,{field:'nodediff-12715', width:120, title: '节点停留天数'} ]] ,page: true ,limits: [10,20,30,40,50,60,70,80,10000] }); //执行一个laydate实例 laydate.render({ elem: '#test1' //指定元素 }); laydate.render({ elem: '#test2' //指定元素 }); /*var dataList; //全部导出 $("#btnExport").click(function () { $.ajax({ type: "POST", url: "http://ip:8090/api/http/report/getWFOvertimeData", data: JSON.stringify({page:1,limit:10000, workflowid:"2869" }), contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { console.log(data); dataList= data.data }, error: function() { console.log("error"); } }); alert("123213") console.log(dataList); table.exportFile(dataList, 'xls'); //默认导出 csv,也可以为:xls }) */ }); </script> <script type="text/html" id="toolbarDemo"> <div class="layui-btn-container"> <div class="layui-inline"> <!-- 注意:这一层元素并不是必须的 --> <input type="text" class="layui-input" id="test1"> </div> <div class="layui-inline"> <!-- 注意:这一层元素并不是必须的 --> <input type="text" class="layui-input" id="test2"> </div> <button class="layui-btn layui-btn-sm" lay-event="add">添加</button> <button class="layui-btn layui-btn-sm" lay-event="delete">删除</button> <button class="layui-btn layui-btn-sm" lay-event="query">查询</button> <button class="layui-btn layui-btn-sm" lay-event="export" id="btnExport">显示全部数据</button> </div> </script> </body> <style type="text/css"> #test1 { position: relative; top: -5px; } #test2 { position: relative; top: -5px; } </style> </html>