hflllll 1 week ago
parent
commit
1ac9910043
5 changed files with 423 additions and 278 deletions
  1. +3
    -3
      src/components/layout/Footer.vue
  2. +2
    -2
      src/components/layout/NavBar.vue
  3. +5
    -5
      src/router/index.ts
  4. +174
    -88
      src/views/Community.vue
  5. +239
    -180
      src/views/Technology.vue

+ 3
- 3
src/components/layout/Footer.vue View File

@ -25,8 +25,8 @@ const currentYear = new Date().getFullYear();
<!-- Logo & Description -->
<div class="wow animate__animated animate__fadeIn animate__duration-fast">
<div class="flex items-center mb-4">
<img src="/public/LOGO.png" alt="MOSE Logo" class="h-8 w-auto mr-2" />
<span class="text-xl font-bold text-primary-light">MOSE</span>
<img src="/public/real_logo.png" alt="MOSE Logo" class="h-8 w-auto mr-2" />
<!-- <span class="text-xl font-bold text-primary-light">MOSE</span> -->
</div>
<p class="text-sm mb-6">
{{ t('home.hero.subtitle') }}
@ -70,7 +70,7 @@ const currentYear = new Date().getFullYear();
<!-- Resources -->
<div class="wow animate__animated animate__fadeIn animate__delay-sm animate__duration-fast">
<h3 class="text-lg font-medium text-text mb-4">{{ t('nav.resources') }}</h3>
<h3 class="text-lg font-medium text-text mb-4">{{ t('nav.about') }}</h3>
<ul class="space-y-2">
<li class="wow animate__animated animate__fadeInUp animate__duration-fast"><router-link to="/resources/docs" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.docs') }}</router-link></li>
<li class="wow animate__animated animate__fadeInUp animate__delay-xs animate__duration-fast"><router-link to="/resources/github" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.github') }}</router-link></li>


+ 2
- 2
src/components/layout/NavBar.vue View File

@ -121,13 +121,13 @@ const emit = defineEmits(['changeLanguage']);
</router-link>
<!-- 动画演示 -->
<router-link
<!-- <router-link
to="/animations"
class="text-text-secondary hover:text-text transition-colors duration-200 animate__animated animate__fadeInDown animate__duration-fast animate__delay-lg"
:class="{ 'text-primary-light font-medium': $route.path === '/animations' }"
>
动画演示
</router-link>
</router-link> -->
<!-- Language Selector -->
<div class="relative animate__animated animate__fadeInDown animate__delay-lg animate__duration-fast">


+ 5
- 5
src/router/index.ts View File

@ -36,11 +36,11 @@ const routes = [
name: 'Technology',
component: () => import('@/views/Technology.vue')
},
{
path: '/animations',
name: 'Animations',
component: () => import('@/components/AnimationDemo.vue')
},
// {
// path: '/animations',
// name: 'Animations',
// component: () => import('@/components/AnimationDemo.vue')
// },
{
path: '/:pathMatch(.*)*',
name: 'NotFound',


+ 174
- 88
src/views/Community.vue View File

@ -3,6 +3,11 @@ import { useI18n } from 'vue-i18n';
import { ref, onMounted, computed } from 'vue';
import { Icon } from '@iconify/vue';
import { useConfig } from '@/utils/config';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation, Pagination } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import {
queryOfficialMediaList,
queryForumList,
@ -54,26 +59,46 @@ const isSubmitting = ref(false);
// ID
const currentForumId = ref<string | null>(null);
//
const currentCommunityPage = ref(0);
const communitiesPerPage = 1;
// Swiper
const swiperInstance = ref(null);
// Swiper
const swiperOptions = {
slidesPerView: 3,
spaceBetween: 40,
navigation: false,
pagination: false,
modules: [Navigation, Pagination],
breakpoints: {
320: {
slidesPerView: 1,
spaceBetween: 20
},
768: {
slidesPerView: 2,
spaceBetween: 30
},
1024: {
slidesPerView: 3,
spaceBetween: 40
}
}
};
//
const currentCommunities = computed(() => {
const start = currentCommunityPage.value * communitiesPerPage;
return communityList.value.slice(start, start + communitiesPerPage);
});
//
const showDetailModal = ref(false);
const selectedMessage = ref<MessageItem | null>(null);
//
const nextCommunity = () => {
const totalPages = Math.ceil(communityList.value.length / communitiesPerPage);
currentCommunityPage.value = (currentCommunityPage.value + 1) % totalPages;
//
const showMessageDetail = (message: MessageItem) => {
selectedMessage.value = message;
showDetailModal.value = true;
};
//
const prevCommunity = () => {
const totalPages = Math.ceil(communityList.value.length / communitiesPerPage);
currentCommunityPage.value = (currentCommunityPage.value - 1 + totalPages) % totalPages;
//
const closeMessageDetail = () => {
showDetailModal.value = false;
selectedMessage.value = null;
};
//
@ -300,10 +325,10 @@ onMounted(async() => {
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-text mb-6 wow animate__animated animate__fadeInDown animate__duration-fast">
{{ t('community.title') }}
{{ t('community.hero.title') }}
</h1>
<p class="text-lg md:text-xl text-text-secondary mb-8 wow animate__animated animate__fadeIn animate__delay-xs animate__duration-fast">
{{ t('community.subtitle') }}
{{ t('community.hero.subtitle') }}
</p>
</div>
</div>
@ -327,29 +352,76 @@ onMounted(async() => {
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div>
</div>
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div v-else class="space-y-6">
<div
v-for="message in messageList"
:key="message.id"
class="flex bg-background rounded-xl overflow-hidden shadow-card hover:shadow-lg transition-all duration-300 wow animate__animated animate__fadeInUp"
@click="goToMessage(message.id)"
>
<!-- 公告图片 -->
<div class="w-1/3">
<div class="w-1/4">
<img :src="message.image || '/LOGO.png'" :alt="message.title" class="w-full h-full object-cover" />
</div>
<!-- 公告内容 -->
<div class="w-2/3 p-5">
<h3 class="text-lg font-bold text-text mb-2 line-clamp-2">{{ message.title }}</h3>
<p class="text-text-secondary text-sm mb-3 line-clamp-2">{{ message.description }}</p>
<div class="flex items-center text-text-secondary text-xs">
<Icon icon="carbon:time" class="mr-1" />
<div class="w-3/4 p-6">
<h3
class="text-xl font-bold text-text mb-3 line-clamp-2 hover:text-primary hover:bg-primary/10 px-2 py-1 rounded transition-all duration-300 cursor-pointer hover:underline transform hover:scale-105"
@click="showMessageDetail(message)"
>
{{ message.title }}
</h3>
<p class="text-text-secondary text-base mb-4 line-clamp-3">{{ message.description }}</p>
<div class="flex items-center text-text-secondary text-sm">
<Icon icon="carbon:time" class="mr-2" />
<span>{{ formatDate(message.createTime) }}</span>
</div>
</div>
</div>
</div>
<!-- 消息详情弹窗 -->
<div
v-if="showDetailModal"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
@click="closeMessageDetail"
>
<div
class="bg-background rounded-xl max-w-2xl w-full max-h-[80vh] overflow-y-auto"
@click.stop
>
<!-- 弹窗头部 -->
<div class="p-6 border-b border-border">
<div class="flex justify-between items-start">
<h3 class="text-2xl font-bold text-text">{{ selectedMessage?.title }}</h3>
<button
@click="closeMessageDetail"
class="text-text-secondary hover:text-text transition-colors duration-300"
>
<Icon icon="carbon:close" class="h-6 w-6" />
</button>
</div>
<div class="flex items-center text-text-secondary text-sm mt-2">
<Icon icon="carbon:time" class="mr-2" />
<span>{{ formatDate(selectedMessage?.createTime) }}</span>
</div>
</div>
<!-- 弹窗内容 -->
<div class="p-6">
<div v-if="selectedMessage?.image" class="mb-6">
<img
:src="selectedMessage.image"
:alt="selectedMessage.title"
class="w-full h-64 object-cover rounded-lg"
/>
</div>
<div class="prose prose-lg max-w-none">
<div v-html="selectedMessage?.description"></div>
</div>
</div>
</div>
</div>
</div>
</section>
@ -364,65 +436,64 @@ onMounted(async() => {
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div>
</div>
<div v-else class="relative max-w-4xl mx-auto">
<div class="grid grid-cols-1 gap-8">
<div
v-for="(community, index) in currentCommunities"
:key="community.id"
class="bg-background rounded-xl overflow-hidden shadow-card"
<div v-else class="relative">
<div class="relative">
<Swiper
:slides-per-view="swiperOptions.slidesPerView"
:space-between="swiperOptions.spaceBetween"
:navigation="swiperOptions.navigation"
:pagination="false"
:modules="swiperOptions.modules"
:breakpoints="swiperOptions.breakpoints"
class="community-swiper"
@swiper="swiperInstance = $event"
>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<img :src="community.image || '/LOGO.png'" :alt="community.title" class="w-full h-full max-h-64 object-cover" />
<div class="p-6 flex flex-col justify-center">
<h3 class="text-xl font-bold text-text mb-3">{{ community.title }}</h3>
<p class="text-text-secondary mb-4">{{ community.description }}</p>
<a
:href="community.url || '#'"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center text-primary-light hover:text-primary-dark transition-colors"
>
<span>了解更多</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 ml-1" 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>
</a>
<SwiperSlide v-for="community in communityList" :key="community.id">
<div class="bg-background rounded-2xl overflow-hidden shadow-xl hover:shadow-2xl transition-all duration-500 h-full transform hover:scale-105">
<div class="flex flex-col h-full">
<div class="relative overflow-hidden">
<img
:src="community.image || '/LOGO.png'"
:alt="community.title"
class="w-full h-56 object-cover transition-transform duration-700 hover:scale-110"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent"></div>
</div>
<div class="p-8 flex-1 flex flex-col">
<h3 class="text-2xl font-bold text-text mb-4">{{ community.title }}</h3>
<p class="text-text-secondary mb-6 flex-1 leading-relaxed">{{ community.description }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 左右切换控制器 -->
<div class="absolute top-1/2 -left-5 transform -translate-y-1/2 z-10">
</SwiperSlide>
</Swiper>
<!-- 外部自定义导航按钮 -->
<button
@click="prevCommunity"
class="w-10 h-10 rounded-full bg-background-dark flex items-center justify-center hover:bg-primary hover:bg-opacity-20 transition-colors shadow-lg"
@click="swiperInstance?.slidePrev()"
class="absolute left-4 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/90 hover:bg-white rounded-full shadow-lg flex items-center justify-center transition-all duration-300 z-10 group"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-text-secondary" 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>
<Icon icon="carbon:chevron-left" class="h-6 w-6 text-primary group-hover:scale-110 transition-transform duration-300" />
</button>
</div>
<div class="absolute top-1/2 -right-5 transform -translate-y-1/2 z-10">
<button
@click="nextCommunity"
class="w-10 h-10 rounded-full bg-background-dark flex items-center justify-center hover:bg-primary hover:bg-opacity-20 transition-colors shadow-lg"
@click="swiperInstance?.slideNext()"
class="absolute right-4 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/90 hover:bg-white rounded-full shadow-lg flex items-center justify-center transition-all duration-300 z-10 group"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-text-secondary" 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>
<Icon icon="carbon:chevron-right" class="h-6 w-6 text-primary group-hover:scale-110 transition-transform duration-300" />
</button>
</div>
<!-- 指示 -->
<div class="flex justify-center mt-6 gap-2">
<!-- 外部自定义分页 -->
<div class="flex justify-center mt-8 gap-4">
<button
v-for="i in Math.ceil(communityList.length / communitiesPerPage)"
:key="i"
@click="currentCommunityPage = i - 1"
class="w-3 h-3 rounded-full transition-all duration-300"
:class="currentCommunityPage === i - 1 ? 'bg-primary' : 'bg-background-dark'"
v-for="(community, index) in communityList"
:key="index"
@click="swiperInstance?.slideTo(index)"
class="w-5 h-5 rounded-full transition-all duration-300 border-2 cursor-pointer"
:class="swiperInstance?.activeIndex === index
? 'bg-primary border-primary scale-125 shadow-lg'
: 'bg-white/50 border-white/70 hover:bg-white/80'"
></button>
</div>
</div>
@ -539,7 +610,7 @@ onMounted(async() => {
</div>
<button class="flex items-center text-primary-light hover:text-primary-dark transition-colors" @click="prepareComment(forum.id)">
<span>{{ t('community.forum.reply') }}</span>
<span>{{ t('community.forum.add_comment') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
</svg>
@ -552,7 +623,7 @@ onMounted(async() => {
<div class="border-t border-background-light">
<div class="p-6">
<h4 class="text-lg font-bold text-text mb-4 flex items-center justify-between">
<span>{{ t('community.forum.comments') }}</span>
<span>{{ t('community.forum.view_comments') }}</span>
<button class="text-text-secondary hover:text-primary transition-colors" @click="closeComment">
<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="M6 18L18 6M6 6l12 12" />
@ -581,7 +652,7 @@ onMounted(async() => {
</svg>
</div>
<div>
<h5 class="text-sm font-medium text-text">{{ comment.createBy || t('community.forum.anonymous') }}</h5>
<h5 class="text-sm font-medium text-text">{{ comment.createBy || t('community.forum.username') }}</h5>
<p class="text-xs text-text-secondary">{{ formatDate(comment.createTime) }}</p>
</div>
</div>
@ -594,7 +665,7 @@ onMounted(async() => {
<div class="bg-background-dark rounded-lg p-4">
<textarea
v-model="newMessage.content"
:placeholder="t('community.forum.comment_placeholder')"
:placeholder="t('community.forum.comment')"
class="w-full bg-background border border-background-light rounded-lg p-3 text-text-secondary resize-none focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
rows="3"
></textarea>
@ -625,24 +696,21 @@ onMounted(async() => {
</section>
<!-- 3. 信息公示 Section -->
<section class="py-16 px-6 md:px-12 lg:px-24" :style="{ backgroundImage: `url(${getConfigImage('com_mes_bg')})` }">
<!-- <section class="py-16 px-6 md:px-12 lg:px-24" :style="{ backgroundImage: `url(${getConfigImage('com_mes_bg')})` }">
<div class="container mx-auto">
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp">
{{ t('community.announcements.title') }}
</h2>
<!-- 加载中状态 -->
<div v-if="messageLoading" class="flex justify-center items-center py-12">
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
</div>
<!-- 无数据状态 -->
<div v-else-if="messageList.length === 0" class="text-center py-10">
<Icon icon="carbon:no-content" class="mx-auto mb-4" width="48" height="48" />
<p class="text-text-secondary">暂无信息公示数据</p>
</div>
<!-- 信息公示列表 -->
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto mt-8">
<div
v-for="message in messageList"
@ -650,7 +718,6 @@ onMounted(async() => {
class="bg-background-light rounded-xl p-6 shadow-card hover:shadow-lg transition-all duration-300"
>
<div class="flex items-start gap-4">
<!-- 如果有图片则显示 -->
<div v-if="message.image" class="w-16 h-16 rounded-lg overflow-hidden flex-shrink-0">
<img :src="message.image" :alt="message.title" class="w-full h-full object-cover" />
</div>
@ -667,27 +734,23 @@ onMounted(async() => {
</div>
</div>
</div>
</section>
</section> -->
<!-- 4. 社区风采 Section -->
<section class="py-16 px-6 md:px-12 lg:px-24 bg-background-light" :style="{ backgroundImage: `url(${getConfigImage('com_show_bg')})` }">
<div class="container mx-auto">
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp">
{{ t('community.highlights.title') }}
</h2>
<!-- 加载中状态 -->
<div v-if="communityLoading" class="flex justify-center items-center py-12">
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
</div>
<!-- 无数据状态 -->
<div v-else-if="communityList.length === 0" class="text-center py-10">
<Icon icon="carbon:no-content" class="mx-auto mb-4" width="48" height="48" />
<p class="text-text-secondary">暂无社区活动数据</p>
</div>
<!-- 社区活动列表 -->
<div v-else class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
<div
v-for="community in communityList"
@ -728,4 +791,27 @@ onMounted(async() => {
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Swiper分页器样式 */
:deep(.swiper-pagination-bullet) {
width: 12px;
height: 12px;
background: rgba(255, 255, 255, 0.5);
opacity: 1;
border: 2px solid rgba(255, 255, 255, 0.8);
transition: all 0.3s ease;
}
:deep(.swiper-pagination-bullet-active) {
background: var(--color-primary);
border-color: var(--color-primary);
transform: scale(1.3);
box-shadow: 0 0 10px rgba(var(--color-primary-rgb), 0.5);
}
:deep(.swiper-pagination) {
position: relative;
bottom: 0;
margin-top: 20px;
}
</style>

+ 239
- 180
src/views/Technology.vue View File

@ -7,10 +7,12 @@ import EcosystemIntegrationModule from '@/components/technology/EcosystemIntegra
import AppListModule from '@/components/ecosystem/AppListModule.vue';
import { useI18n } from 'vue-i18n';
import { useConfig } from '@/utils/config';
// Swiper使
const { getConfigImage } = useConfig();
import { queryTechnologyList } from '@/api/modules/technology';
import { queryAppList } from '@/api/modules/ecosystem';
import { querySummaryList } from '@/api/modules/config';
import { useSummary } from '@/utils/config';
@ -21,8 +23,6 @@ const tecDesList = computed(() => {
return getSummaryDescription('config_structural_of_technology').split('\n');
});
const { t } = useI18n();
//
@ -71,9 +71,41 @@ const architectures = [
}
];
//
const technologies = [
// API
const technologies = ref([]);
//
const fetchTechnologies = async () => {
try {
const result = await queryTechnologyList({
pageSize: 10,
pageNo: 1
});
if (result && result.length > 0) {
//
technologies.value = result.map((item, index) => {
const colors = ['primary', 'secondary', 'accent', 'primary'];
const icons = ['carbon:security', 'carbon:growth', 'carbon:currency', 'carbon:bridge'];
return {
...item,
color: colors[index % colors.length],
icon: icons[index % icons.length]
};
});
} else {
// 使
technologies.value = defaultTechnologies;
}
} catch (error) {
console.error('获取核心技术列表失败:', error);
technologies.value = defaultTechnologies;
}
};
// API使
const defaultTechnologies = [
{
id: '1',
title: '技术壁垒',
description: 'MOSE采用创新的多层零知识证明协议,确保交易隐私性的同时保持可验证性和安全性。该技术已申请多项国际专利,形成独特的技术壁垒。',
icon: 'carbon:security',
@ -81,6 +113,7 @@ const technologies = [
image: '/LOGO.png' //
},
{
id: '2',
title: '生态优势',
description: '基于创新的跨链技术,MOSE能够无缝连接多种主流区块链,使用户可以在不同链上自由转移和交易资产,同时保持完全隐私。',
icon: 'carbon:growth',
@ -88,6 +121,7 @@ const technologies = [
image: '/LOGO.png' //
},
{
id: '3',
title: '混币器',
description: 'MOSE独创的"混币器"技术,将用户闲置的资产通过智能合约自动参与DeFi流动性挖矿,为用户创造被动收益,同时增强整个生态系统的流动性。',
icon: 'carbon:currency',
@ -95,6 +129,7 @@ const technologies = [
image: '/LOGO.png' //
},
{
id: '4',
title: '跨链桥',
description: 'MOSE跨链桥采用创新的多重签名和状态验证机制,实现资产在不同链间的安全高效转移,并保持交易隐私,解决了传统跨链桥容易成为黑客攻击目标的问题。',
icon: 'carbon:bridge',
@ -171,6 +206,65 @@ const apps = reactive([
}
]);
// API
const appList = ref([]);
//
const fetchAppList = async () => {
try {
const result = await queryAppList({
pageSize: 10,
pageNo: 1
});
if (result && result.length > 0) {
appList.value = result;
} else {
appList.value = apps;
}
} catch (error) {
console.error('获取应用列表失败:', error);
appList.value = apps;
}
};
//
const currentSlide = ref(0);
const autoplayInterval = ref(null);
//
const nextSlide = () => {
if (appList.value.length > 0) {
currentSlide.value = (currentSlide.value + 1) % appList.value.length;
}
};
//
const prevSlide = () => {
if (appList.value.length > 0) {
currentSlide.value = (currentSlide.value - 1 + appList.value.length) % appList.value.length;
}
};
//
const goToSlide = (index: number) => {
currentSlide.value = index;
};
//
const startAutoplay = () => {
autoplayInterval.value = setInterval(() => {
nextSlide();
}, 5000);
};
//
const stopAutoplay = () => {
if (autoplayInterval.value) {
clearInterval(autoplayInterval.value);
autoplayInterval.value = null;
}
};
// Swiper
let swiper = null;
@ -192,8 +286,14 @@ onMounted(() => {
console.error('Failed to initialize WOW.js:', error);
}
// Swiper
initSwiper();
//
fetchTechnologies();
//
fetchAppList();
//
startAutoplay();
});
// Swiper
@ -303,90 +403,102 @@ const initSwiper = () => {
</div>
</section>
<!-- 核心技术模块 - 单行布局 带底图 -->
<section id="innovation" class="py-16 px-6 md:px-12 lg:px-24" :style="{ backgroundImage: `url(${getConfigImage('tec_created_bg')})` }">
<div class="container mx-auto">
<h2 class="text-3xl md:text-4xl font-bold text-text mb-12 text-center wow animate__animated animate__fadeInUp animate__duration-fast">
核心技术
</h2>
<!-- 核心技术模块 - 全屏垂直布局 -->
<section id="innovation" class="relative">
<!-- 核心技术卡片 - 全屏垂直布局 -->
<div
v-for="(tech, index) in technologies"
:key="tech.id"
class="relative w-full h-screen flex items-center justify-center overflow-hidden wow animate__animated animate__fadeInUp"
:class="[`animate__delay-${index}00ms`]"
>
<!-- 背景图片 -->
<div class="absolute inset-0 w-full h-full">
<img :src="tech.image" :alt="tech.title" class="w-full h-full object-cover" />
<div
class="absolute inset-0"
:class="{
'bg-gradient-to-r from-indigo-900/90 via-indigo-900/50 to-transparent': tech.color === 'primary' && index % 2 === 0,
'bg-gradient-to-l from-indigo-900/90 via-indigo-900/50 to-transparent': tech.color === 'primary' && index % 2 === 1,
'bg-gradient-to-r from-emerald-900/90 via-emerald-900/50 to-transparent': tech.color === 'secondary' && index % 2 === 0,
'bg-gradient-to-l from-emerald-900/90 via-emerald-900/50 to-transparent': tech.color === 'secondary' && index % 2 === 1,
'bg-gradient-to-r from-amber-900/90 via-amber-900/50 to-transparent': tech.color === 'accent' && index % 2 === 0,
'bg-gradient-to-l from-amber-900/90 via-amber-900/50 to-transparent': tech.color === 'accent' && index % 2 === 1,
'bg-gradient-to-r from-blue-900/90 via-blue-900/50 to-transparent': tech.color === 'primary' && index === 3 && index % 2 === 0,
'bg-gradient-to-l from-blue-900/90 via-blue-900/50 to-transparent': tech.color === 'primary' && index === 3 && index % 2 === 1
}"
></div>
</div>
<!-- 核心技术卡片 - 一行一个 -->
<div class="space-y-8">
<!-- 内容 - 左右交替布局 -->
<div class="relative z-10 w-full max-w-7xl mx-auto px-8 md:px-12 lg:px-24 flex flex-col md:flex-row items-center">
<!-- 左侧内容 (偶数索引) 右侧内容 (奇数索引) -->
<div
v-for="(tech, index) in technologies"
:key="index"
class="relative overflow-hidden rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 group wow animate__animated animate__fadeInUp"
:class="[`animate__delay-${index}00ms`]"
class="md:w-1/2 mb-8 md:mb-0"
:class="{ 'order-1': index % 2 === 0, 'order-2': index % 2 === 1 }"
>
<!-- 背景图片 -->
<div class="absolute inset-0 w-full h-full">
<img :src="tech.image" :alt="tech.title" class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" />
<div
class="absolute inset-0"
:class="{
'bg-gradient-to-r from-indigo-900/90 via-indigo-900/50 to-transparent': tech.color === 'primary',
'bg-gradient-to-r from-emerald-900/90 via-emerald-900/50 to-transparent': tech.color === 'secondary',
'bg-gradient-to-r from-amber-900/90 via-amber-900/50 to-transparent': tech.color === 'accent',
'bg-gradient-to-r from-blue-900/90 via-blue-900/50 to-transparent': tech.color === 'primary' && index === 3
}"
></div>
<div class="flex items-center mb-6">
<div class="w-16 h-16 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center mr-4">
<Icon :icon="tech.icon" class="h-8 w-8" :class="`text-${tech.color}`" />
</div>
<h3 class="text-3xl md:text-4xl lg:text-5xl font-bold text-white">{{ tech.title }}</h3>
</div>
<div class="text-white/90 text-lg md:text-xl leading-relaxed mb-6" v-html="tech.description">
</div>
<!-- 内容 -->
<div class="relative p-8 md:p-12 min-h-[300px] flex flex-col md:flex-row items-center">
<!-- 左侧内容 -->
<div class="md:w-1/2 mb-6 md:mb-0">
<div class="flex items-center mb-6">
<div class="w-16 h-16 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center mr-4">
<Icon :icon="tech.icon" class="h-8 w-8" :class="`text-${tech.color}`" />
</div>
<h3 class="text-3xl md:text-4xl font-bold text-white">{{ tech.title }}</h3>
</div>
<p class="text-white/90 text-lg md:text-xl leading-relaxed">
{{ tech.description }}
</p>
<!-- 按钮 -->
<div class="mt-8">
<button class="px-6 py-3 bg-white/20 hover:bg-white/30 backdrop-blur-sm rounded-full text-white text-base flex items-center gap-2 transition-all duration-300 border border-white/30">
技术详情
<Icon icon="carbon:arrow-right" />
</button>
</div>
</div>
<!-- 按钮 -->
<div>
<button class="px-6 py-3 bg-white/20 hover:bg-white/30 backdrop-blur-sm rounded-full text-white text-base flex items-center gap-2 transition-all duration-300 border border-white/30">
了解更多
<Icon icon="carbon:arrow-right" />
</button>
</div>
</div>
<!-- 右侧装饰元素 (偶数索引) 左侧装饰元素 (奇数索引) -->
<div
class="md:w-1/2 md:px-12 flex justify-center"
:class="{
'order-2 md:justify-end': index % 2 === 0,
'order-1 md:justify-start': index % 2 === 1
}"
>
<div
class="w-48 h-48 md:w-64 md:h-64 rounded-full border-2 border-white/20 flex items-center justify-center relative overflow-hidden"
:class="{
'bg-indigo-900/20': tech.color === 'primary',
'bg-emerald-900/20': tech.color === 'secondary',
'bg-amber-900/20': tech.color === 'accent',
'bg-blue-900/20': tech.color === 'primary' && index === 3
}"
>
<!-- 内圈 -->
<div class="w-32 h-32 md:w-40 md:h-40 rounded-full border border-white/40 absolute animate-spin-slow"></div>
<!-- 右侧装饰元素 -->
<div class="md:w-1/2 md:pl-8 flex justify-center md:justify-end">
<div
class="w-48 h-48 md:w-64 md:h-64 rounded-full border-2 border-white/20 flex items-center justify-center relative overflow-hidden"
:class="{
'bg-indigo-900/20': tech.color === 'primary',
'bg-emerald-900/20': tech.color === 'secondary',
'bg-amber-900/20': tech.color === 'accent',
'bg-blue-900/20': tech.color === 'primary' && index === 3
}"
>
<!-- 内圈 -->
<div class="w-32 h-32 md:w-40 md:h-40 rounded-full border border-white/40 absolute animate-spin-slow"></div>
<!-- 技术图标 -->
<div class="w-20 h-20 md:w-24 md:h-24 rounded-full bg-white/10 backdrop-blur-md flex items-center justify-center">
<Icon :icon="tech.icon" class="h-10 w-10 md:h-12 md:w-12" :class="`text-${tech.color}`" />
</div>
<!-- 装饰点 -->
<div class="absolute top-1/4 right-1/4 w-3 h-3 rounded-full bg-white"></div>
<div class="absolute bottom-1/4 left-1/4 w-3 h-3 rounded-full bg-white"></div>
</div>
<!-- 技术图标 -->
<div class="w-20 h-20 md:w-24 md:h-24 rounded-full bg-white/10 backdrop-blur-md flex items-center justify-center">
<Icon :icon="tech.icon" class="h-10 w-10 md:h-12 md:w-12" :class="`text-${tech.color}`" />
</div>
</div>
<!-- 序号装饰 -->
<div class="absolute bottom-4 right-8">
<span class="text-8xl font-bold text-white opacity-10">0{{ index + 1 }}</span>
<!-- 装饰点 -->
<div class="absolute top-1/4 right-1/4 w-3 h-3 rounded-full bg-white"></div>
<div class="absolute bottom-1/4 left-1/4 w-3 h-3 rounded-full bg-white"></div>
</div>
</div>
</div>
<!-- 序号装饰 -->
<div
class="absolute bottom-8"
:class="{ 'right-12': index % 2 === 0, 'left-12': index % 2 === 1 }"
>
<span class="text-9xl font-bold text-white opacity-10">0{{ index + 1 }}</span>
</div>
<!-- 滚动提示 -->
<div class="absolute bottom-8 left-1/2 transform -translate-x-1/2 text-white/60 animate-bounce">
<Icon icon="carbon:arrow-down" class="h-6 w-6" />
</div>
</div>
</section>
@ -398,83 +510,63 @@ const initSwiper = () => {
</h2>
<div class="relative wow animate__animated animate__fadeIn animate__duration-fast">
<!-- Swiper轮播 -->
<div class="swiper-container">
<div class="swiper-wrapper">
<!-- 应用卡片 -->
<!-- 简单轮播 -->
<div class="relative overflow-hidden rounded-2xl shadow-lg h-96">
<div class="relative w-full h-full">
<div
v-for="(app, index) in apps"
v-for="(app, index) in appList"
:key="app.id"
class="swiper-slide"
class="absolute inset-0 transition-opacity duration-500"
:class="{ 'opacity-100': index === currentSlide, 'opacity-0': index !== currentSlide }"
>
<div class="app-card relative overflow-hidden rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 mx-4 my-8 h-[500px]">
<!-- 背景渐变 -->
<div class="absolute inset-0 bg-gradient-to-br" :class="app.color"></div>
<!-- 装饰图形 -->
<div class="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full blur-3xl transform translate-x-1/2 -translate-y-1/2"></div>
<div class="absolute bottom-0 left-0 w-48 h-48 bg-black/10 rounded-full blur-3xl transform -translate-x-1/2 translate-y-1/2"></div>
<!-- 内容 -->
<div class="relative p-8 flex flex-col h-full">
<!-- 应用图标 -->
<div class="mb-6 flex justify-center">
<div class="w-24 h-24 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-4 border-white/30">
<Icon :icon="app.icon" class="h-12 w-12 text-white" />
</div>
</div>
<!-- 应用名称 -->
<h3 class="text-3xl font-bold text-white text-center mb-4">{{ app.name }}</h3>
<!-- 应用描述 -->
<p class="text-white/90 text-center text-lg mb-8">
{{ app.description }}
</p>
<!-- 装饰线 -->
<div class="w-24 h-1 bg-white/30 mx-auto mb-8"></div>
<!-- 功能列表 -->
<div class="space-y-4 mt-auto">
<div class="flex items-center text-white">
<Icon icon="carbon:checkmark" class="h-5 w-5 mr-3" />
<span>多链支持</span>
</div>
<div class="flex items-center text-white">
<Icon icon="carbon:checkmark" class="h-5 w-5 mr-3" />
<span>隐私保护</span>
</div>
<div class="flex items-center text-white">
<Icon icon="carbon:checkmark" class="h-5 w-5 mr-3" />
<span>安全加密</span>
</div>
</div>
<!-- 按钮 -->
<div class="mt-8 flex justify-center">
<button class="px-6 py-3 bg-white text-primary font-medium rounded-full hover:bg-opacity-90 transition-all duration-300 flex items-center gap-2">
立即体验
<Icon icon="carbon:launch" />
</button>
</div>
<!-- 应用编号 -->
<div class="absolute top-6 right-6 bg-white/20 backdrop-blur-sm w-8 h-8 rounded-full flex items-center justify-center">
<span class="text-white font-bold">{{ app.id }}</span>
</div>
<img
:src="app.image"
:alt="app.title"
class="w-full h-full object-cover"
/>
<!-- 应用信息覆盖层 -->
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent flex items-end">
<div class="p-8 text-white">
<h3 class="text-2xl font-bold mb-2">{{ app.title }}</h3>
<p class="text-white/90 mb-4">{{ app.description }}</p>
<a
:href="app.link"
target="_blank"
class="inline-flex items-center gap-2 bg-white/20 hover:bg-white/30 backdrop-blur-sm rounded-full text-white text-sm px-4 py-2 transition-all duration-300 border border-white/30"
>
立即体验
<Icon icon="carbon:launch" />
</a>
</div>
</div>
</div>
</div>
<!-- 导航按钮 -->
<button
@click="prevSlide"
class="absolute left-4 top-1/2 transform -translate-y-1/2 w-10 h-10 rounded-full bg-black bg-opacity-30 hover:bg-opacity-50 text-white flex items-center justify-center transition-all duration-300"
>
<Icon icon="carbon:chevron-left" />
</button>
<button
@click="nextSlide"
class="absolute right-4 top-1/2 transform -translate-y-1/2 w-10 h-10 rounded-full bg-black bg-opacity-30 hover:bg-opacity-50 text-white flex items-center justify-center transition-all duration-300"
>
<Icon icon="carbon:chevron-right" />
</button>
<!-- 分页器 -->
<div class="swiper-pagination mt-8"></div>
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2">
<button
v-for="(app, index) in appList"
:key="index"
@click="goToSlide(index)"
class="w-3 h-3 rounded-full transition-all duration-300"
:class="index === currentSlide ? 'bg-white' : 'bg-white bg-opacity-50'"
></button>
</div>
</div>
<!-- 导航按钮 -->
<div class="swiper-button-prev !text-primary after:!text-lg"></div>
<div class="swiper-button-next !text-primary after:!text-lg"></div>
</div>
</div>
@ -562,37 +654,4 @@ const initSwiper = () => {
background: var(--color-primary);
transform: scale(1.2);
}
:deep(.swiper-button-prev),
:deep(.swiper-button-next) {
color: var(--color-primary);
background: rgba(255, 255, 255, 0.3);
width: 50px;
height: 50px;
border-radius: 50%;
backdrop-filter: blur(4px);
transition: all 0.3s;
}
:deep(.swiper-button-prev:hover),
:deep(.swiper-button-next:hover) {
background: rgba(255, 255, 255, 0.5);
}
:deep(.swiper-button-prev:after),
:deep(.swiper-button-next:after) {
font-size: 20px;
font-weight: bold;
}
/* 卡片悬停效果 */
.app-card {
transition: all 0.5s;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
}
.app-card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}
</style>

Loading…
Cancel
Save