若依二开 根据购物车生成订单
任务
根据购物车生成订单:
1.可单独在购物车列表点击某件产品生成订单。
2.可多选购物车生成订单。
3.展示订单信息:
1)主表展示信息:订单号,总金额,下单人。
2)子表展示信息:商品名称,单价,数量,总金额。
3)订单菜单只需要展示主表信息。
流程
- 生成订单: 前端将单选(多选)的数据 cartId 传给后端 => 后端按 id 查询购物车信息 => 把 (数量*单价=总价) 等商品信息 insert 进 tb_order 表和 tb_order_detail 表 => 删除购物车表中的记录
- 删除订单: 前端将单选(多选)的数据 cartId 传给后端 => 后端按 id 删除购物车信息
后端
- 新建订单表(主表)
tb_order
: 订单号(id) 总金额 下单人
create table tb_order
(
order_id bigint auto_increment comment '订单ID'
primary key,
sum double default 0 not null comment '总金额',
create_by varchar(64) default '' null comment '下单人',
create_time datetime null comment '下单时间'
)
comment '订单表';
- 新建订单表(子表)
tb_order_detail
: id 商品名称 单价 数量 总金额 订单号
create table tb_order_detail
(
order_detail_id bigint auto_increment comment '订单商品详情ID'
primary key,
goods_name varchar(30) not null comment '商品名称',
goods_price double null comment '商品单价',
goods_quantity mediumtext null comment '商品数量',
sum double not null comment '总金额',
create_time datetime null comment '下单时间',
order_id bigint null comment '订单ID'
)
comment '订单商品详情表';
create index tb_order_detail_tb_order_order_id_fk
on tb_order_detail (order_id);
-
执行
若依代码生成工具
的 sql 语句新建订单菜单 -
使用
若依代码生成工具
完成两个表的 controller service mapper 层, 继承 MybatisPlus 的类(也可使用 IDEA 的插件MybatisX-Generator
) -
controller 中新增生成订单接口方法
remove(Long[] cartIds)
重写删除订单方法buy(Long[] orderIds)
/**
* 删除订单表
*/
@PreAuthorize("@ss.hasPermi('shopping:order:remove')")
@Log(title = "订单表", businessType = BusinessType.DELETE)
@DeleteMapping("/{orderIds}")
public AjaxResult remove(@PathVariable Long[] orderIds)
{
return toAjax(tbOrderService.deleteByIds(orderIds));
}
/**
* 生成订单
* @param cartIds
* @return
*/
@PreAuthorize("@ss.hasPermi('shopping:cart:buy')")
@PostMapping("/{cartIds}")
public AjaxResult buy(@PathVariable Long[] cartIds) {
return toAjax(tbOrderService.generateOrders(cartIds));
}
- service 层实现
generateOrders(Long[] cartIds)
和deleteByIds(Long[] orderIds)
的业务逻辑
@Override
public int generateOrders(Long[] cartIds) {
// 通过购物车 id 查询购物车信息, 将信息保存到 cartList 变量里
List<TbCart> cartList = new LinkedList<>();
for (Long cartId : cartIds) {
cartList.add(tbCartMapper.selectTbCartByCartId(cartId));
}
// 创建一个订单作为当前用户订单 (返回订单id)
TbOrder tbOrder = new TbOrder();
tbOrder.setCreateBy(SecurityUtils.getUsername());
tbOrder.setCreateTime(DateUtils.getNowDate());
tbOrderMapper.insert(tbOrder);
// 循环每一个 cart, 计算金额总和, 创建对应数量的 tb_order_detail 记录, 绑定 订单详情id 为订单id
double sum = 0.0;
Long orderId = tbOrder.getOrderId();
for (TbCart tbCart : cartList) {
sum += tbCart.getGoodsPrice() * tbCart.getGoodsQuantity();
TbOrderDetail tbOrderDetail = new TbOrderDetail();
tbOrderDetail.setGoodsName(tbCart.getGoodsName());
tbOrderDetail.setGoodsPrice(tbCart.getGoodsPrice());
tbOrderDetail.setGoodsQuantity(tbCart.getGoodsQuantity());
tbOrderDetail.setSum(tbCart.getGoodsPrice() * tbCart.getGoodsQuantity());
tbOrderDetail.setCreateTime(DateUtils.getNowDate());
tbOrderDetail.setOrderId(orderId);
tbOrderDetailMapper.insert(tbOrderDetail);
}
// 给订单总金额赋值
tbOrder.setSum(sum);
tbOrderMapper.updateById(tbOrder);
// 创建订单后, 将购物车记录删除
for (Long cartId : cartIds) {
tbCartMapper.deleteTbCartByCartId(cartId);
}
return cartIds.length;
}
@Override
public int deleteByIds(Long[] orderIds) {
// 删除 tb_order 表中的数据
for (Long orderId : orderIds) {
tbOrderMapper.deleteById(orderId);
}
// 删除 tb_order_detail 表中的数据
List<TbOrderDetail> tbOrderDetails = new LinkedList<>();
QueryWrapper<TbOrderDetail> queryWrapper = new QueryWrapper<>();
// 将所有 tbOrderDetail 表中需要删除的数据保存在 tbOrderDetails 数组中
for (Long orderId : orderIds) {
queryWrapper.eq("order_id", orderId);
tbOrderDetailMapper.selectList(queryWrapper).stream().forEach(item -> {
tbOrderDetails.add(item);
});
}
// 根据 id 删除 tbOrderDetails 数据
tbOrderDetails.forEach(item -> {
tbOrderDetailMapper.deleteById(item.getOrderDetailId());
});
return orderIds.length;
}
前端
- 使用
若依代码生成工具
生成tb_order
表的前端增删改查代码 完成订单表展示主表信息
任务
- order/index.vue
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="下单人" prop="createBy">
<el-input
v-model="queryParams.createBy"
placeholder="请输入下单人"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['shopping:order:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['shopping:order:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['shopping:order:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['shopping:order:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="orderList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="订单ID" align="center" prop="orderId" />
<el-table-column label="总金额" align="center" prop="sum" />
<el-table-column label="下单人" align="center" prop="createBy" />
<el-table-column label="下单时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['shopping:order:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['shopping:order:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改订单表对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="总金额" prop="sum">
<el-input v-model="form.sum" placeholder="请输入总金额" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listOrder, getOrder, delOrder, addOrder, updateOrder } from "@/api/shopping/order";
export default {
name: "Order",
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 订单表表格数据
orderList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
createBy: null,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 查询订单表列表 */
getList() {
this.loading = true;
listOrder(this.queryParams).then(response => {
this.orderList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
orderId: null,
sum: null,
createBy: null,
createTime: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.orderId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加订单表";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const orderId = row.orderId || this.ids
getOrder(orderId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改订单表";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.orderId != null) {
updateOrder(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addOrder(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const orderIds = row.orderId || this.ids;
this.$modal.confirm('是否确认删除订单表编号为"' + orderIds + '"的数据项?').then(function() {
return delOrder(orderIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('shopping/order/export', {
...this.queryParams
}, `order_${new Date().getTime()}.xlsx`)
}
}
};
</script>
- 购物车管理页面新增"购买"按钮, 设置
@click()
函数handleBuy(row)
参数为row.cartId(点击当前行的"购买"按钮)
或this.ids(多选后点击列表上放的"购买"按钮)
- cart.vue
/** 生成订单 */
handleBuy(row) {
this.reset();
const cartIds = row.cartId || this.ids;
this.$modal.confirm('是否确认将编号为"' + cartIds + '"购物车计入订单?').then(function() {
return generateOrder(cartIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("购买成功");
}).catch(() => {})
},
操作展示
单选购买
-
生成订单
-
删除订单
多选购买
-
生成订单
-
删除订单
今日踩坑总结
- 怎么才能在一张表上数据变化后 另一张表的数据自动变化 (想法: 先创建 tb_order 表, 再创建 tb_order_detail 表 激活触发器 修改 tb_order 表里的信息): 这个功能似乎暂时不需要自动变化, 只需要对两个表分别新增数据记录即可实现
- 当
tb_order
表中的数据被删除后,tb_order_detail
表中的数据相应被删除 或者 分别删除两个表中的记录(但是后者需要根据 order_id 查询 order_detail_id 再进行删除–MybatisPlus的 deleteById
, 较麻烦): 最后使用了较麻烦的方法, 网上的触发器只有实现一对一删除, 但我的一个tb_order
表的记录可以对应多个tb_order_detail
表的记录, 我仍不清楚触发器是否能实现一对多删除
来了来了
空手来的?