Files
spa-view/src/views/frontend/Detail.vue
2025-04-24 20:47:00 +08:00

417 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
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 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', 'TypeScript', 'MongoDB', 'Docker'],
author: '技术团队',
price: '¥ 29,999',
description: '基于微服务架构的电商平台包含商品管理、订单系统、支付对接等模块。采用前后端分离设计提供完整的API文档和部署方案。系统具有高度可扩展性和定制化能力适合中小型企业快速搭建自有电商平台。',
features: [
'响应式设计,支持多端访问',
'完整的商品管理系统',
'订单处理和物流跟踪',
'多种支付方式集成',
'会员管理和积分系统',
'数据分析和报表功能'
],
technicalStack: ['前端Vue3 + TypeScript', '后端PHP【Laravel 12.x】 + 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: 'http://d-jy.nailaoyun.cn//storage/video//20250327/2cc1abf9bd69410ce7c69660daf54260.mp4',
wechatQR: '/assets/qr-code.png'
}
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="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>
<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>
<!-- 项目信息卡片 -->
<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>
<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="微信二维码"-->
<!-- />-->
<img
src="@/assets/qr-code.png"
class="w-48 h-68 object-cover rounded-lg border border-gray-200 dark:border-gray-700"
alt="微信二维码"
/>
</div>
</div>
</div>
</div>
</div>
<!-- 相关项目 -->
<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>
</section>
</div>
</div>
</template>
<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;
}
: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>