Files
Market-Front/src/pages/order/ContentPage.vue

417 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<UserLayout>
<div class="order-page">
<el-card class="order-card">
<template #header>
<div class="order-header">
<span>我的订单</span>
</div>
</template>
<div v-if="orderList.length === 0" class="empty-orders">
<el-empty description="暂无订单" />
</div>
<div v-else>
<!-- 订单列表 -->
<div class="order-list">
<el-table :data="orderList" style="width: 100%" row-key="id">
<el-table-column prop="orderNo" label="订单号" min-width="200" />
<el-table-column
prop="createTime"
label="下单时间"
min-width="180"
>
<template #default="scope">
{{ formatDate(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column
prop="productCount"
label="商品数量"
min-width="100"
/>
<el-table-column
prop="totalAmount"
label="订单总额"
min-width="120"
>
<template #default="scope">
¥{{ scope.row.totalAmount.toFixed(2) }}
</template>
</el-table-column>
<el-table-column
prop="statusText"
label="订单状态"
min-width="100"
/>
<el-table-column label="操作" min-width="120">
<template #default="scope">
<el-button
type="primary"
link
@click="viewOrderDetail(scope.row)"
>
查看详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[5, 10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</el-card>
</div>
<!-- 订单详情模态框 -->
<el-dialog
v-model="dialogVisible"
title="订单详情"
width="900px"
class="order-detail-dialog"
>
<div v-if="currentOrder" class="order-detail">
<h3 class="section-title">订单信息</h3>
<el-descriptions :column="2" border>
<el-descriptions-item label="订单号">
{{ currentOrder.orderNo }}
</el-descriptions-item>
<el-descriptions-item label="下单时间">
{{ formatDateTime(currentOrder.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="订单状态">
{{ getOrderStatusText(currentOrder.status) }}
</el-descriptions-item>
<el-descriptions-item label="支付方式">
{{ getPayTypeText(currentOrder.payType) }}
</el-descriptions-item>
<el-descriptions-item label="订单总额">
¥{{ currentOrder.totalAmount.toFixed(2) }}
</el-descriptions-item>
<el-descriptions-item label="实付金额">
¥{{ currentOrder.payAmount.toFixed(2) }}
</el-descriptions-item>
</el-descriptions>
<h3 class="section-title">收货信息</h3>
<el-descriptions :column="1" border>
<el-descriptions-item label="收货人">
{{ currentOrder.receiverName }}
</el-descriptions-item>
<el-descriptions-item label="联系电话">
{{ currentOrder.receiverPhone }}
</el-descriptions-item>
<el-descriptions-item label="收货地址">
{{ currentOrder.receiverAddress }}
</el-descriptions-item>
</el-descriptions>
<h3 class="section-title">商品信息</h3>
<div class="order-items">
<el-table :data="currentOrder.orderItems" style="width: 100%">
<el-table-column prop="productImage" label="商品" width="300">
<template #default="scope">
<div class="product-info">
<el-image
:src="scope.row.productImage"
class="product-image"
fit="cover"
/>
<div class="product-details">
<div class="product-name">
{{ scope.row.productName }}
</div>
<div class="product-sku">{{ scope.row.skuName }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="price" label="单价" width="168">
<template #default="scope">
¥{{ scope.row.price.toFixed(2) }}
</template>
</el-table-column>
<el-table-column prop="quantity" label="数量" width="200" />
<el-table-column prop="totalPrice" label="小计" width="200">
<template #default="scope">
¥{{ scope.row.totalPrice.toFixed(2) }}
</template>
</el-table-column>
</el-table>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</UserLayout>
</template>
<script setup lang="ts">
import UserLayout from "@/layouts/UserLayout.vue";
import { ref, onMounted } from "vue";
import { useUserStore } from "@/stores/UserStore";
import { ElMessage } from "element-plus";
import { getOrderList, getOrderDetail } from "@/apis/order";
import type { OrderListItem, OrderDetail } from "@/types/order";
const userStore = useUserStore();
// 订单列表相关
const orderList = ref<OrderListItem[]>([]);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 订单详情相关
const dialogVisible = ref(false);
const currentOrder = ref<OrderDetail | null>(null);
// 获取订单列表
const loadOrderList = async () => {
if (!userStore.userInfo) {
ElMessage.warning("请先登录");
return;
}
try {
const res = await getOrderList({
page: currentPage.value,
size: pageSize.value,
userId: userStore.userInfo.id,
});
if (res.code === 200) {
orderList.value = res.data.list;
total.value = res.data.total;
} else {
ElMessage.error(res.message || "获取订单列表失败");
}
} catch (err) {
console.error(err);
ElMessage.error("获取订单列表失败");
}
};
// 处理页面大小变化
const handleSizeChange = (val: number) => {
pageSize.value = val;
currentPage.value = 1;
loadOrderList();
};
// 处理页码变化
const handleCurrentChange = (val: number) => {
currentPage.value = val;
loadOrderList();
};
// 查看订单详情
const viewOrderDetail = async (order: OrderListItem) => {
if (!userStore.userInfo) {
ElMessage.warning("请先登录");
return;
}
try {
const res = await getOrderDetail(order.id, userStore.userInfo.id);
if (res.code === 200) {
currentOrder.value = res.data;
dialogVisible.value = true;
} else {
ElMessage.error(res.message || "获取订单详情失败");
}
} catch (err) {
console.error(err);
ElMessage.error("获取订单详情失败");
}
};
// 格式化日期 (用于列表中的日期)
const formatDate = (date: string | Date | number[]) => {
// 检查是否为空值
if (!date) return "-";
try {
let d: Date;
// 如果是数组格式 [year, month, day, hour, minute, second]
if (Array.isArray(date)) {
if (date.length < 6) return "-";
// 注意JavaScript 中月份是从0开始的所以需要减1
d = new Date(date[0], date[1] - 1, date[2], date[3], date[4], date[5]);
}
// 如果是字符串并且是 ISO 8601 格式 (如: 2025-12-21T00:04:18)
else if (typeof date === "string" && date.includes("T")) {
d = new Date(date);
}
// 其他格式处理
else {
d = new Date(date);
}
// 检查是否为有效日期
if (isNaN(d.getTime())) return "-";
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const hours = String(d.getHours()).padStart(2, "0");
const minutes = String(d.getMinutes()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}`;
} catch (e) {
console.error("日期格式化错误:", e, "输入值:", date);
return "-";
}
};
// 格式化日期时间 (用于详情中的日期时间)
const formatDateTime = (date: string | Date | number[]) => {
// 检查是否为空值
if (!date) return "-";
try {
let d: Date;
// 如果是数组格式 [year, month, day, hour, minute, second]
if (Array.isArray(date)) {
if (date.length < 6) return "-";
// 注意JavaScript 中月份是从0开始的所以需要减1
d = new Date(date[0], date[1] - 1, date[2], date[3], date[4], date[5]);
}
// 如果是字符串并且是 ISO 8601 格式 (如: 2025-12-21T00:04:18)
else if (typeof date === "string" && date.includes("T")) {
d = new Date(date);
}
// 其他格式处理
else {
d = new Date(date);
}
// 检查是否为有效日期
if (isNaN(d.getTime())) return "-";
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const hours = String(d.getHours()).padStart(2, "0");
const minutes = String(d.getMinutes()).padStart(2, "0");
const seconds = String(d.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (e) {
console.error("日期时间格式化错误:", e, "输入值:", date);
return "-";
}
};
// 获取订单状态文本
const getOrderStatusText = (status: number) => {
const statusMap: Record<number, string> = {
0: "待付款",
1: "待发货",
2: "待收货",
3: "已完成",
4: "已取消",
};
return statusMap[status] || "未知状态";
};
// 获取支付方式文本
const getPayTypeText = (payType: number) => {
const payTypeMap: Record<number, string> = {
0: "未支付",
1: "微信",
2: "支付宝",
};
return payTypeMap[payType] || "未知";
};
onMounted(() => {
loadOrderList();
});
</script>
<style scoped>
.order-page {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.order-header {
font-size: 18px;
font-weight: bold;
}
.empty-orders {
text-align: center;
padding: 40px 0;
}
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
.section-title {
margin: 20px 0 10px 0;
font-size: 16px;
font-weight: bold;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
}
/* 商品信息样式仿照购物车 */
.product-info {
display: flex;
align-items: center;
gap: 15px;
}
.product-image {
width: 80px;
height: 80px;
border-radius: 4px;
}
.product-details {
flex: 1;
}
.product-name {
font-weight: bold;
margin-bottom: 5px;
}
.product-sku {
color: #999;
font-size: 12px;
}
.order-items {
margin-top: 20px;
}
</style>