实现了订单相关功能
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import http from "../utils/http";
|
||||
import type {
|
||||
OrderCreateDTO,
|
||||
// OrderListItem,
|
||||
OrderDetail,
|
||||
OrderPageParams,
|
||||
@@ -23,3 +24,25 @@ export const getOrderDetail = (id: number, userId: number) => {
|
||||
params: { userId },
|
||||
});
|
||||
};
|
||||
|
||||
// 创建订单
|
||||
export const createOrder = (data: OrderCreateDTO) => {
|
||||
return http<{ orderId: number }>({
|
||||
url: "/order",
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
// 直接购买创建订单
|
||||
export const createOrderDirectly = (
|
||||
productId: number,
|
||||
skuId: number,
|
||||
data: OrderCreateDTO,
|
||||
) => {
|
||||
return http<{ orderId: number }>({
|
||||
url: `/order/${productId}?skuId=${skuId}`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +1,51 @@
|
||||
<script lang="ts" setup>
|
||||
import MainLayout from "@/layouts/MainLayout.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useUserStore } from "@/stores/UserStore";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { getProductList } from "@/apis/product";
|
||||
import type { ProductListItem } from "@/types/product";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 跳转登录/注册
|
||||
const goToLogin = () => router.push("/user/login");
|
||||
const goToRegister = () => router.push("/user/register");
|
||||
// 热门商品列表
|
||||
const hotProducts = ref<ProductListItem[]>([]);
|
||||
|
||||
// 获取热门商品
|
||||
const fetchHotProducts = async () => {
|
||||
try {
|
||||
const response = await getProductList({
|
||||
page: 1,
|
||||
size: 4,
|
||||
status: 1, // 只获取上架商品
|
||||
});
|
||||
|
||||
if (response.code === 200) {
|
||||
hotProducts.value = response.data.list;
|
||||
} else {
|
||||
ElMessage.error(response.message || "获取商品列表失败");
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error("获取商品列表失败");
|
||||
console.error("获取商品列表失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到商品详情页
|
||||
const goToProductDetail = (id: number) => {
|
||||
router.push(`/product/detail/${id}`);
|
||||
};
|
||||
|
||||
// 跳转到商品列表页
|
||||
const goToProductList = () => {
|
||||
router.push("/product/product");
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchHotProducts();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -23,20 +62,31 @@ const goToRegister = () => router.push("/user/register");
|
||||
<p class="text-xl md:text-2xl text-blue-100 mb-8">
|
||||
一站式购物平台,品质保障,售后无忧
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row justify-center gap-4">
|
||||
<div
|
||||
v-if="!userStore.userInfo"
|
||||
class="flex flex-col sm:flex-row justify-center gap-4"
|
||||
>
|
||||
<button
|
||||
@click="goToLogin"
|
||||
@click="$router.push('/user/login')"
|
||||
class="px-8 py-3 bg-white text-blue-700 font-semibold rounded-lg hover:bg-blue-50 transition-colors shadow-lg"
|
||||
>
|
||||
立即登录
|
||||
</button>
|
||||
<button
|
||||
@click="goToRegister"
|
||||
@click="$router.push('/user/register')"
|
||||
class="px-8 py-3 bg-transparent border-2 border-white text-white font-semibold rounded-lg hover:bg-white/10 transition-colors shadow-lg"
|
||||
>
|
||||
免费注册
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="flex flex-col sm:flex-row justify-center gap-4">
|
||||
<button
|
||||
@click="$router.push('/product/product')"
|
||||
class="px-8 py-3 bg-white text-blue-700 font-semibold rounded-lg hover:bg-blue-50 transition-colors shadow-lg"
|
||||
>
|
||||
开始购物
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 装饰元素 -->
|
||||
@@ -46,146 +96,135 @@ const goToRegister = () => router.push("/user/register");
|
||||
</section>
|
||||
|
||||
<!-- 特色板块 -->
|
||||
<section class="py-16 bg-slate-50">
|
||||
<section class="py-16 bg-slate-50 dark:bg-gray-800">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl font-bold text-gray-800">为什么选择我们</h2>
|
||||
<p class="mt-4 text-gray-600">用心服务,让购物更简单</p>
|
||||
<h2 class="text-3xl font-bold text-gray-800 dark:text-white">
|
||||
为什么选择我们
|
||||
</h2>
|
||||
<p class="mt-4 text-gray-600 dark:text-gray-300">
|
||||
用心服务,让购物更简单
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<!-- 特色1 -->
|
||||
<div
|
||||
class="bg-white p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
class="bg-white dark:bg-gray-700 p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<div
|
||||
class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
class="w-16 h-16 bg-blue-100 dark:bg-blue-900 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
>
|
||||
<i class="fa-solid fa-shield-halved text-2xl text-blue-600"></i>
|
||||
<i
|
||||
class="fa-solid fa-shield-halved text-2xl text-blue-600 dark:text-blue-400"
|
||||
></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-center mb-3">品质保障</h3>
|
||||
<p class="text-gray-600 text-center">
|
||||
<h3
|
||||
class="text-xl font-semibold text-center mb-3 text-gray-800 dark:text-white"
|
||||
>
|
||||
品质保障
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-300 text-center">
|
||||
所有商品均经过严格筛选,正品保障,假一赔十
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 特色2 -->
|
||||
<div
|
||||
class="bg-white p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
class="bg-white dark:bg-gray-700 p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<div
|
||||
class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
class="w-16 h-16 bg-green-100 dark:bg-green-900 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
>
|
||||
<i class="fa-solid fa-truck-fast text-2xl text-blue-600"></i>
|
||||
<i
|
||||
class="fa-solid fa-truck-fast text-2xl text-green-600 dark:text-green-400"
|
||||
></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-center mb-3">极速配送</h3>
|
||||
<p class="text-gray-600 text-center">
|
||||
全国覆盖的物流网络,最快24小时送达
|
||||
<h3
|
||||
class="text-xl font-semibold text-center mb-3 text-gray-800 dark:text-white"
|
||||
>
|
||||
快速配送
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-300 text-center">
|
||||
多仓发货,极速配送,准时送达
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 特色3 -->
|
||||
<div
|
||||
class="bg-white p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
class="bg-white dark:bg-gray-700 p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<div
|
||||
class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
class="w-16 h-16 bg-purple-100 dark:bg-purple-900 rounded-full flex items-center justify-center mb-6 mx-auto"
|
||||
>
|
||||
<i class="fa-solid fa-headset text-2xl text-blue-600"></i>
|
||||
<i
|
||||
class="fa-solid fa-headset text-2xl text-purple-600 dark:text-purple-400"
|
||||
></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-center mb-3">贴心售后</h3>
|
||||
<p class="text-gray-600 text-center">
|
||||
7天无理由退换,专业客服团队24小时在线
|
||||
<h3
|
||||
class="text-xl font-semibold text-center mb-3 text-gray-800 dark:text-white"
|
||||
>
|
||||
贴心服务
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-300 text-center">
|
||||
专业客服团队,7×24小时在线服务
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 热门商品推荐 (占位) -->
|
||||
<section class="py-16 bg-white">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl font-bold text-gray-800">热门商品</h2>
|
||||
<p class="mt-4 text-gray-600">为你精选热门好物</p>
|
||||
</div>
|
||||
<!-- 热门商品 -->
|
||||
<div class="mt-16">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl font-bold text-gray-800 dark:text-white">
|
||||
热门商品
|
||||
</h2>
|
||||
<p class="mt-4 text-gray-600 dark:text-gray-300">
|
||||
为您精选最受欢迎的商品
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-6">
|
||||
<!-- 商品卡片占位 -->
|
||||
<div
|
||||
class="bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow overflow-hidden"
|
||||
>
|
||||
<div class="bg-gray-200 h-48 flex items-center justify-center">
|
||||
<i class="fa-solid fa-box text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h4 class="font-medium text-gray-800 mb-2">商品名称</h4>
|
||||
<p class="text-red-600 font-bold">¥99.00</p>
|
||||
<button
|
||||
class="mt-4 w-full py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
加入购物车
|
||||
</button>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div
|
||||
v-for="product in hotProducts"
|
||||
:key="product.id"
|
||||
class="bg-white dark:bg-gray-700 rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow cursor-pointer"
|
||||
@click="goToProductDetail(product.id)"
|
||||
>
|
||||
<div class="aspect-square overflow-hidden">
|
||||
<img
|
||||
:src="product.mainImage || '/placeholder.jpg'"
|
||||
:alt="product.name"
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3
|
||||
class="font-medium text-gray-800 dark:text-white line-clamp-2 h-12"
|
||||
:title="product.name"
|
||||
>
|
||||
{{ product.name }}
|
||||
</h3>
|
||||
<div class="mt-2 flex items-center justify-between">
|
||||
<span class="text-red-600 dark:text-red-400 font-bold"
|
||||
>¥{{ product.price }}</span
|
||||
>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>销量: {{ product.sales }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 重复3个占位卡片 -->
|
||||
<div
|
||||
class="bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow overflow-hidden"
|
||||
>
|
||||
<div class="bg-gray-200 h-48 flex items-center justify-center">
|
||||
<i class="fa-solid fa-box text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h4 class="font-medium text-gray-800 mb-2">商品名称</h4>
|
||||
<p class="text-red-600 font-bold">¥199.00</p>
|
||||
<button
|
||||
class="mt-4 w-full py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
加入购物车
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow overflow-hidden"
|
||||
>
|
||||
<div class="bg-gray-200 h-48 flex items-center justify-center">
|
||||
<i class="fa-solid fa-box text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h4 class="font-medium text-gray-800 mb-2">商品名称</h4>
|
||||
<p class="text-red-600 font-bold">¥299.00</p>
|
||||
<button
|
||||
class="mt-4 w-full py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
加入购物车
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow overflow-hidden"
|
||||
>
|
||||
<div class="bg-gray-200 h-48 flex items-center justify-center">
|
||||
<i class="fa-solid fa-box text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h4 class="font-medium text-gray-800 mb-2">商品名称</h4>
|
||||
<p class="text-red-600 font-bold">¥399.00</p>
|
||||
<button
|
||||
class="mt-4 w-full py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
加入购物车
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 查看更多按钮 -->
|
||||
<div class="text-center mt-10">
|
||||
<button
|
||||
class="px-8 py-3 border border-blue-600 text-blue-600 rounded-lg hover:bg-blue-50 transition-colors"
|
||||
>
|
||||
查看更多商品
|
||||
</button>
|
||||
<!-- 查看更多按钮 -->
|
||||
<div class="text-center mt-10">
|
||||
<button
|
||||
@click="goToProductList"
|
||||
class="px-8 py-3 border border-blue-600 text-blue-600 dark:text-blue-400 dark:border-blue-400 rounded-lg hover:bg-blue-50 dark:hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
查看更多商品
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
{{ currentOrder.orderNo }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="下单时间">
|
||||
{{ formatDate(currentOrder.createTime) }}
|
||||
{{ formatDateTime(currentOrder.createTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单状态">
|
||||
{{ getOrderStatusText(currentOrder.status) }}
|
||||
@@ -152,7 +152,6 @@
|
||||
</el-dialog>
|
||||
</MainLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MainLayout from "@/layouts/MainLayout.vue";
|
||||
import { ref, onMounted } from "vue";
|
||||
@@ -233,10 +232,81 @@ const viewOrderDetail = async (order: OrderListItem) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString() + " " + date.toLocaleTimeString();
|
||||
// 格式化日期 (用于列表中的日期)
|
||||
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 "-";
|
||||
}
|
||||
};
|
||||
|
||||
// 获取订单状态文本
|
||||
|
||||
@@ -16,11 +16,19 @@ import {
|
||||
ElDivider,
|
||||
ElIcon,
|
||||
ElMessage,
|
||||
ElDialog,
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElRadioGroup,
|
||||
ElRadio,
|
||||
} from "element-plus";
|
||||
import { ArrowLeft, Plus, Minus } from "@element-plus/icons-vue";
|
||||
import { getProductDetail } from "@/apis/product";
|
||||
import type { ProductDetail, ProductSku } from "@/types/product";
|
||||
import { addCart } from "@/apis/shoppingcart.ts";
|
||||
import { createOrderDirectly } from "@/apis/order.ts";
|
||||
import type { OrderCreateDTO } from "@/types/order.ts";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -33,9 +41,31 @@ const loading = ref(true);
|
||||
const quantity = ref(1);
|
||||
const selectedSku = ref<ProductSku | null>(null);
|
||||
|
||||
//获取用户信息
|
||||
// 获取用户信息
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 订单对话框相关
|
||||
const orderDialogVisible = ref(false);
|
||||
const orderFormRef = ref();
|
||||
const orderForm = ref({
|
||||
receiverName: "",
|
||||
receiverPhone: "",
|
||||
receiverAddress: "",
|
||||
payType: 1, // 默认微信支付
|
||||
});
|
||||
|
||||
const orderFormRules = {
|
||||
receiverName: [
|
||||
{ required: true, message: "请输入收货人姓名", trigger: "blur" },
|
||||
],
|
||||
receiverPhone: [
|
||||
{ required: true, message: "请输入收货人手机号", trigger: "blur" },
|
||||
],
|
||||
receiverAddress: [
|
||||
{ required: true, message: "请输入收货地址", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
|
||||
// 获取商品详情
|
||||
const fetchProductDetail = async () => {
|
||||
const productId = route.params.id as string;
|
||||
@@ -134,14 +164,68 @@ const buyNow = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 这里应该是跳转到订单确认页面
|
||||
// 暂时用提示代替
|
||||
ElMessage.success("立即购买功能待实现");
|
||||
console.log("立即购买:", {
|
||||
productId: product.value.id,
|
||||
skuId: selectedSku.value.id,
|
||||
quantity: quantity.value,
|
||||
});
|
||||
// 检查用户是否已登录
|
||||
if (!userStore.userInfo) {
|
||||
ElMessage.warning("请先登录");
|
||||
router.push("/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示订单对话框
|
||||
orderDialogVisible.value = true;
|
||||
|
||||
// 初始化表单数据(如果用户有默认地址可以在这里填充)
|
||||
orderForm.value = {
|
||||
receiverName: "",
|
||||
receiverPhone: "",
|
||||
receiverAddress: "",
|
||||
payType: 1,
|
||||
};
|
||||
};
|
||||
|
||||
// 提交订单
|
||||
const submitOrder = async () => {
|
||||
if (!userStore.userInfo) {
|
||||
ElMessage.error("用户未登录");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!product.value || !selectedSku.value) {
|
||||
ElMessage.error("商品信息不完整");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await orderFormRef.value.validate();
|
||||
|
||||
const orderData: OrderCreateDTO = {
|
||||
userId: userStore.userInfo.id,
|
||||
receiverName: orderForm.value.receiverName,
|
||||
receiverPhone: orderForm.value.receiverPhone,
|
||||
receiverAddress: orderForm.value.receiverAddress,
|
||||
payType: orderForm.value.payType,
|
||||
};
|
||||
|
||||
// 使用直接购买接口
|
||||
const response = await createOrderDirectly(
|
||||
product.value.id,
|
||||
selectedSku.value.id,
|
||||
orderData,
|
||||
);
|
||||
|
||||
if (response.code === 200) {
|
||||
ElMessage.success("订单创建成功");
|
||||
orderDialogVisible.value = false;
|
||||
|
||||
// 跳转到订单页面
|
||||
router.push(`/order/content?orderId=${response.data.orderId}`);
|
||||
} else {
|
||||
ElMessage.error(response.message || "订单创建失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("创建订单失败:", error);
|
||||
ElMessage.error("创建订单失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 选择SKU
|
||||
@@ -318,6 +402,75 @@ onMounted(() => {
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单确认对话框 -->
|
||||
<el-dialog
|
||||
v-model="orderDialogVisible"
|
||||
title="确认订单信息"
|
||||
width="500px"
|
||||
:before-close="
|
||||
() => {
|
||||
orderDialogVisible = false;
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-form
|
||||
ref="orderFormRef"
|
||||
:model="orderForm"
|
||||
:rules="orderFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="收货人" prop="receiverName">
|
||||
<el-input
|
||||
v-model="orderForm.receiverName"
|
||||
placeholder="请输入收货人姓名"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="手机号" prop="receiverPhone">
|
||||
<el-input
|
||||
v-model="orderForm.receiverPhone"
|
||||
placeholder="请输入收货人手机号"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="收货地址" prop="receiverAddress">
|
||||
<el-input
|
||||
v-model="orderForm.receiverAddress"
|
||||
type="textarea"
|
||||
placeholder="请输入详细收货地址"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付方式" prop="payType">
|
||||
<el-radio-group v-model="orderForm.payType">
|
||||
<el-radio :label="1">微信支付</el-radio>
|
||||
<el-radio :label="2">支付宝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品信息">
|
||||
<div v-if="product && selectedSku" class="product-summary">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<div>{{ product.name }} - {{ selectedSku.skuName }}</div>
|
||||
<div>数量: {{ quantity }}</div>
|
||||
</div>
|
||||
<div class="font-bold">
|
||||
¥{{ (selectedSku.price * quantity).toFixed(2) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="orderDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitOrder">提交订单</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</MainLayout>
|
||||
</template>
|
||||
|
||||
@@ -380,4 +533,11 @@ onMounted(() => {
|
||||
.description-content {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.product-summary {
|
||||
padding: 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 4px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,7 +30,11 @@
|
||||
<span class="total-price"
|
||||
>合计:¥{{ totalPrice.toFixed(2) }}</span
|
||||
>
|
||||
<el-button type="primary" :disabled="selectedCount === 0">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="selectedCount === 0"
|
||||
@click="handleCheckout"
|
||||
>
|
||||
结算
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -111,6 +115,63 @@
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 结算对话框 -->
|
||||
<el-dialog
|
||||
v-model="checkoutDialogVisible"
|
||||
title="确认订单信息"
|
||||
width="500px"
|
||||
>
|
||||
<el-form
|
||||
ref="checkoutFormRef"
|
||||
:model="checkoutForm"
|
||||
:rules="checkoutRules"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="收货人" prop="receiverName">
|
||||
<el-input v-model="checkoutForm.receiverName" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="联系电话" prop="receiverPhone">
|
||||
<el-input v-model="checkoutForm.receiverPhone" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="收货地址" prop="receiverAddress">
|
||||
<el-input v-model="checkoutForm.receiverAddress" type="textarea" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付方式" prop="payType">
|
||||
<el-select
|
||||
v-model="checkoutForm.payType"
|
||||
placeholder="请选择支付方式"
|
||||
>
|
||||
<el-option label="微信支付" :value="1" />
|
||||
<el-option label="支付宝" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品总数">
|
||||
<span>{{ selectedCount }} 件</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单总额">
|
||||
<span class="total-price">¥{{ totalPrice.toFixed(2) }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="checkoutDialogVisible = false">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="submitOrder"
|
||||
:loading="isSubmitting"
|
||||
>
|
||||
提交订单
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</MainLayout>
|
||||
</template>
|
||||
|
||||
@@ -124,7 +185,9 @@ import {
|
||||
updateCartChecked,
|
||||
deleteCart,
|
||||
} from "@/apis/shoppingcart";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { createOrder } from "@/apis/order";
|
||||
import { ElMessage, ElMessageBox, FormInstance } from "element-plus";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
interface CartItem {
|
||||
id: number;
|
||||
@@ -141,8 +204,39 @@ interface CartItem {
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
const cartItems = ref<CartItem[]>([]);
|
||||
|
||||
// 结算相关
|
||||
const checkoutDialogVisible = ref(false);
|
||||
const checkoutFormRef = ref<FormInstance>();
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const checkoutForm = ref({
|
||||
receiverName: "",
|
||||
receiverPhone: "",
|
||||
receiverAddress: "",
|
||||
payType: 1, // 默认微信支付
|
||||
});
|
||||
|
||||
const checkoutRules = {
|
||||
receiverName: [
|
||||
{ required: true, message: "请输入收货人姓名", trigger: "blur" },
|
||||
],
|
||||
receiverPhone: [
|
||||
{ required: true, message: "请输入联系电话", trigger: "blur" },
|
||||
{
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: "请输入正确的手机号",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
receiverAddress: [
|
||||
{ required: true, message: "请输入收货地址", trigger: "blur" },
|
||||
],
|
||||
payType: [{ required: true, message: "请选择支付方式", trigger: "change" }],
|
||||
};
|
||||
|
||||
// 计算属性
|
||||
const selectAll = computed({
|
||||
get: () =>
|
||||
@@ -332,6 +426,75 @@ const handleClearSelected = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理结算
|
||||
const handleCheckout = () => {
|
||||
if (!userStore.userInfo) {
|
||||
ElMessage.warning("请先登录");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems.value.length === 0) {
|
||||
ElMessage.warning("请选择要结算的商品");
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化表单数据
|
||||
checkoutForm.value = {
|
||||
receiverName: "",
|
||||
receiverPhone: "",
|
||||
receiverAddress: "",
|
||||
payType: 1,
|
||||
};
|
||||
|
||||
checkoutDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 提交订单
|
||||
const submitOrder = async () => {
|
||||
if (!userStore.userInfo) {
|
||||
ElMessage.warning("请先登录");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkoutFormRef.value) return;
|
||||
|
||||
await checkoutFormRef.value.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
|
||||
isSubmitting.value = true;
|
||||
|
||||
try {
|
||||
const orderData = {
|
||||
userId: userStore.userInfo!.id,
|
||||
receiverName: checkoutForm.value.receiverName,
|
||||
receiverPhone: checkoutForm.value.receiverPhone,
|
||||
receiverAddress: checkoutForm.value.receiverAddress,
|
||||
payType: checkoutForm.value.payType,
|
||||
};
|
||||
|
||||
const res = await createOrder(orderData);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("订单创建成功");
|
||||
checkoutDialogVisible.value = false;
|
||||
|
||||
// 从购物车中移除已下单的商品
|
||||
cartItems.value = cartItems.value.filter((item) => item.checked !== 1);
|
||||
|
||||
// 跳转到订单页面
|
||||
router.push("/order/content");
|
||||
} else {
|
||||
ElMessage.error(res.message || "订单创建失败");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
ElMessage.error("订单创建失败");
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadCartItems();
|
||||
});
|
||||
@@ -404,4 +567,10 @@ onMounted(() => {
|
||||
.cart-items {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,3 +62,12 @@ export interface OrderPageResponse {
|
||||
page: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
// 创建订单DTO
|
||||
export interface OrderCreateDTO {
|
||||
userId: number;
|
||||
receiverName: string;
|
||||
receiverPhone: string;
|
||||
receiverAddress: string;
|
||||
payType?: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user