完善功能
This commit is contained in:
parent
a568ed012f
commit
608391a9af
|
@ -3,6 +3,7 @@
|
|||
import { useEffect, useState, Suspense } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import Image from "next/image";
|
||||
import PaymentModal from "@/components/PaymentModal";
|
||||
|
||||
function CheckoutContent() {
|
||||
const router = useRouter();
|
||||
|
@ -11,6 +12,7 @@ function CheckoutContent() {
|
|||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [address, setAddress] = useState(null);
|
||||
const [showPaymentModal, setShowPaymentModal] = useState(false);
|
||||
|
||||
// 获取地址的函数
|
||||
const fetchAddress = async (token) => {
|
||||
|
@ -129,6 +131,10 @@ function CheckoutContent() {
|
|||
)}&${params.toString()}`;
|
||||
};
|
||||
|
||||
const handleSubmitOrder = () => {
|
||||
setShowPaymentModal(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 pb-20">
|
||||
<div className="p-4">
|
||||
|
@ -215,10 +221,17 @@ function CheckoutContent() {
|
|||
<button
|
||||
className="w-full bg-red-500 text-white py-3 rounded-full"
|
||||
disabled={!address}
|
||||
onClick={handleSubmitOrder}
|
||||
>
|
||||
提交订单
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<PaymentModal
|
||||
isOpen={showPaymentModal}
|
||||
onClose={() => setShowPaymentModal(false)}
|
||||
amount={total}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
BIN
app/favicon.ico
BIN
app/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -10,5 +10,4 @@
|
|||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ export default function ProductDetail() {
|
|||
throw new Error("获取商品详情失败");
|
||||
}
|
||||
const data = await res.json();
|
||||
console.log(data);
|
||||
setProduct(data);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
|
|
|
@ -1,28 +1,16 @@
|
|||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: "宠物用品商城",
|
||||
description: "专业的宠物用品购物平台,为您的宠物提供优质商品",
|
||||
keywords: "宠物用品,宠物商城,宠物食品,宠物玩具",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en" data-theme="light">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<html lang="zh-CN">
|
||||
<body>
|
||||
{children}
|
||||
<Toaster
|
||||
toastOptions={{
|
||||
|
|
17
app/page.js
17
app/page.js
|
@ -1,5 +1,20 @@
|
|||
import Image from "next/image";
|
||||
"use client";
|
||||
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Home() {
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const url = searchParams.get("url");
|
||||
if (url) {
|
||||
router.replace(decodeURIComponent(url));
|
||||
} else if (!searchParams.toString()) {
|
||||
router.replace("/tab");
|
||||
}
|
||||
}, [searchParams, router]);
|
||||
|
||||
return <div></div>;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ export default function Profile() {
|
|||
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
|
||||
const [userData, setUserData] = React.useState(null);
|
||||
const [points, setPoints] = useState(0);
|
||||
const [currentImageIndex, setCurrentImageIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
// 检查本地存储中是否有用户信息
|
||||
|
@ -44,6 +45,14 @@ export default function Profile() {
|
|||
fetchUserPoints();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % 3);
|
||||
}, 3000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-gray-50">
|
||||
{/* 顶部用户信息区域 */}
|
||||
|
@ -51,7 +60,10 @@ export default function Profile() {
|
|||
{isLoggedIn && userData ? (
|
||||
<Link href="/user/profile" className="flex items-center gap-6">
|
||||
<Image
|
||||
src={userData.avatar || "https://imageplaceholder.net/150x150"}
|
||||
src={
|
||||
userData.avatar ||
|
||||
"https://s2.loli.net/2025/02/11/miDGcVpHvQUzNwr.jpg"
|
||||
}
|
||||
alt="avatar"
|
||||
width={80}
|
||||
height={80}
|
||||
|
@ -169,6 +181,45 @@ export default function Profile() {
|
|||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 宠物相册区域 */}
|
||||
<div className="p-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-bold">推荐商品</h3>
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-48 rounded-lg overflow-hidden">
|
||||
{[
|
||||
"https://s2.loli.net/2025/02/11/QCxNUXcDaPeRohE.png",
|
||||
"https://s2.loli.net/2025/02/11/FdX5giEp9DjGx4J.png",
|
||||
"https://s2.loli.net/2025/02/11/9zRiqkcn43BjHvp.png",
|
||||
].map((url, index) => (
|
||||
<Link href="/tab" key={index}>
|
||||
<Image
|
||||
src={url}
|
||||
alt={`商品 ${index + 1}`}
|
||||
fill
|
||||
className={`object-cover transition-opacity duration-500 ${
|
||||
index === currentImageIndex ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<div className="absolute bottom-2 left-0 right-0 flex justify-center gap-1">
|
||||
{[0, 1, 2].map((index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`w-1.5 h-1.5 rounded-full ${
|
||||
index === currentImageIndex
|
||||
? "bg-yellow-400"
|
||||
: "bg-white opacity-60"
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,10 @@ export default function UserProfile() {
|
|||
<div className="bg-yellow-400 p-8">
|
||||
<div className="flex items-center gap-6">
|
||||
<Image
|
||||
src={userData.avatar || "https://imageplaceholder.net/150x150"}
|
||||
src={
|
||||
userData.avatar ||
|
||||
"https://s2.loli.net/2025/02/11/miDGcVpHvQUzNwr.jpg"
|
||||
}
|
||||
alt="avatar"
|
||||
width={80}
|
||||
height={80}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import React from "react";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export default function PaymentModal({ isOpen, onClose, amount }) {
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handlePayment = () => {
|
||||
toast.error("微信支付接口调用失败");
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center">
|
||||
<div className="bg-white w-[90%] max-w-md rounded-lg">
|
||||
<div className="p-4 border-b">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-lg font-medium">支付方式</h3>
|
||||
<button onClick={onClose} className="text-gray-400">
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
<div className="text-center mb-4">
|
||||
<p>支付金额</p>
|
||||
<p className="text-xl font-bold">{amount.toFixed(2)}元</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg mb-4">
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
className="w-6 h-6 mr-3 text-[#07c160]"
|
||||
viewBox="0 0 28 28"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M9.442 15.027c-0.12 0.060-0.239 0.088-0.359 0.088-0.239 0-0.458-0.109-0.598-0.309l-0.050-0.070-2.157-4.633c-0.020-0.040-0.020-0.070-0.020-0.109 0-0.199 0.159-0.359 0.359-0.359 0.080 0 0.149 0.020 0.219 0.060l2.546 1.796c0.189 0.129 0.408 0.199 0.648 0.199 0.189 0 0.369-0.050 0.527-0.139l12.036-7.284c-2.267-2.616-5.821-4.314-9.843-4.314-7.005 0-12.69 5.247-12.69 11.721 0 3.514 1.796 6.668 4.593 8.743 0.219 0.159 0.359 0.408 0.359 0.697 0 0.080-0.020 0.159-0.040 0.229-0.129 0.478-0.349 1.264-0.359 1.294-0.020 0.070-0.040 0.149-0.040 0.219 0 0.199 0.159 0.359 0.359 0.359 0.070 0 0.139-0.020 0.199-0.070l2.367-1.365c0.189-0.109 0.408-0.169 0.627-0.169 0.109 0 0.229 0.020 0.329 0.050 1.614 0.478 3.347 0.737 5.148 0.737 7.005 0 12.69-5.247 12.69-11.721 0-1.944-0.548-3.769-1.505-5.375l-14.342 8.693z" />
|
||||
</svg>
|
||||
<span>微信支付</span>
|
||||
</div>
|
||||
<div className="w-6 h-6 rounded-full border-2 border-yellow-400 flex items-center justify-center">
|
||||
<div className="w-3 h-3 bg-yellow-400 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="w-full bg-yellow-400 text-white py-3 rounded-full"
|
||||
onClick={handlePayment}
|
||||
>
|
||||
确认支付
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "imageplaceholder.net",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
|
@ -1,4 +1,17 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
const nextConfig = {
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "imageplaceholder.net",
|
||||
},
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "s2.loli.net",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
Loading…
Reference in New Issue