组合关系&采购单&easyUI日历插件

组合关系:就是强聚合,双向的多对一、一对多,他们之间是不能分割的。
在JPA中组合关系的配置:级联,级联要么不配,要么就配置最强的:all+孤儿删除
在单据的地方可配置级联+孤儿删除
UML,如果是实心的菱形,就是组合关系,如果是空心的菱形就是聚合关系。
要想整体和部分不可分割,代码就要配置级联。
一对多,性能超级差
双向一对多的话,就要让一方放弃关系维护,才能提高性能。
组合关系-采购订单模型
分析表字段:
1、每个字段的意思
2、这个字段的类型(为什么要用这个类型)
3、字段是否可以为空
4、这个字段的值应该从哪里来

配置采购单关系

  private Date vdate;
    
    private BigDecimal totalamount;
    
    private BigDecimal totalnum;
    
    private Date inputtime=new Date();
    
    private Date auditortime;
//  状态
    private Integer status=0;

//   与 供应商的表关系
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "supplier_id")
    private Supplier supplier;
//    与审核人的关系
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "auditor_id")
    private Employee auditor;
//    与录入员的关系
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inputUser_id")
    private Employee inputuser;
//    与采购员的关系
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "buyer_id")
    private Employee buyer;

//    一般组合关系使用list
    @OneToMany(cascade = CascadeType.ALL,mappedBy = "bill",fetch = FetchType.LAZY,orphanRemoval = true)
    private List<Purchasebillitem> items=new ArrayList<>();
配置采购详单关系
  private BigDecimal price;
    
    private BigDecimal num;
    
    private BigDecimal amount;
    
    private String descs;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "bill_id")
//    表示不用理他
    @JsonIgnore
    private Purchasebill bill;

purchasebill.jsp
表格部分

<tr>

    <th data-options="field:'vdate',width:100">交易时间</th>

    <th data-options="field:'totalamount',width:100">总金额</th>

    <th data-options="field:'totalnum',width:100">总数量</th>

    <th data-options="field:'inputtime',width:100">录入时间</th>

    <th data-options="field:'supplier',width:100,formatter:formatName">供应商</th>

    <th data-options="field:'auditor',width:100,formatter:formatName">审核人</th>

    <th data-options="field:'inputuser',width:100,formatter:formatName">录入人</th>

    <th data-options="field:'buyer',width:100,formatter:formatName">采购员</th>
    <th data-options="field:'status',width:100,formatter:formatStatus">状态</th>

</tr>

高级查询部分

<div>
    <form id="searchForm">
        交易时间:
        <input name="beginDate" class="easyui-datebox" style="width:120px"/>--
        <input name="endDate" class="easyui-datebox" style="width:120px"/>
        状态:
        <select  class="easyui-combobox" panelHeight="auto" name="status" style="width:120px;">
            <option value="">--请选择--</option>
            <option value="0">待审核</option>
            <option value="1">已审核</option>
            <option value="-1">已废除</option>
        </select>
        <a href="javascript:;" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
    </form>
</div>

使前台显示的交易时间为我们定义的格式

我们用一个easyUI的日历插件来获取时间,设置日期格式,加上东八区

//添加下面的注解,进行时间配置,使前台显示的交易时间为我们定义的格式
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    public Date getVdate() {
        return vdate;
    }

提醒自己:jsp表格里面的field必须和domain里面配置的字段一样

做高级查询

后台接受前台的数据
PurchasebillQuery,get/set,

   private String name;
//    查询的开始时间
      private Date beginDate;
//    查询的结束时间
      private Date endDate;
//    状态
      private Integer status;


    
    //这里帮我们直接返回Specification这个对象
    //StringUtils.isNotBlank(stru):不为空且不是空字符串
//    ge:大于等于,le:小于等于,lt:小于
    @Override
    public Specification  createSpec(){
//        想在采购单管理表里面的高级查询里面,选择查询一天之内任何时间的数据,lang3给我们提供了这个方法
//       先在结束时间上加一天
        Date addDays=null;
        if(endDate!=null){
            addDays = DateUtils.addDays(endDate, 1);
        }
        Specification<Purchasebill> spec = Specifications.<Purchasebill>and()
                .like(StringUtils.isNotBlank(name),"name", "%"+name+"%")
                .ge(beginDate!=null,"vdate" ,beginDate )
//                为了能够实现可以查询一天内的所有数据,下面还要将上面加1的字段写入
                .lt(endDate!=null,"vdate" ,addDays )
                .eq(status!=null,"status",status)
                .build();
        return spec;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBeginDate() {
        return beginDate;
    }
//   在SpringMVC里面,要想接收一个日期参数,需要在set上面加上一个下面的注解,并配置格式
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }

    public Date getEndDate() {
        return endDate;
    }
    //   在SpringMVC里面,要想接收一个日期参数,需要在set上面加上一个下面的注解,并配置格式
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }
}

小知识:400错误,表示参数类型出错。

SpringMVC接受日期参数

在SpringMVC里面,如果想要接受一个日期参数,要set上面加一个下面的注解@DateTimeFormat
在这里插入图片描述

后台的数据传到前台

在这里插入图片描述

在做高级查询的时候,时间选择我们使用日历,直接将class改成下图所示就可以了
在这里插入图片描述

设计高级查询

在设计高级查询的时候,做一个下拉框,在后台写死

<div>
    <form id="searchForm">
        交易时间:
        <input name="beginDate" class="easyui-datebox" style="width:120px"/>--
        <input name="endDate" class="easyui-datebox" style="width:120px"/>
        状态:
        <select  class="easyui-combobox" panelHeight="auto" name="status" style="width:120px;">
            <option value="">--请选择--</option>
            <option value="0">待审核</option>
            <option value="1">已审核</option>
            <option value="-1">已废除</option>
        </select>
        <a href="javascript:;" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
    </form>
</div>

调节下拉框的长度(panelHeight)

在这里插入图片描述

在高级查询里面查询一天内所有的数据

想在高级查询里面,查一天之中的所有数据怎么办,结束时间加一天,然后下面写小于

@Override
    public Specification  createSpec(){
//        想在采购单管理表里面的高级查询里面,选择查询一天之内任何时间的数据,lang3给我们提供了这个方法
//       先在结束时间上加一天
        Date addDays=null;
        if(endDate!=null){
            addDays = DateUtils.addDays(endDate, 1);
        }
        Specification<Purchasebill> spec = Specifications.<Purchasebill>and()
                .like(StringUtils.isNotBlank(name),"name", "%"+name+"%")
                .ge(beginDate!=null,"vdate" ,beginDate )
//                为了能够实现可以查询一天内的所有数据,下面还要将上面加1的字段写入
                .lt(endDate!=null,"vdate" ,addDays )
                .eq(status!=null,"status",status)
                .build();
        return spec;
    }

增删改查

弹出的操作数据表单,交易时间、供应商、采购员,只需要这三个是我们需要进行选择的。
供应商和采购员的下拉框,从数据库中读出来

<input id="purchasebillId" type="hidden" name="id"/>
<table cellpadding="5">
    <tr>
        <td>交易时间:</td>
        <td><input name="vdate" type="text" class="easyui-datebox" data-options="required:true"/>
        </td>
    </tr>
    <tr>
        <td>供应商:</td>
        <td><input name="supplier.id" class="easyui-combobox" panelHeight="auto" style="width:120px"
                   data-options="valueField:'id',textField:'name',url:'/util/supplierList'"/>
        </td>
    </tr>
    <tr>
        <td>采购员:</td>
        <td><input name="buyer.id" class="easyui-combobox" style="width:120px"
                   data-options="valueField:'id',textField:'username',url:'/util/buyerList'"/>
        </td>
    </tr>
</table>

通过部门筛选拿到采购部所有员工

我忘记的小知识:所有的下拉框数据获取都写在UtilController里面,拿到所有采购员的方法,是下面写的通过部门筛选拿到的采购部的所有员工的方法。

@RequestMapping("/buyerList")
@ResponseBody
public List<Employee> buyerList(){
    return employeeService.findBuyer();
}

JPQL

在EmployeeRepository里面字儿JPQL查询语句,当需要进行选择查询的时候

//查询出部门
    @Query("select o from Employee o where o.department.name=?1")
    List<Employee> findByDeptName(String deptName);

IEmployeeService

List<Employee> findBuyer();

EmployeeServiceImpl

@Override
public List<Employee> findBuyer() {
    return employeeRepository.findByDeptName("采购部");
}

小知识:时间格式里面的东八区只有获取的时候才需要。
继续上面的操作:

添加保存功能:

在采购单controller里面,记得在save方法里面获取当前登录用户,不然无法保存数据,会报错。

 @RequestMapping("/save")
    @ResponseBody
    public JsonResult save(Purchasebill purchasebill){
//        拿到当前的登录对象
        Employee loginUser = UserContext.getUser();
        purchasebill.setInputuser(loginUser);
        return saveOrUpdate(purchasebill);
    }

明细数据保存
效果图:
在这里插入图片描述
需要引入的js

<!-- 编辑框支持 -->
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.getColumnInfo.js"></script>
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.editors.js"></script>
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.edit.cellEdit.js"></script>

解决可编辑grid的问题,easyUI一定要版本1.6.3,不然兼容器有问题

js有顺序问题,
将上面选中部分的内容拷贝到采购单管理的js文件中,要记得放到function最后面

//dg代表要操作的表格
//defaultRow:默认行,表格里面的列属性
//insertPosition:数据插入的位置,top,表示从上面插入,bottom,表示从下面插入
var dg = $("#dg1"),
    defaultRow = { product: "", productcolor: "", productImage: "", num: "", price: "", amount: "", descs: "" },
    insertPosition = "bottom";
//表格的初始化操作
var dgInit = function () {
    //表格里面的列里面的数据
    var getColumns = function () {
        var result = [];

        var normal = [
            {
                field: 'product', title: '产品', width: 180,
                editor: {
                    type: "combobox",//编辑器类型,这里我们写入产品通过下拉列表,不用验证
                    //编辑器的属性
                    options: {
                        valueField:'id',
                        textField:'name',
                        url:'/util/productList',
                        panelHeight:"auto",
                        required: true
                    }
                },
                formatter:function(value){
                    return value?value.name:"";
                }
            },
            {
                field: 'productcolor', title: '颜色', width: 180,
                formatter:function(v,r,i){
                    if(r && r.product){
                        //我也不知道为什么,这里要想显示颜色,就必须要写显示的范围
                        return `<div style='width: 20px;height: 20px;background-color: ${r.product.color}'></div>`
                    }
                }
            },
            {
                field: 'productImage', title: '图片', width: 100,
                formatter:function(v,r,i){
                    if(r && r.product){
                        return `<img style='height: 50px;' alt="" src='${r.product.smallpic}'>`;
                    }
                }
            },
            {
                field: 'num', title: '数量', width: 100,
                editor: {
                    type: "numberbox",
                    options: {
                        required: false,
                        precision:2  //保留两位小数
                    }
                }
            },
            {
                field: 'price', title: '价格', width: 100,
                editor: {
                    type: "numberbox",
                    options: {
                        required: false,
                        precision:2  //保留两位小数
                    }
                }
            },
            {
                field: 'amount', title: '小计', width: 100,
                formatter:function (v,r,i){
                    if (r.num && r.price){
                        //toFixed,表示将结果保留两位小数
                        return (r.num*r.price).toFixed(2);
                    }
                }
            },
            {
                field: 'descs', title: '描述', width: 100,
                editor: {
                    type: "text",
                }
            }
        ];
        result.push(normal);
        return result;
    };
    //这里的option是grid的所有属性
    var options = {
        idField: "ID",
        rownumbers: true,//行号
        fitColumns: true,//自适应列
        fit: true,//自适应父容器
        border: true,//border为true,表示给grid添加边框
        toolbar:"#editGridTools",//这里写的是按钮的id
        singleSelect: true,//单选,只选中一行
        columns: getColumns(),//获取到grid里面的所有的列
        enableCellEdit: true  //表示开启单元格编辑功能
    };

    dg.datagrid(options);

};
//下面的这个方法是为了得到每次插入行的索引
//dg.datagrid("getRows").length,拿到最后一行的索引
var getInsertRowIndex = function () {
    //返回的类型是number
    return insertPosition == "top" ? 0 : dg.datagrid("getRows").length;
}
//这里是添加一行,删除一行按钮的绑定事件
var buttonBindEvent = function () {
    //表示注册一个添加事件
    $("#btnInsert").click(function () {
        //这里拿到插入的数据的索引位置
        var targetIndex = getInsertRowIndex(), targetRow = $.extend({}, defaultRow, { ID: $.util.guid() });
        dg.datagrid("insertRow", { index: targetIndex, row: targetRow });
        //index表示第几行,field表示要操作那个字段
        dg.datagrid("editCell", { index: targetIndex, field: "product" });
    });
    //删除行,不用连接到数据库,只是在添加,修改的时候一次性删除多余不要的行
    $("#btnRemove").click(function () {
        //拿到选中的行
        var row = dg.datagrid("getSelected");
        //如果不为空
        if(row){
            //拿到当前选中行的索引
            var index=dg.datagrid("getRowIndex",row)
        //    通过索引将选中行直接从grid里面删除
            dg.datagrid("deleteRow",index);
        }
    });
};
//执行上面的两个方法
dgInit(); buttonBindEvent();


可以在option里面添加边框属性,

border: true,//border为true,表示给grid添加边框

配置两个按钮,在purchasebill.jsp里面

<table id="dg1" style="width: 680px;height: 260px"></table>
<div id="editGridTools" class="datagrid-toolbar">
    <a id="btnInsert" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true">新增一行</a>
    <a id="btnRemove" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true">删除一行</a>
</div>

按钮效果:
在这里插入图片描述
dg:代表要操作的表格

为grid添加上对应的字段:

var dg = $("#dg1"),
    defaultRow = { product: "", productcolor: "", productImage: "", num: "", price: "", amount: "", descs: "" },
    insertPosition = "bottom";
需要编辑的表格,要有edit
//表格的初始化操作
var dgInit = function () {
    //表格里面的列里面的数据
    var getColumns = function () {
        var result = [];

        var normal = [
            {
                field: 'product', title: '产品', width: 180,
                editor: {
                    type: "combobox",//编辑器类型,这里我们写入产品通过下拉列表,不用验证
                    //编辑器的属性
                    options: {
                        valueField:'id',
                        textField:'name',
                        url:'/util/productList',
                        panelHeight:"auto",
                        required: true
                    }
                },
                formatter:function(value){
                    return value?value.name:"";
                }
            },
            {
                field: 'productcolor', title: '颜色', width: 180,
                formatter:function(v,r,i){
                    if(r && r.product){
                        //我也不知道为什么,这里要想显示颜色,就必须要写显示的范围
                        return `<div style='width: 20px;height: 20px;background-color: ${r.product.color}'></div>`
                    }
                }
            },
            {
                field: 'productImage', title: '图片', width: 100,
                formatter:function(v,r,i){
                    if(r && r.product){
                        return `<img style='height: 50px;' alt="" src='${r.product.smallpic}'>`;
                    }
                }
            },
            {
                field: 'num', title: '数量', width: 100,
                editor: {
                    type: "numberbox",
                    options: {
                        required: false,
                        precision:2  //保留两位小数
                    }
                }
            },
            {
                field: 'price', title: '价格', width: 100,
                editor: {
                    type: "numberbox",
                    options: {
                        required: false,
                        precision:2  //保留两位小数
                    }
                }
            },
            {
                field: 'amount', title: '小计', width: 100,
                formatter:function (v,r,i){
                    if (r.num && r.price){
                        //toFixed,表示将结果保留两位小数
                        return (r.num*r.price).toFixed(2);
                    }
                }
            },
            {
                field: 'descs', title: '描述', width: 100,
                editor: {
                    type: "text",
                }
            }
        ];
        result.push(normal);
        return result;
    };

点击添加按钮,绑定一个事件,添加一行

//下面的这个方法是为了得到每次插入行的索引
//dg.datagrid("getRows").length,拿到最后一行的索引
var getInsertRowIndex = function () {
    //返回的类型是number
    return insertPosition == "top" ? 0 : dg.datagrid("getRows").length;
}
//这里是添加一行,删除一行按钮的绑定事件
var buttonBindEvent = function () {
    //表示注册一个添加事件
    $("#btnInsert").click(function () {
        //这里拿到插入的数据的索引位置
        var targetIndex = getInsertRowIndex(), targetRow = $.extend({}, defaultRow, { ID: $.util.guid() });
        dg.datagrid("insertRow", { index: targetIndex, row: targetRow });
        //index表示第几行,field表示要操作那个字段
        dg.datagrid("editCell", { index: targetIndex, field: "product" });
    });
    //删除行,不用连接到数据库,只是在添加,修改的时候一次性删除多余不要的行
    $("#btnRemove").click(function () {
        //拿到选中的行
        var row = dg.datagrid("getSelected");
        //如果不为空
        if(row){
            //拿到当前选中行的索引
            var index=dg.datagrid("getRowIndex",row)
        //    通过索引将选中行直接从grid里面删除
            dg.datagrid("deleteRow",index);
        }
    });
};
//执行上面的两个方法
dgInit(); buttonBindEvent();

当点击保存的时候,前台页面被保存的数据中没有总金额和总数量,数据库里面,只有采购单里面添加了数据,但是还是没有总金额和总数量,采购单明细里面没有添加任何数据。
当点击保存两条数据的时候,前台的显示只有一条数据,而且没有数量和价格和小计,因为他只提交了添加表单的上半部分。

在这里插入图片描述
在这里插入图片描述 在这里插入图片描述
上面的错误可能是保存的时候一方和多方不能相互找到。,测试结果,多方找一方找不到。
尝试解决这个错误
在这里插入图片描述
双方都能找到对方,但是还是出错,因为产品没有传id
下面前台代码传一个product.id
在这里插入图片描述
双方添加成功,但是没有计算小计和总数,我们需要在java代码中进行计算。
直接相乘的话,会报错,因为BigDecimal不支持。应该写下面的格式。
在这里插入图片描述

关于添加表单的清除

add(){
    //将被隐藏的密码框和确认密码框显示出来
    $("*[data-show]").show();
    $("*[data-show] input").validatebox("enable");
    //打开对话框
    purchasebillDialog.dialog("center").dialog("open");
// 清空上次添加的数据
    purchasebillForm.form("clear");
//    清空额外的数据
    dg.datagrid("loadData",[]);
},

修改表单额外数据的回显

edit(){
    //获取选中的行
    var row = purchasebillDataGrid.datagrid("getSelected");
    //判断是否选中
    if(!row){
        $.messager.alert("提示","亲,您还没有选中哦","info");
        return;
    }
    //将被显示的密码框和确认密码框隐藏起来出来
    $("*[data-show]").hide();
    $("*[data-show] input").validatebox("disable");
    //打开对话框
    purchasebillDialog.dialog("center").dialog("open");
    //把form表单里面的数据清空
    purchasebillForm.form("clear");
    //回显数据
    //回显供应商
    if(row.supplier){
        row["supplier.id"]=row.supplier.id;
    }
    if(row.buyer){
        row["buyer.id"]=row.buyer.id;
    }
    //回显数据
    purchasebillForm.form("load",row);
//    回显额外的数据
//    要先复制一条出来,因为如果不先复制一条的话,到时候在前台点击修改,
    // 修改了里面的数据之后,又点击取消,再次打开,数据就会发生变化
    var copyItems=[...row.items];
    dg.datagrid("loadData",copyItems);
},

修改数据只加不减,不然就报n to n错误

在这里插入图片描述

解决

@ModelAttribute("editPurchasebill")
public Purchasebill beforeEdit(Long id,String cmd){
    //只有修改才做查询
    if(id!=null && "update".equals(cmd)){
        Purchasebill dbPurchasebill = purchasebillService.findOne(id);
        //解决n-to-n的问题(凡是要传过来的关联对象,都把它清空)

        dbPurchasebill.setSupplier(null);
        dbPurchasebill.setBuyer(null);
        dbPurchasebill.getItems().clear();
        return dbPurchasebill;
    }
    return null;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值