国外MOSE官网
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

817 lines
32 KiB

<script setup lang="ts">
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,
queryCommentsList,
queryMessageList,
queryCommunityList,
addComments,
type OfficialMediaItem,
type ForumItem,
type CommentItem,
type MessageItem,
type CommunityItem
} from '@/api/modules';
const { getConfigImage } = useConfig();
const { t } = useI18n();
// 社交媒体账号数据
const socialMediaAccounts = ref<OfficialMediaItem[]>([]);
const socialMediaLoading = ref(true);
// 论坛信息数据
const forumList = ref<ForumItem[]>([]);
const forumLoading = ref(true);
// 评论信息数据
const commentsMap = ref<Record<string, CommentItem[]>>({});
const commentsLoading = ref(true);
// 信息公示数据
const messageList = ref<MessageItem[]>([]);
const messageLoading = ref(true);
// 社区活动数据
const communityList = ref<CommunityItem[]>([]);
const communityLoading = ref(true);
// 新留言
const newMessage = ref({
forumId: null as string | null,
content: '',
createBy: ''
});
// 是否正在提交
const isSubmitting = ref(false);
// 当前查看的帖子ID
const currentForumId = ref<string | null>(null);
// 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 showDetailModal = ref(false);
const selectedMessage = ref<MessageItem | null>(null);
// 显示消息详情弹窗
const showMessageDetail = (message: MessageItem) => {
selectedMessage.value = message;
showDetailModal.value = true;
};
// 关闭消息详情弹窗
const closeMessageDetail = () => {
showDetailModal.value = false;
selectedMessage.value = null;
};
// 跳转到公告详情
const goToMessage = (id: string) => {
console.log('查看公告详情:', id);
// 跳转到公告详情页面实现
};
// 格式化日期
const formatDate = (dateString: string) => {
if (!dateString) return '';
const date = new Date(dateString);
return new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date);
};
// 加载社交媒体数据
const loadSocialMedia = async () => {
try {
socialMediaLoading.value = true;
const data = await queryOfficialMediaList({
pageSize: 10,
pageNo: 1
});
socialMediaAccounts.value = data;
} catch (error) {
console.error('加载社交媒体数据失败:', error);
} finally {
socialMediaLoading.value = false;
}
};
// 加载论坛数据
const loadForum = async () => {
try {
forumLoading.value = true;
const data = await queryForumList({
pageSize: 10,
pageNo: 1
});
forumList.value = data;
// 为每个论坛加载对应的评论
await Promise.all(data.map(forum => loadComments(forum.id)));
} catch (error) {
console.error('加载论坛数据失败:', error);
} finally {
forumLoading.value = false;
}
};
// 加载评论数据
const loadComments = async (forumId: string) => {
try {
commentsLoading.value = true;
const data = await queryCommentsList({
forumId
});
commentsMap.value[forumId] = data;
} catch (error) {
console.error(`加载论坛${forumId}的评论数据失败:`, error);
} finally {
commentsLoading.value = false;
}
};
// 加载信息公示数据
const loadMessages = async () => {
try {
messageLoading.value = true;
const data = await queryMessageList({
pageSize: 10,
pageNo: 1
});
messageList.value = data;
} catch (error) {
console.error('加载信息公示数据失败:', error);
} finally {
messageLoading.value = false;
}
};
// 加载社区数据
const loadCommunity = async () => {
try {
communityLoading.value = true;
const data = await queryCommunityList({
pageSize: 6,
pageNo: 1
});
communityList.value = data;
} catch (error) {
console.error('加载社区数据失败:', error);
} finally {
communityLoading.value = false;
}
};
// 提交留言
const submitComment = async (forumId: string) => {
if (newMessage.value.content) {
isSubmitting.value = true;
try {
await addComments({
forumId: forumId,
content: newMessage.value.content
});
// 重新加载评论
await loadComments(forumId);
// 重置表单
newMessage.value.createBy = '';
newMessage.value.content = '';
newMessage.value.forumId = null;
} catch (error) {
console.error('提交评论失败:', error);
} finally {
isSubmitting.value = false;
}
}
};
// 准备留言
const prepareComment = (forumId: string) => {
// 记录当前滚动位置
const scrollPosition = window.scrollY;
// 设置当前查看的帖子ID
currentForumId.value = forumId;
newMessage.value.forumId = forumId;
// 使用setTimeout确保DOM更新后再恢复滚动位置
setTimeout(() => {
window.scrollTo({
top: scrollPosition,
behavior: 'auto'
});
}, 0);
};
// 关闭评论
const closeComment = () => {
// 记录当前滚动位置
const scrollPosition = window.scrollY;
// 关闭评论区
currentForumId.value = null;
// 使用setTimeout确保DOM更新后再恢复滚动位置
setTimeout(() => {
window.scrollTo({
top: scrollPosition,
behavior: 'auto'
});
}, 0);
};
// 获取特定论坛的评论
const getComments = (forumId: string): CommentItem[] => {
return commentsMap.value[forumId] || [];
};
// 计算帖子发布时间
const getTimeAgo = (timestamp: string) => {
const now = new Date();
const postTime = new Date(timestamp);
const diffTime = Math.abs(now.getTime() - postTime.getTime());
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays < 1) {
return t('community.time.today');
} else if (diffDays === 1) {
return t('community.time.yesterday');
} else if (diffDays < 7) {
return t('community.time.days_ago', { days: diffDays });
} else {
return new Date(timestamp).toLocaleDateString();
}
};
// 根据平台名称获取图标
const getSocialIcon = (title: string) => {
const lowerTitle = title.toLowerCase();
if (lowerTitle.includes('twitter') || lowerTitle.includes('x')) {
return 'mdi:twitter';
} else if (lowerTitle.includes('telegram')) {
return 'mdi:telegram';
} else if (lowerTitle.includes('discord')) {
return 'mdi:discord';
} else if (lowerTitle.includes('medium')) {
return 'mdi:medium';
} else if (lowerTitle.includes('github')) {
return 'mdi:github';
} else if (lowerTitle.includes('reddit')) {
return 'mdi:reddit';
} else if (lowerTitle.includes('facebook')) {
return 'mdi:facebook';
} else if (lowerTitle.includes('instagram')) {
return 'mdi:instagram';
} else {
return 'mdi:web';
}
};
onMounted(async() => {
await Promise.all([
loadSocialMedia(),
loadForum(),
loadMessages(),
loadCommunity()
]);
});
</script>
<template>
<div class="bg-background min-h-screen">
<!-- Hero Section -->
<section class="relative py-24 px-6 md:px-12 lg:px-24 bg-background-dark overflow-hidden">
<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.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.hero.subtitle') }}
</p>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-10">
<div class="absolute -top-24 -left-24 w-64 h-64 rounded-full bg-primary-light blur-3xl wow animate__animated animate__pulse animate__infinite"></div>
<div class="absolute top-1/2 right-0 w-80 h-80 rounded-full bg-secondary blur-3xl wow animate__animated animate__pulse animate__infinite animate__delay-sm"></div>
<div class="absolute -bottom-24 left-1/3 w-72 h-72 rounded-full bg-accent blur-3xl wow animate__animated animate__pulse animate__infinite animate__delay-md"></div>
</div>
</section>
<!-- 官方公告 Section -->
<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-2xl md:text-3xl font-bold text-text mb-8 text-center wow animate__animated animate__fadeInUp animate__duration-fast">
官方公告
</h2>
<div v-if="messageLoading" class="flex justify-center py-10">
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div>
</div>
<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"
>
<!-- 公告图片 -->
<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-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>
<!-- 社区风采 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-2xl md:text-3xl font-bold text-text mb-8 text-center wow animate__animated animate__fadeInUp animate__duration-fast">
社区风采
</h2>
<div v-if="communityLoading" class="flex justify-center py-10">
<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">
<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"
>
<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>
</SwiperSlide>
</Swiper>
<!-- 外部自定义导航按钮 -->
<button
@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"
>
<Icon icon="carbon:chevron-left" class="h-6 w-6 text-primary group-hover:scale-110 transition-transform duration-300" />
</button>
<button
@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"
>
<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-8 gap-4">
<button
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>
</div>
</section>
<!-- 社交媒体账号 Section -->
<section class="py-16 px-6 md:px-12 lg:px-24" :style="{ backgroundImage: `url(${getConfigImage('com_media_bg')})` }">
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-8 text-center wow animate__animated animate__fadeInUp animate__duration-fast">
{{ t('community.social_media.title') }}
</h2>
<div v-if="socialMediaLoading" class="flex justify-center py-10">
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div>
</div>
<div v-else-if="socialMediaAccounts.length === 0" class="text-center py-10 text-text-secondary">
{{ t('community.social_media.no_accounts') }}
</div>
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div
v-for="account in socialMediaAccounts"
:key="account.id"
class="bg-background rounded-xl p-6 shadow-card hover:shadow-lg transition-all duration-300 wow animate__animated animate__fadeInUp"
>
<div class="flex items-center mb-4">
<div class="w-12 h-12 rounded-full bg-primary bg-opacity-10 flex items-center justify-center mr-4">
<Icon :icon="getSocialIcon(account.title)" class="h-6 w-6 text-primary" />
</div>
<div>
<h3 class="text-lg font-bold text-text">{{ account.title }}</h3>
<p class="text-text-secondary text-sm">{{ account.username }}</p>
</div>
</div>
<p class="text-text-secondary mb-4" v-html="account.description"></p>
<a
:href="account.url"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center text-primary-light hover:text-primary-dark transition-colors"
>
<span>{{ t('community.social_media.follow_us') }}</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="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
</a>
</div>
</div>
</div>
</section>
<!-- 社区论坛 Section -->
<section class="py-16 px-6 md:px-12 lg:px-24 bg-background-light" :style="{ backgroundImage: `url(${getConfigImage('com_forum_bg')})` }" >
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-8 text-center wow animate__animated animate__fadeInUp animate__duration-fast">
{{ t('community.forum.title') }}
</h2>
<div v-if="forumLoading" class="flex justify-center py-10">
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div>
</div>
<div v-else-if="forumList.length === 0" class="text-center py-10 text-text-secondary">
{{ t('community.forum.no_topics') }}
</div>
<div v-else class="space-y-6">
<div
v-for="forum in forumList"
:key="forum.id"
class="bg-background rounded-xl shadow-card overflow-hidden wow animate__animated animate__fadeInUp"
>
<!-- 帖子内容 -->
<div class="p-6">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary bg-opacity-10 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
</svg>
</div>
<div>
<h3 class="text-lg font-bold text-text">{{ forum.title }}</h3>
<div class="flex items-center text-text-secondary text-sm">
<span>{{ forum.createBy }}</span>
<span class="mx-2">•</span>
<span>{{ formatDate(forum.createTime) }}</span>
</div>
</div>
</div>
<div class="mb-4">
<p class="text-text-secondary" v-html="forum.content"></p>
</div>
<div class="flex justify-between items-center">
<div class="flex items-center space-x-4">
<button class="flex items-center text-text-secondary hover:text-primary transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5" />
</svg>
<span>{{ forum.likeCount || 0 }}</span>
</button>
<button class="flex items-center text-text-secondary hover:text-primary transition-colors" @click="prepareComment(forum.id)">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
</svg>
<span>{{ getComments(forum.id).length }}</span>
</button>
</div>
<button class="flex items-center text-primary-light hover:text-primary-dark transition-colors" @click="prepareComment(forum.id)">
<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>
</button>
</div>
</div>
<!-- 评论区 -->
<div v-if="currentForumId === forum.id">
<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.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" />
</svg>
</button>
</h4>
<div v-if="commentsLoading" class="flex justify-center py-4">
<div class="animate-spin rounded-full h-6 w-6 border-t-2 border-b-2 border-primary"></div>
</div>
<div v-else-if="getComments(forum.id).length === 0" class="text-center py-4 text-text-secondary">
{{ t('community.forum.no_comments') }}
</div>
<div v-else class="space-y-4 mb-6">
<div
v-for="comment in getComments(forum.id)"
:key="comment.id"
class="bg-background-dark rounded-lg p-4"
>
<div class="flex items-center mb-2">
<div class="w-8 h-8 rounded-full bg-primary bg-opacity-10 flex items-center justify-center mr-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
</div>
<div>
<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>
<p class="text-text-secondary" v-html="comment.content"></p>
</div>
</div>
<!-- 评论表单 -->
<div class="bg-background-dark rounded-lg p-4">
<textarea
v-model="newMessage.content"
: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>
<div class="flex justify-end mt-3">
<button
@click="submitComment(forum.id)"
:disabled="!newMessage.content || isSubmitting"
class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<span v-if="isSubmitting">
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
{{ t('community.forum.submitting') }}
</span>
<span v-else>{{ t('community.forum.submit') }}</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 3. 信息公示 Section -->
<!-- <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"
:key="message.id"
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>
<div v-else class="w-16 h-16 rounded-lg bg-primary bg-opacity-10 flex items-center justify-center flex-shrink-0">
<Icon icon="carbon:notification" width="32" height="32" class="text-primary" />
</div>
<div class="flex-1">
<h3 class="text-lg font-bold text-text mb-2">{{ message.title }}</h3>
<p class="text-sm text-text-secondary mb-2" v-html="message.content"></p>
<div class="text-xs text-text-secondary">{{ formatDate(message.createTime || '') }}</div>
</div>
</div>
</div>
</div>
</div>
</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"
:key="community.id"
class="bg-background rounded-xl overflow-hidden shadow-card hover:shadow-lg transition-all duration-300"
>
<div v-if="community.image" class="h-48 overflow-hidden">
<img :src="community.image" :alt="community.title" class="w-full h-full object-cover hover:scale-105 transition-transform duration-300">
</div>
<div v-else class="h-48 bg-primary bg-opacity-10 flex items-center justify-center">
<Icon icon="carbon:events" width="64" height="64" class="text-primary opacity-50" />
</div>
<div class="p-6">
<h4 class="text-lg font-bold text-text mb-2">{{ community.title }}</h4>
<p class="text-text-secondary text-sm mb-2" v-html="community.content"></p>
<p class="text-text-secondary text-xs">{{ formatDate(community.createTime || '') }}</p>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<style scoped>
.shadow-card {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.shadow-card:hover {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-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>