From c372f5d89335320b2b263a6eab36711cf1c1f857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=96=B9=E6=88=90?= Date: Mon, 3 Nov 2025 21:45:23 +0800 Subject: [PATCH] first commit --- package-lock.json | 159 ++++- package.json | 1 + src/app/create/page.tsx | 137 ++++ src/app/create/perfume-group/page.tsx | 190 +++++ src/app/create/perfume-split/page.tsx | 289 ++++++++ src/app/distribution/orders/page.tsx | 221 ++++++ src/app/distribution/page.tsx | 749 +++++++++----------- src/app/globals.css | 56 ++ src/app/group/page.tsx | 439 +++++------- src/app/page.tsx | 8 +- src/app/product/[id]/page.tsx | 562 +++++++++++++++ src/app/subscription/page.tsx | 26 +- src/components/bottom-navigation.tsx | 24 +- src/components/product-card.tsx | 181 ++--- src/components/product-selector.tsx | 302 ++++++++ src/components/ui/toast.tsx | 12 +- src/components/ui/tooltip.tsx | 13 +- src/lib/{toast-utils.ts => toast-utils.tsx} | 6 +- tailwind.config.ts | 1 + 说明文档.md | 149 ++++ 20 files changed, 2730 insertions(+), 795 deletions(-) create mode 100644 src/app/create/page.tsx create mode 100644 src/app/create/perfume-group/page.tsx create mode 100644 src/app/create/perfume-split/page.tsx create mode 100644 src/app/distribution/orders/page.tsx create mode 100644 src/app/product/[id]/page.tsx create mode 100644 src/components/product-selector.tsx rename src/lib/{toast-utils.ts => toast-utils.tsx} (70%) create mode 100644 说明文档.md diff --git a/package-lock.json b/package-lock.json index 8b8b28f..92307ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "@reactuses/core": "^6.0.5", "@tanstack/react-query": "^5.82.0", "@tanstack/react-table": "^8.21.3", + "autoprefixer": "^10.4.21", "axios": "^1.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -5657,6 +5658,42 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5750,6 +5787,14 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", + "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -5787,6 +5832,38 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -5938,9 +6015,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001739", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz", - "integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==", + "version": "1.0.30001750", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", + "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", "funding": [ { "type": "opencollective", @@ -5954,8 +6031,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/ccount": { "version": "2.0.1", @@ -6756,6 +6832,11 @@ "fast-check": "^3.23.1" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.234", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.234.tgz", + "integrity": "sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==" + }, "node_modules/embla-carousel": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", @@ -7144,6 +7225,14 @@ "@esbuild/win32-x64": "0.25.9" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-carriage": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/escape-carriage/-/escape-carriage-1.3.1.tgz", @@ -7904,6 +7993,18 @@ "node": ">=0.4.x" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/framer-motion": { "version": "12.23.24", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", @@ -10917,6 +11018,11 @@ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", "license": "MIT" }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==" + }, "node_modules/nodemon": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", @@ -10979,6 +11085,14 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nypm": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", @@ -11360,7 +11474,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -11385,6 +11498,11 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/preact": { "version": "10.27.1", "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.1.tgz", @@ -13397,6 +13515,35 @@ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index b4ab34f..9be9c9f 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@reactuses/core": "^6.0.5", "@tanstack/react-query": "^5.82.0", "@tanstack/react-table": "^8.21.3", + "autoprefixer": "^10.4.21", "axios": "^1.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/app/create/page.tsx b/src/app/create/page.tsx new file mode 100644 index 0000000..0d1d6d3 --- /dev/null +++ b/src/app/create/page.tsx @@ -0,0 +1,137 @@ +'use client' + +import { useState } from 'react' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { + Plus, + ArrowRight, + Droplets, + Package, + Sparkles +} from 'lucide-react' +import BottomNavigation from '@/components/bottom-navigation' +import { FadeIn, SlideIn, StaggerContainer, StaggerItem } from '@/components/animations' + +export default function CreatePage() { + const [selectedType, setSelectedType] = useState(null) + + const createOptions = [ + { + id: 'perfume-group', + title: '香水团购', + description: '发起香水团购活动,人数越多折扣越大', + icon: Droplets, + color: 'bg-pink-500', + gradient: 'from-pink-500 to-rose-600', + features: ['阶梯折扣', '正品保证', '快速成团'] + }, + { + id: 'perfume-split', + title: '香水分装', + description: '发起香水分装服务,小容量更实惠', + icon: Package, + color: 'bg-indigo-500', + gradient: 'from-indigo-500 to-purple-600', + features: ['小容量', '超值价格', '多款选择'] + } + ] + + const handleCreateClick = (type: string) => { + setSelectedType(type) + // 根据类型跳转到不同的创建页面 + if (type === 'perfume-group') { + // 跳转到香水团购创建页面 + window.location.href = '/create/perfume-group' + } else if (type === 'perfume-split') { + // 跳转到香水分装创建页面 + window.location.href = '/create/perfume-split' + } else { + console.log(`创建 ${type}`) + } + } + + return ( +
+ {/* 优化后的顶部标题 */} + +
+
+ +
+ +
+

+ 创建内容 +

+

选择您想要创建的内容类型

+
+
+
+
+
+
+ + {/* 创建选项 */} +
+ + {createOptions.map((option, index) => { + const IconComponent = option.icon + return ( + +
setSelectedType(option.id)} + > +
+ {/* 优化后的图标 */} +
+ +
+ + {/* 内容 */} +
+

{option.title}

+

{option.description}

+ + {/* 特性标签 */} +
+ {option.features.map((feature, index) => ( + + {feature} + + ))} +
+ + {/* 创建按钮 */} + +
+
+
+
+ ) + })} +
+
+ + {/* 底部导航 */} + +
+ ) +} \ No newline at end of file diff --git a/src/app/create/perfume-group/page.tsx b/src/app/create/perfume-group/page.tsx new file mode 100644 index 0000000..f459943 --- /dev/null +++ b/src/app/create/perfume-group/page.tsx @@ -0,0 +1,190 @@ +'use client' + +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { ProductSelector } from '@/components/product-selector' +import { + ArrowLeft, + Droplets, + Users, + Clock, + Calendar +} from 'lucide-react' + +interface Product { + id: string + name: string + brand: string + price: number + originalPrice: number + image: string + category: string + tags: string[] + rating: number + reviews: number + stock: number + description: string + volume?: string +} + +export default function CreatePerfumeGroupPage() { + const router = useRouter() + const [selectedProduct, setSelectedProduct] = useState(null) + const [formData, setFormData] = useState({ + duration: '7', // 团购持续天数 + minParticipants: '3', + maxParticipants: '50' + }) + + const handleInputChange = (field: string, value: string) => { + setFormData(prev => ({ ...prev, [field]: value })) + } + + const handleSubmit = () => { + // 这里处理表单提交逻辑 + console.log('创建香水团购:', { selectedProduct, formData }) + // 可以跳转到团购详情页或返回列表页 + router.push('/create') + } + + return ( +
+ {/* 头部 */} +
+
+
+
+ +
+

创建香水团购

+

选择香水,设置团购参数

+
+
+
+
+ + {/* 表单内容 */} +
+ {/* 商品选择 */} + + + + + 选择香水 + + + + + + + + {/* 团购设置 */} + + + + + 团购设置 + + + +
+
+ + handleInputChange('duration', e.target.value)} + className="mt-1" + /> +
+
+ + handleInputChange('minParticipants', e.target.value)} + className="mt-1" + /> +
+
+ + handleInputChange('maxParticipants', e.target.value)} + className="mt-1" + /> +
+
+
+
+ + {/* 商品预览 */} + {selectedProduct && ( + + + + + 团购预览 + + + +
+
+
+ +
+
+

{selectedProduct.name}

+

{selectedProduct.brand}

+
+
¥{selectedProduct.price}
+
+ {formData.minParticipants}-{formData.maxParticipants}人团购 +
+
+
+
+ +
+
+ 团购时长 + {formData.duration}天 +
+
+
+
+
+ )} + + {/* 创建按钮 */} +
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/create/perfume-split/page.tsx b/src/app/create/perfume-split/page.tsx new file mode 100644 index 0000000..c5fc86c --- /dev/null +++ b/src/app/create/perfume-split/page.tsx @@ -0,0 +1,289 @@ +'use client' + +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { ProductSelector } from '@/components/product-selector' +import { + ArrowLeft, + Package, + Droplets, + Plus, + Minus, + Beaker, + Clock +} from 'lucide-react' + +interface SplitOption { + volume: number // ml + price: number + quantity: number // 可分装数量 +} + +interface Product { + id: string + name: string + brand: string + price: number + originalPrice: number + image: string + category: string + tags: string[] + rating: number + reviews: number + stock: number + description: string + volume?: string +} + +export default function CreatePerfumeSplitPage() { + const router = useRouter() + const [selectedProduct, setSelectedProduct] = useState(null) + const [formData, setFormData] = useState({ + originalVolume: '100', // 原装容量 ml + duration: '14', // 分装活动持续天数 + }) + + const [splitOptions, setSplitOptions] = useState([ + { volume: 5, price: 0, quantity: 10 }, + { volume: 10, price: 0, quantity: 8 }, + { volume: 20, price: 0, quantity: 4 } + ]) + + const handleInputChange = (field: string, value: string) => { + setFormData(prev => ({ ...prev, [field]: value })) + } + + const addSplitOption = () => { + const lastOption = splitOptions[splitOptions.length - 1] + setSplitOptions(prev => [...prev, { + volume: lastOption.volume + 5, + price: 0, + quantity: 1 + }]) + } + + const removeSplitOption = (index: number) => { + if (splitOptions.length > 1) { + setSplitOptions(prev => prev.filter((_, i) => i !== index)) + } + } + + const updateSplitOption = (index: number, field: keyof SplitOption, value: number) => { + setSplitOptions(prev => prev.map((option, i) => + i === index ? { ...option, [field]: value } : option + )) + } + + const handleSubmit = () => { + console.log('创建香水分装:', { selectedProduct, formData, splitOptions }) + router.push('/create') + } + + return ( +
+ {/* 头部 */} +
+
+
+
+ +
+

创建香水分装

+

选择香水,设置分装规格

+
+
+
+
+ + {/* 表单内容 */} +
+ {/* 商品选择 */} + + + + + 选择香水 + + + + + + + + {/* 分装设置 */} + + + + + 分装设置 + + + +
+
+ + handleInputChange('originalVolume', e.target.value)} + className="mt-1" + /> +
+
+ + handleInputChange('duration', e.target.value)} + className="mt-1" + /> +
+
+
+
+ + {/* 分装规格 */} + + +
+ + + 分装规格 + + +
+
+ + {splitOptions.map((option, index) => ( +
+
+
+ + updateSplitOption(index, 'volume', parseInt(e.target.value) || 0)} + className="mt-1 h-8" + /> +
+
+ + updateSplitOption(index, 'price', parseInt(e.target.value) || 0)} + className="mt-1 h-8" + /> +
+
+ + updateSplitOption(index, 'quantity', parseInt(e.target.value) || 0)} + className="mt-1 h-8" + /> +
+
+ + {splitOptions.length > 1 && ( + + )} +
+ ))} +
+
+ + {/* 分装预览 */} + {selectedProduct && splitOptions.some(opt => opt.price > 0) && ( + + + + + 分装预览 + + + +
+
+
+ +
+
+

{selectedProduct.name}

+

{selectedProduct.brand}

+
+ 原装 {formData.originalVolume}ml · 分装 {formData.duration}天 +
+
+
+ +
+ {splitOptions.filter(opt => opt.price > 0).map((option, index) => ( +
+
+
+ +
+
+
{option.volume}ml
+
限量 {option.quantity} 份
+
+
+
+
¥{option.price}
+
¥{(option.price / option.volume).toFixed(1)}/ml
+
+
+ ))} +
+
+
+
+ )} + + {/* 创建按钮 */} +
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/distribution/orders/page.tsx b/src/app/distribution/orders/page.tsx new file mode 100644 index 0000000..4a01fb5 --- /dev/null +++ b/src/app/distribution/orders/page.tsx @@ -0,0 +1,221 @@ +'use client' + +import { useState, useEffect } from 'react' +import { useRouter, useSearchParams } from 'next/navigation' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { ArrowLeft, ShoppingBag, Calendar, DollarSign, TrendingUp, Package } from 'lucide-react' + +export default function MemberOrdersPage() { + const router = useRouter() + const searchParams = useSearchParams() + const memberId = searchParams.get('memberId') + const memberName = searchParams.get('memberName') + + // 模拟团队成员订单数据 + const [memberOrders, setMemberOrders] = useState([]) + const [loading, setLoading] = useState(true) + + useEffect(() => { + // 模拟获取订单数据 + const mockOrders = [ + { + id: 'ORD001', + productName: '高端护肤套装', + amount: 299, + commission: 29.9, + time: '2024-01-15 14:30', + status: 'completed' + }, + { + id: 'ORD002', + productName: '智能手表', + amount: 1299, + commission: 129.9, + time: '2024-01-14 10:20', + status: 'completed' + }, + { + id: 'ORD003', + productName: '运动鞋', + amount: 599, + commission: 59.9, + time: '2024-01-13 16:45', + status: 'pending' + }, + { + id: 'ORD004', + productName: '蓝牙耳机', + amount: 199, + commission: 19.9, + time: '2024-01-12 09:15', + status: 'completed' + }, + { + id: 'ORD005', + productName: '咖啡机', + amount: 899, + commission: 89.9, + time: '2024-01-11 20:30', + status: 'completed' + } + ] + + setTimeout(() => { + setMemberOrders(mockOrders) + setLoading(false) + }, 500) + }, [memberId]) + + const totalCommission = memberOrders.reduce((sum, order) => sum + order.commission, 0) + const completedOrders = memberOrders.filter(order => order.status === 'completed').length + const totalAmount = memberOrders.reduce((sum, order) => sum + order.amount, 0) + + if (loading) { + return ( +
+
+
+

加载中...

+
+
+ ) + } + + return ( +
+ {/* 优化后的头部区域 - 与主页面风格一致 */} +
+ {/* 背景装饰 */} +
+
+
+ +
+ {/* 导航和用户信息 */} +
+ +
+ + + + {memberName?.charAt(0)} + + +
+

{memberName}

+

共 {memberOrders.length} 笔订单

+
+
+
+ + {/* 统计概览卡片 */} +
+
+
+
+ +
+

总佣金

+

¥{totalCommission.toFixed(1)}

+
+
+
+ +
+

已完成

+

{completedOrders}

+
+
+
+ +
+

总金额

+

¥{(totalAmount/1000).toFixed(1)}k

+
+
+
+
+
+ +
+ {/* 订单列表卡片 */} + + + + + 订单明细 + + + +
+ {memberOrders.map((order, index) => ( +
+
+
+ + {order.status === 'completed' ? '已完成' : '待确认'} + + #{order.id} +
+
+ +¥{order.commission} +

佣金

+
+
+ +

{order.productName}

+ +
+
+ + 订单金额: ¥{order.amount} + +
+
+ + {order.time} +
+
+
+ ))} +
+
+
+ + {/* 空状态优化 */} + {memberOrders.length === 0 && ( + + +
+ +
+

暂无订单记录

+

该成员还没有产生任何订单

+
+
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/src/app/distribution/page.tsx b/src/app/distribution/page.tsx index 9adf036..ab6db05 100644 --- a/src/app/distribution/page.tsx +++ b/src/app/distribution/page.tsx @@ -1,13 +1,14 @@ 'use client' import { useState } from 'react' +import { useRouter } from 'next/navigation' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Separator } from '@/components/ui/separator' +import BottomNavigation from '@/components/bottom-navigation' import { Users, TrendingUp, @@ -20,17 +21,22 @@ import { MessageCircle, Download, Star, - Zap, ArrowUpRight, Calendar, ShoppingBag, - Share2, - ShoppingCart, - Home + Eye, + Wallet, + UserPlus, + BarChart3, + Sparkles, + Info, + Clock, + CreditCard } from 'lucide-react' export default function DistributionPage() { const [activeTab, setActiveTab] = useState('overview') + const router = useRouter() // 模拟数据 const stats = { @@ -41,7 +47,9 @@ export default function DistributionPage() { level: '品鉴分销员', nextLevelProgress: 65, monthlyOrders: 45, - monthlyRevenue: 8950.00 + monthlyRevenue: 8950.00, + weeklyGrowth: 12.5, + conversionRate: 8.3 } const teamMembers = [ @@ -50,36 +58,45 @@ export default function DistributionPage() { name: '小美', avatar: '小', level: '探索分销员', - joinTime: '2025-03-15', totalOrders: 15, commission: 234.50, - status: 'active', - monthlyOrders: 8, - avatarUrl: '/api/placeholder/40/40' + avatarUrl: 'https://picsum.photos/40/40?random=30', + growth: '+15%', + orders: [ + { id: 'ORD001', productName: '经典玫瑰香水30ml', amount: 199.00, commission: 19.90, time: '2025-04-01 10:30', status: 'completed' }, + { id: 'ORD002', productName: '薰衣草精油礼盒', amount: 299.00, commission: 29.90, time: '2025-04-02 14:20', status: 'completed' }, + { id: 'ORD003', productName: '茉莉花香水50ml', amount: 399.00, commission: 39.90, time: '2025-04-03 16:45', status: 'pending' } + ] }, { id: '2', name: '香香公主', avatar: '香', level: '品鉴分销员', - joinTime: '2025-03-10', totalOrders: 28, commission: 456.80, - status: 'active', - monthlyOrders: 12, - avatarUrl: '/api/placeholder/40/40' + avatarUrl: 'https://picsum.photos/40/40?random=31', + growth: '+23%', + orders: [ + { id: 'ORD004', productName: '白茶香水礼盒装', amount: 599.00, commission: 59.90, time: '2025-04-01 09:15', status: 'completed' }, + { id: 'ORD005', productName: '柑橘调香水30ml', amount: 259.00, commission: 25.90, time: '2025-04-02 11:30', status: 'completed' }, + { id: 'ORD006', productName: '木质调香水50ml', amount: 459.00, commission: 45.90, time: '2025-04-03 13:20', status: 'completed' } + ] }, { id: '3', name: '花仙子', avatar: '花', level: '调香分销员', - joinTime: '2025-03-01', totalOrders: 42, commission: 789.20, - status: 'active', - monthlyOrders: 18, - avatarUrl: '/api/placeholder/40/40' + avatarUrl: 'https://picsum.photos/40/40?random=32', + growth: '+8%', + orders: [ + { id: 'ORD007', productName: '限量版香水套装', amount: 899.00, commission: 89.90, time: '2025-04-01 15:45', status: 'completed' }, + { id: 'ORD008', productName: '花香调香水30ml', amount: 329.00, commission: 32.90, time: '2025-04-02 17:10', status: 'completed' }, + { id: 'ORD009', productName: '东方调香水礼盒', amount: 699.00, commission: 69.90, time: '2025-04-03 19:30', status: 'pending' } + ] } ] @@ -91,7 +108,6 @@ export default function DistributionPage() { productName: '经典玫瑰香水30ml', type: 'direct', amount: 19.90, - rate: 0.10, status: 'settled', time: '2025-04-02 14:30', orderAmount: 199.00 @@ -103,96 +119,31 @@ export default function DistributionPage() { productName: '薰衣草精油礼盒', type: 'indirect', amount: 14.95, - rate: 0.05, status: 'pending', time: '2025-04-02 13:15', orderAmount: 299.00 - }, - { - id: '3', - orderNo: 'ORD20250402003', - customerName: '王小姐', - productName: '小样体验包', - type: 'direct', - amount: 0.10, - rate: 0.10, - status: 'settled', - time: '2025-04-02 10:45', - orderAmount: 1.00 } ] - const materials = [ - { - id: '1', - title: '宝妈话术模板', - content: '自用省50,分享赚100!香氛好物,自用省钱,分享赚钱', - category: '话术', - usage: 1250, - rating: 4.8, - image: '/api/placeholder/200/150' - }, - { - id: '2', - title: '产品种草文案', - content: '这款玫瑰香水太绝了!留香一整天,闺蜜都问我要链接', - category: '文案', - usage: 890, - rating: 4.6, - image: '/api/placeholder/200/150' - }, - { - id: '3', - title: '拼团分享海报', - content: '精美海报模板,一键生成分享图', - category: '海报', - usage: 2100, - rating: 4.9, - image: '/api/placeholder/200/150' - }, - { - id: '4', - title: '产品介绍视频', - content: '专业拍摄的产品展示视频,适合短视频平台', - category: '视频', - usage: 650, - rating: 4.7, - image: '/api/placeholder/200/150' - } - ] - - const tasks = [ + const achievements = [ { id: '1', title: '邀请3位好友', description: '成功邀请3位好友注册并完成首单', - reward: '解锁高佣金商品推广权', progress: 2, target: 3, - status: 'in_progress', - icon: Users, + reward: '解锁高佣金商品推广权', + icon: UserPlus, color: 'blue' }, { id: '2', - title: '月销10单', - description: '本月完成10笔有效订单', - reward: '获得限量香氛礼品', - progress: 7, - target: 10, - status: 'in_progress', - icon: ShoppingBag, - color: 'green' - }, - { - id: '3', - title: '团队建设', - description: '团队人数达到20人', + title: '月销售额达到5000元', + description: '单月团队销售额突破5000元', + progress: 4200, + target: 5000, reward: '晋升为调香分销员', - progress: 23, - target: 20, - status: 'completed', - icon: Crown, + icon: Target, color: 'purple' } ] @@ -209,361 +160,335 @@ export default function DistributionPage() { } } - const copyMaterial = async (content: string) => { - try { - await navigator.clipboard.writeText(content) - alert('内容已复制到剪贴板') - } catch (error) { - console.error('复制失败') - } - } - return ( -
- {/* Header */} -
-
-
-
-
- +
+ {/* 优化后的紧凑顶部区域 */} +
+ {/* 背景装饰 */} +
+
+
+ +
+ {/* 紧凑的用户信息区域 */} +
+
+
+
-

分销中心

-

{stats.level} · 团队 {stats.teamSize} 人

+

分销中心

+
+ + {stats.level} + + 团队 {stats.teamSize} 人 +
-
-

累计佣金

-

¥{stats.totalCommission.toFixed(2)}

- + +
+ + {/* 累计佣金展示 */} +
+

累计佣金

+

¥{stats.totalCommission.toFixed(2)}

+ + {/* 等级进度条 */} +
+
+ 升级进度 + {stats.nextLevelProgress}% +
+
-
- {/* 统计卡片 */} -
- - -
-
-

今日佣金

-

¥{stats.todayCommission.toFixed(2)}

-

+12.5% 较昨日

-
-
- +
+ {/* 核心数据概览卡片 - 合并设计 */} + + + + + 数据概览 + + + + {/* 主要指标网格 */} +
+
+
+ + 今日佣金
+

¥{stats.todayCommission.toFixed(0)}

+ + +{stats.weeklyGrowth}% +
- - - - - -
-
-

团队人数

-

{stats.teamSize}

-

活跃 {stats.activeMembers} 人

-
-
- + +
+
+ + 团队人数
+

{stats.teamSize}

+ + {stats.activeMembers}活跃 +
- - - - - -
-
-

本月订单

-

{stats.monthlyOrders}

-

¥{stats.monthlyRevenue.toFixed(0)}

-
-
- -
-
-
-
- - - -
-
-

等级进度

-

{stats.nextLevelProgress}%

- -
-
- -
-
-
-
-
- - - - 数据概览 - 团队管理 - 素材库 - 任务体系 - - - {/* 数据概览 */} - -
- {/* 佣金明细 */} - - -
- 佣金明细 - -
-
- -
- {commissions.map((commission) => ( -
-
-
- {commission.customerName} - - {commission.type === 'direct' ? '直推' : '间推'} - - - {commission.status === 'settled' ? '已结算' : '待结算'} - -
-

{commission.productName}

-

{commission.orderNo} · {commission.time}

-
-
-

¥{commission.amount.toFixed(2)}

-

{(commission.rate * 100).toFixed(0)}%

-

订单¥{commission.orderAmount}

-
-
- ))} -
-
-
- - {/* 业绩趋势 */} - - - 业绩趋势 - - -
-
-
-

本周佣金

-

¥568.00

-

+8.2%

-
-
-

新增成员

-

5人

-

+25%

-
-
- -
-

业绩趋势图表

-
-
-
-
-
- - {/* 团队管理 */} - - - -
- 团队成员 ({teamMembers.length}) - + + {/* 次要指标 */} +
+
+
+
+ +
+
+

本月订单

+

{stats.monthlyOrders}

+
+
+ +
+
+
+ +
+
+

月度营收

+

¥{(stats.monthlyRevenue/1000).toFixed(1)}K

+
+
+
+
+ + {/* 转化率指标 */} +
+
+
+
+ +
+ 转化率 +
+
+

{stats.conversionRate}%

+

行业领先

+
+
+
+ + + + {/* 标签页内容 */} + + + 概览 + 团队 + 收益 + + + + {/* 成就系统 - 优化布局 */} + + + + + 成就进度 + - -
- {teamMembers.map((member) => ( -
-
- - - {member.avatar} - -
-

{member.name}

-

{member.level}

+ + {achievements.map((achievement) => { + const IconComponent = achievement.icon + const progressPercentage = (achievement.progress / achievement.target) * 100 + + return ( +
+
+
+ +
+
+

{achievement.title}

+

{achievement.description}

+
+
+ + {achievement.progress} / {achievement.target} + + + {Math.round(progressPercentage)}% + +
+ +
+
+ + {achievement.reward} +
-
-

总订单

-

{member.totalOrders}

-
-
-

本月订单

-

{member.monthlyOrders}

-
-
-

佣金

-

¥{member.commission.toFixed(2)}

-
-
-

加入时间

-

{member.joinTime}

-
-
-
- {member.status === 'active' ? '活跃' : '离线'} -
-
- ))} -
+ + ) + })} - - {/* 素材库 */} - -
- {materials.map((material) => ( - -
- {material.title} -
- -
-

{material.title}

- {material.category} -
-

{material.content}

-
-
- - {material.rating} + + {/* 团队标签页 - 优化布局 */} + + + + 团队成员 + + {teamMembers.length} 人 + + + +
    + {teamMembers.map((member) => ( +
  • + + + + {member.avatar} + + +
    +
    +

    {member.name}

    + + {member.level} + +
    +
    + 订单 {member.totalOrders} + 佣金 ¥{member.commission} + + {member.growth} + +
    - 使用 {material.usage} 次 -
-
- - -
- - - ))} -
+ + ))} + +
+
- - {/* 任务体系 */} - -
- {tasks.map((task) => ( - - -
-
- {task.status === 'completed' ? ( - - ) : ( - - )} -
-
-

{task.title}

-

{task.description}

-
- - {task.status === 'completed' ? '已完成' : '进行中'} - + + {/* 收益标签页 - 优化布局 */} + + {/* 佣金结算说明 */} + + + + + 佣金结算说明 + + + +
+ {/* 结算周期 */} +
+ +
+

结算周期

+

每月1日结算上月佣金,T+7个工作日到账

- -
-
- 进度 - {task.progress}/{task.target} -
- +
+ + {/* 佣金比例 */} +
+ +
+

佣金比例

+

直推订单10%,团队订单5%,高级分销员享受更高比例

- -
-
- - 奖励:{task.reward} -
+
+ + {/* 提现规则 */} +
+ +
+

提现规则

+

最低提现金额100元,每月可提现2次,手续费2元/笔

- - - ))} -
+
+ + {/* 冻结说明 */} +
+ +
+

冻结说明

+

订单完成后佣金冻结15天,确保售后服务质量

+
+
+
+ + + + + + 佣金明细 + + +
    + {commissions.map((commission) => ( +
  • +
    +
    + + {commission.type === 'direct' ? '直推' : '团队'} + + {commission.productName} +
    + +¥{commission.amount} +
    +
    + 来自: {commission.customerName} + {commission.time} +
    +
  • + ))} +
+
+
- {/* 小程序风格底部导航栏 */} - + {/* 底部导航 */} +
) } \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index 550855a..2c226d9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,9 +1,65 @@ @import "tailwindcss"; @layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96%; + --secondary-foreground: 222.2 84% 4.9%; + --muted: 210 40% 96%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96%; + --accent-foreground: 222.2 84% 4.9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } + * { border-color: hsl(var(--border)); } + body { background-color: hsl(var(--background)); color: hsl(var(--foreground)); diff --git a/src/app/group/page.tsx b/src/app/group/page.tsx index 8ba11f3..9040916 100644 --- a/src/app/group/page.tsx +++ b/src/app/group/page.tsx @@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Avatar, AvatarFallback } from '@/components/ui/avatar' +import BottomNavigation from '@/components/bottom-navigation' import { Users, Clock, @@ -31,7 +32,7 @@ export default function GroupListPage() { id: '1', title: '3人拼团 玫瑰香水盲盒', description: '经典玫瑰香调,优雅女神范', - image: '/api/placeholder/300/200', + image: 'https://picsum.photos/300/200?random=20', originalPrice: 199, groupPrice: 139, groupSize: 3, @@ -48,312 +49,264 @@ export default function GroupListPage() { }, { id: '2', - title: '5人拼团 薰衣草精油套装', - description: '纯天然薰衣草精油,助眠神器', - image: '/api/placeholder/300/200', + title: '5人拼团 薰衣草助眠套装', + description: '天然薰衣草精油,助眠好伴侣', + image: 'https://picsum.photos/300/200?random=21', originalPrice: 299, groupPrice: 199, groupSize: 5, - currentMembers: 3, - timeLeft: '1天5小时', + currentMembers: 4, + timeLeft: '5小时12分', status: 'active', host: { - name: '精油达人', - avatar: '精', + name: '花仙子', + avatar: '花', rating: 4.8 }, - category: '精油', - tags: ['新品'] + category: '护理', + tags: ['新品', '热销'] }, { id: '3', - title: '2人拼团 茉莉香氛蜡烛', - description: '手工制作,天然大豆蜡', - image: '/api/placeholder/300/200', + title: '2人拼团 柠檬清香车载香薰', + description: '清新柠檬香,净化车内空气', + image: 'https://picsum.photos/300/200?random=22', originalPrice: 89, groupPrice: 59, groupSize: 2, currentMembers: 1, - timeLeft: '6小时12分', + timeLeft: '1天8小时', status: 'active', host: { - name: '蜡烛工坊', - avatar: '蜡', + name: '清风徐来', + avatar: '清', rating: 4.7 }, - category: '香薰', - tags: ['手工', '天然'] + category: '车载', + tags: ['清新'] }, { id: '4', - title: '4人拼团 小样体验包', - description: '10款热门香水小样,超值体验', - image: '/api/placeholder/300/200', - originalPrice: 99, - groupPrice: 29, + title: '4人拼团 茉莉花茶香氛礼盒', + description: '优雅茉莉花香,送礼首选', + image: 'https://picsum.photos/300/200?random=23', + originalPrice: 399, + groupPrice: 299, groupSize: 4, - currentMembers: 4, - timeLeft: '已成团', - status: 'success', + currentMembers: 3, + timeLeft: '3小时45分', + status: 'active', host: { - name: '小样控', - avatar: '样', - rating: 4.9 + name: '茉莉小姐', + avatar: '茉', + rating: 5.0 }, - category: '小样', - tags: ['超值', '体验'] + category: '礼盒', + tags: ['礼品', '高端'] }, { id: '5', - title: '3人拼团 沉香木手串', - description: '天然沉香木,淡雅香韵', - image: '/api/placeholder/300/200', - originalPrice: 399, - groupPrice: 299, - groupSize: 3, - currentMembers: 1, - timeLeft: '3天2小时', - status: 'active', + title: '6人拼团 混合香调体验装', + description: '多种香调小样,发现你的专属香味', + image: 'https://picsum.photos/300/200?random=24', + originalPrice: 159, + groupPrice: 99, + groupSize: 6, + currentMembers: 5, + timeLeft: '30分钟', + status: 'urgent', host: { - name: '香木匠人', - avatar: '木', - rating: 4.6 + name: '香调师', + avatar: '调', + rating: 4.9 }, - category: '香木', - tags: ['天然', '收藏'] + category: '体验', + tags: ['体验装', '紧急'] } ] const handleLike = (groupId: string) => { - setLikedGroups(prev => - prev.includes(groupId) + setLikedGroups(prev => + prev.includes(groupId) ? prev.filter(id => id !== groupId) : [...prev, groupId] ) } - const getFilteredGroups = () => { - switch (activeTab) { + const getProgressPercentage = (current: number, total: number) => { + return (current / total) * 100 + } + + const getStatusColor = (status: string) => { + switch (status) { + case 'urgent': + return 'text-red-600 bg-red-50' case 'active': - return groupBuys.filter(group => group.status === 'active') - case 'success': - return groupBuys.filter(group => group.status === 'success') - case 'hot': - return groupBuys.filter(group => group.tags.includes('热门')) + return 'text-green-600 bg-green-50' default: - return groupBuys + return 'text-gray-600 bg-gray-50' } } - const getStatusBadge = (group: any) => { - if (group.status === 'success') { - return 已成团 - } - if (group.currentMembers === group.groupSize - 1) { - return 差1人 - } - return 拼团中 - } + const filteredGroups = groupBuys.filter(group => { + if (activeTab === 'all') return true + if (activeTab === 'urgent') return group.status === 'urgent' + if (activeTab === 'new') return group.tags.includes('新品') + return true + }) return ( -
- {/* 小程序风格顶部导航 */} -
-
-
-

拼团专区

-
-
- - -
-
+
+ {/* 顶部导航 */} +
+
+
+

团队拼团

+ +
+ + {/* 标签切换 */} +
+ + +
-
- {/* 小程序风格统计卡片 */} -
-
-
156
-
进行中
+ {/* 统计信息 */} +
+
+
+
{groupBuys.length}
+
进行中
-
-
89
-
今日成团
+
+
156
+
已完成
-
-
2.3k
-
参团人数
+
+
89
+
参与人数
+
- {/* 小程序风格分类标签 */} -
- {[ - { key: 'all', label: '全部' }, - { key: 'active', label: '进行中' }, - { key: 'hot', label: '热门' }, - { key: 'success', label: '已成团' } - ].map((tab) => ( - - ))} -
- - {/* 拼团商品列表 - 小程序风格 */} -
- {getFilteredGroups().map((group) => ( - -
- {/* 商品图片 */} -
- {group.title} -
- {getStatusBadge(group)} -
- {group.tags.map((tag, index) => ( - - {tag} - - ))} -
- - {/* 商品信息 */} -
-
-

- {group.title} -

- -
- - {/* 价格信息 */} -
- ¥{group.groupPrice} - ¥{group.originalPrice} -
- - {/* 拼团进度 */} -
-
-
- - 拼团进度 + {/* 拼团列表 */} +
+
+ {filteredGroups.map((group) => ( + + + +
+ {/* 商品图片 */} +
+ {group.title} +
+ + {/* 内容区域 */} +
+
+
+

+ {group.title} +

+

+ {group.description} +

+
+
- - {group.currentMembers}/{group.groupSize}人 - -
- -
- - {/* 底部信息 */} -
-
-
- - {group.host.avatar} - - + + {/* 价格和进度 */} +
+
+ ¥{group.groupPrice} + ¥{group.originalPrice} +
+
+ {group.currentMembers}/{group.groupSize}人 +
+
+ + {/* 进度条 */} +
+ +
+ + {/* 底部信息 */} +
+
+ + + {group.host.avatar} + + + {group.host.name} +
+ + {group.host.rating} +
+
+
+ + {group.timeLeft} +
- {group.host.name} - - {group.host.rating} -
-
- - {group.timeLeft}
-
-
- - {/* 操作按钮 */} -
- - -
+ ))}
- - {/* 空状态 */} - {getFilteredGroups().length === 0 && ( -
- -

暂无拼团活动

-

敬请期待更多精彩拼团活动

-
- )}
- {/* 小程序风格底部导航栏 */} - + {/* 底部导航 */} +
) } \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 69f6671..5c6af44 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -64,7 +64,7 @@ export default function HomePage() { { id: '1', name: '玫瑰香水盲盒', - image: '/api/placeholder/400/400', + image: 'https://picsum.photos/400/400?random=1', price: 139, originalPrice: 199, discount: '7折', @@ -82,7 +82,7 @@ export default function HomePage() { { id: '2', name: '薰衣草助眠香氛', - image: '/api/placeholder/400/400', + image: 'https://picsum.photos/400/400?random=2', price: 89, originalPrice: 129, discount: '69折', @@ -104,7 +104,7 @@ export default function HomePage() { { id: '1', title: '3人拼团 玫瑰香水', - image: '/api/placeholder/400/400', + image: 'https://picsum.photos/400/400?random=3', originalPrice: 199, groupPrice: 139, groupSize: 3, @@ -120,7 +120,7 @@ export default function HomePage() { { id: '2', title: '5人拼团 薰衣草套装', - image: '/api/placeholder/400/400', + image: 'https://picsum.photos/400/400?random=4', originalPrice: 299, groupPrice: 199, groupSize: 5, diff --git a/src/app/product/[id]/page.tsx b/src/app/product/[id]/page.tsx new file mode 100644 index 0000000..6c2fe9a --- /dev/null +++ b/src/app/product/[id]/page.tsx @@ -0,0 +1,562 @@ +'use client' + +import { useState, useEffect, useRef } from 'react' +import { useRouter, useParams } from 'next/navigation' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { + Heart, + Share2, + ShoppingCart, + Star, + ArrowLeft, + Plus, + Minus, + Shield, + Truck, + RotateCcw, + ChevronLeft, + ChevronRight +} from 'lucide-react' +import { showSuccessToast, showLikeToast, showShareToast } from '@/lib/toast-utils' + +interface Product { + id: string + name: string + images: string[] + price: number + originalPrice: number + discount: string + rating: number + reviews: number + likes: number + comments: number + description: string + tags: string[] + stock: number + category: string + isHot: boolean + isNew: boolean + specifications: { + brand: string + capacity: string + fragrance: string + duration: string + origin: string + } + details: { + ingredients: string[] + usage: string + storage: string + notes: { + top: string[] + middle: string[] + base: string[] + } + } +} + +export default function ProductDetailPage() { + const router = useRouter() + const params = useParams() + const productId = params.id as string + const scrollContainerRef = useRef(null) + + const [product, setProduct] = useState(null) + const [currentImageIndex, setCurrentImageIndex] = useState(0) + const [quantity, setQuantity] = useState(1) + const [isLiked, setIsLiked] = useState(false) + const [isLoading, setIsLoading] = useState(true) + + // 模拟商品数据 + useEffect(() => { + const mockProduct: Product = { + id: productId, + name: '玫瑰香水盲盒', + images: [ + 'https://picsum.photos/600/600?random=10', + 'https://picsum.photos/600/600?random=11', + 'https://picsum.photos/600/600?random=12', + 'https://picsum.photos/600/600?random=13', + 'https://picsum.photos/600/600?random=14', + 'https://picsum.photos/600/600?random=15' + ], + price: 139, + originalPrice: 199, + discount: '7折', + rating: 4.8, + reviews: 234, + likes: 567, + comments: 89, + description: '经典玫瑰香调,优雅女神范,持久留香8小时。采用法国进口玫瑰精油,层次丰富,前调清新,中调浓郁,后调温暖。适合日常使用,也是送礼的绝佳选择。', + tags: ['热销', '限量', '法国进口'], + stock: 15, + category: 'floral', + isHot: true, + isNew: false, + specifications: { + brand: 'Elegant Rose', + capacity: '50ml', + fragrance: '花香调', + duration: '6-8小时', + origin: '法国' + }, + details: { + ingredients: ['玫瑰精油', '茉莉花精华', '白麝香', '雪松木', '香草'], + usage: '喷洒在脉搏处,如手腕、耳后、颈部等部位,避免直接接触衣物。', + storage: '请存放在阴凉干燥处,避免阳光直射和高温环境。', + notes: { + top: ['柠檬', '佛手柑', '粉红胡椒'], + middle: ['玫瑰', '茉莉', '牡丹'], + base: ['白麝香', '雪松', '香草'] + } + } + } + + setTimeout(() => { + setProduct(mockProduct) + setIsLoading(false) + }, 1000) + }, [productId]) + + const handleLike = () => { + setIsLiked(!isLiked) + showLikeToast() + } + + const handleShare = () => { + if (navigator.share) { + navigator.share({ + title: product?.name, + text: `来看看这个超棒的香氛产品!`, + url: window.location.href + }) + } else { + navigator.clipboard.writeText(window.location.href) + showShareToast() + } + } + + const handleAddToCart = () => { + if (!product) return + + // 检查库存 + if (quantity > product.stock) { + showSuccessToast('库存不足,请减少购买数量') + return + } + + // 模拟添加到购物车的逻辑 + const cartItem = { + productId: product.id, + name: product.name, + price: product.price, + quantity: quantity, + image: product.images[0] + } + + // 这里可以调用实际的购物车API + console.log('添加到购物车:', cartItem) + + showSuccessToast(`已添加 ${quantity} 件 "${product.name}" 到购物车`) + } + + const handleBuyNow = () => { + if (!product) return + + // 检查库存 + if (quantity > product.stock) { + showSuccessToast('库存不足,请减少购买数量') + return + } + + // 模拟立即购买的逻辑 + const orderItem = { + productId: product.id, + name: product.name, + price: product.price, + quantity: quantity, + totalAmount: product.price * quantity, + image: product.images[0] + } + + // 这里可以跳转到结算页面或调用支付API + console.log('立即购买:', orderItem) + + showSuccessToast(`正在为您处理 ${quantity} 件商品的订单,总金额 ¥${product.price * quantity}`) + + // 模拟跳转到结算页面 + setTimeout(() => { + showSuccessToast('订单创建成功!正在跳转到支付页面...') + }, 1500) + } + + const increaseQuantity = () => { + if (product && quantity < product.stock) { + setQuantity(quantity + 1) + } + } + + const decreaseQuantity = () => { + if (quantity > 1) { + setQuantity(quantity - 1) + } + } + + // 图片滑动功能 + const scrollToImage = (index: number) => { + setCurrentImageIndex(index) + if (scrollContainerRef.current) { + const container = scrollContainerRef.current + const imageWidth = container.clientWidth + container.scrollTo({ + left: imageWidth * index, + behavior: 'smooth' + }) + } + } + + const handlePrevImage = () => { + if (!product) return + const prevIndex = currentImageIndex > 0 ? currentImageIndex - 1 : product.images.length - 1 + scrollToImage(prevIndex) + } + + const handleNextImage = () => { + if (!product) return + const nextIndex = currentImageIndex < product.images.length - 1 ? currentImageIndex + 1 : 0 + scrollToImage(nextIndex) + } + + // 监听滑动事件 + const handleScroll = () => { + if (scrollContainerRef.current && product) { + const container = scrollContainerRef.current + const imageWidth = container.clientWidth + const scrollLeft = container.scrollLeft + const newIndex = Math.round(scrollLeft / imageWidth) + if (newIndex !== currentImageIndex && newIndex >= 0 && newIndex < product.images.length) { + setCurrentImageIndex(newIndex) + } + } + } + + if (isLoading) { + return ( +
+
+
+

加载商品详情中...

+
+
+ ) + } + + if (!product) { + return ( +
+
+

商品不存在

+ +
+
+ ) + } + + return ( +
+ {/* 顶部导航 */} +
+
+ +

商品详情

+
+ + +
+
+
+ +
+ {/* 商品图片轮播区域 */} +
+ {/* 主图片滑动容器 */} +
+ {product.images.map((image, index) => ( +
+
+ {`${product.name} + {/* 标签 */} + {index === 0 && ( +
+ {product.isHot && ( + 热销 + )} + {product.isNew && ( + 新品 + )} +
+ )} +
+
+ ))} +
+ + {/* 左右切换按钮 */} + + + + {/* 图片指示器 */} +
+ {product.images.map((_, index) => ( +
+
+ + {/* 商品基本信息 */} +
+ {/* 标签 */} +
+ {product.tags.map((tag, index) => ( + + {tag} + + ))} +
+ + {/* 商品名称 */} +

{product.name}

+ + {/* 评分和评价 */} +
+
+ + {product.rating} + ({product.reviews}条评价) +
+
+ {product.likes} 人喜欢 +
+
+ + {/* 价格 */} +
+ ¥{product.price} + ¥{product.originalPrice} + {product.discount} +
+ + {/* 商品描述 */} +

{product.description}

+
+ + {/* 购买选项 */} +
+ {/* 数量选择 */} +
+ 购买数量 +
+ +
+ {quantity} +
+ +
+
+ + {/* 库存和小计 */} +
+ 库存 {product.stock} 件 + 小计 ¥{(product.price * quantity).toFixed(2)} +
+ + {/* 库存状态提示 */} + {product.stock === 0 && ( +
+ 商品已售罄 +
+ )} + + {product.stock > 0 && product.stock <= 5 && ( +
+ ⚠️ 库存紧张,仅剩 {product.stock} 件 +
+ )} +
+ + {/* 商品详情 */} +
+ + + 商品详情 + 规格参数 + 用户评价 + + + +
+
+

香调层次

+
+
+ 前调 + {product.details.notes.top.join('、')} +
+
+ 中调 + {product.details.notes.middle.join('、')} +
+
+ 后调 + {product.details.notes.base.join('、')} +
+
+
+ +
+

主要成分

+

{product.details.ingredients.join('、')}

+
+ +
+

使用方法

+

{product.details.usage}

+
+ +
+

保存方法

+

{product.details.storage}

+
+
+
+ + +
+ {Object.entries(product.specifications).map(([key, value]) => ( +
+ + {key === 'brand' ? '品牌' : + key === 'capacity' ? '容量' : + key === 'fragrance' ? '香调' : + key === 'duration' ? '持香时间' : + key === 'origin' ? '产地' : key} + + {value} +
+ ))} +
+
+ + +
+
+ +
+

暂无用户评价

+

成为第一个评价此商品的用户

+
+
+
+
+ + {/* 服务保障 */} +
+

服务保障

+
+
+
+ +
+ 正品保证 +
+
+
+ +
+ 免费配送 +
+
+
+ +
+ 7天退换 +
+
+
+
+ + {/* 底部固定购买栏 */} +
+
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/subscription/page.tsx b/src/app/subscription/page.tsx index 5149919..1592a7f 100644 --- a/src/app/subscription/page.tsx +++ b/src/app/subscription/page.tsx @@ -12,6 +12,7 @@ import { Label } from '@/components/ui/label' import { Checkbox } from '@/components/ui/checkbox' import { Slider } from '@/components/ui/slider' import { Separator } from '@/components/ui/separator' +import BottomNavigation from '@/components/bottom-navigation' import { Crown, Star, @@ -671,29 +672,8 @@ export default function SubscriptionPage() {
- {/* Bottom Navigation */} - + {/* 底部导航 */} +
) } \ No newline at end of file diff --git a/src/components/bottom-navigation.tsx b/src/components/bottom-navigation.tsx index 2fd7e21..b593122 100644 --- a/src/components/bottom-navigation.tsx +++ b/src/components/bottom-navigation.tsx @@ -5,9 +5,9 @@ import { useRouter, usePathname } from 'next/navigation' import { Button } from '@/components/ui/button' import { Home, - Search, + TrendingUp, PlusSquare, - ShoppingBag, + Bell, User } from 'lucide-react' @@ -18,9 +18,9 @@ export default function BottomNavigation() { // 根据当前路径确定活跃标签 const getActiveTab = () => { if (pathname === '/') return 'home' - if (pathname.startsWith('/discover')) return 'discover' + if (pathname.startsWith('/distribution')) return 'distribution' if (pathname.startsWith('/create')) return 'create' - if (pathname.startsWith('/orders')) return 'orders' + if (pathname.startsWith('/subscription')) return 'subscription' if (pathname.startsWith('/profile')) return 'profile' return 'home' } @@ -48,11 +48,11 @@ export default function BottomNavigation() { +
- {/* 库存提醒 */} + {/* 库存警告 */} {product.stock <= 5 && (
- + 仅剩{product.stock}件
)} - {/* 查看详情按钮 */} -
- +
+ + 查看详情 +
+ {/* 内容区域 */} -
- {/* 标题和描述 */} -
-

{product.name}

-

{product.description}

+
+ {product.tags.slice(0, 2).map((tag, index) => ( + + {tag} + + ))} +
+ +

{product.name}

+

{product.description}

+ +
+
+ + {product.rating} + ({product.reviews}条评价)
- - {/* 评分和评价 */} -
-
- - {product.rating} -
- {product.reviews} 评价 - 库存 {product.stock} -
- - {/* 价格区域 */} -
- ¥{product.price} - {product.originalPrice > product.price && ( - ¥{product.originalPrice} - )} - {discountPercentage > 0 && ( - - 省¥{product.originalPrice - product.price} - - )} -
- - {/* 互动区域 */} -
-
- - -
- +
+ {product.likes} 人喜欢
+ +
+ ¥{product.price} + {product.originalPrice > product.price && ( + ¥{product.originalPrice} + )} + + {product.discount} + +
+ +
+ + + +
) -} \ No newline at end of file +} + +export default ProductCard \ No newline at end of file diff --git a/src/components/product-selector.tsx b/src/components/product-selector.tsx new file mode 100644 index 0000000..6e96fd4 --- /dev/null +++ b/src/components/product-selector.tsx @@ -0,0 +1,302 @@ +'use client' + +import { useState, useEffect } from 'react' +import { Search, Check, Package, Star, Tag } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Badge } from '@/components/ui/badge' +import { Card, CardContent } from '@/components/ui/card' +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' + +interface Product { + id: string + name: string + brand: string + price: number + originalPrice: number + image: string + category: string + tags: string[] + rating: number + reviews: number + stock: number + description: string + volume?: string +} + +interface ProductSelectorProps { + selectedProduct?: Product | null + onProductSelect: (product: Product) => void + placeholder?: string + disabled?: boolean +} + +export function ProductSelector({ + selectedProduct, + onProductSelect, + placeholder = "选择商品", + disabled = false +}: ProductSelectorProps) { + const [isOpen, setIsOpen] = useState(false) + const [searchQuery, setSearchQuery] = useState('') + const [selectedCategory, setSelectedCategory] = useState('all') + const [products, setProducts] = useState([]) + + // 模拟商品数据 + useEffect(() => { + const mockProducts: Product[] = [ + { + id: '1', + name: '迪奥小姐香水', + brand: 'Dior', + price: 899, + originalPrice: 1299, + image: 'https://picsum.photos/200/200?random=1', + category: 'floral', + tags: ['热销', '经典'], + rating: 4.8, + reviews: 1234, + stock: 50, + description: '经典花香调,优雅迷人', + volume: '100ml' + }, + { + id: '2', + name: '香奈儿五号香水', + brand: 'Chanel', + price: 1299, + originalPrice: 1599, + image: 'https://picsum.photos/200/200?random=2', + category: 'floral', + tags: ['经典', '限量'], + rating: 4.9, + reviews: 2156, + stock: 30, + description: '永恒经典,女性魅力象征', + volume: '100ml' + }, + { + id: '3', + name: '爱马仕大地香水', + brand: 'Hermès', + price: 1199, + originalPrice: 1499, + image: 'https://picsum.photos/200/200?random=3', + category: 'woody', + tags: ['男士', '木质'], + rating: 4.7, + reviews: 856, + stock: 25, + description: '木质调香水,成熟男士首选', + volume: '100ml' + }, + { + id: '4', + name: '祖马龙英国梨香水', + brand: 'Jo Malone', + price: 799, + originalPrice: 999, + image: 'https://picsum.photos/200/200?random=4', + category: 'fruity', + tags: ['清新', '果香'], + rating: 4.6, + reviews: 678, + stock: 40, + description: '清新果香,日常必备', + volume: '100ml' + }, + { + id: '5', + name: '汤姆福特黑兰花香水', + brand: 'Tom Ford', + price: 1599, + originalPrice: 1899, + image: 'https://picsum.photos/200/200?random=5', + category: 'oriental', + tags: ['奢华', '东方调'], + rating: 4.8, + reviews: 432, + stock: 15, + description: '神秘东方调,奢华体验', + volume: '100ml' + }, + { + id: '6', + name: '宝格丽紫水晶香水', + brand: 'Bulgari', + price: 699, + originalPrice: 899, + image: 'https://picsum.photos/200/200?random=6', + category: 'floral', + tags: ['女士', '花香'], + rating: 4.5, + reviews: 789, + stock: 35, + description: '优雅花香,女性魅力', + volume: '65ml' + } + ] + setProducts(mockProducts) + }, []) + + const categories = [ + { id: 'all', name: '全部' }, + { id: 'floral', name: '花香调' }, + { id: 'woody', name: '木质调' }, + { id: 'fruity', name: '果香调' }, + { id: 'oriental', name: '东方调' } + ] + + const filteredProducts = products.filter(product => { + const matchesSearch = product.name.toLowerCase().includes(searchQuery.toLowerCase()) || + product.brand.toLowerCase().includes(searchQuery.toLowerCase()) + const matchesCategory = selectedCategory === 'all' || product.category === selectedCategory + return matchesSearch && matchesCategory + }) + + const handleProductSelect = (product: Product) => { + onProductSelect(product) + setIsOpen(false) + } + + return ( + + + + + + + + + + 选择商品 + + + +
+ {/* 搜索栏 */} +
+ + setSearchQuery(e.target.value)} + className="pl-10" + /> +
+ + {/* 分类筛选 */} +
+ {categories.map((category) => ( + + ))} +
+ + {/* 商品列表 */} +
+
+ {filteredProducts.map((product) => ( + handleProductSelect(product)} + > + +
+ {product.name} +
+
+
+

{product.name}

+

{product.brand} · {product.volume}

+
+ {selectedProduct?.id === product.id && ( + + )} +
+ +
+
+ + {product.rating} + ({product.reviews}) +
+ + 库存 {product.stock} + +
+ +
+
+ ¥{product.price} + {product.originalPrice > product.price && ( + ¥{product.originalPrice} + )} +
+
+ {product.tags.slice(0, 2).map((tag, index) => ( + + {tag} + + ))} +
+
+ +

{product.description}

+
+
+
+
+ ))} +
+ + {filteredProducts.length === 0 && ( +
+ +

没有找到匹配的商品

+

请尝试调整搜索条件

+
+ )} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx index 2d96b40..3a35297 100644 --- a/src/components/ui/toast.tsx +++ b/src/components/ui/toast.tsx @@ -25,13 +25,13 @@ const ToastViewport = React.forwardRef< ToastViewport.displayName = ToastPrimitives.Viewport.displayName const toastVariants = cva( - "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", + "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-lg border p-4 pr-6 shadow-lg backdrop-blur-sm transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", { variants: { variant: { - default: "border bg-background text-foreground", + default: "border-gray-200 bg-white/95 text-foreground shadow-xl", destructive: - "destructive group border-destructive bg-destructive text-destructive-foreground", + "destructive group border-red-200 bg-red-50/95 text-red-900 shadow-xl shadow-red-100/50", }, }, defaultVariants: { @@ -77,7 +77,7 @@ const ToastClose = React.forwardRef< (({ className, ...props }, ref) => ( )) @@ -106,7 +106,7 @@ const ToastDescription = React.forwardRef< >(({ className, ...props }, ref) => ( )) diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index 4ee26b3..aabcc86 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -36,7 +36,7 @@ function TooltipTrigger({ function TooltipContent({ className, - sideOffset = 0, + sideOffset = 8, children, ...props }: React.ComponentProps) { @@ -46,13 +46,20 @@ function TooltipContent({ data-slot="tooltip-content" sideOffset={sideOffset} className={cn( - "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", + // 优化后的现代化 tooltip 样式 + "bg-gray-900/95 text-white backdrop-blur-sm border border-gray-700/50", + "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", + "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + "z-50 w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin)", + "rounded-lg px-3 py-2 text-sm font-medium leading-relaxed", + "shadow-lg shadow-black/20", + "text-balance break-words", className )} {...props} > {children} - + ) diff --git a/src/lib/toast-utils.ts b/src/lib/toast-utils.tsx similarity index 70% rename from src/lib/toast-utils.ts rename to src/lib/toast-utils.tsx index 39ec578..9f8a492 100644 --- a/src/lib/toast-utils.ts +++ b/src/lib/toast-utils.tsx @@ -1,3 +1,4 @@ +import React from 'react' import { toast } from '@/hooks/use-toast' export const showSuccessToast = (message: string) => { @@ -17,8 +18,9 @@ export const showErrorToast = (message: string) => { export const showLikeToast = () => { toast({ - title: "已点赞", - description: "您已为这个内容点赞", + title: "点赞成功 ❤️", + description: "感谢您的喜欢!", + className: "border-pink-200 bg-gradient-to-r from-pink-50 to-red-50 shadow-lg shadow-pink-100/50", }) } diff --git a/tailwind.config.ts b/tailwind.config.ts index fc48e48..b357781 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -7,6 +7,7 @@ const config: Config = { "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "./app/**/*.{js,ts,jsx,tsx,mdx}", + "./src/**/*.{js,ts,jsx,tsx,mdx}", ], theme: { extend: { diff --git a/说明文档.md b/说明文档.md new file mode 100644 index 0000000..56cbfe3 --- /dev/null +++ b/说明文档.md @@ -0,0 +1,149 @@ + +## 一、核心功能模块 + + 1.1 商品管理系统 + + 1.1.1 商品基础信息 +2.1商品属性2.1: 名称、描述、价格、原价、图片、分类、标签 +2.1库存管理2.1: 库存数量、销量统计、商品状态 +2.1分类体系2.1: 花香调(floral)、草本调(herbal)等香调分类 + + 1.1.2 商品展示 +2.1多视图模式2.1: 网格视图、列表视图切换 +2.1商品卡片2.1: 包含价格、折扣、评分、评论数、点赞数 +2.1商品详情2.1: 详细描述、用户评价、相关推荐 + + 1.2 拼团购买系统 + + 1.2.1 拼团配置 +2.1阶梯拼团2.1: + 3人团:7折优惠,团长获得200积分 + 5人团:5折优惠,团长获得300积分 +2.1时间限制2.1: 默认24小时拼团时间 +2.1每日限量2.1: 支持设置每日拼团限量 + + 1.2.2 拼团流程 +2.1发起拼团2.1: 用户选择商品和拼团规模 +2.1邀请参团2.1: 分享拼团链接邀请好友 +2.1实时进度2.1: 显示当前参团人数和剩余时间 +2.1自动成团2.1: 达到目标人数自动成团 +2.1溯源码2.1: 成功拼团生成唯一溯源码 + + 1.2.3 秒杀功能 +2.1秒杀配置2.1: 特定时间点(如10:00)开启秒杀 +2.1限量抢购2.1: 设置秒杀库存和价格 +2.1防刷机制2.1: 避免恶意刷单 + + 1.3 订阅盲盒系统 + + 1.3.1 订阅计划 +2.1月度订阅2.1: 每月配送香水盲盒 +2.1季度订阅2.1: 每季度配送,享受更多优惠 +2.1配送设置2.1: 用户可选择配送频率和日期 + + 1.3.2 盲盒机制 +2.1香调排除2.1: 用户可排除不喜欢的香调 +2.1解锁系统2.1: 逐步解锁新香调 +2.1个性化推荐2.1: 基于用户偏好推荐 + + 1.3.3 会员折扣 +2.1探索会员2.1: 95折优惠 +2.1品鉴会员2.1: 85折优惠 +2.1调香会员2.1: 专属折扣和服务 + + 1.4 会员积分体系 + + 1.4.1 积分获取 +2.1购买获得2.1: 消费金额的一定比例 +2.1拼团奖励2.1: 团长额外积分奖励 +2.1分销奖励2.1: 推广订单获得积分 +2.1UGC内容2.1: 发布评价、教程等获得积分 + + 1.4.2 会员等级 +2.1探索会员2.1: 无门槛,享受基础权益 +2.1品鉴会员2.1: 累计消费满500元,享受更多优惠 +2.1调香会员2.1: 累计消费满2000元,享受VIP服务 + + 1.4.3 积分使用 +2.1商品兑换2.1: 积分兑换商品或优惠券 +2.1线下体验2.1: 积分兑换线下调香体验 +2.1会员升级2.1: 积分加速会员等级提升 + + 1.5 分销推广系统 + + 1.5.1 分销员体系 +2.1等级制度2.1: 探索、品鉴、调香三级分销员 +2.1佣金比例2.1: + 直接推广: 10%佣金 + 间接推广: 5%佣金 +2.1团队管理2.1: 查看下级分销员和业绩 + + 1.5.2 推广工具 +2.1分享链接2.1: 生成专属推广链接 +2.1素材库2.1: 提供推广图片和文案 +2.1数据统计2.1: 实时查看推广效果 + + 1.5.3 佣金结算 +2.1结算周期2.1: 订单完成后进入结算流程 +2.1提现功能2.1: 支持佣金提现到账户 +2.1税务处理2.1: 符合相关税务规定 + + 1.6 用户生成内容系统 + + 1.6.1 内容类型 +2.1商品评价2.1: 用户购买后的使用体验分享 +2.1使用教程2.1: 香水使用技巧和搭配指南 +2.1香水故事2.1: 个人香水使用故事和心得 + + 1.6.2 激励机制 +2.1积分奖励2.1: 发布优质内容获得积分奖励 +2.1精选推荐2.1: 优质内容获得平台首页推荐 +2.1专家认证2.1: 优秀创作者获得专家标识 + + 1.6.3 内容管理 +2.1审核机制2.1: 内容发布前进行质量审核 +2.1互动功能2.1: 支持点赞、评论、分享功能 +2.1数据统计2.1: 查看内容浏览量和互动数据 + + 1.7 订单管理系统 + + 1.7.1 订单流程 +2.1下单2.1: 选择商品、数量、配送信息 +2.1支付2.1: 支持多种支付方式 +2.1发货2.1: 商家发货并提供物流信息 +2.1收货2.1: 用户确认收货完成交易 + + 1.7.2 订单状态 +2.1待支付2.1: 订单创建等待支付 +2.1已支付2.1: 支付完成等待发货 +2.1已发货2.1: 商品已发出在途中 +2.1已完成2.1: 用户确认收货 +2.1已取消2.1: 订单被取消 + + 1.7.3 售后服务 +2.1退换货2.1: 支持7天无理由退换货 +2.1客服支持2.1: 在线客服解决问题 +2.1投诉处理2.1: 完善的投诉处理机制 + +## 二、用户角色与权限 + + 2.1 普通用户 +浏览商品、参与拼团 +购买商品、管理订单 +参与订阅服务 +发布UGC内容 +查看积分和会员信息 + + 2.2 分销员 +普通用户所有权限 +生成推广链接 +查看推广数据 +管理下级分销员 +佣金提现 + + 2.3 管理员 +商品管理 +订单管理 +用户管理 +数据统计 +系统配置