aisell_报表

一、报表

  • 报表的概念:
    连接多张数据表,通过一系列的运算得到的结果.
    报表就是用表格、图表等格式来动态显示数据,可以用公式表示为:“报表 = 多样的格式 + 动态的数据”
  • 报表的实现方式:
    表格:详细数据
    图表: 直观
  • 报表常识:
    生成的数据报表,不具有增加、删除、修改数据的功能。只能够查询数据。
    只返回前端需要的数据,以此来提高性能。
  • 在此处需要连接的数据库表有:
    采购订单明细、采购订单、供货商、员工表、产品表、产品类型表
  • 达到的效果
    页面查询效果;
    在这里插入图片描述
    图像页面效果:
    在这里插入图片描述

二、使用EasyUI(datagrid-groupview) 控件

先在EasyUi官网扩展处找到数据网格分组视图(DataGrid GroupView)

  • 下载相应的控件
    datagrid-groupview.js文件
  • 研究插件源码
    jsp页面:
<body>
	<table id="tt"></table>
</body>

使用js代码创建数据表格

<script>
	$(function(){
		$('#tt').datagrid({
			title:'DataGrid - GroupView',
			width:500,
			height:250,
			rownumbers:true,
			remoteSort:false, //是否支持远程排序
			nowrap:false,
			fitColumns:true,
			url:'datagrid_data.json', //访问数据的路径
			columns:[[
				{field:'productid',title:'Product ID',width:100,sortable:true},
				{field:'listprice',title:'List Price',width:80,align:'right',sortable:true},
				{field:'unitcost',title:'Unit Cost',width:80,align:'right',sortable:true},
				{field:'attr1',title:'Attribute',width:150,sortable:true},
				{field:'status',title:'Status',width:60,align:'center'}
			]],
			groupField:'productid', //根据哪一个字段分组
			view: groupview, //分组视图必需要加这个
			//value:分组的值 rows:这一组的所有值
			groupFormatter:function(value, rows){ //分组位置的显示
				return value + ' - ' + rows.length + ' Item(s)';
			}
		});
	});
</script>

路径datagrid_data.json显示写死,以后会根据自己路径访问

在这里插入图片描述

三、创建项目的报表

  • 注意:报表是多张表连接起来,然后运算出一些结果

  • 专门为报表中的字段新建一个domain,来装报表中需要的数据
    vo:value object值对象。用于业务之间的数据传递,和po一样,仅仅包含数据而已。new出来的抽象对象。
    po:persistent object持久对象。通常对应数据库,本身还有部分业务逻辑处理,可看成是与数据库中的表相隐射的java对象。po中应该不包含任何对数据库的操作。

  • 准备一个报表的vo类PurchasebillitemVo.java。报表展示中需要的字段。
    准备:

    1. 将 表单明细Purchasebillitem对象装换为报表的PurchasebillitemVo对象,通过构造方法。
    2. springmvc处理时间的格式:使用注解。在get方法上使用 @JsonFormat(pattern = “yyyy-MM-dd”,timezone = “GMT+8”)
    3. 解决分组字段写死问题(供应商、采购员和月份),定义一个分组字段。就是在Purchasebillitem.js中的分组字段。js中的分组字段就决定了页面以什么字段展示数据。
/*
*   报表字段。所有数据是要返回给前台的
* */
public class PurchasebillitemVo {
    //编号
    private Long id;
    //供应商
    private String supplier;
    //采购员
    private String buyer;
    //产品
    private String product;
    //产品类型
    private String productType;
    //交易时间
    private Date vdate;
    //采购数量
    private BigDecimal num;
    //价格
    private BigDecimal price;
    //小计=价格*数量
    private BigDecimal amount;
    //状态  0表示待审 1表示以审 -1表示作废
    private Integer status;//默认就是待审状态

    //分组字段。定义一个分组字段,好在PurchasebillitemVo.js中能灵活的拿到分组字段,解决写死问题
    private String groupField;
    public PurchasebillitemVo(){}
//--------------------------------------------------------------------------    
    //提供一个有参构造,当new PurchasebillitemVo的时候就直接将将每一个Purchasebillitem对象变成PurchasebillitemVo对象
    public PurchasebillitemVo (Purchasebillitem item, PurchasebillitemQuery query){
        this.id=item.getId();
        //PurchasebillitemVo对象=Purchasebillitem对象的关联表的字段BillId的关联的供货商字段supplier的供货商类Supplier名字
        this.supplier=item.getBillId().getSupplier().getName();
        //查找方法与上面的一样,注意不同表之间的关联字段,分部拿到就可以相应的值
        this.buyer=item.getBillId().getBuyer().getUsername();
        this.product=item.getProduct().getName();
        this.productType=item.getProduct().getTypes().getName();
        this.vdate=item.getBillId().getVdate();
        this.num=item.getNum();
        this.price=item.getPrice();
        this.amount=item.getAmount();
        this.status=item.getBillId().getStatus();
        System.out.println(status);
//----------------------------------------------------------------------

//拿到分组字段。就是PurchasebillitemVo.js中的以什么字段分组
    //只能一个一个的获取,不符合业务
        //如果是供应商分组
        //this.groupField = this.supplierName;
        //如果是采购员分组
        //this.groupField = this.buyerName;
        //如果是月份
        //Calendar cal = Calendar.getInstance();
       //cal.setTime(vdate);
        //this.groupField =  (cal.get(Calendar.MONTH)+1) + "月";
//---------------PurchasebillitemQuery就是前台传过来的查询对象-----------------------------
        //通过witch语句完成判断分组字段。从PurchasebillitemQuery中拿到分组字段
        switch (query.getGroupType()){//变量分别可能为1、2、3,然后对应下面的值
            case 1:
                this.groupField = this.supplier;
                break;
            case 2:
                this.groupField = this.buyer;
                break;
            case 3:
                //从交易日期中拿到月份
                Calendar cal = Calendar.getInstance();
                cal.setTime(vdate);
                this.groupField =  (cal.get(Calendar.MONTH)+1) + "月";
                break;
            default:
                //定义默认为供应商
                this.groupField = this.supplier;
        }
    }
//-------------------------------------------------------------------    
    //springmvc处理时间格式。响应给前台
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    public Date getVdate() {
        return vdate;
    }

    public void setVdate(Date vdate) {
        this.vdate = vdate;
    }
    //省略其他字段的get、set方法
  • query层。(开始时间、结束时间、状态、分组字段)
    其中分组字段groupType就是Purchasebillitem.jsp中对应的分组字段的name值
public class PurchasebillitemQuery extends BaseQuery {
    //开始时间
    private Date beginDate;
    //结束时间
    private Date endDate;
    //状态
    private Integer status;
//-----------分组字段------------------------------    
    //定义一个分组的字段,已解决分组字段写死问题,从前台传过来。1.供应商 2.采购员 3.月份
    private Integer groupType=1;//默认为供应商
//----------------------------------------
    //直接返回Specification这个对象
    /*
     *重点:大于等于开始时间,小于结束时间加一天
     * */
    @Override
    public Specification createSpec() {
        //根据条件把数据返回即可
        //结束时间加一天
        Date tempDate=null;
        if(endDate!=null){
            //DateUtils:lang3包的方法
            tempDate= DateUtils.addDays(endDate,1 );
        }
//----------------------------------------------------        
        //gt:大于  ge:大于等于
        //lt:小于  le:小于等于  eq:等于
        Specification<Purchasebillitem> spec = Specifications.<Purchasebillitem>and()
                .ge(beginDate!=null,"billId.vdate",beginDate)//Purchasebillitem上没有vdate字段,billId这个属性才有
                .lt(endDate!=null,"billId.vdate",tempDate)
                .eq(status!=null,"billId.status",status)
                .build();
        return spec;
    }
//----------------------------------------------------        
    public Date getBeginDate() {
        return beginDate;
    }

    //在SpringMVC中,如果要接收日期参数,一般都要加上注解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }

    //在SpringMVC中,如果要接收日期参数,一般都要加上注解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public Date getEndDate() {
        return endDate;
    }
    //省略get、set方法
  • repository层的父类层写了个根据查询对象查询数据的方法
//根据Query拿到对应的有数据(不分所页)
List<T> findByQuery(BaseQuery baseQuery);
  • service层的接口写一个根据查询条件去数据库查询的方法
//根据查询对象获取到订单报表中的所有明细.泛型就确认类型是PurchasebillitemVo
List<PurchasebillitemVo> findItems(PurchasebillitemQuery query);
  • service层的实现类。主要就是根据查询对象将数据查出来,然后将Purchasebillitem数据通过上面的构造函数转换为报表PurchasebillitemVo对象
@Service
public class PurchasebillitemServiceImpl extends BaseServiceImpl<Purchasebillitem,Long> implements IPurchasebillitemService {

    @Autowired
    private PurchasebillitemRepository purchasebillitemRepository;

    //将查询出来的订单明细Purchasebillitem对象转换为报表PurchasebillitemVo对象。
    @Override
    public List<PurchasebillitemVo> findItems(PurchasebillitemQuery query) {
        //1.准备一个空的PurchasebillitemVO集合容器
        List<PurchasebillitemVo> vos=new ArrayList<>();
        //2.根据查询条件获得所有的订单明细
        List<Purchasebillitem> byQuery = purchasebillitemRepository.findByQuery(query);
        //3.遍历查询出来的所有数据(将每一个Purchasebillitem对象变成PurchasebillitemVo对象)
        for (Purchasebillitem purchasebillitem : byQuery) {
            //4.在PurchasebillitemVo的domain中创建了个构造函数(在new的时候传参过去的purchasebillitem会返回一个purchasebillitemVo)
            PurchasebillitemVo purchasebillitemVo = new PurchasebillitemVo(purchasebillitem,query);
            //5.将得到的purchasebillitemVo对象装进集合中去
            vos.add(purchasebillitemVo);
        }
        //6.将purchasebillitemVo集合返回
        return vos;
    }
}
  • controller层
@RequestMapping("/findItems")
public List<PurchasebillitemVo> findItems(PurchasebillitemQuery query) {
     return purchasebillitemService.findItems(query);
 }

jsp层:

在这里插入图片描述
js:拷贝插件中的代码修改

$('#purchaseBillItemGrid').datagrid({
        fit:true,
        rownumbers:true,
        remoteSort:false, //是否支持远程排序
        nowrap:false,
        fitColumns:true,
        singleSelect:true,
        toolbar:"#gridToolBar",
        url:'/purchasebillitem/findItems', //访问数据的路径
        columns:[[
            {field:'id',title:'编号',width:20,sortable:true},
            {field:'supplier',title:'供应商',width:80,align:'right',sortable:true},
            {field:'buyer',title:'采购员',width:80,align:'right',sortable:true},
            {field:'product',title:'产品',width:40,sortable:true},
            {field:'productType',title:'产品类型',width:60,align:'center'},
            {field:'vdate',title:'交易时间',width:60,align:'center'},
            {field:'price',title:'价格',width:60,align:'center'},
            {field:'num',title:'数量',width:60,align:'center'},
            {field:'amount',title:'小计',width:60,align:'center'},
            {field:'status',title:'状态',width:60,align:'center',formatter:formatStatus}
        ]],
        groupField:'groupField', //根据哪一个字段分组
        view: groupview, //分组视图必需要加这个
        //value:分组的值 rows:这一组的所有值
        groupFormatter:function(value, rows){ //分组位置的显示
            //总数量
            var totalNum=0;
            //总金额
            var totalAmount=0;
            //遍历拿到的组的所有值
            for(let e of rows){
                //数量相加
                totalNum+=e.num;
                //金额相加
                totalAmount+=e.amount;
            }
            return value + ' - ' + `${rows.length}条数据 
                <span style="color: #00ee00">共${totalNum}个商品</span> 
                <span style="color: #ee4b95">总金额:${totalAmount}</span>
               `;
        }
    });
  • 总结图:
    在这里插入图片描述

四、图像页面效果报表

使用3D饼图

  • 使用flash技术和H5技术可以做出来
    在这里插入图片描述
  • 使用插件:EChars 、HighChart
  • 项目中引入HighChart

在这里插入图片描述

  • 在purchasebillitem.jsp中
    引入highcharts中的要使用的js文件
    在这里插入图片描述
    在这里插入图片描述
  • 找到要使用的3D图的原JS代码并拷贝过来加以改动
    在这里插入图片描述
  • 在purchasebillitem.jsp中新增一个3D图按钮
<a href="javascript:;" data-method="chart3d" class="easyui-linkbutton" iconCls="icon-search">3D图</a>

在这里插入图片描述

  • 在purchasebillitem.js中给3D按钮的data-method="chart3d"注册一个事件,点击按钮就能打开3D图形报表。
chart3d(){
            //弹出相应的diagle
            chartDialog.dialog("center").dialog("open");
            //把表单中的参数传过去。
            var params = searchForm.serializeObject();
            //发送ajax请求到后台,并将form表单中的额外参数(时间、状态)也一并提交到后台处理
            $.post("/purchasebillitem/findCharts",params,function (result) {
                //数据得到后进行展示
                Highcharts.chart('chartDialog', {
                    chart: {
                        type: 'pie',
                        options3d: {
                            enabled: true,
                            alpha: 45,
                            beta: 0
                        }
                    },
                    title: {
                        text: '采购订单图形报表'
                    },
                    // 鼠标移上去的文字
                    tooltip: {
                        pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
                    },
                    plotOptions: {
                        pie: {
                            allowPointSelect: true,
                            cursor: 'pointer', //指针样式
                            depth: 30,
                            dataLabels: {
                                enabled: true,
                                format: '{point.name}'
                            }
                        }
                    },
                    //饼中展示的数据(从数据库中查询出来的)
                    series: [{
                        type: 'pie',
                        name: '移上来',
                        // 数据。map集合形式。通过上面的ajax请求将map集合的数据从后台传到前台展示
                        data: result
                    }]
                });
            })
        },
  • 获取3D饼图要展示的数据,从数据库中查询出来。
    在js中3D图需要的数据类型是map集合形式。
    IPurchasebillitemService层:
//获取3D饼图形中需要的数据(在purchasebillitem.jsp中3D饼图展示的数据时map集合形式)
List<Map> findCharts(PurchasebillitemQuery query);

service实现类
在这里插入图片描述

  • purchasebillitemQuery层;接收前台传过来的查询对象参数
/*
* 报表的高级查询
* */
public class PurchasebillitemQuery extends BaseQuery {
    //开始时间
    private Date beginDate;
    //结束时间
    private Date endDate;
    //状态
    private Integer status;
    //定义一个分组的字段,已解决分组字段写死问题,从前台传过来。1.供应商 2.采购员 3.月份
    private Integer groupType=1;//默认为供应商
    //直接返回Specification这个对象
    /*
     *重点:大于等于开始时间,小于结束时间加一天
     * */
    @Override
    public Specification createSpec() {
        //根据条件把数据返回即可
        //结束时间加一天
        Date tempDate=null;
        if(endDate!=null){
            //DateUtils:lang3包的方法
            tempDate= DateUtils.addDays(endDate,1 );
        }
        //gt:大于  ge:大于等于
        //lt:小于  le:小于等于  eq:等于
        Specification<Purchasebillitem> spec = Specifications.<Purchasebillitem>and()
                //Purchasebillitem上没有vdate字段,billId这个属性才有
                .ge(beginDate!=null,"billId.vdate",beginDate)
                .lt(endDate!=null,"billId.vdate",tempDate)
                .eq(status!=null,"billId.status",status)
                .build();
        return spec;
    }
    /*
        String类型的字符串拼接:三种方式的区别
     *String:不适合用于字符串拼接(每次都创建一个新的,性能比较低)
     * StringBuffer:拼接字符串性能高,线程安全
     * StringBuilder:拼接字符串性能最高,线程不安全
     * 只返回  JPQL : where status = ? and date>= beginDate and ...
     * */
    //准备一个parmas集合用来接收JS中的ajax请求传过来的额外参数
    private List parmas=new ArrayList();
//----------拿到前台传来的查询条件(开始时间、结束时间、状态)用于拼接jpql-------    
    //提供一个拼接jpql的方法
    public String createWhereJPQL(){
        StringBuilder jpql = new StringBuilder();
        if(beginDate!=null){
            //大于等于开始时间
            jpql.append(" and o.billId.vdate >=? ");
            parmas.add(beginDate);
        }
        if(endDate!=null){
            //小于结束时间加上1天
            Date tempDate = DateUtils.addDays(endDate,1);
            jpql.append(" and o.billId.vdate<? ");
            parmas.add(tempDate);
        }
        if(status!=null){
            //状态
            jpql.append(" and o.billId.status=? ");
            parmas.add(status);
        }
        //重点:拼接JPQL语句的时候将第一个and替换成where
        return jpql.toString().replaceFirst("and","where");
    }
 //--------------------拿到分组对象值,用于拼接jpql---------------------------
    //拿到分组的值。前台会传查询的query对象(供应商、采购员、月份)
    public String getGroupName(){
        if(groupType==1){
            return "o.billId.supplier.name";
        }else if(groupType==2){
            return "o.billId.buyer.username";
        }else if(groupType==3){
            //获取到日期的月份
            return "MONTH(o.billId.vdate)";
        }else{
            return "o.billId.supplier.name";
        }
    }
    //在SpringMVC中,如果要接收日期参数,一般都要加上注解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }

    //在SpringMVC中,如果要接收日期参数,一般都要加上注解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }
  • controller层
//3D图像报表的ajax请求数据路径
@RequestMapping("/findCharts")
@ResponseBody//返回json数据
public List<Map> findCharts(PurchasebillitemQuery query) {
    return purchasebillitemService.findCharts(query);
}
  • 图解
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Abdullahi_kanye/article/details/88876711