对实际业务需求抽象简化——通用化
设计需求(需求简化):如图三级指标,除第一级外其他级都可以添加修改删除一个或多个指标并生成指标报表。
如图所示:
页面结果后面再讲,先对需求进行实体设计
后台代码设计
报表主体实体类:
主键、报表主体字段、报表状态(0:待填报[默认]:1:已填报)、报表版本
指标实体类
主键、指标主体字段、父id、排序号、指标等级(一二三级)、版本号、下一级子类数、下二级子类数、子类指标实体list
指定填报值实体类
主键、报表id、指标id、填报值实体字段
其中指标版本对应报表版本(实际报表版本更复杂多条件参数)
设计思路:
指标通过父id形成树结构,指标等级明确指标等级,排序号该指标在其父类指标下的子指标中的序号(页面保持顺序等)。
报表主体版本包含指标版本信息,指标配置改变时,该报表可以与其指标绑定,下一级子类数和下二级子类数方便其在页面布局(如占行数,导出等使用),子类指标实体list即为其指标主要结构。
具体业务处理
配置初始化
1、 页面加载时生成一级指标数据,也可以根据需求生成多级指标数据
2、 PerformanceTargetsIndexs performanceTargetsIndexs1 = new PerformanceTargetsIndexs();
3、 performanceTargetsIndexs1.setName("产出指标");
4、 performanceTargetsIndexs1.setOrderIndex(1);
5、 performanceTargetsIndexs1.setLevel(1);
6、 performanceTargetsIndexs1.setPid("-1");
7、 performanceTargetsIndexs1.setStatus(0);
8、 performanceTargetsIndexs1.setFirstChildrenCount(1);
9、 reulstMap.put(performanceTargetsIndexs1, null);
10、
11、 PerformanceTargetsIndexs performanceTargetsIndexs2 = new PerformanceTargetsIndexs();
12、 performanceTargetsIndexs2.setName("效益指标");
13、 performanceTargetsIndexs2.setOrderIndex(2);
14、 performanceTargetsIndexs2.setLevel(1);
15、 performanceTargetsIndexs2.setPid("-1");
16、 performanceTargetsIndexs2.setStatus(0);
17、 performanceTargetsIndexs2.setFirstChildrenCount(1);
18、 reulstMap.put(performanceTargetsIndexs2, null);
19、
20、 PerformanceTargetsIndexs performanceTargetsIndexs3 = new PerformanceTargetsIndexs();
21、 performanceTargetsIndexs3.setName("满意度指标");
22、 performanceTargetsIndexs3.setOrderIndex(3);
23、 performanceTargetsIndexs3.setLevel(1);
24、 performanceTargetsIndexs3.setPid("-1");
25、 performanceTargetsIndexs3.setStatus(0);
26、 performanceTargetsIndexs3.setFirstChildrenCount(1);
27、 reulstMap.put(performanceTargetsIndexs3, null);
28、
配置保存
配置VO对象信息
private int version;
private PerformanceTargetsIndexs[] level1Index;
private PerformanceTargetsIndexs[][] level2Index;
private PerformanceTargetsIndexs[][][] level3Index;
保存指标配置
List<PerformanceTargetsIndexs> performanceTargetsIndexs =iPerformanceTargetsIndexsService.findNewIndexsByDepartmentId(currentUser.getDepartmentId(),reportCategory);
int oldVersion = performanceTargetsIndexs.get(0).getVersion();
int newVersion = oldVersion+1;
Date createTime = new Date();
PerformanceTargetsIndexs[] tempLevel1Index = vo.getLevel1Index();
PerformanceTargetsIndexs[][] tempLevel2Index = vo.getLevel2Index();
PerformanceTargetsIndexs[][][] tempLevel3Index = vo.getLevel3Index();
int level1OrderIndex = 0;
for (int i = 0; i < tempLevel1Index.length; i++) {
PerformanceTargetsIndexs level1Index = tempLevel1Index[i];
level1Index.setId(UuidUtil.uuidStr());
level1Index.setPid("-1");
level1Index.setLevel(1);
level1Index.setVersion(newVersion);
level1Index.setCreateTime(createTime);
level1Index.setOrderIndex(level1OrderIndex++);
level1Index.setBelongsDepartmentId(currentUser.getDepartmentId());
level1Index.setCategory(reportCategory);
list.add(level1Index);
if(tempLevel2Index != null) {
int level2OrderIndex = 0;
if(tempLevel2Index.length<=i) continue;
for (int j = 0; j < tempLevel2Index[i].length; j++) {
PerformanceTargetsIndexs level2Index = tempLevel2Index[i][j];
level2Index.setId(UuidUtil.uuidStr());
level2Index.setPid(level1Index.getId());
level2Index.setLevel(2);
level2Index.setVersion(newVersion);
level2Index.setCreateTime(createTime);
level2Index.setOrderIndex(level2OrderIndex++);
level2Index.setBelongsDepartmentId(currentUser.getDepartmentId());
level2Index.setCategory(reportCategory);
list.add(level2Index);
if(tempLevel3Index != null) {
int level3OrderIndex = 0;
try {
System.out.println(tempLevel3Index[i][j].length);
} catch (Exception e) {
System.out.println(i+":"+j+"下标问题已处理");
continue;
}
for (int k = 0; k < tempLevel3Index[i][j].length; k++) {
PerformanceTargetsIndexs level3Index = tempLevel3Index[i][j][k];
level3Index.setId(UuidUtil.uuidStr());
level3Index.setPid(level2Index.getId());
level3Index.setLevel(3);
level3Index.setVersion(newVersion);
level3Index.setCreateTime(createTime);
level3Index.setOrderIndex(level3OrderIndex++);
level3Index.setBelongsDepartmentId(currentUser.getDepartmentId());
level3Index.setCategory(reportCategory);
list.add(level3Index);
}
}
}
}
}
iPerformanceTargetsIndexsService.save(list);
项目加载配置生成报表
获取配置
根据查询最新版本的一级指标配置
List<PerformanceTargetsIndexs> performanceTargetsIndexss = performanceTargetsIndexsDao.findNewLevel1IndexsByDepartmentId();
sql
String sql = "select a.* from c_performance_targets_indexs a, "
+ "(SELECT BELONGS_DEPARTMENT_ID, max(version) max_version from C_PERFORMANCE_TARGETS_INDEXS WHERE GROUP BY BELONGS_DEPARTMENT_ID) b "
+ "WHERE pid='-1' and project_id is null and a.BELONGS_DEPARTMENT_ID=b.BELONGS_DEPARTMENT_ID AND a.VERSION=b.max_version ORDER BY a.ORDER_INDEX";
这里顺便提一下得到一级获取二、三级指标
public void initChildrenData(List<PerformanceTargetsIndexs> performanceTargetsIndexss) {
for (PerformanceTargetsIndexs performanceTargetsIndexs : performanceTargetsIndexss) {
//修改配置时每次都是新增记录,所以这里重新初始化每个指标的id
String newLevel1Id = UuidUtil.uuidStr();
performanceTargetsIndexs.setCreateTime(null);
//查询二级指标
List<PerformanceTargetsIndexs> level2Indexs = performanceTargetsIndexsDao.findTreeListByPid(performanceTargetsIndexs.getId());
//计算一级指标有多少个三级指标
int leve3IndexCount = 0;
for (PerformanceTargetsIndexs performanceTargetsIndexs2 : level2Indexs) {
performanceTargetsIndexs2.setCreateTime(null);
//修改配置时每次都是新增记录,所以这里重新初始化每个指标的id
String newLevel2Id = UuidUtil.uuidStr();
//查询三级指标
List<PerformanceTargetsIndexs> level3Indexs = performanceTargetsIndexsDao.findTreeListByPid(performanceTargetsIndexs2.getId());
for (PerformanceTargetsIndexs performanceTargetsIndexs3 : level3Indexs) {
performanceTargetsIndexs3.setCreateTime(null);
//修改配置时每次都是新增记录,所以这里重新初始化每个指标的id
// performanceTargetsIndexs3.setId(UuidUtil.uuidStr());
// performanceTargetsIndexs3.setPid(newLevel2Id);
}
// performanceTargetsIndexs2.setId(newLevel2Id);
// performanceTargetsIndexs2.setPid(newLevel1Id);
performanceTargetsIndexs2.setChildren(level3Indexs);
leve3IndexCount+=level3Indexs.size();
}
//设置一级指标对应的二级、三级指标个数
performanceTargetsIndexs.setFirstChildrenCount(level2Indexs.size()>1? level2Indexs.size():1);
performanceTargetsIndexs.setSecondChildrenCount(leve3IndexCount);
// performanceTargetsIndexs.setId(newLevel1Id);
performanceTargetsIndexs.setChildren(level2Indexs);
}
通过一级指标,拿的配置版本,生成报表(生成的报表版本和指标版本一致)
填报报表VO
public class PerformanceTargetsReportVo {
private PerformanceTargetsMainReport mainReport;
private PerformanceTargetsChildReport[][][] childReport;
获取报表数据(同上获取指标数据及报表主体数据)
保存报表数据
PerformanceTargetsMainReport mainReport = vo.getMainReport();
mainReport.setCreateTime(new Date());
mainReport.setReportStatus("1");
PerformanceTargetsChildReport[][][] childReport = vo.getChildReport();
List<PerformanceTargetsChildReport> list = new ArrayList<PerformanceTargetsChildReport>();
if(CollectionUtil.isNotEmpty(childReport)){
for (PerformanceTargetsChildReport[][] performanceTargetsChildReports : childReport) {
for (PerformanceTargetsChildReport[] performanceTargetsChildReports2 : performanceTargetsChildReports) {
for (PerformanceTargetsChildReport performanceTargetsChildReport : performanceTargetsChildReports2) {
performanceTargetsChildReport.setId(UuidUtil.uuidStr());
performanceTargetsChildReport.setMainReportId(mainReport.getId());
list.add(performanceTargetsChildReport);
}
}
}
}
iPerformanceTargetsMainReportService.updateMainSaveChild(mainReport, list);
public void updateMainSaveChild(PerformanceTargetsMainReport mainReport,
List<PerformanceTargetsChildReport> chilReports) {
this.update(mainReport);
iPerformanceTargetsChildReportService.save(chilReports);
}
关于页面数据格式等,不赘述,代码如下:
页面显示
<input value="数量指标" class="jxb-input" autocomplete="off" name="level2Index[0][0].name">
<input value="" class="jxb-input" name="level3Index[0][1][1].name" placeholder="请输入三级指标">
页面代码
<input type="hidden" name="childReport[${a.index}][${i.index}][${m.index}].indexId" value="${level3Index.id}">
<input value="${childReportMap[level3Index.id].indexValue}" class="jxb-input" autocomplete="off" required lay-verify="required" name="childReport[${a.index}][${i.index}][${m.index}].indexValue">
前端设计
配置页面
<body class="f-oh f-p layui-form">
<div class="f-bg-white f-h-full f-webkit-box f-box-vertical">
<div class="skin-chart-title f-m-b">报表</div>
<div class="f-bg-f0fcff f-p-t-sm f-p-b-sm f-p-l f-color-03A9F4"><i class="icon-gantanhao iconfont f-left f-m-r-sm"></i>请你在以下指标中配置绩效目标表,如果无需修改点击预览后下发,如果更改了配置点击保存后再预览。</div>
<div class="f-box-flex1 f-relative">
<div class="f-absolute-all f-p f-y-auto">
<table class="skin-table-style9 f-h-37">
<thead>
<tr>
<th width="212">一级指标</th>
<th width="212">二级指标</th>
<th>三级指标</th>
<th width="300">指标值说明</th>
</tr>
</thead>
<input type="hidden" name="version" value="${performanceTargetsIndexs[0].version}">
<input type="hidden" name="reportCategory" value="${reportCategory}">
<c:forEach items="${performanceTargetsIndexs}" var="level1Index" varStatus="a">
<tbody class="stair">
<tr>
<td>
<div class="text">
<input type="hidden" name="level1Index[${a.index}].name" value="${level1Index.name}">
<span>${level1Index.name}</span>
<i class="icon-add f-right iconfont f-color-666 f-mcp f-size-19" title="添加二级指标" pid="${a.index}"></i>
</div>
</td>
<td colspan="3">
<c:forEach items="${level1Index.children}" var="level2Index" varStatus="i">
<table class="skin-table-style10">
<tr>
<td width="211">
<div class="text skin-table-input">
<c:choose>
<c:when test="${level2Index.name eq '经济效益指标'}">
<select name="level2Index[${a.index}][${i.index}].name" lay-verify="required">
<option value=""></option>
<option value="经济效益指标" <c:if test="${level2Index.name eq '经济效益指标'}">selected='selected' </c:if> >经济效益指标</option>
<option value="社会效益指标" <c:if test="${level2Index.name eq '社会效益指标'}">selected='selected' </c:if> >社会效益指标</option>
<option value="可持续影响效益指标" <c:if test="${level2Index.name eq '可持续影响效益指标'}">selected='selected' </c:if> >可持续影响效益指标</option>
</select>
</c:when>
<c:otherwise>
<input value="${level2Index.name}" class="jxb-input" autocomplete="off" name="level2Index[${a.index}][${i.index}].name">
</c:otherwise>
</c:choose>
<c:if test="${i.index > 0 && level2Index.name ne '数量指标' && level2Index.name ne '质量指标' && level2Index.name ne '时效指标' && level2Index.name ne '成本指标' && level2Index.name ne '经济效益指标'}"><i class="icon-guanbi1 iconfont f-color-666 f-mcp" title="删除二级指标"></i></c:if>
<i class="icon-add iconfont f-color-666 f-mcp f-size-19" title="添加三级指标" pid="${a.index},${i.index}"></i>
</div>
</td>
<td>
<table class="skin-table-style11">
<c:if test="${level2Index.children.size() eq 0}">
<tr>
<td>
<div class="text skin-table-input">
<input value="${level3Index.name}" class="jxb-input" autocomplete="off" name="level3Index[${a.index}][${i.index}][0].name">
</div>
</td>
<td width="300">
<div class="text skin-table-input">
<input value="${level3Index.explain}" class="jxb-input" autocomplete="off" name="level3Index[${a.index}][${i.index}][0].explain">
</div>
</td>
</tr>
</c:if>
<c:forEach items="${level2Index.children}" var="level3Index" varStatus="m">
<tr>
<td>
<div class="text skin-table-input">
<input value="${level3Index.name}" class="jxb-input" autocomplete="off" name="level3Index[${a.index}][${i.index}][${m.index}].name">
<c:if test="${m.index > 0}">
<i class="icon-guanbi1 f-right iconfont f-color-666 f-mcp" title="删除三级指标"></i>
</c:if>
</div>
</td>
<td width="300">
<div class="text skin-table-input">
<input value="${level3Index.explain}" class="jxb-input" autocomplete="off" name="level3Index[${a.index}][${i.index}][${m.index}].explain">
</div>
</td>
</tr>
</c:forEach>
</table>
</td>
</tr>
</table>
</c:forEach>
</td>
</tr>
</tbody>
</c:forEach>
</table>
</div>
</div>
<div class="f-info-c f-p-t f-p-b">
<button type="reset" class="layui-btn layui-btn-sm layui-btn-primary" id="closed">关闭</button>
<button id="submit" type="button" class="layui-btn layui-btn-sm layui-btn-normal" lay-submit lay-filter="submit">保存</button>
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="preview">预览</button>
</div>
</div>
</body>
<script>
//排序
function orderLevel2Index(pid){
$(this).find("[name^='level2Index']").each(function(j) {
var nameStr = $(this).attr("name");
var newName = nameStr.replace(/\?|\d+/, pid);
$(this).attr("name", newName);
});
}
layui.use(['element','form','layer'], function(){
var $ = layui.$,
form = layui.form;
element = layui.element,
layer = layui.layer;
$("body").on("click",".icon-add",function(){ //添加指标
var title = $(this).attr('title'),pid = $(this).attr('pid');
switch(title){
case '添加二级指标':
var html = '<table class="skin-table-style10">'+
'<tr>'+
'<td width="211">'+
'<div class="text skin-table-input">'+
'<input value="" class="jxb-input" name="level2Index[?][?].name" placeholder="请输入二级指标">'+
'<i class="icon-guanbi1 f-right iconfont f-color-666 f-mcp" title="删除二级指标"></i>'+
'<i class="icon-add f-right iconfont f-color-666 f-mcp f-size-19" title="添加三级指标" pid="'+pid+'"></i>'+
'</div>'+
'</td>'+
'<td></td>'+
'</tr>'+
'</table>';
$(this).parent().parent().next().append(html);
$(this).parent().parent().next().find("[name^='level2Index']").each(function(j) {
var nameStr = $(this).attr("name");
var newName = nameStr.replace('?', pid).replace('?', j);
$(this).attr("name", newName);
});
$(this).parent().parent().next().find("[pid^='"+pid+"']").each(function(j) {
$(this).attr("pid", pid+","+j);
});
break;
case '添加三级指标':
if($(this).parent().parent().next().children().length>0){
var html = '<tr>'+
'<td>'+
'<div class="text skin-table-input">'+
'<input value="" class="jxb-input" name="level3Index[?][?][?].name" placeholder="请输入三级指标">'+
'<i class="icon-guanbi1 f-right iconfont f-color-666 f-mcp" title="删除三级指标"></i>'+
'</div>'+
'</td>'+
'<td width="300">'+
'<div class="text skin-table-input">'+
'<input class="jxb-input" autocomplete="off" name="level3Index[?][?][?].explain" placeholder="请输入指标值说明">'+
'</div>'+
'</td>'+
'</tr>';
$(this).parent().parent().next().children('.skin-table-style11').append(html);
}else{
var html = '<table class="skin-table-style11">'+
'<tr>'+
'<td>'+
'<div class="text skin-table-input">'+
'<input value="" class="jxb-input" name="level3Index[?][?][?].name" placeholder="请输入三级指标">'+
'<i class="icon-guanbi1 f-right iconfont f-color-666 f-mcp" title="删除三级指标"></i>'+
'</div>'+
'</td>'+
'<td width="300">'+
'<div class="text skin-table-input">'+
'<input class="jxb-input" autocomplete="off" name="level3Index[?][?][?].explain" placeholder="请输入指标值说明">'+
'</div>'+
'</td>'+
'</tr>'+
'</table>';
$(this).parent().parent().next().append(html);
}
var pids = pid.split(",");
$(this).parent().parent().next().find("[name^='level3Index'][name$='name']").each(function(j) {
var nameStr = $(this).attr("name");
var newName = nameStr.replace('?', pids[0]).replace('?', pids[1]).replace('?', j);
$(this).attr("name", newName);
});
$(this).parent().parent().next().find("[name^='level3Index'][name$='explain']").each(function(j) {
var nameStr = $(this).attr("name");
var newName = nameStr.replace('?', pids[0]).replace('?', pids[1]).replace('?', j);
$(this).attr("name", newName);
});
break;
}
});
$("body").on("click",".icon-guanbi1",function(){ // 删除指标
var title = $(this).attr('title');
switch(title){
case '删除三级指标':
var $root = $(this).parent().parent().parent().parent();
if($(this).parent().parent().parent().siblings().length>0){
$(this).parent().parent().parent().remove();
}else{
$(this).parent().parent().parent().parent().parent().remove();
};
$root.find("[name^='level3Index'][name$='name']").each(function(j) {
var nameStr = $(this).attr("name");
var nameStrs = nameStr.split(".");
var newNamePre = nameStrs[0].substring(0,nameStrs[0].length-2)+j+"]";
var newName = newNamePre + "." + nameStrs[1];
$(this).attr("name", newName);
});
$root.find("[name^='level3Index'][name$='explain']").each(function(j) {
var nameStr = $(this).attr("name");
var nameStrs = nameStr.split(".");
var newNamePre = nameStrs[0].substring(0,nameStrs[0].length-2)+j+"]";
var newName = newNamePre + "." + nameStrs[1];
$(this).attr("name", newName);
});
break;
case '删除二级指标':
var $root = $(this).parent().parent().parent().parent().parent().parent();
if($(this).parent().parent().parent().parent().parent().parent().parent().siblings().length>0){
$(this).parent().parent().parent().parent().parent().parent().parent().remove();
}else{
$(this).parent().parent().parent().parent().parent().remove();
};
$root.find("[name^='level2Index'][name$='name']").each(function(j) {
var nameStr = $(this).attr("name");
var nameStrs = nameStr.split(".");
var newNamePre = nameStrs[0].substring(0,nameStrs[0].length-2)+j+"]";
var newName = newNamePre + "." + nameStrs[1];
$(this).attr("name", newName);
});
break;
}
})
填报页面
<table class="skin-table-style13">
<colgroup>
<col width="109">
<col width="109">
<col width="320">
<col width="176">
<col width="300">
</colgroup>
<thead>
<tr>
<th class="skin-table-head">一级指标</th>
<th class="skin-table-head">二级指标</th>
<th class="skin-table-head">三级指标</th>
<th class="skin-table-head">指标值</th>
<th class="skin-table-head">指标值说明</th>
<!-- <th class="skin-table-head">责任单位</th> -->
</tr>
</thead>
<tbody>
<c:forEach items="${performanceTargetsIndexs}" var="level1Index" varStatus="a">
<tr>
<td class="skin-table-head">${level1Index.name}</td>
<td class="f-p-n" colspan="5">
<table class="skin-table-style13">
<c:forEach items="${level1Index.children}" var="level2Index" varStatus="i">
<tr>
<td class="skin-table-head" width="108">${level2Index.name}</td>
<td class="f-p-n">
<table class="skin-table-style13">
<c:forEach items="${level2Index.children}" var="level3Index" varStatus="m">
<tr>
<td width="319">${level3Index.name}</td>
<td class="f-p-n" width="176">
<input type="hidden" name="childReport[${a.index}][${i.index}][${m.index}].indexId" value="${level3Index.id}">
<input type="text" name="childReport[${a.index}][${i.index}][${m.index}].indexValue" required lay-verify="required" placeholder="" maxlength="120" autocomplete="off" class="layui-input">
</td>
<td>${level3Index.explain}</td>
<%-- <td class="f-p-n">
<input type="text" name="childReport[${a.index}][${i.index}][${m.index}].responsibleUnit" required lay-verify="required" placeholder="" autocomplete="off" class="layui-input">
</td> --%>
</tr>
</c:forEach>
</table>
</td>
</tr>
</c:forEach>
</table>
</td>
</tr>
</c:forEach>
</tbody>
</table>
其中代码可以包含其他需求可以忽略。