智能商贸系统09-采购订单

本文档详细介绍了智能商贸系统中采购订单的管理,包括准备数据、采购订单分析、数据展示、高级查询、添加与修改操作。分析了Purchasebill与Purchasebillitem的强聚合关系,并阐述了级联保存与删除的实现。在数据展示和高级查询部分,讨论了供应商、采购员、状态的格式化显示以及根据时间和状态的查询方法。添加和修改功能中,涉及了datagrid-edit插件的使用以及控制器中的处理逻辑。
摘要由CSDN通过智能技术生成

1、准备数据

完成下面几个类的基本CRUD,具体的页面后面完成

  • systemdictionarytype:数据字典类型
  • systemdictionarydetail:数据字典明细
  • Supplier:供应商
  • Product:产品

2、采购订单分析

拿到数据库中的表,主要从下面3点进行分析

  • 每个字段的含义
  • 这个字段是否可以为null
  • 这个字段从哪里来?

2.1、采购订单Purchasebill

  • 订单与订单详细为组合关系,组合关系为强聚合
  • 聚合关系为多对一和一对多的关系,强聚合为不可分割的聚合关系
  • 组合关系,一般一方放弃维护关系,交给多方(mappedBy)
  • CascadeType级联,使用all。并且使用orphanRemoval
  • 级联保存,确保一方找到多方,多方找到一方
  • 级联删除,比较危险,删除自己并且删除关系的,所以使用orphanRemoval,先解除关系,再删除
/*
* 采购订单
* */
@Entity
@Table(name = "purchasebill")
public class Purchasebill extends BaseDomain {
    //交易时间,前台传来
    private Date vdate;
    //总金额,计算
    private BigDecimal totalAmount;
    //总数量,计算出来
    private BigDecimal totalNum;
    //录入时间,当前系统时间
    private Date inputTime = new Date();
    //审核时间,可以为空,当前系统时间
    private Date auditorTime;
    //状态,0待审。1已申。2作废
    private Integer status = 0;
    //供应商,optional不能为空,前台传来
    @ManyToOne(fetch = FetchType.LAZY,optional = false)
    @JoinColumn(name = "supplier_id")
    private Supplier supplier;
    //审核员,可以为空,自动获取当前登录的
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "auditor_id")
    private Employee auditor;
    //采购员,不能为空,前台传过来
    @ManyToOne(fetch = FetchType.LAZY,optional = false)
    @JoinColumn(name = "buyer_id")
    private Employee buyer;
    //录入人,当前登录人
    @ManyToOne(fetch = FetchType.LAZY,optional = false)
    @JoinColumn(name = "inputUser_id")
    private Employee inputUser;
    // 一般组合关系使用List,mappedBy放弃维护,交给多方,注意bill与多方的字段名必须一致。
    //CascadeType级联,级联删除,删除自己并且删除关系的
    //orphanRemoval孤儿删除,先解除关系,再删除
    //级联保存,双向都必须找到对方
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
    private List<Purchasebillitem> items = new ArrayList<Purchasebillitem>();
    //get set

2.2、采购订单明细Purchasebillitem

/*
* 采购订单明细
* */
@Entity
@Table(name = "purchasebillitem")
public class Purchasebillitem extends BaseDomain {
    //单价,成本价,前台传
    private BigDecimal price;
    //数量,前台传
    private BigDecimal num;
    //总数量,算出来
    private BigDecimal amount;
    //描述,可以为空,传过来
    private String descs;
    //采购单
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "bill_id")
    @JsonIgnore
    private Purchasebill bill;
    //商品
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "product_id")
    private Product product;
    //get set

3、数据展示

3.1、purchasebill/index.jsp

供应商、采购员、状态格式化展示

<tr>
        <th data-options="field:'',width:100,checkbox:true">多选</th>
        <th data-options="field:'id',width:100">序号</th>
        <th data-options="field:'vdate',width:100">交易时间</th>
        <th data-options="field:'supplier',width:100,formatter:objFormat">供应商</th>
        <th data-options="field:'buyer',width:100,formatter:objFormat">采购员</th>
        <th data-options="field:'totalAmount',width:100">总金额</th>
        <th data-options="field:'totalNum',width:100">总数量</th>
        <th data-options="field:'status',width:100,formatter:statusFormat">状态</th>
    </tr>

3.2、purchasebill.js

function objFormat(v) {
    return v?v.name||v.username:"";
}
function statusFormat(v) {
    if(v == 0){
        return "<span style='color: red'>待审</span>";
    }else if (v == 1){
        return "<span style='color: green;'>已审</span>";
    }else{
        return "<s style='color: grey;'>作废</s>";
    }
}

4、高级查询

根据时间状态查询
在这里插入图片描述

4.1、purchasebill/index.jsp

    <form id="searchForm" method="post">
        交易时间: <input name="beginDate" class="easyui-datebox" style="width:120px"> -
        <input name="endDate" class="easyui-datebox" style="width:120px">
        状态: <select class="easyui-combobox" name="status" style="width:100px;" panelHeight="auto">
        <option value="">--所有--</option>
        <option value="0">待审</option>
        <option value="1">已审</option>
        <option value="-1">作废</option>
    </select>
        <a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
    </form>

4.2、PurchasebillQuery

public class PurchasebillQuery extends BaseQuery {
    //开始时间
    private Date beginDate;
    //结束时间
    private Date endDate;
    //状态
    private Integer status;
    private Long isdelete;

    /*
     *这里需要注意:
     *      如果日期中出现了时间,如2015-04-21 00:00:00
     *      在使用2015-04-21 - 2015-04-21 查询时,会出现只能查到2015-04-21 00:00:00,而2015-04-21 12:00:00查不到
     *      这里可以使用日期+1的方法解决这个问题,但是又会出现一个新的问题,会查到2015-04-22 00:00:00
     *      这样的话就把le(小于等于改成lt小于)
     *
     * */
    @Override
    public Specification createSpecification() {
        //结束时间加1天,lang3包内的方法
        if(endDate!=null){
            endDate = DateUtils.addDays(endDate,1);
        }
        Specification<PurchasebillQuery> specification = Specifications.<PurchasebillQuery>and()
                //大于等于
                .ge(beginDate != null, "vdate", beginDate)
                //小于等于
                .lt(endDate != null, "vdate", endDate)
                .eq(status!=null,"status",status)
                .eq(true, "isdelete", 1L)
                .build();
        return specification;
    }

    @Override
    public Specification createSpecificationRe() {
        Specification<PurchasebillQuery> specification = Specifications.<PurchasebillQuery>and()
                //大于等于
                .ge(beginDate != null, "vdate", beginDate)
                //小于等于
                .lt(endDate != null, "vdate", endDate)
                .eq(status!=null,"status",status)
                .eq(true, "isdelete", 2L)
                .build();
        return specification;
    }
}
@DateTimeFormat(pattern = "yyyy-MM-dd")
public void setBeginDate(Date beginDate) {
     this.beginDate = beginDate;
 }
@DateTimeFormat(pattern = "yyyy-MM-dd")
 public void setEndDate(Date endDate) {
     this.endDate = endDate;
 }  
 //get set

5、添加

需要从前台传过去的内容有:

  • 交易时间vdate
  • 供应商supplier.id
  • 采购员buyer.id
  • 订单明细items
  • 订单明细使用EasyUI扩展中的一个插件datagrid-edit
  • 级联保存,一方找到多方,多方也要找到一方,在controller中设置
    在这里插入图片描述

5.1、purchasebill/index.jsp

引入必须js库,其中[query-1.11.0.js]、[jquery.jdirk.js]、[jquery.easyui.min.js]已经在head.js中引用

 <%--引入编辑支持的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>

准备一个table及两个按钮,在js中动态创建datagrid-edit

 <table id="itemsGrid" style="width: 800px"></table>
  <div id="itemsButtons">
            <a href="#" id="btnInsert" plain="true" iconCls="icon-add" class="easyui-linkbutton">添加</a>
            <a href="#" id="btnRemove"plain="true" iconCls="icon-remove" class="easyui-linkbutton">删除</a>
        </div>

5.2、purchasebill.jsp

添加,自动生成交易时间

add() {
            //打开面板前把里面的数据清除
            editForm.form("clear");
            //修改添加框的标题
            editDialog.dialog({title:'添加用户'});
            //设置交易时间
            $("#nowdate").datebox("setValue", '12/32/2020');
            //把添加框(editDialog)打开
            editDialog.dialog("center").dialog("open");
            //数据进行清空(用空数据把原来数据给换了)
            dg.datagrid("loadData",[]);
        },

创建itemsGrid

  /**
     * dg:获取到你要编辑的grid控件
     * defaultRow:默认行(等会儿会试一下)
     * insertPosition:插入的位置 bottom/top
     */

    var dg = $("#itemsGrid"),
        defaultRow = { product: "", productColor: "", productPic: "", num: 1, price: 0, amount: 0, descs: "" },
        insertPosition = "bottom";

    /**
     *  grid控件的初始化工作
     */
    var dgInit = function () {
        //获取列数据
        var getColumns = function () {
            var result = [];
            //列标题
            /**
             * editor:代表这一列是可以编辑的
             *      type:代表这个编辑器类型
             *      options:代表这个编辑器的属性
             */
            var normal = [
                {
                    field: 'product', title: '产品', width: 100,
                    editor: {
                        type: "combobox",
                        options: {
                            required: true,
                            valueField:'id',textField:'name',panelHeight:'auto',url:'/product/list'
                        }
                    },
                    //注意:这个应该和列同级
                    formatter:objFormat
                },
                {
                    field: 'productColor', title: '颜色', width: 100,
                    // v:格子中数据 r:行数据   i:索引
                    formatter:function (v,r,i) {
                        if(r && r.product){
                            return `<div style="width: 20px;height: 20px;background-color:${r.product.color}"></div>`;
                        }
                        return "";
                    }
                },
                {
                    field: 'productPic', title: '图片', width: 100,
                    // v:格子中数据 r:行数据   i:索引
                    formatter:function (v,r,i) {
                        if(r && r.product){
                            return `<image src="${r.product.smallPic}" style="width: 50px;height: 50px;" />`;
                        }
                        return "";
                    }
                },
                {
                    field: 'num', title: '数量', width: 100,
                    editor: {
                        type: "numberbox",
                        options: {
                            precision:2,
                            required: true
                        }
                    }
                },
                {
                    field: 'price', title: '价格', width: 100,
                    editor: {
                        type: "numberbox",
                        options: {
                            precision:2,
                            required: true
                        }
                    }
                },
                {
                    field: 'amount', title: '小计', width: 100,
                    formatter:function (v,r,i) {
                        if(r && r.num && r.price){
                            // toFixed:保留两位小数
                            return (r.num * r.price).toFixed(2);
                        }
                        return "";
                    }
                },
                {
                    field: 'descs', title: '备注', width: 100,
                    editor: {
                        type: "text"
                    }
                }
            ];
            result.push(normal);

            return result;
        };
        //grid控件的属性
        var options = {
            idField: "ID",
            rownumbers: true,
            fitColumns: true,
            fit: true,
            border: true,
            singleSelect: true,
            columns: getColumns(),
            bodyCls:"itemsBody",
            toolbar:"#itemsButtons",
            //表示开启单元格编辑功能
            enableCellEdit: true
        };
        //创建grid控件
        dg.datagrid(options);

    };

    /**
     *  获取到插件的行位置
     */
    var getInsertRowIndex = function () {
        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 });
            dg.datagrid("editCell", { index: 0, field: "Code" });
        });
        //删除一行数据
        $("#btnRemove").click(function () {
            //1.拿到这一行
            var row = dg.datagrid("getSelected");
            //2.拿到这一行的索引
            var index = dg.datagrid("getRowIndex",row);
            //3.根据索引删除它
            dg.datagrid("deleteRow",index)
        });
    };

    //页面加载完成后调用对应方法
    dgInit(); buttonBindEvent();

保存

save(){
            var url = "/purchasebill/save";
            console.debug(editForm);
            if ($("#purchasebillId").val()){
                url = "/purchasebill/update?_cmd=update";
            }
            editForm.form('submit', {
                //提交路径,变量名相同可以直接写
                url:url,
                onSubmit: function(param){
                    //拿到所有的行(明细的)
                    var rows = dg.datagrid("getRows");
                    for(var i=0;i<rows.length;i++){
                        var r = rows[i];
                        param[`items[${i}].product.id`] = r.product.id;
                        param[`items[${i}].num`] = r.num;
                        param[`items[${i}].price`] = r.price;
                        param[`items[${i}].descs`] = r.descs;
                    }
                    //提交前验证
                    return $(this).form('validate');
                },
                //data是一个json字符串{"success":true}
                success:function(data){
                    //把一个Json字符串转成JSON对象
                    //eval("("+data+")")
                    var result = JSON.parse(data);
                    if(result.success){
                        //成功就刷新当前页面
                        datagrid.datagrid("reload");
                    }else{
                        $.messager.alert('警告',`添加失败,原因是:${result.msg}`,"warning");
                    }
                    //关闭对话框
                    xuxusheng.close();
                }
            });
        },

5.3、controller

    //将保存和修改两个方法合并
    public JsonResult saveOrUpdate(Purchasebill purchasebill) {
        try {
            //设置录入员
            Employee employee = UserContext.getUser();
            purchasebill.setInputUser(employee);
            //级联保存,需要一方找到多方,多方也能找到一方
            //一方获取多方
            List<Purchasebillitem> items = purchasebill.getItems();
            //①.准备总金额与总数量
            BigDecimal totalAmount = new BigDecimal(0);
            BigDecimal totalNum = new BigDecimal(0);
            for (Purchasebillitem item : items){
                item.setBill(purchasebill);
                //计算当前明细的小计  multiply:乘法
                item.setAmount(item.getNum().multiply(item.getPrice()));
                //②.计算总金额与总数量
                totalAmount = totalAmount.add(item.getAmount());
                totalNum = totalNum.add(item.getNum());
            }
            //③.把总金额与总数量放到采购订单中
            purchasebill.setTotalAmount(totalAmount);
            purchasebill.setTotalNum(totalNum);
            purchasebill.setIsdelete(1L);
            purchasebillService.save(purchasebill);
            return new JsonResult();
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResult(false, e.getMessage());
        }
    }

6、修改

数据回显,表单元素和非表单元素回显

 edit() {
            //获取选择的行
            var row = datagrid.datagrid("getSelected");
            //判断是否选择了一行
            //没有选择提示并结束
            if (!row) {
                $.messager.alert('提示', '请先选择一行进行修改', "info");
                return;
            }else {
                //修改添加框的标题
                editDialog.dialog({title:'修改用户'});
                //把添加框(editDialog)打开
                editDialog.dialog("center").dialog("open");
                //清空表单中的数据
                editForm.form("clear");
                //设置供应商的回显
                if(row.supplier){
                    row["supplier.id"] = row.supplier.id;
                }
                if(row.buyer){
                    row["buyer.id"] = row.buyer.id;
                }
               //回显其他内容
                editForm.form('load',row);
                //回显grid中的数据
                //1.拿到当前这一行的所有明细(复制)
                var items = [...row.items];
                //2.把明细放到grid中
                dg.datagrid("loadData",items);
            }
        },
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值