页面优化

This commit is contained in:
2025-04-24 19:07:24 +08:00
parent 6d199e7bf7
commit 34e97fb6f7
3 changed files with 628 additions and 157 deletions

View File

@@ -1,106 +1,411 @@
<script setup>
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Autoplay, Pagination, Navigation, EffectFade } from 'swiper/modules'
import AOS from 'aos'
import 'aos/dist/aos.css'
import 'swiper/css'
import 'swiper/css/pagination'
import 'swiper/css/navigation'
import 'swiper/css/effect-fade'
const route = useRoute()
const activeKey = ref('1')
const activeTab = ref('1')
const modules = [Autoplay, Pagination, Navigation, EffectFade]
onMounted(() => {
AOS.init({
duration: 1200,
offset: 120,
easing: 'ease-out-cubic',
once: false
})
})
const project = {
id: route.params.id,
title: '电商平台',
cover: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
category: 'Web应用',
tags: ['Vue3', 'Node.js'],
tags: ['Vue3', 'Node.js', 'TypeScript', 'MongoDB', 'Docker'],
author: '技术团队',
price: '¥ 29,999',
description: '基于微服务架构的电商平台,包含商品管理、订单系统、支付对接等模块',
description: '基于微服务架构的电商平台,包含商品管理、订单系统、支付对接等模块。采用前后端分离设计提供完整的API文档和部署方案。系统具有高度可扩展性和定制化能力适合中小型企业快速搭建自有电商平台。',
features: [
'响应式设计,支持多端访问',
'完整的商品管理系统',
'订单处理和物流跟踪',
'多种支付方式集成',
'会员管理和积分系统',
'数据分析和报表功能'
],
technicalStack: ['前端Vue3 + TypeScript', '后端NestJS + MySQL', '部署Docker + Kubernetes'],
screenshots: [
'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280'
],
video: 'https://www.youtube.com/embed/dQw4w9WgXcQ',
wechatQR: 'https://via.placeholder.com/200x200'
wechatQR: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280'
}
const relatedProjects = [
{
id: 1,
title: 'CRM系统',
cover: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
tags: ['Vue3', 'Express'],
price: '¥ 19,999'
},
{
id: 2,
title: '数据分析平台',
cover: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
tags: ['React', 'Python'],
price: '¥ 24,999'
},
{
id: 3,
title: '企业官网',
cover: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
tags: ['Nuxt.js', 'Tailwind'],
price: '¥ 9,999'
}
]
// 轮播图自动播放配置
const swiperOptions = {
delay: 5000,
disableOnInteraction: false
}
</script>
<template>
<div class="container mx-auto px-4 py-8">
<!-- 项目封面 -->
<div class="mb-8" data-aos="fade-up">
<img :src="project.cover" class="w-full h-64 md:h-96 object-cover rounded-xl" />
</div>
<div class="bg-gradient-to-b from-gray-50 to-white dark:from-gray-900 dark:to-gray-800 min-h-screen py-12">
<div class="max-w-6xl mx-auto px-6">
<!-- 项目封面 -->
<div class="mb-10" data-aos="fade-up">
<div class="relative h-[50vh] min-h-[400px] rounded-3xl overflow-hidden shadow-2xl">
<img
:src="project.cover"
class="w-full h-full object-cover"
alt="项目封面"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent"></div>
<!-- 基本信息卡片 -->
<a-card class="mb-8 shadow-lg" data-aos="fade-up">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<h1 class="text-2xl font-bold mb-2">{{ project.title }}</h1>
<a-tag color="blue" class="mb-2">{{ project.category }}</a-tag>
<div class="flex flex-wrap gap-2">
<a-tag v-for="tag in project.tags" :key="tag">{{ tag }}</a-tag>
<div class="absolute bottom-0 left-0 right-0 p-8 md:p-12">
<div class="flex flex-wrap gap-2 mb-4">
<span
class="px-4 py-1.5 bg-white/10 backdrop-blur-md text-white text-sm font-medium rounded-full border border-white/20"
>
{{ project.category }}
</span>
</div>
<h1 class="text-3xl md:text-5xl font-bold text-white mb-4">{{ project.title }}</h1>
<div class="flex flex-wrap gap-2 mb-6">
<span
v-for="tag in project.tags"
:key="tag"
class="px-3 py-1 bg-rose-500/20 backdrop-blur-md text-rose-100 text-sm font-medium rounded-full border border-rose-500/30"
>
{{ tag }}
</span>
</div>
</div>
</div>
<div class="space-y-2">
<p class="text-gray-600">作者{{ project.author }}</p>
<p class="text-xl text-red-500 font-bold">{{ project.price }}</p>
</div>
<!-- 项目信息卡片 -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-12" data-aos="fade-up">
<!-- 左侧信息 -->
<div class="lg:col-span-2">
<div class="bg-white dark:bg-gray-800 rounded-3xl shadow-xl p-8">
<!-- 标签页导航 -->
<div class="border-b border-gray-200 dark:border-gray-700 mb-8">
<nav class="flex space-x-8">
<button
@click="activeTab = '1'"
class="py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200"
:class="activeTab === '1' ? 'border-rose-500 text-rose-600 dark:text-rose-400' : 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'"
>
项目详情
</button>
<button
@click="activeTab = '2'"
class="py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200"
:class="activeTab === '2' ? 'border-rose-500 text-rose-600 dark:text-rose-400' : 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'"
>
项目截图
</button>
<button
@click="activeTab = '3'"
class="py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200"
:class="activeTab === '3' ? 'border-rose-500 text-rose-600 dark:text-rose-400' : 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'"
>
演示视频
</button>
</nav>
</div>
<!-- 标签页内容 -->
<div>
<!-- 项目详情 -->
<div v-if="activeTab === '1'" class="space-y-8">
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</span>
项目描述
</h3>
<p class="text-gray-600 dark:text-gray-300 leading-relaxed">{{ project.description }}</p>
</div>
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</span>
核心功能
</h3>
<ul class="grid grid-cols-1 md:grid-cols-2 gap-3">
<li
v-for="(feature, index) in project.features"
:key="index"
class="flex items-start"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3 mt-0.5">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">{{ feature }}</span>
</li>
</ul>
</div>
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
</span>
技术栈
</h3>
<ul class="space-y-2">
<li
v-for="(tech, index) in project.technicalStack"
:key="index"
class="flex items-center bg-gray-50 dark:bg-gray-700/50 rounded-lg p-3"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">{{ tech }}</span>
</li>
</ul>
</div>
</div>
<!-- 项目截图 -->
<div v-else-if="activeTab === '2'">
<swiper
:modules="modules"
:effect="'fade'"
:autoplay="swiperOptions"
:pagination="{
clickable: true,
dynamicBullets: true,
dynamicMainBullets: 3
}"
:navigation="true"
:loop="true"
class="rounded-2xl overflow-hidden shadow-lg"
>
<swiper-slide
v-for="(img, index) in project.screenshots"
:key="index"
>
<div class="relative h-[50vh] min-h-[400px] w-full">
<img
:src="img"
class="w-full h-full object-contain bg-gray-100 dark:bg-gray-900"
:alt="`项目截图 ${index + 1}`"
/>
</div>
</swiper-slide>
</swiper>
</div>
<!-- 演示视频 -->
<div v-else-if="activeTab === '3'">
<div class="aspect-w-16 aspect-h-9 rounded-2xl overflow-hidden shadow-lg">
<iframe
:src="project.video"
class="w-full h-[50vh] min-h-[400px]"
frameborder="0"
allowfullscreen
></iframe>
</div>
</div>
</div>
</div>
</div>
<div class="flex items-center justify-center">
<a-button type="primary" size="large" class="w-full">立即咨询</a-button>
<!-- 右侧信息 -->
<div>
<div class="bg-white dark:bg-gray-800 rounded-3xl shadow-xl p-8 sticky top-8">
<div class="mb-6">
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">价格</p>
<p class="text-3xl font-bold text-rose-600 dark:text-rose-400">{{ project.price }}</p>
</div>
<div class="mb-6">
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">开发团队</p>
<p class="text-gray-900 dark:text-white font-medium">{{ project.author }}</p>
</div>
<div class="space-y-4">
<button class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center">
<span>立即咨询</span>
</button>
<button class="w-full py-3 bg-white dark:bg-gray-700 text-rose-600 dark:text-rose-400 border border-rose-200 dark:border-rose-800/30 rounded-xl shadow-md hover:shadow-lg transition-all duration-300 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
<span>收藏项目</span>
</button>
</div>
<div class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700">
<p class="text-center text-gray-500 dark:text-gray-400 mb-4">扫码添加客服</p>
<div class="flex justify-center">
<img
:src="project.wechatQR"
class="w-32 h-32 object-cover rounded-lg border border-gray-200 dark:border-gray-700"
alt="微信二维码"
/>
</div>
</div>
</div>
</div>
</div>
</a-card>
<!-- 详情标签页 -->
<a-tabs v-model:activeKey="activeKey" class="mb-8" data-aos="fade-up">
<a-tab-pane key="1" tab="项目详情">
<div class="prose max-w-none">
<h3 class="text-xl font-bold mb-4">项目描述</h3>
<p class="text-gray-600 mb-6">{{ project.description }}</p>
<h3 class="text-xl font-bold mb-4">技术栈</h3>
<ul class="list-disc pl-6 mb-6">
<li v-for="tech in project.technicalStack" :key="tech">{{ tech }}</li>
</ul>
<!-- 相关项目 -->
<section class="mb-12" data-aos="fade-up">
<h2 class="text-2xl md:text-3xl font-bold mb-8 text-gray-900 dark:text-white">
<span class="relative">
相关项目
<span class="absolute -bottom-2 left-0 w-1/4 h-1 bg-gradient-to-r from-rose-400 to-rose-600 rounded-full"></span>
</span>
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div
v-for="related in relatedProjects"
:key="related.id"
class="group bg-white dark:bg-gray-800 rounded-3xl shadow-lg hover:shadow-xl transition-all duration-500 overflow-hidden transform hover:-translate-y-2"
>
<div class="relative h-48 overflow-hidden">
<img
:src="related.cover"
class="w-full h-full object-cover transform transition-transform duration-700 group-hover:scale-110"
:alt="related.title"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
<div class="p-6">
<h3 class="text-lg font-bold mb-2 text-gray-900 dark:text-white group-hover:text-rose-600 dark:group-hover:text-rose-400 transition-colors">
{{ related.title }}
</h3>
<div class="flex flex-wrap gap-2 mb-4">
<span
v-for="tag in related.tags"
:key="tag"
class="px-3 py-1 bg-rose-50 dark:bg-rose-900/20 text-rose-600 dark:text-rose-300 text-xs font-medium rounded-lg"
>
{{ tag }}
</span>
</div>
<div class="flex justify-between items-center">
<p class="font-bold text-rose-600 dark:text-rose-400">{{ related.price }}</p>
<button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</button>
</div>
</div>
</div>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="项目截图">
<swiper
:slides-per-view="1"
:space-between="30"
class="mb-6"
>
<swiper-slide v-for="(img, index) in project.screenshots" :key="index">
<img :src="img" class="w-full h-96 object-contain" />
</swiper-slide>
</swiper>
</a-tab-pane>
<a-tab-pane key="3" tab="演示视频">
<div class="aspect-w-16 aspect-h-9">
<iframe
:src="project.video"
class="w-full h-96"
frameborder="0"
allowfullscreen
/>
</div>
</a-tab-pane>
<a-tab-pane key="4" tab="联系作者">
<div class="text-center">
<img :src="project.wechatQR" class="w-48 h-48 mx-auto mb-4" />
<p class="text-gray-600">扫描二维码添加微信咨询</p>
</div>
</a-tab-pane>
</a-tabs>
</section>
</div>
</div>
</template>
<style lang="scss" scoped>
.prose :deep(h3) {
@apply border-l-4 border-blue-500 pl-4 mb-4;
<style scoped>
/* 优化 Swiper 导航样式 */
:deep(.swiper-button-next),
:deep(.swiper-button-prev) {
width: 3rem;
height: 3rem;
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(8px);
border-radius: 50%;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
color: #111827;
transition: all 0.3s ease;
}
</style>
:deep(.swiper-button-next:hover),
:deep(.swiper-button-prev:hover) {
background-color: white;
color: #f43f5e;
transform: scale(1.05);
}
:deep(.swiper-button-next::after),
:deep(.swiper-button-prev::after) {
font-size: 1.25rem;
font-weight: bold;
}
:deep(.swiper-pagination-bullet) {
width: 10px;
height: 10px;
background-color: rgba(255, 255, 255, 0.5);
transition: all 0.3s ease;
}
:deep(.swiper-pagination-bullet-active) {
background-color: #f43f5e;
width: 24px;
border-radius: 5px;
}
/* 添加轻奢风格的渐变背景和阴影效果 */
.bg-gradient-luxury {
background: linear-gradient(135deg, #f6f8fb 0%, #f0f4f8 100%);
}
/* 暗色模式下的轻奢风格 */
@media (prefers-color-scheme: dark) {
.bg-gradient-luxury {
background: linear-gradient(135deg, #1a1d23 0%, #111827 100%);
}
}
</style>

View File

@@ -7,6 +7,19 @@ import 'aos/dist/aos.css'
// Initialize userStore outside of userData to avoid conditional hook call
const userStore = useUserStore()
// Initialize userData with default values
const userData = ref({
username: '张三',
avatar: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
createdAt: '2023-01-15',
lastLogin: '2023-06-20',
email: 'user@example.com',
phone: '138****1234',
role: '企业客户',
projects: 5,
favorites: 12
})
onMounted(() => {
AOS.init({
duration: 1200,
@@ -14,19 +27,14 @@ onMounted(() => {
easing: 'ease-out-cubic',
once: false
})
})
// 模拟用户数据
const userData = ref({
username: userStore.user?.username || '张三',
avatar: userStore.user?.avatar || 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
createdAt: userStore.user?.createdAt || '2023-01-15',
lastLogin: userStore.user?.lastLogin || '2023-06-20',
email: 'user@example.com',
phone: '138****1234',
role: '企业客户',
projects: 5,
favorites: 12
// Update userData from userStore after component is mounted
if (userStore.user) {
userData.value.username = userStore.user.username || '张三'
userData.value.avatar = userStore.user.avatar || 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280'
userData.value.createdAt = userStore.user.createdAt || '2023-01-15'
userData.value.lastLogin = userStore.user.lastLogin || '2023-06-20'
}
})
const userStats = [

View File

@@ -1,98 +1,256 @@
<script setup>
import { ref, computed } from 'vue'
import { Tag, Card, Select } from 'ant-design-vue'
import { ref, computed, onMounted } from 'vue'
import AOS from 'aos'
import 'aos/dist/aos.css'
onMounted(() => {
AOS.init({
duration: 1200,
offset: 120,
easing: 'ease-out-cubic',
once: false
})
})
// 模拟项目数据
const projects = ref(Array.from({ length: 12 }, (_, i) => ({
id: i + 1,
title: `项目 ${i + 1}`,
cover: 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
tags: ['Vue3', 'Node.js', 'TypeScript'],
category: ['Web应用', '移动端'][i % 2],
tags: ['Vue3', 'Node.js', 'TypeScript'].slice(0, Math.floor(Math.random() * 3) + 1),
category: ['Web应用', '移动端', '小程序', '企业系统'][i % 4],
author: '开发者' + (i + 1),
price: (Math.random() * 10000).toFixed(2),
createdAt: new Date().toISOString()
price: (Math.random() * 10000 + 5000).toFixed(2),
createdAt: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
description: '这是一个示例项目描述,包含了项目的主要功能和技术特点。实际项目中会有更详细的描述信息。'
})))
// 筛选排序逻辑
const selectedCategory = ref('all')
const sortBy = ref('date')
const searchQuery = ref('')
const categories = [
{ value: 'all', label: '全部分类' },
{ value: 'Web应用', label: 'Web应用' },
{ value: '移动端', label: '移动端' },
{ value: '小程序', label: '小程序' },
{ value: '企业系统', label: '企业系统' }
]
const sortOptions = [
{ value: 'date', label: '最新发布' },
{ value: 'price-high', label: '价格从高到低' },
{ value: 'price-low', label: '价格从低到高' }
]
const filteredProjects = computed(() => {
return projects.value
.filter(p =>
selectedCategory.value === 'all' ||
p.category === selectedCategory.value
)
.sort((a, b) => {
if (sortBy.value === 'date') {
return new Date(b.createdAt) - new Date(a.createdAt)
}
return b.price - a.price
})
.filter(p =>
(selectedCategory.value === 'all' || p.category === selectedCategory.value) &&
(searchQuery.value === '' || p.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
p.description.toLowerCase().includes(searchQuery.value.toLowerCase()))
)
.sort((a, b) => {
if (sortBy.value === 'date') {
return new Date(b.createdAt) - new Date(a.createdAt)
} else if (sortBy.value === 'price-high') {
return parseFloat(b.price) - parseFloat(a.price)
} else if (sortBy.value === 'price-low') {
return parseFloat(a.price) - parseFloat(b.price)
}
return 0
})
})
const formatDate = (dateString) => {
const date = new Date(dateString)
return date.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' })
}
const formatPrice = (price) => {
return '¥ ' + parseFloat(price).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}
</script>
<template>
<div class="container mx-auto px-4 py-8">
<!-- 过滤排序栏 -->
<div class="mb-8 flex flex-col md:flex-row gap-4">
<Select
v-model:value="selectedCategory"
class="w-full md:w-48"
:options="[
{ value: 'all', label: '全部分类' },
{ value: 'Web应用', label: 'Web应用' },
{ value: '移动端', label: '移动端' },
]"
/>
<Select
v-model:value="sortBy"
class="w-full md:w-48"
:options="[
{ value: 'date', label: '最新发布' },
{ value: 'price', label: '价格排序' },
]"
/>
</div>
<div class="bg-gradient-to-b from-gray-50 to-white dark:from-gray-900 dark:to-gray-800 min-h-screen py-12">
<div class="max-w-6xl mx-auto px-6">
<!-- 页面标题 -->
<div class="text-center mb-16" data-aos="fade-up">
<h1 class="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">
<span class="relative">
项目展示
<span class="absolute -bottom-2 left-0 right-0 mx-auto w-1/3 h-1 bg-gradient-to-r from-rose-400 to-rose-600 rounded-full"></span>
</span>
</h1>
<p class="text-lg text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
探索我们的精选项目从Web应用到移动端解决方案满足您的各种数字化需求
</p>
</div>
<!-- 项目卡片网格 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<Card
v-for="project in filteredProjects"
:key="project.id"
class="hover:shadow-xl transition-shadow duration-300"
>
<template #cover>
<img
:src="'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280'"
class="h-48 w-full object-cover"
alt="项目封面"
/>
</template>
<div class="p-4">
<h3 class="text-lg font-semibold mb-2">{{ project.title }}</h3>
<div class="flex flex-wrap gap-2 mb-4">
<Tag
v-for="(tag, index) in project.tags"
:key="index"
:color="['#87d068', '#108ee9', '#2db7f5'][index % 3]"
>
{{ tag }}
</Tag>
</div>
<div class="flex justify-between items-center text-gray-600">
<span>{{ project.category }}</span>
<span>¥{{ project.price }}</span>
</div>
<div class="mt-4 text-sm text-gray-500 flex justify-between">
<span>{{ project.author }}</span>
<span>{{ new Date(project.createdAt).toLocaleDateString() }}</span>
<!-- 过滤排序栏 -->
<div class="mb-10" data-aos="fade-up">
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- 搜索框 -->
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<input
v-model="searchQuery"
type="text"
placeholder="搜索项目..."
class="pl-10 pr-4 py-2 w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl focus:ring-rose-500 focus:border-rose-500 dark:text-white"
/>
</div>
<!-- 分类选择 -->
<div>
<select
v-model="selectedCategory"
class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"
>
<option
v-for="category in categories"
:key="category.value"
:value="category.value"
>
{{ category.label }}
</option>
</select>
</div>
<!-- 排序选择 -->
<div>
<select
v-model="sortBy"
class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"
>
<option
v-for="option in sortOptions"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</option>
</select>
</div>
</div>
</div>
</Card>
</div>
<!-- 项目卡片网格 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div
v-for="project in filteredProjects"
:key="project.id"
class="group bg-white dark:bg-gray-800 rounded-3xl shadow-lg hover:shadow-xl transition-all duration-500 overflow-hidden transform hover:-translate-y-2"
data-aos="fade-up"
>
<div class="relative h-56 overflow-hidden">
<img
:src="project.cover"
class="w-full h-full object-cover transform transition-transform duration-700 group-hover:scale-110"
:alt="project.title"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div class="absolute top-4 right-4">
<span
class="px-3 py-1 bg-black/50 backdrop-blur-md text-white text-xs font-medium rounded-full"
>
{{ project.category }}
</span>
</div>
</div>
<div class="p-6">
<div class="flex flex-wrap gap-2 mb-3">
<span
v-for="tag in project.tags"
:key="tag"
class="px-2 py-1 bg-rose-50 dark:bg-rose-900/20 text-rose-600 dark:text-rose-300 text-xs font-medium rounded-lg"
>
{{ tag }}
</span>
</div>
<h3 class="text-xl font-bold mb-2 text-gray-900 dark:text-white group-hover:text-rose-600 dark:group-hover:text-rose-400 transition-colors">
{{ project.title }}
</h3>
<p class="text-gray-600 dark:text-gray-300 text-sm mb-4 line-clamp-2">
{{ project.description }}
</p>
<div class="flex justify-between items-center">
<div>
<p class="text-lg font-bold text-rose-600 dark:text-rose-400">{{ formatPrice(project.price) }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ formatDate(project.createdAt) }}</p>
</div>
<button class="w-10 h-10 rounded-full bg-rose-50 dark:bg-rose-900/20 text-rose-600 dark:text-rose-400 flex items-center justify-center hover:bg-rose-100 dark:hover:bg-rose-900/40 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="mt-16 flex justify-center" data-aos="fade-up">
<nav class="flex items-center space-x-2">
<button class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<button class="w-10 h-10 rounded-full bg-rose-600 text-white flex items-center justify-center">
1
</button>
<button class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
2
</button>
<button class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
3
</button>
<span class="text-gray-500 dark:text-gray-400">...</span>
<button class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
10
</button>
<button class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</nav>
</div>
</div>
</div>
</template>
</template>
<style scoped>
/* 添加轻奢风格的渐变背景和阴影效果 */
.bg-gradient-luxury {
background: linear-gradient(135deg, #f6f8fb 0%, #f0f4f8 100%);
}
/* 暗色模式下的轻奢风格 */
@media (prefers-color-scheme: dark) {
.bg-gradient-luxury {
background: linear-gradient(135deg, #1a1d23 0%, #111827 100%);
}
}
</style>