【项目完结】小兔鲜Vue3 项目学习笔记 Day07

系列文章

【B站 heima 】小兔鲜Vue3 项目学习笔记 Day01
【B站 heima 】小兔鲜Vue3 项目学习笔记 Day02
【B站 heima】小兔鲜Vue3 项目学习笔记 Day03
【B站 heima】小兔鲜Vue3 项目学习笔记 Day04
【B站 heima】小兔鲜Vue3 项目学习笔记 Day05
【B站 heima】小兔鲜Vue3 项目学习笔记 Day06

Day 07


支付中心

1. 整体功能梳理和路由配置

  • 准备路由views/Member/index.vue
<!-- 会员中心 -->
<script setup></script>

<template>
    <div class="container">
        <div class="xtx-member-aside">
            <div class="user-manage">
                <h4>我的账户</h4>
                <div class="links">
                    <RouterLink to="/member/user">个人中心</RouterLink>
                </div>
                <h4>交易管理</h4>
                <div class="links">
                    <RouterLink to="/member/order">我的订单</RouterLink>
                </div>
            </div>
        </div>
        <div class="article">
            <!-- 三级路由的挂载点 -->
            <!-- <RouterView /> -->
        </div>
    </div>
</template>

<style scoped lang="scss">
.container {
    display: flex;
    padding-top: 20px;

    .xtx-member-aside {
        width: 220px;
        margin-right: 20px;
        border-radius: 2px;
        background-color: #fff;

        .user-manage {
            background-color: #fff;

            h4 {
                font-size: 18px;
                font-weight: 400;
                padding: 20px 52px 5px;
                border-top: 1px solid #f6f6f6;
            }

            .links {
                padding: 0 52px 10px;
            }

            a {
                display: block;
                line-height: 1;
                padding: 15px 0;
                font-size: 14px;
                color: #666;
                position: relative;

                &:hover {
                    color: $xtxColor;
                }

                &.active,
                &.router-link-exact-active {
                    color: $xtxColor;

                    &:before {
                        display: block;
                    }
                }

                &:before {
                    content: '';
                    display: none;
                    width: 6px;
                    height: 6px;
                    border-radius: 50%;
                    position: absolute;
                    top: 19px;
                    left: -16px;
                    background-color: $xtxColor;
                }
            }
        }
    }

    .article {
        width: 1000px;
        background-color: #fff;
    }
}
</style>
  • 配置路由,引入,二级路由
{
	path: 'member',
	component: Member
}
  • views/Member/components/UserInfo.vue(个人信息组件)
<!-- 个人信息组件 -->
<script setup>
const userStore = {}
</script>

<template>
    <div class="home-overview">
        <!-- 用户信息 -->
        <div class="user-meta">
            <div class="avatar">
                <img :src="userStore.userInfo?.avatar" />
            </div>
            <h4>{{ userStore.userInfo?.account }}</h4>
        </div>
        <div class="item">
            <a href="javascript:;">
                <span class="iconfont icon-hy"></span>
                <p>会员中心</p>
            </a>
            <a href="javascript:;">
                <span class="iconfont icon-aq"></span>
                <p>安全设置</p>
            </a>
            <a href="javascript:;">
                <span class="iconfont icon-dw"></span>
                <p>地址管理</p>
            </a>
        </div>
    </div>
    <div class="like-container">
        <div class="home-panel">
            <div class="header">
                <h4 data-v-bcb266e0="">猜你喜欢</h4>
            </div>
            <div class="goods-list">
                <!-- <GoodsItem v-for="good in likeList" :key="good.id" :good="good" /> -->
            </div>
        </div>
    </div>
</template>

<style scoped lang="scss">
.home-overview {
    height: 132px;
    background: url(@/assets/images/center-bg.png) no-repeat center / cover;
    display: flex;

    .user-meta {
        flex: 1;
        display: flex;
        align-items: center;

        .avatar {
            width: 85px;
            height: 85px;
            border-radius: 50%;
            overflow: hidden;
            margin-left: 60px;

            img {
                width: 100%;
                height: 100%;
            }
        }

        h4 {
            padding-left: 26px;
            font-size: 18px;
            font-weight: normal;
            color: white;
        }
    }

    .item {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: space-around;

        &:first-child {
            border-right: 1px solid #f4f4f4;
        }

        a {
            color: white;
            font-size: 16px;
            text-align: center;

            .iconfont {
                font-size: 32px;
            }

            p {
                line-height: 32px;
            }
        }
    }
}

.like-container {
    margin-top: 20px;
    border-radius: 4px;
    background-color: #fff;
}

.home-panel {
    background-color: #fff;
    padding: 0 20px;
    margin-top: 20px;
    height: 400px;

    .header {
        height: 66px;
        border-bottom: 1px solid #f5f5f5;
        padding: 18px 0;
        display: flex;
        justify-content: space-between;
        align-items: baseline;

        h4 {
            font-size: 22px;
            font-weight: 400;
        }

    }

    .goods-list {
        display: flex;
        justify-content: space-around;
    }
}
</style>
  • views/Member/components/UserOrder.vue(我的订单组件)
<script setup>
// tab列表
const tabTypes = [
  { name: "all", label: "全部订单" },
  { name: "unpay", label: "待付款" },
  { name: "deliver", label: "待发货" },
  { name: "receive", label: "待收货" },
  { name: "comment", label: "待评价" },
  { name: "complete", label: "已完成" },
  { name: "cancel", label: "已取消" }
]
// 订单列表
const orderList = []

</script>

<template>
  <div class="order-container">
    <el-tabs>
      <!-- tab切换 -->
      <el-tab-pane v-for="item in tabTypes" :key="item.name" :label="item.label" />

      <div class="main-container">
        <div class="holder-container" v-if="orderList.length === 0">
          <el-empty description="暂无订单数据" />
        </div>
        <div v-else>
          <!-- 订单列表 -->
          <div class="order-item" v-for="order in orderList" :key="order.id">
            <div class="head">
              <span>下单时间:{{ order.createTime }}</span>
              <span>订单编号:{{ order.id }}</span>
              <!-- 未付款,倒计时时间还有 -->
              <span class="down-time" v-if="order.orderState === 1">
                <i class="iconfont icon-down-time"></i>
                <b>付款截止: {{order.countdown}}</b>
              </span>
            </div>
            <div class="body">
              <div class="column goods">
                <ul>
                  <li v-for="item in order.skus" :key="item.id">
                    <a class="image" href="javascript:;">
                      <img :src="item.image" alt="" />
                    </a>
                    <div class="info">
                      <p class="name ellipsis-2">
                        {{ item.name }}
                      </p>
                      <p class="attr ellipsis">
                        <span>{{ item.attrsText }}</span>
                      </p>
                    </div>
                    <div class="price">¥{{ item.realPay?.toFixed(2) }}</div>
                    <div class="count">x{{ item.quantity }}</div>
                  </li>
                </ul>
              </div>
              <div class="column state">
                <p>{{ order.orderState }}</p>
                <p v-if="order.orderState === 3">
                  <a href="javascript:;" class="green">查看物流</a>
                </p>
                <p v-if="order.orderState === 4">
                  <a href="javascript:;" class="green">评价商品</a>
                </p>
                <p v-if="order.orderState === 5">
                  <a href="javascript:;" class="green">查看评价</a>
                </p>
              </div>
              <div class="column amount">
                <p class="red">¥{{ order.payMoney?.toFixed(2) }}</p>
                <p>(含运费:¥{{ order.postFee?.toFixed(2) }})</p>
                <p>在线支付</p>
              </div>
              <div class="column action">
                <el-button  v-if="order.orderState === 1" type="primary"
                  size="small">
                  立即付款
                </el-button>
                <el-button v-if="order.orderState === 3" type="primary" size="small">
                  确认收货
                </el-button>
                <p><a href="javascript:;">查看详情</a></p>
                <p v-if="[2, 3, 4, 5].includes(order.orderState)">
                  <a href="javascript:;">再次购买</a>
                </p>
                <p v-if="[4, 5].includes(order.orderState)">
                  <a href="javascript:;">申请售后</a>
                </p>
                <p v-if="order.orderState === 1"><a href="javascript:;">取消订单</a></p>
              </div>
            </div>
          </div>
          <!-- 分页 -->
          <div class="pagination-container">
            <el-pagination background layout="prev, pager, next" />
          </div>
        </div>
      </div>

    </el-tabs>
  </div>

</template>

<style scoped lang="scss">
.order-container {
  padding: 10px 20px;

  .pagination-container {
    display: flex;
    justify-content: center;
  }

  .main-container {
    min-height: 500px;

    .holder-container {
      min-height: 500px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}

.order-item {
  margin-bottom: 20px;
  border: 1px solid #f5f5f5;

  .head {
    height: 50px;
    line-height: 50px;
    background: #f5f5f5;
    padding: 0 20px;
    overflow: hidden;

    span {
      margin-right: 20px;

      &.down-time {
        margin-right: 0;
        float: right;

        i {
          vertical-align: middle;
          margin-right: 3px;
        }

        b {
          vertical-align: middle;
          font-weight: normal;
        }
      }
    }

    .del {
      margin-right: 0;
      float: right;
      color: #999;
    }
  }

  .body {
    display: flex;
    align-items: stretch;

    .column {
      border-left: 1px solid #f5f5f5;
      text-align: center;
      padding: 20px;

      >p {
        padding-top: 10px;
      }

      &:first-child {
        border-left: none;
      }

      &.goods {
        flex: 1;
        padding: 0;
        align-self: center;

        ul {
          li {
            border-bottom: 1px solid #f5f5f5;
            padding: 10px;
            display: flex;

            &:last-child {
              border-bottom: none;
            }

            .image {
              width: 70px;
              height: 70px;
              border: 1px solid #f5f5f5;
            }

            .info {
              width: 220px;
              text-align: left;
              padding: 0 10px;

              p {
                margin-bottom: 5px;

                &.name {
                  height: 38px;
                }

                &.attr {
                  color: #999;
                  font-size: 12px;

                  span {
                    margin-right: 5px;
                  }
                }
              }
            }

            .price {
              width: 100px;
            }

            .count {
              width: 80px;
            }
          }
        }
      }

      &.state {
        width: 120px;

        .green {
          color: $xtxColor;
        }
      }

      &.amount {
        width: 200px;

        .red {
          color: $priceColor;
        }
      }

      &.action {
        width: 140px;

        a {
          display: block;

          &:hover {
            color: $xtxColor;
          }
        }
      }
    }
  }
}
</style>
  • 配置三级路由
import MemberInfo from '@/views/Member/components/UserInfo.vue'
import MemberOrder from '@/views/Member/components/UserOrder.vue'


{
  path: '/member',
  component: Member,
  children: [
    {
      path: 'user',
      component: MemberInfo
    },
    {
      path: 'order',
      component: MemberOrder
    }
  ]
}

记得把这里放开:

在这里插入图片描述

效果:

在这里插入图片描述

2. 个人中心信息渲染

  • 用户头像和名字使用的时pinia里面的数据进行渲染
<script setup>
// 导入userStore
import { useUserStore } from '@/stores/userStore'
const userStore = useUserStore()
</script>


	<div class="user-meta">
            <div class="avatar">
                <img :src="userStore.userInfo?.avatar" />
            </div>
            <h4>{{ userStore.userInfo?.account }}</h4>
	</div>

在这里插入图片描述

  • 封装并调用 猜你喜欢 接口
//apis/user.js
//猜你喜欢 接口
export const getLikeListAPI = ({ limit = 4 }) => {
    return httpInstance({
        url: '/goods/relevant',
        params: {
            limit
        }
    })
}
<!-- 个人信息组件 -->

// 导入userStore
import { useUserStore } from '@/stores/user'
import { getLikeListAPI } from '@/apis/user.js'
import { onMounted, ref } from 'vue'
import GoodItem from '@/views/Home/components/GoodItem.vue'


const userStore = useUserStore()
//猜你喜欢 信息
const likeList = ref([])
const getLikeList = async () => {
    const res = await getLikeListAPI({ limit: 4 })
    likeList.value = res.result
}

onMounted(() => getLikeList())

渲染:

 <GoodItem v-for="goods in likeList" :key="goods.id" :goods="goods" />

效果:
在这里插入图片描述

3. 我的订单-基础订单列表实现(主区域)

在这里插入图片描述

  • 封装获取订单接口apis/order.js
import httpInstance from '@/utils/http'


export const getUserOrder = (params) => {
    return httpInstance({
        url: '/member/order',
        method: 'GET',
        params
    })
}
//  UserOrder.vue
import { getUserOrder } from '@/apis/order'
import { onMounted, ref } from 'vue'

// tab列表
const tabTypes = [
    { name: "all", label: "全部订单" },
    { name: "unpay", label: "待付款" },
    { name: "deliver", label: "待发货" },
    { name: "receive", label: "待收货" },
    { name: "comment", label: "待评价" },
    { name: "complete", label: "已完成" },
    { name: "cancel", label: "已取消" }
]
// 获取订单列表
const orderList = ref([])
const params = ref({
    orderState: 0,
    page: 1,
    pageSize: 2
})
const getOrderList = async () => {
    const res = await getUserOrder(params.value)
    orderList.value = res.result.items   //订单列表
    total.value = res.result.counts  //订单总数
}
onMounted(() => getOrderList())

报错的话修改一下http.js中的超时时间,让其长一些试试

在这里插入图片描述

4. 我的订单-tab切换

点击哪一项显示当前项的数据

思路:切换时修改orderState参数,再次发起请求获取数据。

  • 绑定事件
  <el-tabs @tab-change="tabChange">...
  • 逻辑
//切换tab  type是这个组件自带的,用来记录当前点击的是哪一个
const tabChange = (type) => {
    params.value.orderState = type
    getOrderList()  //重新获取数据
}

5. 分页逻辑实现

无论是C端或者B端都会有应用

在这里插入图片描述

使用total绑定总条数,使用page-size属性绑定每页条数。

const total = ref(0)
...
total.value = res.result.counts  //订单总数
...

 <!-- 分页 绑定total-->
<div class="pagination-container">
	 <el-pagination background layout="prev, pager, next" :total="total"
	                page-size="params.pageSize" />
</div>

在这里插入图片描述

实现切换分页:

绑定current-change事件,拿到当前页数,使用最新页数发送请求获取数据

//切换分页
const pageChange = (page) => {
    params.value.page = page
    getOrderList()  //获取最新的数据
}
<!-- 分页 绑定total-->
<div class="pagination-container">
	 <el-pagination background layout="prev, pager, next" :total="total"
	                page-size="params.pageSize" @current-change="pageChange"/>
</div>

在这里插入图片描述

6. 细节优化

  • 当我们跳转到member这个路由时,希望能显示个人中心的数据而不是这样⬇空白

在这里插入图片描述

路由路径置空,修改路径即可

{
          path: 'member',
          component: Member,
          children: [
            {
              path: '',
              component: MemberInfo
            },
            {
              path: 'order',
              component: MemberOrder
            }
          ]
        }
<!--Member/index.vue-->
 <div class="links">
	<RouterLink to="/member">个人中心</RouterLink>
</div>
  • 在这里插入图片描述
//OrderInfo.vue

// 创建格式化函数
  const fomartPayState = (payState) => {
    const stateMap = {
      1: '待付款',
      2: '待发货',
      3: '待收货',
      4: '待评价',
      5: '已完成',
      6: '已取消'
    }
    return stateMap[payState]
  }
<div class="column state">
	<p>{{ fomartPayState(order.orderState) }}</p>
	<p v-if="order.orderState === 3">
		<a href="javascript:;" class="green">查看物流</a>
	</p>
	<p v-if="order.orderState === 4">
		<a href="javascript:;" class="green">评价商品</a>
	</p>
	<p v-if="order.orderState === 5">
		<a href="javascript:;" class="green">查看评价</a>
	</p>
</div>

小结

完结撒花❀❀❀

做完项目及时复盘喔,找出难点重点,理清思路

常看常新哦
在这里插入图片描述

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
小兔项目是一个使用Vue3.0开发的项目。它采用了vuex来管理购物车和用户数据,使得数据的管理更加方便。项目中会使用到vue3.0的新特性,因此会体验到更加嫩、酸爽的开发过程。然而,由于目前大多数第三方UI组件库不支持vue3.0,所以在项目中会大量自己封装和布局组件,并预制一些基本样式。在解决问题时,小兔项目主要使用ref函数和组合式API - computed,这样可以更加灵活地处理项目中的数据。关键文件包括vite.config.js(项目的配置文件,基于vite的配置)、package.json(项目包文件,核心依赖项变成了Vue3.x和vite)、main.js(入口文件,使用createApp函数创建应用实例)和app.vue(根组件,使用SFC单文件组件,包含script、template和style)。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [小兔Vue3.0前端电商项目实战](https://blog.csdn.net/qzc2017/article/details/120634549)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [小兔项目----vue3入门](https://blog.csdn.net/qq_63358859/article/details/130704712)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值