JAVA_SSM框架+MINIUI实现网页报表

来源:互联网 发布:剑网三炮姐脸型数据 编辑:程序博客网 时间:2024/06/01 03:59

最近两日新学了一下报表。
为了代码复用,也为了加深自己的流程印象。
将自己理解写在这里,仅供诸君参考。
如有错误,请见谅,并指出,谢谢。

1.对报表的理解:

报表含列,列有自己的Header,Field等配置参数,下面贴出MINI UI的API文档
这里写图片描述

2.实验流程

2.1报表模型

我这两天实现的表的格式基本上是

C1 C2 C3 C4 数据库中没有的列有行数据 数据库中有的列直接获得数据 数据库中有的列直接获得数据 数据库中没有的列行数据需要计算 数据库中没有的列有行数据 数据库中有的列直接获得数据 数据库中有的列直接获得数据 数据库中没有的列行数据需要计算 数据库中没有的列有行数据 数据库中有的列直接获得数据 数据库中有的列直接获得数据 数据库中没有的列行数据需要计算 附加行( 数据库中没有的列注意自定义对应) 附加行( 数据库中没有的列注意自定义对应) 附加行 ( 数据库中没有的列注意自定义对应) 附加行( 数据库中没有的列注意自定义对应)

要添加自定义列在取表头时添加,要添加行在取数据时添加,注意字段对应。
对于C1基本上数据库里是没有列的(取不到field和header,数据需要取,此列基本上是描述列,静态的,一般只有一两列),作为C2.C3,由于是同一类(可以先写SQL取得列数据的集合,再写SQL利用前一集合取得的field循环获取对应的数据),所以数据库里一般有此列需要的数据。C4是汇总列。自己添加列后在前台做业务实现。

2.2逻辑实现

应该是如此的流程:
①获取列属性(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和前台实现

3.代码如下:

3.1 Dao层

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);    //表数据}

3.2 BUSINESS层

接口

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;        }    }}

3.3 Control层

@Controllerpublic 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    }}

3.4前台页面

<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>