Skip to main content

我的订单页面实现

上一节课实现了订单接口,本节将介绍如何在前端实现一个“我的订单”页面。我们将涵盖以下内容:

  • 路由配置和权限设置
  • 页面结构和布局
  • 发送请求获取订单数据
  • 实现分页功能
  • 根据订单状态筛选订单

路由配置和权限设置

首先,在全局路由文件中配置一个名为"orders"的路由,并设置它需要登录才能访问。例如:

frontend/src/router/index.js
import Orders from '../views/Orders.vue'

{
path: '/orders',
name: 'Orders',
component: Orders,
meta: {
requireLogin: true
}
},

页面结构和布局

在views/路径下创建一个名为"Orders.vue"的页面组件,并在组件中编写HTML代码来布局页面结构。页面包括以下部分:

  1. 表头:包含"我的订单"标题
  2. 订单列表:用于展示订单信息的表格
  3. 订单筛选:用于查询订单和按状态筛选订单的表单

"Orders.vue"代码如下:

frontend/src/views/Orders.vue
<template>
<div id="container" class="text-white text-sm bg-primary-300 min-h-screen pb-4">
<Header />
<div id="main" class="bg-primary-300 p-6 text-black">
<div class="rounded bg-white mx-4 my-4 py-6">
<div class="px-6">
<h1 class="text-lg font-semibold">我的订单</h1>
</div>
</div>
<div class="rounded bg-white mx-4 mt-4 py-6">
<div id="tabs" class="flex justify-start items-center py-4">
<div class="px-4 text-md">
<a href="/orders" class="order-status" data-order-status="all">全部订单</a>
</div>
<div class="px-4 text-md">
<a
href="/orders/?pay_status=paying"
class="order-status"
data-order-status="unpay"
>未付款</a
>
</div>
<div class="px-4 text-md">
<a
href="/orders/?pay_status=trade_success"
class="order-status"
data-order-status="payed"
>已付款</a
>
</div>
<div class="flex items-center ml-4">
<div class="relative shrink">
<form>
<input
v-model="order_sn"
type="text"
name="order_sn"
class="outline-0 h-9 rounded border border-gray-600 placeholder-gray-400 w-64 px-2 py-1"
placeholder="请输入订单号"
/>
<div class="absolute top-0 right-0 flex items-center h-full">
<div class="rounded text-xs text-gray-400 px-2 mr-2">
<button v-on:click.prevent="searchOrder">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="mt-4 mb-3">
<div
class="not-prose relative bg-slate-50 rounded-xl overflow-hidden dark:bg-slate-800/25"
>
<div
class="absolute inset-0 bg-grid-slate-100 [mask-image:linear-gradient(0deg,#fff,rgba(255,255,255,0.6))] dark:bg-grid-slate-700/25 dark:[mask-image:linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.5))]"
style="background-position: 10px 10px"
></div>
<div class="relative rounded-xl overflow-auto">
<div class="shadow-sm overflow-hidden my-8">
<table class="border-collapse table-auto w-full text-sm">
<thead>
<tr>
<th
class="border-b dark:border-slate-600 font-medium p-4 pl-8 pt-0 pb-3 text-slate-400 dark:text-slate-200 text-left"
>
订单号
</th>
<th
class="border-b dark:border-slate-600 font-medium p-4 pt-0 pb-3 text-slate-400 dark:text-slate-200 text-left"
>
商品名称
</th>
<th
class="border-b dark:border-slate-600 font-medium p-4 pt-0 pb-3 text-slate-400 dark:text-slate-200 text-left"
>
购买日期
</th>
<th
class="border-b dark:border-slate-600 font-medium p-4 pt-0 pb-3 text-slate-400 dark:text-slate-200 text-left"
>
金额
</th>
<th
class="border-b dark:border-slate-600 font-medium p-4 pt-0 pb-3 text-slate-400 dark:text-slate-200 text-left"
>
订单状态
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-slate-800">
<tr v-for="order in info.results">
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400"
>
{{ order.order_sn }}
</td>
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400"
>
{{ order.card.card_name }}
</td>
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400"
>
{{ order.created_at }}
</td>
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400"
>
{{ order.order_mount }}
</td>
<td
class="border-b border-slate-100 dark:border-slate-700 py-4 text-slate-500 dark:text-slate-400"
>
<button
v-if="order.pay_status == 'PAYING'"
v-on:click="pay(order)"
class="pay rounded border bg-gray-500 hover:bg-blue-500 hover:text-white text-sm h-8 w-16 text-primary-100"
>
去支付
</button>
<button
v-else-if="order.pay_status == 'TRADE_CLOSED'"
class="rounded border bg-gray-500 text-white text-sm h-8 w-16 cursor-not-allowed"
>
已关闭
</button>
<button
v-else-if="
order.pay_status == 'TRADE_SUCCESS' ||
order.pay_status == 'TRADE_FINISHED'
"
class="rounded border bg-blue-500 text-white text-sm h-8 w-16 cursor-default"
>
已完成
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分页开始 -->
<Page :info="info" />
<!-- 分页结束 -->
<Footer />
</div>
</template>

代码逻辑实现

在Orders.vue页面组件中,在mounted钩子函数中调用this.getOrders()方法来发送GET请求获取订单数据。使用axios库发送请求,请求订单接口的URL为"/api/orders",并将请求结果赋值给this.info。例如:

frontend/src/views/Orders.vue
<script>
import axios, { Axios } from "axios";
import Header from "@/components/Header.vue";
import Footer from "@/components/Footer.vue";
import Page from "@/components/Page.vue";

export default {
name: "Order",
data: function () {
return {
info: "",
order_sn: "",
};
},
components: { Header, Footer, Page },
mounted() {
this.get_orders();
},
methods: {
get_orders() {
let url = "/api/orders";
// 获取page参数值
const page = Number(this.$route.query.page);
const pay_status = this.$route.query.pay_status;
const order_sn = this.$route.query.order_sn;
const params = new URLSearchParams();

if (page) {
params.append("page", page);
}
if (pay_status) {
params.append("pay_status", pay_status);
}

url = url + "?" + params.toString();
axios.get(url).then((response) => {
this.info = response.data;
});
},

},
watch: {
// 监听路由的变化
$route() {
this.get_orders();
},
},
};
</script>
代码解析

这段代码是一个Vue组件,用于展示订单信息。下面是对代码主要部分的解析:

  • 导入依赖: 首先,代码通过import语句引入了axios库(用于发送HTTP请求),以及三个Vue组件(Header, Footer, Page),这些组件可能用于构建页面的头部、底部和订单页面的具体内容。

  • 组件定义: export default定义了一个Vue组件,名为Order

    • data: 组件的数据对象包含info(用于存储订单数据)和order_sn(可能用于存储订单编号,尽管在此代码片段中未使用)。
    • components: 定义了该组件将使用的子组件,即之前导入的Header, Footer, Page
    • mounted: 是一个生命周期钩子,当组件被挂载到DOM上后执行。这里用于调用get_orders方法,即在组件加载完成后立即获取订单数据。
  • 方法定义:

    • get_orders: 此方法用于从服务器获取订单数据。
      • 首先,构造请求URL/api/orders,并从当前路由的查询参数中获取page, pay_status, 和order_sn参数,以构建查询字符串。
      • 使用axios.get发送HTTP GET请求,请求的URL包括之前构造的查询参数。
      • 请求成功返回后,使用response.data更新info数据,这里假设返回的数据是订单信息。
  • 监视器(watch):

    • $route: 这是一个Vue实例的监视器,用于监视$route对象(代表当前路由)。当路由发生变化时(例如,用户通过链接导航到不同的页面),这个监视器会被触发,从而再次调用get_orders方法以获取新的订单数据。

总的来说,这个组件的主要功能是在页面加载和路由变化时,从后端API /api/orders获取订单数据,并将这些数据显示在页面上。通过axios进行异步HTTP请求,获取数据后更新组件的info属性,以反映到页面上。此外,组件还利用Vue的路由系统来响应URL参数的变化,进而重新获取并显示相关订单信息。

点击“未支付”选项,运行效果如下图所示。

图79-全部待支付订单

点击“已付款”按钮,如下图所示。

图79-已支付订单

至此,我们已经完成了前端“我的订单”页面的实现。包括路由配置和权限设置、页面结构和布局、发送请求获取订单数据、实现分页功能以及根据订单状态筛选订单。可以根据实际需求对页面进行进一步优化和扩展。