实习记录 · 2024年2月5日 2

实习记录-2024年2月5日

若依二开 根据购物车生成订单

任务

根据购物车生成订单:
1.可单独在购物车列表点击某件产品生成订单。
2.可多选购物车生成订单。
3.展示订单信息:
    1)主表展示信息:订单号,总金额,下单人。
    2)子表展示信息:商品名称,单价,数量,总金额。
    3)订单菜单只需要展示主表信息。

流程

  1. 生成订单: 前端将单选(多选)的数据 cartId 传给后端 => 后端按 id 查询购物车信息 => 把 (数量*单价=总价) 等商品信息 insert 进 tb_order 表和 tb_order_detail 表 => 删除购物车表中的记录
  2. 删除订单: 前端将单选(多选)的数据 cartId 传给后端 => 后端按 id 删除购物车信息

后端

  1. 新建订单表(主表) 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 '订单表';
  1. 新建订单表(子表) 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);
  1. 执行若依代码生成工具的 sql 语句新建订单菜单

  2. 使用若依代码生成工具完成两个表的 controller service mapper 层, 继承 MybatisPlus 的类(也可使用 IDEA 的插件 MybatisX-Generator)

  3. 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));
}
  1. 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;
    }

前端

  1. 使用若依代码生成工具生成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>
  1. 购物车管理页面新增"购买"按钮, 设置@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(() => {})
},

操作展示

单选购买

  • 生成订单


  • 删除订单


多选购买

  • 生成订单


  • 删除订单


今日踩坑总结

  1. 怎么才能在一张表上数据变化后 另一张表的数据自动变化 (想法: 先创建 tb_order 表, 再创建 tb_order_detail 表 激活触发器 修改 tb_order 表里的信息): 这个功能似乎暂时不需要自动变化, 只需要对两个表分别新增数据记录即可实现
  2. tb_order表中的数据被删除后, tb_order_detail 表中的数据相应被删除 或者 分别删除两个表中的记录(但是后者需要根据 order_id 查询 order_detail_id 再进行删除–MybatisPlus的 deleteById, 较麻烦): 最后使用了较麻烦的方法, 网上的触发器只有实现一对一删除, 但我的一个tb_order表的记录可以对应多个tb_order_detail表的记录, 我仍不清楚触发器是否能实现一对多删除