项目需求:拿到数据库中的物料数据,将数据按照物料编码以及所属物料中心进行分类,然后把相同物料编码的多条数据,按其需求时间,合并成一条数据,并按其需求时间的月份和天动态生成列并展示!看到需求,一脸懵逼,没咋接触过前端的我表示压力好大~~
效果图如下:
说明 : 上图中一条物料信息,对应于数据库中是多条数据
深呼吸~…下面我们开始动手实现功能吧!
1. 获取数据
此处不想多说,我用的是SSM框架,造SQL、写Mapper、搞Controller,呃呃完成!
emmm,此处有个地方需要注意:拿到数据后,在Controller中生成动态表头,将表头和数据放在Map里返回到前端即可!这个也能在Service层去搞,主要目的是把动态的表头给生成并返回到前台。
/**
*因为是公司项目,这里就不放源代码了,只说明大体思路
*/
@RequestMapping(value = "/访问地址")
@ResponseBody
public Map<String, Object> function(HttpServletRequest request,HttpServletResponse response) {
Map<String,Object> result = new HashMap<String, Object>(); //存放返回前台的数据
// 获取数据并将其放入map中
List<Entity> list = service.loadData(); // 获取数据
result.put("val", list); // 将数据放入map中
// 处理数据--获取动态列并将其封装到map2中
Map<String,Map<String,String>> map2 = new TreeMap<String, Map<String,String>>();
Map<String,String> tmp = new TreeMap<String, String>();
for (Entity entity : list) {
//将类似于 2019-01-29 的时间,截取为 2019-01 和 29
String month = entity.getPlanFixTime().substring(0, 7);
String day = entity.getPlanFixTime().substring(8);
// 将年月(yyyy-MM) 作为键,将每个年月中的日(dd) 作为值进行封装
if(map2.containsKey(month)){
tmp = map2.get(month);
tmp.put(day, month+"-"+day);
tmp.put("coltotal", tmp.size()-1+"");
map2.put(month, tmp);
tmp = new TreeMap<String, String>();
}else{
tmp.put(day, month+"-"+day);
tmp.put("coltotal", tmp.size()+"");
map2.put(month, tmp);
}
}
// 将封装的动态列存放到 map中
result.put("field", map2);
return result;
}
# 其返回结果如下格式:
{
"val": [
{
"vehicle": "test1",
"planFixTime": "2019-08-01",
"cycle": "30",
"unit": "EA",
"sumQuantity": 384,
"totalQuantity": "12255.00",
"itemName": "test1",
},
{
"vehicle": "test2",
"planFixTime": "2019-08-23",
"cycle": "61",
"unit": "EA",
"sumQuantity": 384,
"totalQuantity": "5204.00",
"itemName": "test2",
}
],
"field": {
"2019-08": {
"01": "2019-08-01",
"02": "2019-08-02",
"03": "2019-08-03",
"04": "2019-08-04",
"06": "2019-08-06",
"09": "2019-08-09",
"23": "2019-08-23",
"coltotal": "7"
},
"2019-09": {
"01": "2019-09-01",
"03": "2019-09-03",
"coltotal": "2"
}
}
}
本来打算用TreeMap存储,因为TreeMap能将存储的对象自动排序,但在前台显示的过程中不知道什么原因导致天数并未按天增序显示!故此处可以使用任意Map进行存放动态列名
2. 前台加载数据
按照需求,前台使用的是easyUI 框架,因为需要将获取到的数据先进行一遍处理,这里我们用Ajax先获取数据,之后再将数据放入datagrid表格中。
前台实现方面,真的是费了好大劲才搞出来,大体思路如下:
ajax获取数据后,首先拿到后台组装好的动态列数据,然后遍历这些数据并将其拼装成datagrid表头,其中,这些表头按照年月进行合并列,并将年月中的天单列显示。其次,将获取到的数据进行重新组合,将同一个物料中心的相同物料合并为一条数据。其多条数据合并为一条后的数据如下:
物料 | 2019-01 | 2019-07 | ||||||
01 | 03 | 07 | 14 | 01 | 03 | 07 | 14 |
我天,感觉说不清楚了,emmm,就是相同物料中不同天数的不同需求量,按列展示出来,其余相同的数据信息,如编码、名称、所属的物料中心等信息是按行显示的。我觉得这里需要一张图来说明我的意思!
- HTML 代码很简单,只需要定义个表格就OK
<div> <table id="pj_table"></table> </div>
- JS代码就比较麻烦啦,上边思路已经说明,直接上代码,其中有注释
function loadData() { $.ajax({ url: '<%=path%>/dmOverhaulPackageDetailDs/loadPackageDetailsList.act', type: 'POST', dataType: 'json', beforeSend: function () { $('#pj_table').datagrid('loading'); }, success: function (datas) { // 这里需要两个,之前用了一个数组,报错后没有发现错误!换成了两个,静态列和动态父列为数组1,动态子列为数组2 var colData1 = []; var colData2 = []; var columns = new Array(); var heads = datas.field; // 这里可以自己添加静态列 colData1[i] = { 'field' : '字段名', 'title' : '表头名称', 'width' : 120, 'rowspan':2 }; // 将相同的物料编码中的数据,把其进行重新拼接为json数据 // 先将生成的月份,加入到列中 $.each(heads,function(v){ var monthlen = parseInt(heads[v].coltotal); colData1.push({width:100,title:v,colspan:monthlen}) }); columns.push(colData1); // 将每个月对应的日期,加入到列中 $.each(heads,function(v){ $.each(heads[v],function(val){ if(val != 'coltotal'){ colData2.push({ field:heads[v][val], width:100, title:val, formatter : function(value, row, index) { if (value == "" ||value == undefined || value == "\\N" ) { return "0.00"; } return 将数据格式化为自己需要的格式(保留几位小数等); }}) } }); }); // 前边说了,这里要日期正序显示,但用的TreeMap集合不能得到正序的表头,故在此用了个排序【各位有什么其他方案能实现的话,欢迎留言讨论】 colData2 = bubbleSort(colData2); columns.push(colData2); // 这里就是把数据重新组装了,生成咱们需要的格式! var data = formatDetail(datas); $('#pj_table').datagrid({ iconCls : 'glyphicon glyphicon-list', //图标 data : data, columns : columns, fitColumns : false, loadMsg : '数据装载中......', border : false, rownumbers : true, singleSelect : true, autoRowHeight : true, pagination : true, pageList : [ 20, 40, 60, 80 ], //可以调整每页显示的数据,即调整pageSize每次向后台请求数据时的数据 pageSize : 20, fit : true }); } }); } // 将数据重新封装,将相同物料的时间数据封装到一条数据中 function formatDetail(data) { var details = []; var num = 0;//json对象数量 var lastItemCode = null; var lastPjzxCode = null; var tmp = {}; $.each(data, function (idx,obj) { if(idx == "val"){ for (var i = 0; i < obj.length; i++) { // 这种实现方案,自己都觉得很绝望,hhh!待我抽空换个方法~ if(i == 0 || (obj[i].itemCode == obj[i-1].itemCode && obj[i].pjzxCode == obj[i].pjzxCode)){ tmp["itemCode"] = obj[i].itemCode; tmp["itemName"] = obj[i].itemName; tmp["unit"] = obj[i].unit; tmp["cycle"] = obj[i].cycle; tmp["totalQuantity"] = obj[i].totalQuantity; tmp[obj[i].planFixTime] = obj[i].sumQuantity; }else{ details.push(tmp); tmp = {}; tmp["itemCode"] = obj[i].itemCode; tmp["itemName"] = obj[i].itemName; tmp["unit"] = obj[i].unit; tmp["cycle"] = obj[i].cycle; tmp["totalQuantity"] = obj[i].totalQuantity; tmp[obj[i].planFixTime] = obj[i].sumQuantity; } } } }); // 这里需要注意!没有这一条的话,数据会少一条哟! details.push(tmp); details["total"] = details.length; return details; }
总结:实现这一功能,主要思路如下:
1.从后台获取动态列
2.将后台的动态列形成的json对象,从前台解析并填充到datagrid中【要注意生成的动态列需要有唯一的field属性,便于通过datagrid框架填充数据】
3.根据不同的要求,从前台将获取的数据进行处理,并填充到表格中即可