[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-PDQdczrn":3,"public-project-articles-PDQdczrn":17},{"id":4,"uuid":5,"project_id":6,"title":7,"content":8,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},1072,"PDQdczrn",52,"14.1 带你实现订单配送功能","## 效果\n\n表格里展示配送信息\n\n![](https:\u002F\u002Fapi.codenice.cn\u002Fapi\u002Fdrive\u002Fpublic\u002FkOmmwaTS\u002Ffile)\n\n\n## SQL orders\n\n```sql\nCREATE TABLE `orders` (\n  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n  `order_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单编号',\n  `total` decimal(10,2) DEFAULT NULL COMMENT '总价格',\n  `user_id` int DEFAULT NULL COMMENT '下单人ID',\n  `status` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '状态',\n  `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下单时间',\n  `deliver_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '配送类型',\n  `address` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '收货地址',\n  `deliver` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '配送信息',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单信息';\n```\n\n## 后端接口逻辑\n\n### Orders\n\n```java\npackage com.example.entity;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class Orders {\n\n    \u002F**主键ID *\u002F\n    private Integer id;\n    \u002F**订单编号 *\u002F\n    private String orderNo;\n    \u002F**总价格 *\u002F\n    private BigDecimal total;\n    \u002F**下单人ID *\u002F\n    private Integer userId;\n    private String userName;\n    \u002F**状态 *\u002F\n    private String status;\n    \u002F**下单时间 *\u002F\n    private String time;\n    \u002F**配送类型 *\u002F\n    private String deliverType;\n    private String address;\n    private String deliver;\n    private List\u003CCart> cartList;\n    private List\u003COrderDetail> orderDetailList;\n    private String goodsName;\n\n    public String getGoodsName() {\n        return goodsName;\n    }\n\n    public void setGoodsName(String goodsName) {\n        this.goodsName = goodsName;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getDeliver() {\n        return deliver;\n    }\n\n    public void setDeliver(String deliver) {\n        this.deliver = deliver;\n    }\n\n    public List\u003COrderDetail> getOrderDetailList() {\n        return orderDetailList;\n    }\n\n    public void setOrderDetailList(List\u003COrderDetail> orderDetailList) {\n        this.orderDetailList = orderDetailList;\n    }\n\n    public List\u003CCart> getCartList() {\n        return cartList;\n    }\n\n    public void setCartList(List\u003CCart> cartList) {\n        this.cartList = cartList;\n    }\n\n    public String getDeliverType() {\n        return deliverType;\n    }\n\n    public void setDeliverType(String deliverType) {\n        this.deliverType = deliverType;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getOrderNo() {\n        return orderNo;\n    }\n\n    public void setOrderNo(String orderNo) {\n        this.orderNo = orderNo;\n    }\n\n    public BigDecimal getTotal() {\n        return total;\n    }\n\n    public void setTotal(BigDecimal total) {\n        this.total = total;\n    }\n\n    public Integer getUserId() {\n        return userId;\n    }\n\n    public void setUserId(Integer userId) {\n        this.userId = userId;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public String getTime() {\n        return time;\n    }\n\n    public void setTime(String time) {\n        this.time = time;\n    }\n}\n\n```\n\n### OrdersMapper.xml\n\n```xml\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003C!DOCTYPE mapper\n        PUBLIC \"-\u002F\u002Fmybatis.org\u002F\u002FDTD Mapper 3.0\u002F\u002FEN\"\n        \"http:\u002F\u002Fmybatis.org\u002Fdtd\u002Fmybatis-3-mapper.dtd\">\n\u003Cmapper namespace=\"com.example.mapper.OrdersMapper\">\n\n    \u003Cselect id=\"selectAll\" resultType=\"com.example.entity.Orders\">\n        select orders.*, user.name as userName from `orders`\n        left join user on orders.user_id = user.id\n        left join order_detail on order_detail.order_id = orders.id\n        \u003Cwhere>\n            \u003Cif test=\"orderNo != null\"> and orders.order_no like concat('%', #{orderNo}, '%')\u003C\u002Fif>\n            \u003Cif test=\"goodsName != null\"> and order_detail.goods_name like concat('%', #{goodsName}, '%')\u003C\u002Fif>\n            \u003Cif test=\"userId != null\"> and orders.user_id = #{userId}\u003C\u002Fif>\n        \u003C\u002Fwhere>\n        group by orders.id\n        order by orders.id desc\n    \u003C\u002Fselect>\n\n    \u003Cselect id=\"selectById\" resultType=\"com.example.entity.Orders\">\n        select * from `orders` where id = #{id}\n    \u003C\u002Fselect>\n\n    \u003Cdelete id=\"deleteById\">\n        delete from `orders` where id = #{id}\n    \u003C\u002Fdelete>\n\n    \u003Cinsert id=\"insert\" parameterType=\"com.example.entity.Orders\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n        insert into `orders`\n        \u003Ctrim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            \u003Cif test=\"id != null\">id,\u003C\u002Fif>\n            \u003Cif test=\"orderNo != null\">order_no,\u003C\u002Fif>\n            \u003Cif test=\"total != null\">total,\u003C\u002Fif>\n            \u003Cif test=\"userId != null\">user_id,\u003C\u002Fif>\n            \u003Cif test=\"status != null\">status,\u003C\u002Fif>\n            \u003Cif test=\"time != null\">time,\u003C\u002Fif>\n            \u003Cif test=\"deliverType != null\">deliver_type,\u003C\u002Fif>\n            \u003Cif test=\"address != null\">address,\u003C\u002Fif>\n            \u003Cif test=\"deliver != null\">deliver,\u003C\u002Fif>\n        \u003C\u002Ftrim>\n        values\n        \u003Ctrim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            \u003Cif test=\"id != null\">#{id},\u003C\u002Fif>\n            \u003Cif test=\"orderNo != null\">#{orderNo},\u003C\u002Fif>\n            \u003Cif test=\"total != null\">#{total},\u003C\u002Fif>\n            \u003Cif test=\"userId != null\">#{userId},\u003C\u002Fif>\n            \u003Cif test=\"status != null\">#{status},\u003C\u002Fif>\n            \u003Cif test=\"time != null\">#{time},\u003C\u002Fif>\n            \u003Cif test=\"deliverType != null\">#{deliverType},\u003C\u002Fif>\n            \u003Cif test=\"address != null\">#{address},\u003C\u002Fif>\n            \u003Cif test=\"deliver != null\">#{deliver},\u003C\u002Fif>\n        \u003C\u002Ftrim>\n    \u003C\u002Finsert>\n\n    \u003Cupdate id=\"updateById\" parameterType=\"com.example.entity.Orders\">\n        update `orders`\n        \u003Cset>\n            \u003Cif test=\"id != null\">\n                id = #{id},\n            \u003C\u002Fif>\n            \u003Cif test=\"orderNo != null\">\n                order_no = #{orderNo},\n            \u003C\u002Fif>\n            \u003Cif test=\"total != null\">\n                total = #{total},\n            \u003C\u002Fif>\n            \u003Cif test=\"userId != null\">\n                user_id = #{userId},\n            \u003C\u002Fif>\n            \u003Cif test=\"status != null\">\n                status = #{status},\n            \u003C\u002Fif>\n            \u003Cif test=\"time != null\">\n                time = #{time},\n            \u003C\u002Fif>\n            \u003Cif test=\"deliverType != null\">\n                deliver_type = #{deliverType},\n            \u003C\u002Fif>\n            \u003Cif test=\"address != null\">\n                address = #{address},\n            \u003C\u002Fif>\n            \u003Cif test=\"deliver != null\">\n                deliver = #{deliver},\n            \u003C\u002Fif>\n        \u003C\u002Fset>\n        where id = #{id}\n    \u003C\u002Fupdate>\n\n\u003C\u002Fmapper>\n```\n\n### OrdersService.java\n\n```java\npackage com.example.service;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.RandomUtil;\nimport com.example.entity.*;\nimport com.example.exception.CustomException;\nimport com.example.mapper.*;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport jakarta.annotation.Resource;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n\u002F**\n * 业务处理\n **\u002F\n@Service\npublic class OrdersService {\n\n    @Resource\n    private OrdersMapper ordersMapper;\n    @Resource\n    GoodsMapper goodsMapper;\n    @Resource\n    UserMapper userMapper;\n    @Resource\n    OrderDetailMapper orderDetailMapper;\n    @Resource\n    CartMapper cartMapper;\n\n    \u002F**\n     * 购物车批量和单个商品 通用的下单接口\n     *\u002F\n    @Transactional\n    public void add(Orders orders) {\n        orders.setStatus(\"待接单\");\n        orders.setTime(DateUtil.now());\n        \u002F\u002F 随机的订单编号  20251202\n        String orderNo = DateUtil.format(new Date(), \"yyyyMMdd\") + System.currentTimeMillis() + RandomUtil.randomNumbers(4);\n        orders.setOrderNo(orderNo);\n        ordersMapper.insert(orders);\n        Integer orderId = orders.getId();\n        List\u003CCart> cartList = orders.getCartList();\n        User user = userMapper.selectById(orders.getUserId());\n        BigDecimal totalPrice = BigDecimal.ZERO;\n        for (Cart cart : cartList) {\n            Integer goodsId = cart.getGoodsId();\n            Goods goods = goodsMapper.selectById(goodsId);\n            if (goods.getStore() \u003C cart.getNum()) {  \u002F\u002F 库存不足\n                throw new CustomException(goods.getName() + \"商品库存不足\");\n            }\n            goods.setStore(goods.getStore() - cart.getNum());  \u002F\u002F 扣减库存\n            goods.setSaleCount(goods.getSaleCount() + cart.getNum());  \u002F\u002F 增加销量\n            goodsMapper.updateById(goods);  \u002F\u002F 更新商品的库存\n            \u002F\u002F 新增订单详情\n            OrderDetail orderDetail = new OrderDetail();\n            orderDetail.setNum(cart.getNum());\n            orderDetail.setGoodsId(goodsId);\n            orderDetail.setGoodsImg(goods.getImg());\n            orderDetail.setGoodsName(goods.getName());\n            orderDetail.setGoodsPrice(goods.getPrice());\n            orderDetail.setOrderId(orderId);\n            orderDetailMapper.insert(orderDetail);\n\n            \u002F\u002F 删除下单的商品所对应的购物车记录\n            if (cart.getId() != null) {\n                cartMapper.deleteById(cart.getId());\n            }\n\n            totalPrice = totalPrice.add(goods.getPrice().multiply(BigDecimal.valueOf(cart.getNum())));\n        }\n        if (user.getAccount().compareTo(totalPrice) \u003C 0) {  \u002F\u002F 用户的余额小于订单的总价格\n            throw new CustomException(\"对不起，您的账户余额不足，请充值！\");\n        }\n        user.setAccount(user.getAccount().subtract(totalPrice));\n        userMapper.updateById(user);  \u002F\u002F 更新余额\n        orders.setTotal(totalPrice);\n        ordersMapper.updateById(orders);  \u002F\u002F 更新订单总额\n    }\n\n    \u002F**\n     * 删除\n     *\u002F\n    @Transactional\n    public void deleteById(Integer id) {\n        ordersMapper.deleteById(id);\n        orderDetailMapper.deleteByOrderId(id);\n    }\n\n    \u002F**\n     * 修改\n     *\u002F\n    @Transactional\n    public void updateById(Orders orders) {\n        if (\"已取消\".equals(orders.getStatus())) {\n            Integer userId = orders.getUserId();\n            User user = userMapper.selectById(userId);\n            user.setAccount(user.getAccount().add(orders.getTotal()));\n            userMapper.updateById(user);\n            \u002F\u002F 商品库存 加回去   商品的销量 减去\n            OrderDetail orderDetail = new OrderDetail();\n            orderDetail.setOrderId(orders.getId());\n            List\u003COrderDetail> orderDetailList = orderDetailMapper.selectAll(orderDetail);\n            for (OrderDetail detail : orderDetailList) {\n                Integer goodsId = detail.getGoodsId();\n                Goods goods = goodsMapper.selectById(goodsId);\n                if (goods != null) {\n                    goods.setStore(goods.getStore() + detail.getNum());\n                    goods.setSaleCount(goods.getSaleCount() - detail.getNum());\n                    goodsMapper.updateById(goods);\n                }\n            }\n        }\n        ordersMapper.updateById(orders);\n    }\n\n    \u002F**\n     * 根据ID查询\n     *\u002F\n    public Orders selectById(Integer id) {\n        return ordersMapper.selectById(id);\n    }\n\n    \u002F**\n     * 查询所有\n     *\u002F\n    public List\u003COrders> selectAll(Orders orders) {\n        return ordersMapper.selectAll(orders);\n    }\n\n    \u002F**\n     * 分页查询\n     *\u002F\n    public PageInfo\u003COrders> selectPage(Orders orders, Integer pageNum, Integer pageSize) {\n        PageHelper.startPage(pageNum, pageSize);\n        List\u003COrders> list = ordersMapper.selectAll(orders);\n        for (Orders o : list) {\n            OrderDetail orderDetail = new OrderDetail();\n            orderDetail.setOrderId(o.getId());\n            List\u003COrderDetail> orderDetailList = orderDetailMapper.selectAll(orderDetail);\n            o.setOrderDetailList(orderDetailList);\n        }\n        return PageInfo.of(list);\n    }\n\n}\n```\n\n## 前端页面逻辑\n\n### GoodsDetail.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"front-container\" style=\"width: 50%\">\n    \u003Cdiv class=\"card\" style=\"padding: 20px; display: flex; grid-gap: 20px; margin-bottom: 10px\">\n      \u003Cimg :src=\"data.goods.img\" alt=\"\" style=\"width: 300px; height: 300px\">\n      \u003Cdiv style=\"flex: 1\">\n        \u003Cdiv style=\"display: flex; align-items: flex-start; grid-gap: 20px; margin-bottom: 10px\">\n          \u003Cdiv style=\"font-size: 22px; font-weight: bold; line-height: 25px; flex: 1\">\n            \u003Cel-tag style=\"margin-right: 5px; float: left; background-color: red; color: white\" type=\"danger\" v-if=\"data.goods.recommend === '是'\">推荐\u003C\u002Fel-tag>\n            {{ data.goods.name }}\n          \u003C\u002Fdiv>\n          \u003Cdiv style=\"width: 60px; cursor: pointer; color: #666\" @click=\"addCollect\" v-if=\"!data.userCollect?.id\">\n            \u003Cel-icon style=\"position: relative; top: 3px\" size=\"18\">\u003CStar \u002F>\u003C\u002Fel-icon>收藏\n          \u003C\u002Fdiv>\n          \u003Cdiv style=\"width: 100px; cursor: pointer; color: orange\" @click=\"removeCollect\" v-if=\"data.userCollect?.id\">\n            \u003Cel-icon style=\"position: relative; top: 3px\" size=\"18\">\u003CStarFilled \u002F>\u003C\u002Fel-icon>取消收藏\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 20px\">\n          \u003Cspan style=\"color: red; font-size: 18px\">￥\u003C\u002Fspan>\u003Cb style=\"color: red; font-size: 30px\">{{ data.goods.price }}\u003C\u002Fb>\n          \u003Cspan style=\"color: #666; margin-left: 20px\">累计销量 {{ data.goods.saleCount }}\u003C\u002Fspan>\n          \u003Cspan style=\"color: #666; margin-left: 20px\">剩余库存 {{ data.goods.store }}\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 20px; padding: 10px; border-radius: 5px; background-color: #e8e4e4; line-height: 25px; text-align: justify\">{{ data.goods.description }}\u003C\u002Fdiv>\n        \u003Cdiv>\n          \u003Cel-input-number style=\"width: 150px; height: 40px\" :min=\"1\" v-model=\"data.num\">\u003C\u002Fel-input-number>\n          \u003Cel-button @click=\"addCart\" style=\"height: 40px; margin-left: 5px\" type=\"danger\">加入购物车\u003C\u002Fel-button>\n          \u003Cel-button @click=\"handleAddOrder\" style=\"height: 40px; margin-left: 5px\" type=\"danger\">立即购买\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-top: 10px; color: #666\">校园小卖部销售并发货的商品，由小卖部提供发票和相应的售后服务。请您放心购买！\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\" style=\"padding: 20px; margin-bottom: 50px\">\n      \u003Cdiv style=\"font-size: 20px; padding-bottom: 10px; border-bottom: 1px solid #ddd\">\n        \u003Cspan @click=\"changeTab('商品详情')\" style=\"cursor: pointer\" :class=\"{'current-active': data.current === '商品详情' }\">商品详情\u003C\u002Fspan>\n        \u003Cspan @click=\"changeTab('商品评论')\" :class=\"{'current-active': data.current === '商品评论' }\" style=\"cursor: pointer; margin-left: 20px\">商品评论\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n      \u003Cdiv v-if=\"data.current === '商品详情'\" style=\"padding: 10px\" v-html=\"data.goods.content\">\u003C\u002Fdiv>\n      \u003Cdiv v-if=\"data.current === '商品评论'\" style=\"min-height: 700px\">\n        \u003Cdiv v-if=\"data.commentList.length === 0\" style=\"padding: 50px; text-align: center; color: #666\">暂无评论...\u003C\u002Fdiv>\n        \u003Cdiv v-if=\"data.commentList.length > 0\" style=\"padding: 20px; text-align: center\">\n\u003C!--          显示评论列表-->\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"下单信息\" width=\"30%\" v-model=\"data.formVisible\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"100px\" style=\"padding-right: 30px\">\n        \u003Cel-form-item label=\"配送类型\" prop=\"deliverType\">\n          \u003Cel-radio-group v-model=\"data.form.deliverType\">\n            \u003Cel-radio-button value=\"自提\" label=\"自提\">\u003C\u002Fel-radio-button>\n            \u003Cel-radio-button value=\"外送\" label=\"外送\">\u003C\u002Fel-radio-button>\n          \u003C\u002Fel-radio-group>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"收货地址\" prop=\"address\" v-if=\"data.form.deliverType === '外送'\">\n          \u003Cel-input v-model=\"data.form.address\" type=\"textarea\" :rows=\"3\" placeholder=\"请输入外送的接收地址，包括联系人、联系电话、地址信息\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n      \u003Cspan class=\"dialog-footer\">\n        \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"addOrder\">确 认\u003C\u002Fel-button>\n      \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive, ref } from \"vue\";\nimport router from \"@\u002Frouter\";\nimport request from \"@\u002Futils\u002Frequest\";\nimport {ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  id: router.currentRoute.value.query.id,\n  goods: {},\n  num: 1,\n  current: '商品详情',\n  commentList: [],\n  userCollect: {},\n  form: {},\n  formVisible: false,\n  rules: {\n    deliverType: [\n      { required: true, message: '请选择配送类型', trigger: 'change' }\n    ],\n    address: [\n      { required: true, message: '请输入配送地址', trigger: 'blur' }\n    ]\n  }\n})\n\nconst handleAddOrder = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\nconst addOrder = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      data.form.userId = data.user.id\n      data.form.cartList = [ {goodsId: data.id, num: data.num } ]\n      request.post('\u002Forders\u002Fadd', data.form).then(res => {\n        if (res.code === '200') {\n          ElMessage.success('下单成功')\n          load()\n          data.formVisible = false\n        } else {\n          ElMessage.error(res.msg)\n        }\n      })\n    }\n  })\n}\n\nconst addCart = () => {\n  request.post('\u002Fcart\u002Fadd', { goodsId: data.id, num: data.num, userId: data.user.id }).then(res => {\n    if (res.code === '200') {\n      ElMessage.success('加入购物车成功')\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 当前的商品是否被当前登录的用户收藏过\nconst loadCollect = () => {\n  request.get('\u002Fcollect\u002FselectAll', {\n    params:{\n      goodsId: data.id,\n      userId: data.user.id\n    }\n  }).then(res => {\n    if (res.data?.length > 0) {  \u002F\u002F 查询到数据了 表示用户收藏过了\n      data.userCollect = res.data[0]\n    } else {\n      data.userCollect = {}\n    }\n  })\n}\nloadCollect()\n\n\u002F\u002F 取消收藏\nconst removeCollect = () => {\n  request.delete('\u002Fcollect\u002Fdelete\u002F' + data.userCollect.id).then(res => {\n    if (res.code === '200') {\n      ElMessage.success('操作成功')\n      loadCollect()\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst addCollect = () => {\n  request.post('\u002Fcollect\u002Fadd', { goodsId: data.id, userId: data.user.id }).then(res => {\n    if (res.code === '200') {\n      ElMessage.success('操作成功')\n      loadCollect()\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst changeTab = (tabName) => {\n  data.current = tabName\n}\n\nconst load = () => {\n  request.get('\u002Fgoods\u002FselectById\u002F' + data.id).then(res => {\n    data.goods = res.data\n  })\n}\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.current-active {\n  color: red;\n  border-bottom: 2px solid red;\n  padding-bottom: 10px\n}\n\u003C\u002Fstyle>\n```\n\n### UserOrders.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"front-container\" style=\"width: 80%\">\n    \u003Cdiv style=\"margin-bottom: 10px;\">\n      \u003Cel-input clearable @clear=\"load\" v-model=\"data.orderNo\" style=\"width: 400px; height: 40px; margin-right: 10px\" placeholder=\"请输入订单编号查询\">\u003C\u002Fel-input>\n      \u003Cel-input clearable @clear=\"load\" v-model=\"data.goodsName\" style=\"width: 400px; height: 40px; margin-right: 10px\" placeholder=\"请输入商品名称查询\">\u003C\u002Fel-input>\n      \u003Cel-button style=\"height: 40px\" type=\"primary\" @click=\"load\">查 询\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cel-table :data=\"data.tableData\" stripe :cell-style=\"{'backgroundColor': '#e8efff'}\" default-expand-all>\n        \u003Cel-table-column type=\"expand\">\n          \u003Ctemplate #default=\"props\">\n            \u003Cdiv style=\"padding: 10px\">\n              \u003Cel-table :data=\"props.row.orderDetailList\" border>\n                \u003Cel-table-column label=\"商品图片\" prop=\"goodsImg\" width=\"100\">\n                  \u003Ctemplate #default=\"scope\">\n                    \u003Cimg :src=\"scope.row.goodsImg\" alt=\"\" style=\"width: 50px; height: 50px\">\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"商品名称\" prop=\"goodsName\" show-overflow-tooltip>\u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"商品单价\" prop=\"goodsPrice\" width=\"100\">\u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"数量\" prop=\"num\" width=\"100\">\n                  \u003Ctemplate #default=\"scope\">\n                    X {{ scope.row.num }}\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"小计\" width=\"150\">\n                  \u003Ctemplate #default=\"scope\">\n                    \u003Cb style=\"color: red\">{{ (scope.row.goodsPrice * scope.row.num).toFixed(2) }} 元\u003C\u002Fb>\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n              \u003C\u002Fel-table>\n            \u003C\u002Fdiv>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"orderNo\" label=\"订单编号\" width=\"240\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cb style=\"color: #333\">{{ scope.row.orderNo }}\u003C\u002Fb>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"total\" label=\"总价格\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cb style=\"color: red\">{{ scope.row.total }}元\u003C\u002Fb>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"deliverType\" label=\"配送类型\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"status\" label=\"状态\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-tag type=\"danger\" v-if=\"scope.row.status === '已取消'\">已取消\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"warning\" v-if=\"scope.row.status === '待接单'\">待接单\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"primary\" v-if=\"scope.row.status === '已配送'\">已配送\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"primary\" v-if=\"scope.row.status === '已出货'\">已出货\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"success\" v-if=\"scope.row.status === '已完成'\">已完成\u003C\u002Fel-tag>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"time\" label=\"下单时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"address\" label=\"地址\" width=\"300\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"deliver\" label=\"配送信息\" width=\"300\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"订单操作\" align=\"center\" width=\"120\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button @click=\"cancel(scope.row)\"  type=\"danger\" v-if=\"scope.row.status === '待接单'\">取消\u003C\u002Fel-button>\n            \u003Cel-button type=\"success\" v-if=\"scope.row.status === '已完成'\">评价\u003C\u002Fel-button>\n            \u003Cel-button @click=\"done(scope.row)\" type=\"primary\" v-if=\"scope.row.status === '已出货' || scope.row.status === '已配送'\">确认收货\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n\n      \u003Cdiv style=\"margin-top: 20px\">\n        \u003Cel-pagination @current-change=\"load\" layout=\"total, prev, pager, next\" v-model:page-size=\"data.pageSize\" v-model:current-page=\"data.pageNum\" :total=\"data.total\"\u002F>\n      \u003C\u002Fdiv>\n\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport request from \"@\u002Futils\u002Frequest\";\nimport {reactive, ref} from \"vue\";\nimport {ElMessageBox, ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  pageNum: 1,\n  pageSize: 3,\n  total: 0,\n  formVisible: false,\n  form: {},\n  tableData: [],\n  orderNo: null,\n  goodsName: null,\n  rules: {\n    name: [\n      { required: true, message: '请输入名称', trigger: 'blur' },\n    ]\n  }\n})\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Forders\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      orderNo: data.orderNo,\n      goodsName: data.goodsName,\n      userId: data.user.id\n    }\n  }).then(res => {\n    data.tableData = res.data?.list\n    data.total = res.data?.total\n  })\n}\nload()\n\n\u002F\u002F 新增\nconst handleAdd = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\n\u002F\u002F 编辑\nconst handleEdit = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))\n  data.formVisible = true\n}\n\n\u002F\u002F 新增保存\nconst add = () => {\n  request.post('\u002Forders\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst cancel = (row) => {\n  ElMessageBox.confirm('您确认取消订单吗?', '二次确认', { type: 'warning' }).then(res => {\n    data.form = row\n    data.form.status = '已取消'\n    update()\n  }).catch(err => {})\n}\n\nconst done = (row) => {\n  ElMessageBox.confirm('您确认订单货物已经收到了吗?', '二次确认', { type: 'warning' }).then(res => {\n    data.form = row\n    data.form.status = '已完成'\n    update()\n  }).catch(err => {})\n}\n\n\u002F\u002F 编辑保存\nconst update = () => {\n  request.put('\u002Forders\u002Fupdate', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 弹窗保存\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      \u002F\u002F data.form有id就是更新，没有就是新增\n      data.form.id ? update() : add()\n    }\n  })\n}\n\n\u002F\u002F 删除\nconst handleDelete = (id) => {\n  ElMessageBox.confirm('删除后数据无法恢复，您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {\n    request.delete('\u002Forders\u002Fdelete\u002F' + id).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 重置\nconst reset = () => {\n  data.orderNo = null\n  data.goodsName = null\n  load()\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.el-tag {\n  font-weight: bold;\n}\n.el-tag--warning {\n  color: orange;\n  background-color: #fff2de;\n}\n\u003C\u002Fstyle>\n```\n\n### Orders.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px;\">\n      \u003Cel-input v-model=\"data.orderNo\" style=\"width: 300px; margin-right: 10px\" placeholder=\"请输入订单编号查询\">\u003C\u002Fel-input>\n      \u003Cel-button type=\"primary\" @click=\"load\">查询\u003C\u002Fel-button>\n      \u003Cel-button type=\"info\" style=\"margin: 0 10px\" @click=\"reset\">重置\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-table :data=\"data.tableData\" stripe :cell-style=\"{'backgroundColor': '#e8efff'}\" default-expand-all>\n        \u003Cel-table-column type=\"expand\">\n          \u003Ctemplate #default=\"props\">\n            \u003Cdiv style=\"padding: 10px\">\n              \u003Cel-table :data=\"props.row.orderDetailList\" border>\n                \u003Cel-table-column label=\"商品图片\" prop=\"goodsImg\" width=\"100\">\n                  \u003Ctemplate #default=\"scope\">\n                    \u003Cimg :src=\"scope.row.goodsImg\" alt=\"\" style=\"width: 50px; height: 50px\">\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"商品名称\" prop=\"goodsName\" show-overflow-tooltip>\u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"商品单价\" prop=\"goodsPrice\" width=\"100\">\u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"数量\" prop=\"num\" width=\"100\">\n                  \u003Ctemplate #default=\"scope\">\n                    X {{ scope.row.num }}\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n                \u003Cel-table-column label=\"小计\" width=\"150\">\n                  \u003Ctemplate #default=\"scope\">\n                    \u003Cb style=\"color: red\">{{ (scope.row.goodsPrice * scope.row.num).toFixed(2) }} 元\u003C\u002Fb>\n                  \u003C\u002Ftemplate>\n                \u003C\u002Fel-table-column>\n              \u003C\u002Fel-table>\n            \u003C\u002Fdiv>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"orderNo\" label=\"订单编号\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cb style=\"color: #333\">{{ scope.row.orderNo }}\u003C\u002Fb>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"total\" label=\"总价格\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cb style=\"color: red\">{{ scope.row.total }}元\u003C\u002Fb>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"userName\" label=\"下单人\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"deliverType\" label=\"配送类型\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"status\" label=\"状态\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-tag type=\"danger\" v-if=\"scope.row.status === '已取消'\">已取消\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"warning\" v-if=\"scope.row.status === '待接单'\">待接单\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"primary\" v-if=\"scope.row.status === '已配送'\">已配送\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"primary\" v-if=\"scope.row.status === '已出货'\">已出货\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"success\" v-if=\"scope.row.status === '已完成'\">已完成\u003C\u002Fel-tag>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"time\" label=\"下单时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"address\" label=\"地址\" width=\"300\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"deliver\" label=\"配送信息\" width=\"300\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"订单操作\" align=\"center\" width=\"100\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button v-if=\"scope.row.deliverType === '自提' && scope.row.status === '待接单'\" type=\"primary\" @click=\"out(scope.row)\">出货\u003C\u002Fel-button>\n            \u003Cel-button v-if=\"scope.row.deliverType === '外送' && scope.row.status === '待接单'\" type=\"primary\" @click=\"handleDeliver(scope.row)\">配送\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"删除\" align=\"center\" width=\"100\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button type=\"danger\" @click=\"handleDelete(scope.row.id)\">删除\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cel-pagination @current-change=\"load\" background layout=\"total, prev, pager, next\" v-model:page-size=\"data.pageSize\" v-model:current-page=\"data.pageNum\" :total=\"data.total\"\u002F>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"订单信息\" width=\"30%\" v-model=\"data.formVisible\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"80px\" style=\"padding-right: 30px; padding-top: 20px\">\n        \u003Cel-form-item label=\"配送信息\" prop=\"deliver\">\n          \u003Cel-input placeholder=\"请输入配送员名称、联系方式\" type=\"textarea\" :rows=\"3\" v-model=\"data.form.deliver\" autocomplete=\"off\" \u002F>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n      \u003Cspan class=\"dialog-footer\">\n        \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"save\">保 存\u003C\u002Fel-button>\n      \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport request from \"@\u002Futils\u002Frequest\";\nimport {reactive, ref} from \"vue\";\nimport {ElMessageBox, ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  pageNum: 1,\n  pageSize: 3,\n  total: 0,\n  formVisible: false,\n  form: {},\n  tableData: [],\n  name: null,\n  rules: {\n    deliver: [\n      { required: true, message: '请输入配送信息', trigger: 'blur' },\n    ]\n  }\n})\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Forders\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      orderNo: data.orderNo\n    }\n  }).then(res => {\n    data.tableData = res.data?.list\n    data.total = res.data?.total\n  })\n}\nload()\n\n\u002F\u002F 新增\nconst handleAdd = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\n\u002F\u002F 编辑\nconst handleDeliver = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))\n  data.formVisible = true\n}\n\n\u002F\u002F 新增保存\nconst add = () => {\n  request.post('\u002Forders\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst out = (row) => {\n  ElMessageBox.confirm('您确认订单已出货吗?', '二次确认', { type: 'warning' }).then(res => {\n    data.form = row\n    data.form.status = '已出货'\n    request.put('\u002Forders\u002Fupdate', data.form).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n        data.formVisible = false\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 编辑保存\nconst update = () => {\n  if (data.form.deliverType === '自提') {\n    data.form.status = '已出货'\n  }\n  if (data.form.deliverType === '外送') {\n    data.form.status = '已配送'\n  }\n  request.put('\u002Forders\u002Fupdate', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 弹窗保存\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      \u002F\u002F data.form有id就是更新，没有就是新增\n      data.form.id ? update() : add()\n    }\n  })\n}\n\n\u002F\u002F 删除\nconst handleDelete = (id) => {\n  ElMessageBox.confirm('删除后数据无法恢复，您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {\n    request.delete('\u002Forders\u002Fdelete\u002F' + id).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 重置\nconst reset = () => {\n  data.orderNo = null\n  load()\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.el-tag {\n  font-weight: bold;\n}\n.el-tag--warning {\n  color: orange;\n  background-color: #fff2de;\n}\n\u003C\u002Fstyle>\n```\n\n### Cart.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"front-container\">\n    \u003Cdiv class=\"card\" style=\"padding: 20px\">\n      \u003Cdiv>\n        \u003Cel-table :data=\"data.tableData\" stripe @selection-change=\"handleSelectionChange\">\n          \u003Cel-table-column type=\"selection\" width=\"55\" \u002F>\n          \u003Cel-table-column label=\"商品图片\">\n            \u003Ctemplate #default=\"scope\">\n              \u003Cimg style=\"width: 50px; height: 50px; display: block\" :src=\"scope.row.goodsImg\" alt=\"\">\n            \u003C\u002Ftemplate>\n          \u003C\u002Fel-table-column>\n          \u003Cel-table-column label=\"商品名称\" prop=\"goodsName\">\u003C\u002Fel-table-column>\n          \u003Cel-table-column label=\"商品单价\">\n            \u003Ctemplate #default=\"scope\">\n              \u003Cb style=\"color: red\">￥{{ scope.row.goodsPrice }}\u003C\u002Fb>\n            \u003C\u002Ftemplate>\n          \u003C\u002Fel-table-column>\n          \u003Cel-table-column label=\"商品数量\">\n            \u003Ctemplate #default=\"scope\">\n              \u003Cel-input-number @change=\"changeNum(scope.row)\" v-model=\"scope.row.num\" :min=\"1\" style=\"width: 150px\">\u003C\u002Fel-input-number>\n            \u003C\u002Ftemplate>\n          \u003C\u002Fel-table-column>\n          \u003Cel-table-column label=\"操作\" align=\"center\" width=\"100\">\n            \u003Ctemplate #default=\"scope\">\n              \u003Cel-button type=\"danger\" @click=\"handleDelete(scope.row.id)\">删除\u003C\u002Fel-button>\n            \u003C\u002Ftemplate>\n          \u003C\u002Fel-table-column>\n        \u003C\u002Fel-table>\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"text-align: right; margin-top: 20px; font-size: 20px\">总价格：\n        \u003Cb style=\"color: red; display: inline-block; min-width: 60px; text-align: left\">{{ data.total }} 元\u003C\u002Fb>\n        \u003Cdiv style=\"margin-top: 10px\">\u003Cel-button :disabled=\"data.total === 0\" @click=\"handleAddOrder\" type=\"danger\">立即下单\u003C\u002Fel-button>\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n\n    \u003Cel-dialog title=\"下单信息\" width=\"30%\" v-model=\"data.formVisible\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"100px\" style=\"padding-right: 30px\">\n        \u003Cel-form-item label=\"配送类型\" prop=\"deliverType\">\n          \u003Cel-radio-group v-model=\"data.form.deliverType\">\n            \u003Cel-radio-button value=\"自提\" label=\"自提\">\u003C\u002Fel-radio-button>\n            \u003Cel-radio-button value=\"外送\" label=\"外送\">\u003C\u002Fel-radio-button>\n          \u003C\u002Fel-radio-group>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"收货地址\" prop=\"address\" v-if=\"data.form.deliverType === '外送'\">\n          \u003Cel-input v-model=\"data.form.address\" type=\"textarea\" :rows=\"3\" placeholder=\"请输入外送的接收地址，包括联系人、联系电话、地址信息\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n      \u003Cspan class=\"dialog-footer\">\n        \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"addOrder\">确 认\u003C\u002Fel-button>\n      \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport request from \"@\u002Futils\u002Frequest\";\nimport {reactive, ref} from \"vue\";\nimport {ElMessageBox, ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  total: 0,\n  formVisible: false,\n  form: {},\n  tableData: [],\n  selectedRows: [],\n  rules: {\n    deliverType: [\n      { required: true, message: '请选择配送类型', trigger: 'change' }\n    ],\n    address: [\n      { required: true, message: '请输入配送地址', trigger: 'blur' }\n    ]\n  }\n})\n\nconst handleAddOrder = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\nconst addOrder = () => {\n  if (!data.selectedRows?.length) {\n    ElMessage.warning('请选择商品')\n    return\n  }\n  data.form.userId = data.user.id\n  data.form.cartList = data.selectedRows\n  request.post('\u002Forders\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      ElMessage.success('下单成功')\n      data.formVisible = false\n      load()\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst changeNum = (row) => {\n  calTotal()\n  data.form = row\n  update()\n}\n\nconst calTotal = () => {\n  data.total = 0\n  \u002F\u002F rows是选中行\n  data.selectedRows.forEach(item => {\n    data.total += item.goodsPrice * item.num\n  })\n  if (data.total > 0) {\n    data.total = data.total.toFixed(2)\n  }\n}\n\nconst handleSelectionChange = (rows) => {\n  data.selectedRows = rows\n  calTotal()\n}\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Fcart\u002FselectAll', {\n    params: {\n      userId: data.user.id\n    }\n  }).then(res => {\n    data.tableData = res.data\n  })\n}\nload()\n\n\u002F\u002F 新增\nconst handleAdd = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\n\u002F\u002F 编辑\nconst handleEdit = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))\n  data.formVisible = true\n}\n\n\u002F\u002F 新增保存\nconst add = () => {\n  request.post('\u002Fcart\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 编辑保存\nconst update = () => {\n  request.put('\u002Fcart\u002Fupdate', data.form).then(res => {\n    if (res.code === '200') {\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 弹窗保存\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      \u002F\u002F data.form有id就是更新，没有就是新增\n      data.form.id ? update() : add()\n    }\n  })\n}\n\n\u002F\u002F 删除\nconst handleDelete = (id) => {\n  ElMessageBox.confirm('您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {\n    request.delete('\u002Fcart\u002Fdelete\u002F' + id).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 重置\nconst reset = () => {\n  data.name = null\n  load()\n}\n\u003C\u002Fscript>\n```\n\n","coding",1,2772,2097,"2025-12-03 16:10:40","2026-05-07 15:36:12.649662+00","青哥带小白做毕设2026所有资料汇总","qingge-code-2026",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,28,35,42,49,56,63,70,77,84,91,98,105,112,119,126,127,134],{"id":21,"uuid":22,"project_id":6,"title":23,"type":9,"status":10,"public_enabled":10,"views":24,"sort":25,"created_at":26,"updated_at":27,"project_title":15,"project_slug":16},993,"mgoFKmGT","00. 带小白做毕设课程介绍以及脚手架获取",32061,1966,"2026-03-29 19:37:39","2026-05-03 22:49:02",{"id":29,"uuid":30,"project_id":6,"title":31,"type":9,"status":10,"public_enabled":10,"views":32,"sort":33,"created_at":34,"updated_at":27,"project_title":15,"project_slug":16},998,"1kCk1d2E","01. 导入并运行项目脚手架",14398,1974,"2025-11-11 16:24:50",{"id":36,"uuid":37,"project_id":6,"title":38,"type":9,"status":10,"public_enabled":10,"views":39,"sort":40,"created_at":41,"updated_at":27,"project_title":15,"project_slug":16},1003,"8ZlQ12IX","02. 带你开发一个基础的用户管理模块（上）",12150,1987,"2025-11-12 16:53:01",{"id":43,"uuid":44,"project_id":6,"title":45,"type":9,"status":10,"public_enabled":10,"views":46,"sort":47,"created_at":48,"updated_at":27,"project_title":15,"project_slug":16},1006,"6mmUNf9i","03. 带你开发一个基础的用户管理模块（下）",7782,1994,"2025-11-13 16:48:27",{"id":50,"uuid":51,"project_id":6,"title":52,"type":9,"status":10,"public_enabled":10,"views":53,"sort":54,"created_at":55,"updated_at":27,"project_title":15,"project_slug":16},1011,"3XNG04wA","04. 带你开发用户登录、注册、个人信息、修改密码功能",6474,2003,"2025-11-17 17:03:58",{"id":57,"uuid":58,"project_id":6,"title":59,"type":9,"status":10,"public_enabled":10,"views":60,"sort":61,"created_at":62,"updated_at":27,"project_title":15,"project_slug":16},1017,"LnAAYydZ","05. 带你开发商品分类管理功能",5467,2012,"2025-11-24 17:30:23",{"id":64,"uuid":65,"project_id":6,"title":66,"type":9,"status":10,"public_enabled":10,"views":67,"sort":68,"created_at":69,"updated_at":27,"project_title":15,"project_slug":16},1018,"584qohhy","06. 开发商品信息管理功能",4836,2013,"2025-11-24 17:30:12",{"id":71,"uuid":72,"project_id":6,"title":73,"type":9,"status":10,"public_enabled":10,"views":74,"sort":75,"created_at":76,"updated_at":27,"project_title":15,"project_slug":16},1024,"scxsifCZ","07. 开发轮播图信息管理功能",3313,2021,"2025-11-24 17:29:58",{"id":78,"uuid":79,"project_id":6,"title":80,"type":9,"status":10,"public_enabled":10,"views":81,"sort":82,"created_at":83,"updated_at":27,"project_title":15,"project_slug":16},1041,"AjujV8Gq","08. 带你实现前台首页功能",4058,2039,"2025-11-24 17:31:31",{"id":85,"uuid":86,"project_id":6,"title":87,"type":9,"status":10,"public_enabled":10,"views":88,"sort":89,"created_at":90,"updated_at":27,"project_title":15,"project_slug":16},1045,"p6yD8ZxS","09. 带你实现商品搜索、商品分类检索功能",3005,2048,"2025-11-25 16:35:45",{"id":92,"uuid":93,"project_id":6,"title":94,"type":9,"status":10,"public_enabled":10,"views":95,"sort":96,"created_at":97,"updated_at":27,"project_title":15,"project_slug":16},1050,"7gHUek7z","10. 带你实现商品详情页功能",2622,2053,"2025-11-26 17:22:20",{"id":99,"uuid":100,"project_id":6,"title":101,"type":9,"status":10,"public_enabled":10,"views":102,"sort":103,"created_at":104,"updated_at":27,"project_title":15,"project_slug":16},1059,"aX7rviTw","11. 带你实现商品收藏功能",2667,2067,"2025-11-28 17:00:21",{"id":106,"uuid":107,"project_id":6,"title":108,"type":9,"status":10,"public_enabled":10,"views":109,"sort":110,"created_at":111,"updated_at":27,"project_title":15,"project_slug":16},1060,"xcmGXr9E","12. 带你开发用户模拟充值功能",2442,2068,"2026-02-02 14:24:37",{"id":113,"uuid":114,"project_id":6,"title":115,"type":9,"status":10,"public_enabled":10,"views":116,"sort":117,"created_at":118,"updated_at":27,"project_title":15,"project_slug":16},1065,"z8IN0tX8","13. 带你实现购物车功能",2461,2078,"2025-12-01 17:16:05",{"id":120,"uuid":121,"project_id":6,"title":122,"type":9,"status":10,"public_enabled":10,"views":123,"sort":124,"created_at":125,"updated_at":27,"project_title":15,"project_slug":16},1069,"NfBIfhVx","14. 带你实现商品下单功能",3131,2086,"2025-12-02 16:57:21",{"id":4,"uuid":5,"project_id":6,"title":7,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},{"id":128,"uuid":129,"project_id":6,"title":130,"type":9,"status":10,"public_enabled":10,"views":131,"sort":132,"created_at":133,"updated_at":27,"project_title":15,"project_slug":16},1075,"RYH15Bfu","15. 带你实现订单评价功能",2507,2103,"2025-12-04 17:10:47",{"id":135,"uuid":136,"project_id":6,"title":137,"type":9,"status":10,"public_enabled":10,"views":138,"sort":139,"created_at":140,"updated_at":27,"project_title":15,"project_slug":16},1079,"iUdzrNPu","16. 带你实现后台数据统计功能",2991,2107,"2025-12-05 17:37:57"]