對實際業務需求抽象簡化——通用化
設計需求(需求簡化):如圖三級指標,除第一級外其他級都可以添加修改刪除一個或多個指標並生成指標報表。
如圖所示:
頁面結果後面再講,先對需求進行實體設計
後臺代碼設計
報表主體實體類:
主鍵、報表主體字段、報表狀態(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>
其中代碼可以包含其他需求可以忽略。