1.准备工作 创建 实体类 配置关系和 前端页面 展示
1.Purchasebill组合关系的一方
package cn.itsource.aisell.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* (Purchasebill)实体类
*
* @author jie
* @since 2019-08-13 18:54:08
*/
@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; //审核时间
private Integer status; //单据状态 0 未审核 -1 不通过 1 通过
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "supplier_id")
private Supplier supplier;// 多对一 供应商(需要选择) 可以为空
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "auditor_id")
private Employee auditor; //审核人 录入可以为null
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "inputuser_id")
private Employee inputuser;//录入人 不能为null 当前登陆用户
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "buyer_id")
private Employee buyer; //采购员
//明細 强级联 orphanRemoval 一方解除关系 去删除
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy ="bill",orphanRemoval = true)
private List<Purchasebillitem> items = new ArrayList<>();
//格式化时间 最好写在 getset方法上
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
public Date getVdate() {
return vdate;
}
@JsonFormat(pattern = "yyyy-MM-dd")
public void setVdate(Date vdate) {
this.vdate = vdate;
}
2.purchasebillitem组合关系的多方
private BigDecimal price; //价格
private BigDecimal num; //数量
private BigDecimal amount; //产品小计 价格*数量
private String descs; //描述
// 非空 产品
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "product_id")
private Product product;
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "bill_id")
@JsonIgnore // 返回页面 不展示出来 生成json 的时候忽略这个属性
private Purchasebill bill;
3.purchasebill.jsp
<table id="purchasebillGrid" class="easyui-datagrid" data-options="fit:true,fixed:true,fitColumns:true,toolbar:'#tb',singleSelect:true";
url="/purchasebill/page"
iconCls="icon-save"
rownumbers="true" pagination="true">
<thead>
<tr>
<th width="20" field="vdate">交易时间</th>
<th width="20" field="supplier" data-options="formatter:formatObj">供应商</th>
<th width="20" field="buyer" data-options="formatter:formatEmp">采购员</th>
<th width="20" field="totalNum">总数量</th>
<th width="20" field="totalAmount" >总金额</th>
<th width="20" field="status" data-options="formatter:formatStatus" >状态</th>
</tr>
</thead>
</table>
4.purchasebill.js
//表格数据格式化 formatObj 供应商转换
function formatObj(value){
if(value){
return value.name;
}
}
//ormatEmp 采购员
function formatEmp(value){
if(value){
return value.username;
}
}
// 状态转换 0 1 -1
function formatStatus(value){
var data = {
0:"<div style='color: green'>审核中</div>",
1:"<div style='color: red'>审核通过</div>",
"-1":"<div><s>审核未通过</s></div>"
};
return data[value];
}
2.添加 查询条件 主要是时间查询 首先添加查询组件
<div id="cc" class="easyui-calendar"></div>
<form id="searchForm" action="/purchasebill/download" method="post">
日期 : <input name="beginDate" class="easyui-datebox" style="height:32px" sharedCalendar="#cc">
- <input name="endDate" class="easyui-datebox" style="height:32px" sharedCalendar="#cc">
状态 :<select class="easyui-combobox" name="status"
data-options="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>
**1 在query 层 添加查询条件 **
/**
* 单独的查询对象
* PurchasebillQuery
* DepartmentQuery
*
* PurchasebillController search(PurchasebillQuery query)
*/
public class PurchasebillQuery extends BaseQuery{
private String name;
//接收时间和状态
private Date beginDate;
private Date endDate;
private Integer status;
public Date getBeginDate() {
return beginDate;
}
@DateTimeFormat(pattern = "yyyy-MM-dd")
public void setBeginDate(Date beginDate) {
this.beginDate = beginDate;
}
public Date getEndDate() {
return endDate;
}
@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;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽取查询
@Override
public Specification createSpecification() {
// 接收时间
// 前端的日期时分秒按照0:00:00来处理,如果不对日期+1处理,结束时间是不能成功获取查询的值.
// 如下单时间是09-30 15:00:00,而endDate输入09-30,后台获取到09-30 0:00:00
Date tempDate = null;
if(this.endDate!=null){
//直接用 DateUtils.addDays 表示在当前日期加上一天 ,如果是月底最后一天 会自动转到下个月
tempDate = DateUtils.addDays(this.endDate,1 );
System.out.println(tempDate);
}
Specification<Purchasebill> spe = Specifications.<Purchasebill>and()
.ge(this.beginDate != null, "vdate",this.beginDate )// 大于等于
//这里因为上面的时间加了一天 所以不能用小于等于 只能用小于
.lt(this.endDate!=null,"vdate",tempDate)
.eq(this.status!=null && !"".equals(this.status),"status",this.status)
.build();
return spe;
}
}
**2 添加采购订单 的 from表单 和明细表单 **
首先要引用js 其他基本的easyui 的那些就省略了
<!-- 编辑框支持 -->
<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>
然后弹出窗口组件
<!-- 弹出相应的功能框 -->
<div id="purchasebillDialog" class="easyui-dialog" title="数据操作" data-options="closed:true,modal:true" style="width:800px;padding:10px">
<form id="purchasebillForm" method="post">
<input id="purchasebillId" type="hidden" name="id">
<table cellpadding="5">
<tr>
<td>交易时间:</td>
<td><input class="easyui-datebox"name="vdate" data-options="required:true"></input></td>
</tr>
<tr>
<td>供应商:</td>
<td>
<input class="easyui-combobox" name="supplier.id"
data-options="valueField:'id',textField:'name',panelHeight:'auto',url:'/util/findAllSupplier'">
</td>
</tr>
<tr>
<td>采购员:</td>
<td>
<input class="easyui-combobox" name="buyer.id"
data-options="valueField:'id',textField:'username',url:'/util/findAllBuyer'">
</td>
</tr>
</table>
<!-- 明细表格-->
<table id="gridItem" title="明细编辑" style="width:100%;height:300px"></table>
<!-- 采购单明细的按钮准备 -->
<div id="itemBtns">
<a href="javascript:;" id="btnInsert" class="easyui-linkbutton"
data-options="iconCls:'icon-add',plain:true">添加</a>
<a href="javascript:;" id="btnRemove" class="easyui-linkbutton"
data-options="iconCls:'icon-remove',plain:true">删除</a>
</div>
<div style="text-align:center;padding:5px">
<a href="javascript:void(0)" class="easyui-linkbutton" data-method="save">提交</a>
<a href="javascript:void(0)" class="easyui-linkbutton" onclick="$('#purchasebillDialog').dialog('close')">取消</a>
</div>
</form>
</div>
2 在 UtilController后台 写查询方法 来支持下拉
2.1 findAllSupplier 直接查询就行了
@RequestMapping("/findAllSupplier")
@ResponseBody
public List<Supplier> findAllSupplier() {
return supplierService.findAll();
}
2.2 findAllBuyer 需要在底层覆写查询条件
EmployeeRepository 层
这里可以根据部门ID 和名字查询 都是一样的
@Query("select o from Employee o where o.department.name = ?1 ")
List<Employee> getEmpByDept(String deptName);
在service 层添加方法
//根据部门名称 查询
List<Employee> getEmpByDept(String deptName);
实现层
@Override
public List<Employee> getEmpByDept(String deptName) {
return employeeRepository2.getEmpByDept(deptName);
}
@RequestMapping("/findAllBuyer")
@ResponseBody
public List<Employee> findAllBuyer() {
return employeeService.getEmpByDept("采购部");
}
**3 保存出错 在save方法里 **
@Override
public void save(Purchasebill purchasebill) {
//当前登录用户为录入人 从作用域取当前登录用户
Employee loginUser = UserContext.getUser();
purchasebill.setInputUser(loginUser);
super.save(purchasebill);
}
3 数据明细操作
在utilcontroller 工具类里 在添加一个查询 所有员工的方法
@RequestMapping("/findAllProduct")
@ResponseBody
public List<Product> findAllProduct(){
return productService.findAll();
}
purchasebill.js (包含所有的CRUD 以及事务处理,逻辑判断等等)
//表格数据格式化
function formatObj(value){
if(value){
return value.name;
}
}
function formatEmp(value){
if(value){
return value.username;
}
}
function formatStatus(value){
var data = {
0:"<div style='color: green'>审核中</div>",
1:"<div style='color: red'>审核通过</div>",
"-1":"<div><s>审核未通过</s></div>"
};
return data[value];
}
$(function(){
//定义form表单
var searchForm = $("#searchForm");
var purchasebillGrid = $("#purchasebillGrid");
//获取purchasebillDialog
var purchasebillDialog = $("#purchasebillDialog");
//定义表单新增的form
var purchasebillForm = $("#purchasebillForm");
//绑定事件 easyui 第二天的时候
$("a[data-method]").on('click',function(){
//获取 data-method属性 <a data-method="seacher">
var methodName = $(this).data("method");
//动态调用方法 itsource["seacher"]
itsource[methodName]();
});
//对象
var itsource = {
search:function(){
//怎么完成高级查询 jquery.jdirk.js 这个方法 这是jquery扩展方法
//该方法返回一个 JSON Object,返回对象中的每个数据都表示一个表单控件值。
var param = searchForm.serializeObject();
//发送查询数据库 --加载表格 发送请求 /purchasebill/page
purchasebillGrid.datagrid('load',param);
},
add:function(){
//清空表单
purchasebillForm.form('clear');
//新增 --弹出一个对话框--装一个表单
purchasebillDialog.dialog('center').dialog('open');
//把明细的数据清空
$("#gridItem").datagrid('load',[]);
},
edit:function(){
//选择一条数据进行修改
var row = purchasebillGrid.datagrid('getSelected');
if(row){
//弹出对话框
purchasebillDialog.dialog('center').dialog('open');
//供货商
if(row.supplier){
row["supplier.id"] = row.supplier.id;
}
//供货商
if(row.buyer){
row["buyer.id"] = row.buyer.id;
}
// 回显 加载相应的数据(要看product的名称是否可以对应上)
for(var i=0;i<row.items.length;i++){
var item = row.items[i];
item["productId"] = item.product;
}
var items = $.extend([], row.items);
//明细表格回显
$("#gridItem").datagrid('loadData',items);
//修改 -- 回显示数据
purchasebillForm.form('load',row);
}else{
//提示用户
$.messager.alert('温馨提示:','请选中一条数据进行修改','info');
return;
}
},
del:function(){
//判断表格里面是否选中得数据
var row = purchasebillGrid.datagrid('getSelected');
if(row){
//是否确认要删除数据
$.messager.confirm('温馨提示','你确定要删除吗?',function(value){
if(value){
//获取id值
//发送ajax到后台进行删除数据
$.get('/purchasebill/delete',{"id":row.id},function(data){
//返回json对象
if(data.success){
$.messager.alert('温馨提示:','删除成功','info');
//重新加载数据
purchasebillGrid.datagrid('reload');
}else{
$.messager.alert('温馨提示:','删除失败'+data.msg,'error');
}
});
}
})
}else{
//提示用户
$.messager.alert('温馨提示:','请选中一条数据进行删除','info');
return;
}
},
save:function(){
var url = "/purchasebill/save";
//获取隐藏域里面id值
var id = $("#purchasebillId").val();
if(id){
url = "/purchasebill/update?cmd=update"
}
//保存方法 --提交表单的数据到后台
purchasebillForm.form('submit', {
url:url,
onSubmit: function(){
//提交 封装 items
//得到明细表格所有的数据 price num descs
//获取当前行 的所有数据
var rows = $("#gridItem").datagrid('getRows');
for(var i=0;i<rows.length;i++){
var rowData = rows[i];
param["items["+i+"].descs"] = rowData.descs;
param["items["+i+"].price"] = rowData.price;
param["items["+i+"].num"] = rowData.num;
param["items["+i+"].product.id"] = rowData.productId.id;
}
// 提交之前的验证
return purchasebillForm.form('validate');
},
success:function(data){
//字符串 转换成json对象
var dataJson = $.parseJSON(data);
if(dataJson.success){
$.messager.alert('温馨提示:','操作成功','info');
//重新加载数据
purchasebillGrid.datagrid('reload');
//关闭对话框
purchasebillDialog.dialog('close');
}else{
$.messager.alert('温馨提示:','保存失败'+dataJson.msg,'error');
purchasebillDialog.dialog('close');
}
}
});
}
}
});
$(function () {
//明细表格
var dg = $("#gridItem"),
//默认行
defaultRow = { productId: "", color: "", smallpic: "", num: 0, price: 0, amount: 0, descs: "" },
insertPosition = "bottom";//插的位置
//表格初始化
var dgInit = function () {
//得到所有列
var getColumns = function () {
var result = [];
//具体列的配置
var normal = [
{
field: 'productId', title: '产品', width: 180,
editor: {
type: "combobox",
options: {
required: true,
valueField:'id',
textField:'name',
url:'/util/findAllProduct',
panelHeight:'auto'
}
},
formatter:function(value,row){
//value当前这个单元格的值 row整个行的值
return value.name;
}
},
{
field: 'color', title: '颜色', width: 180,
/* editor: {
type: "validatebox",
options: {
required: false,
readonly: true
}
},*/
formatter:function(value,row){
console.log(value);
console.log(row.productId.color);
if(row && row.productId){
return "<div style='width:20px;height:20px;background-color: "+row.productId.color+"' ></div>"
}
}
},
{
field: 'smallpic', title: '图片', width: 100,
formatter:function(value,row){
console.log(row.productId);
if(row && row.productId.smallPic){
return "<img src='"+row.productId.smallPic+"' width='20px' height='20px'/>"
}
}
},
{
field: 'num', title: '产品数量', width: 100,
editor: {
type: "numberbox",
options: {
required: true
}
}
},
{
field: 'price', title: '价格', width: 100,
editor: {
type: "numberbox",
required: true
}
},
{
field: 'amount', title: '小计', width: 100,
formatter:function(value,row){
//小计
if(row.num && row.price) {
return row.num * row.price;
}
}
},
{
field: 'descs', title: '备注', width: 100,
editor: {
type: "text"
}
}
];
result.push(normal);
return result;
};
//设置表格配置
var options = {
idField: "productId",
rownumbers: true,
fitColumns: true,
fit: true,
border: true,//边框
singleSelect: true,
toolbar:"#itemBtns",
columns: getColumns(),//得到所有列
//表示开启单元格编辑功能
enableCellEdit: true
};
//创建编辑表格
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: "productId" });
});
//删除表格里面单元格
$("#btnRemove").click(function () {
//得到选中的行
var row = dg.datagrid('getSelected');
if(row) {
//得到行索引
var index = dg.datagrid('getRowIndex', row);
//通过索引删除
dg.datagrid('deleteRow',index);
}
});
};
//调用初始化表格 创建表格
dgInit();
buttonBindEvent();//绑定事件
});
1.后台进行保存
//添加或者修改
private Map<String,Object> saveOrUpdate( Purchasebill purchasebill){
Map<String,Object> map = new HashMap<>();
try {
//1 准备总数量与总金额
BigDecimal totalAmount = new BigDecimal(0);
BigDecimal totalNum = new BigDecimal(0);
//2 拿到相应的明细
List<Purchasebillitem> items = purchasebill.getItems();
for (Purchasebillitem item : items) {
item.setBill(purchasebill);//让一方也多方也建立关系
item.setAmount(item.getNum().multiply(item.getPrice()));//计算明细小计
//总数量与总金额累加
totalAmount = totalAmount.add(item.getAmount());
totalNum = totalNum.add(item.getNum());
}
//3 设置总数量与总金额
purchasebill.setTotalAmount(totalAmount);
purchasebill.setTotalNum(totalNum);
purchasebillService.save(purchasebill);
map.put(SUCCESS, true);
} catch (Exception e) {
e.printStackTrace();
map.put(SUCCESS, false);
map.put("msg", e.getMessage());
}
return map;
}
2 解决n-to-n的相应问题
@ModelAttribute("editPurchasebill")
public Purchasebill beforeEdit(Long id,String cmd){
Purchasebill purchasebill = null;
if("update".equals(cmd) && id != null && !"".equals(id) ){
purchasebill = purchasebillService.findOne(id);
//就住这就话:在修改的时候的时候,关联对象设置null,保永生
//purchasebill.setDepartment(null);
//把有关系的对象移除
purchasebill.setSupplier(null);
purchasebill.setBuyer(null);
purchasebill.getItems().clear();
}
return purchasebill;
}