赞
踩
最近两日新学了一下报表。
为了代码复用,也为了加深自己的流程印象。
将自己理解写在这里,仅供诸君参考。
如有错误,请见谅,并指出,谢谢。
报表含列,列有自己的Header,Field等配置参数,下面贴出MINI UI的API文档
我这两天实现的表的格式基本上是
C1 | C2 | C3 | C4 |
---|---|---|---|
数据库中没有的列有行数据 | 数据库中有的列直接获得数据 | 数据库中有的列直接获得数据 | 数据库中没有的列行数据需要计算 |
数据库中没有的列有行数据 | 数据库中有的列直接获得数据 | 数据库中有的列直接获得数据 | 数据库中没有的列行数据需要计算 |
数据库中没有的列有行数据 | 数据库中有的列直接获得数据 | 数据库中有的列直接获得数据 | 数据库中没有的列行数据需要计算 |
附加行( 数据库中没有的列注意自定义对应) | 附加行( 数据库中没有的列注意自定义对应) | 附加行 ( 数据库中没有的列注意自定义对应) | 附加行( 数据库中没有的列注意自定义对应) |
要添加自定义列在取表头时添加,要添加行在取数据时添加,注意字段对应。
对于C1基本上数据库里是没有列的(取不到field和header,数据需要取,此列基本上是描述列,静态的,一般只有一两列),作为C2.C3,由于是同一类(可以先写SQL取得列数据的集合,再写SQL利用前一集合取得的field循环获取对应的数据),所以数据库里一般有此列需要的数据。C4是汇总列。自己添加列后在前台做业务实现。
应该是如此的流程:
①获取列属性(C2,C3),表中没有的在业务层里加(C1,C4,在数据库里定义了列对象为自定义的COLUMN类型,再一层层加到LIST里返回一个LIST)
到前台JSON解析为:[{header:xx,field:xx,……},
{header:xx,field:xx,……},
{header:xx,field:xx,……}]
②获取列对应数据,依据列的Field在数据库中找寻,Field一定要相匹配
其中注意,前台用TreeGrid实现,其中TreeGrid的PARENTCODE属性为层级关系,也就是树的节点依据.
③其他实现的业务在BUSINESS和前台实现
XML
select COLUMN_NAME as header, --列的名称
COLUMN_CODE as field, --列的字段,此值要与后面取出来的数据字段对应
'120' as width, --列的宽度
'center' as align, --列的
'center' as headerAlign,
'currency' as dataType,
COLUMN_CODE as name
from RPTCOLUMN t where t.report_code = 'RPT1'
查询表数据:
SELECT T1.ROW_CODE AS ROW_CODE, -- 树的行字段,前台可以通过此字段指定单元格所在行,PS:根据Field制定单元格所在列
T1.ORD AS ORD, -- ORD,暂时
T1.ITEM_DESC AS ITEM_DESC, -- 第一列表头数据 记得在SERVICE加表头与之对应
T1.PARENT_CODE AS PARENT_CODE, -- 所使用的层级描述,树的层级关系
<foreach collection="headers" index="index" item="item">
,NVL(SUM(CASE WHEN T2.COLUMN_CODE= #{item.name} THEN T2.DATA END),0) AS "${item.field}"
</foreach> --利用循环取得,要显示的表头字段,我设置中文的话显示有错误 最好不要用中文,这里为了方便取name为1,2 这里取得1,2的数据 。collection="headers"为接口定义中利用查询的表头作为参数 做数据的取得
FROM RPTCOLUMN T1LEFT JOIN RPTDATA T2 ON T1.REPORT_CODE = 'RPT1'AND T1.ROW_CODE = T2.ROW_CODE WHERE T1.REPORT_CODE = 'RPT1'GROUP BY T1.ROW_CODE ,T1.ORD,T1.ITEM_DESC,T1.PARENT_CODE ORDER BY T1.ORD
接口
public interface Rpt1Mapper {
List<Column> queryRpt1Header(HashMap<String,String> param);
//表头
List<HashMap<String,String>> queryRpt1ListByHeader(@Param("headers") List<Column> headers,@Param("record") HashMap<String,String> record);
//表数据
}
接口
public interface ReportBusiness {
List<Column> queryRpt1Header(HashMap<String,String> param);
//表头
List<HashMap<String,String>> queryRpt1ListByHeader(HashMap<String,String> record);
//表数据
}
实现
@Component(value = "RSTReportBiz")
public class ReportBusinessImpl implements ReportBusiness {
@Autowired
private Rpt1Mapper rpt1Mapper ;
@Override
public List<Column> queryRpt1Header(HashMap<String, String> param) {
// 表头处理
List<Column> allCols =new ArrayList<Column>();
Column firstCol = new Column(); //设置返回List的集合中的数据 first
firstCol.setHeader("C1");
firstCol.setAlign("left");
firstCol.setField("ITEM_DESC");
firstCol.setWidth("430");
firstCol.setHeaderAlign("center");
firstCol.setName("ITEM_DESC");
List<Column> cols = rptRpt1Mapper.queryRpt1Header(param);
Column lastCol = new Column(); //设置返回List的集合中的数据 total
lastCol.setHeader("TOTAL");
lastCol.setAlign("right");
lastCol.setField("TOTAL");
lastCol.setWidth("300");
lastCol.setHeaderAlign("center");
lastCol.setName("TOTAL");
if (cols == null || cols.size() == 0) {
return null;
} else {
allCols.add(firstCol); //传入自己设置的Item first
allCols.addAll(cols); //传入cols的Item
allCols.add(lastCol);
return allCols;
}
}
@Override
public List<HashMap<String, String>> queryRpt1ListByHeader(HashMap<String, String> record) {
// 表数据处理
List<HashMap<String, String>> result =new ArrayList<HashMap<String, String>>();
HashMap<String, String> h1 =new HashMap<String, String>();
h1.put("ROW_CODE", "4"); //行数据的行数
h1.put("ORD", "17");
h1.put("ITEM_DESC", "第四行"); //第一列的值字段要对应
h1.put("PARENT_CODE", ""); //有层级关系再加,我这里没有
HashMap<String, String> h2 =new HashMap<String, String>();
h2.put("ROW_CODE", "5");
h2.put("ORD", "17");
h2.put("ITEM_DESC", "第五行");
h2.put("PARENT_CODE", "");
List<Column> columns = rptRpt1Mapper.queryRpt1Header(record);
//先取出表头以传入queryRpt1ListByHeader,即Dao层XML里queryRpt1ListByHeader查询表数据中用到的循环 集合headers
if (columns != null && columns.size() > 0) {
result.addAll(rptRpt1Mapper.queryRpt1ListByHeader(columns, record)); //取出数据表中的数据
result.add(h1); //我所要加的行
result.add(h2);
return result;
} else {
return null;
}
}
}
@Controller
public class ReportController {
@Autowired
private ReportBusiness ReportBiz;
@RequestMapping(value = "/showRpt1View")
public String showRpt1View(){
return "alm/rptrst/Rpt1View";
}
//表头
@RequestMapping(value = "/queryC001RstHeader")
@ResponseBody
public AjaxObj queryC001RstHeader(@RequestParam HashMap<String,String> record){
List<Column> columns = RSTReportBiz.queryC001RstHeader(record);
return new AjaxObj(0,null,columns);
}
//报表数据
@RequestMapping(value = "/queryC001RstListByHeader")
@ResponseBody
public Pager<HashMap<String,String>> queryC001RstListByHeader(SystemContext systemContext,@RequestParam HashMap<String,String> record) {
List<HashMap<String,String>> page = RSTReportBiz.queryC001RstListByHeader(record);
return new Pager<HashMap<String,String>>(0, page); //Pager是一个封装的分页对象这里不需要分页,所以传入参数需要分页的总数total为0
}
}
<body>
<div class="description">
<h3>报表</h3>
</div>
<div class="mini-toolbar" style="padding: 0px; border: 0;background:#fff">
<div id="form1">
<table style="width: 100%;">
<tr>
<td style="width: 100%;"></td>
<td style="white-space: nowrap; text-align: right;padding-right:10px">
报表日期:<input id="reportDt" name="reportDt" class="mini-combobox" style="width:110px"
textField="TEXT" valueField="TEXT" valueFromSelect="true"
url="<%=path %>/queryC001RstReportDtList"
allowInput="true" dataField="data" onvaluechanged="onReportDtChanged"
showNullItem="false" emptyText="请选择报表日期" NullItemText="请选择报表日期"
/>
报表货币:<input id="currency" name="currency" class="mini-combobox" style="width:70px"
textField="dictText" valueField="dictValue"
url="<%=path %>/queryDicyEntryByDictCode?dictCode=1018"
required="true" allowInput="false" dataField="data"
showNullItem="false" emptyText="请选择报表货币" NullItemText="请选择报表货币"
onvaluechanged="search"/>
<a class="mini-button"
iconCls="icon-search" onclick="search()">查询</a>
<a class="mini-button"
iconCls="icon-download" onclick="exportExcel()">导出</a>
</td>
</tr>
</table>
</div>
</div>
<div class="mini-fit" style="height: 100%; width: 100%">
<div id="treegrid1" class="mini-datagrid"
style="width: 99%; height: 100%;"
url="<%=path %>/queryRpt1ListByHeader"
treeColumn="ITEM_DESC" idField="ROW_CODE" parentField="PARENT_CODE"
resultAsTree="false" expandOnLoad="true" showTreeIcon="false"
showExpandButtons='false' virtualScroll="true" autoLoad="false"
dataField="datas"
allowRowSelect="true" enableHotTrack="false" editNextOnEnterKey="true"
allowCellEdit="true" allowCellSelect="true" cellEditAction="cellclick">
<div property="columns"></div>
</div>
</div>
<script type="text/javascript">
mini.parse();
var form = new mini.Form("#form1"); //这边表单传数据,但是我在SQL中没有演示
var grid = mini.get("treegrid1");
var reportDtCombo = mini.get("reportDt");
var currencyCombo = mini.get("currency");
reportDtCombo.select(0);
currencyCombo.select(0);
search();
function search(){
var formData = form.getData();
var url = path + '/queryRpt1Header';
myui.loadAjax(url,formData,function(o){
var data = o.data;
var header = [];
var j = 0;
//下面是演示如何在JS中添加表头(列数据对象),跟在BUSINESS中实现的业务相同,不过我COLUMN中没有设置editor,即可编辑属性,添加此属性,实现效果相同.自己代码中后台BUSINESS没有添加表头在前台添加的,因为要求要可以编辑
header[j++]={"header":"C1",align:"left",field:"ITEM_DESC",name:"ITEM_DESC",width:"300",headerAlign:"left"};
for(var i = 0;i<data.length;i++){
header[j++] = {"header":data[i].header,align:"center",field:data[i].field,dataType:"currency",editor:{ type: "textbox",minWidth: "50"},width:"120",headerAlign:"center"};
}
header[j++]={"header":"TOTAL",align:"right",field:"TOTAL",width:"150",headerAlign:"center",dataType:"currency"};
grid.setColumns(header);
grid.on("load",function(){
grid.mergeColumns(["ITEM_DESC"]);
});
grid.load(formData);
},function(e){
alert(e.responseText);
});
}
function onReportDtChanged(){
var reportDt = reportDtCombo.getValue();
if(reportDt == null || reportDt.length <= 0){
reportDtCombo.select(0);
}
search();
}
grid.on("drawcell", function (e) {
var record = e.record,
column = e.column,
field = e.field,
value = e.value;
var val1;
var val2;
if(field == "TOTAL"){
val1=isNaN(record[1]) ? 0 : record[1]; //Field为1的数据
val2=isNaN(record[2]) ? 0 : record[2]; //Field为2的数据
var html = parseFloat(val1) + parseFloat(val2); //更新此行TOTAL的数据
e.cellHtml = formatCurrency(html);
}
});
grid.on("cellbeginedit", function(e) { //只有第四行的可以单元格可以编辑,而且只有Field为'1','2'的列可以编辑,也就是两个单元格列为C2,C3;行为第四行的单元格可以编辑
var editor = e.editor;
var record = e.record;
if(record.ROW_CODE=="4"){
}else{
e.cancel = true;
}
});
var fieldBool = true;
grid.on("cellcommitedit", function(e) {
var field = e.field;
if (fieldBool) {
fieldBool = false;
var record = e.record;
if(record.ROW_CODE == "4"){
var data1 = grid.findRow(function(row) { //第一行
if (row.ROW_CODE == "1")
return true;
});
var updateRow = grid.findRow(function(row) { //需要更新的行
if (row.ROW_CODE == "5")
return true;
});
if(field == "1"){
var val1 = isNaN(data1[1]) ? 0 : data1[1]; //第一行,Field为1的数据 我C2,C3列的Field分别为1和2
var val2 = isNaN(e.value) ? 0 : e.value; //取此单元格编辑的数据:e.value
var val = parseFloat(val1) - parseFloat(val2);
grid.updateRow(updateRow, { //调用更新行的方法
"1" : val
});
}
if(field == "2"){ //实现在Field为2的那一列的逻辑
var val1 = isNaN(data1[2]) ? 0 : data1[2];
var val2 = isNaN(e.value) ? 0 : e.value;
var val = parseFloat(val1) - parseFloat(val2);
grid.updateRow(updateRow, {
"2" : val
});
}
}
}
fieldBool = true;
});
</script>
</body>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。