|
@ -3,6 +3,11 @@ import { useI18n } from 'vue-i18n'; |
|
|
import { ref, onMounted, computed } from 'vue'; |
|
|
import { ref, onMounted, computed } from 'vue'; |
|
|
import { Icon } from '@iconify/vue'; |
|
|
import { Icon } from '@iconify/vue'; |
|
|
import { useConfig } from '@/utils/config'; |
|
|
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 { |
|
|
import { |
|
|
queryOfficialMediaList, |
|
|
queryOfficialMediaList, |
|
|
queryForumList, |
|
|
queryForumList, |
|
@ -54,26 +59,46 @@ const isSubmitting = ref(false); |
|
|
// 当前查看的帖子ID |
|
|
// 当前查看的帖子ID |
|
|
const currentForumId = ref<string | null>(null); |
|
|
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="container mx-auto relative z-10"> |
|
|
<div class="max-w-3xl mx-auto text-center"> |
|
|
<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"> |
|
|
<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> |
|
|
</h1> |
|
|
<p class="text-lg md:text-xl text-text-secondary mb-8 wow animate__animated animate__fadeIn animate__delay-xs animate__duration-fast"> |
|
|
<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> |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</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 class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6"> |
|
|
|
|
|
|
|
|
<div v-else class="space-y-6"> |
|
|
<div |
|
|
<div |
|
|
v-for="message in messageList" |
|
|
v-for="message in messageList" |
|
|
:key="message.id" |
|
|
: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" |
|
|
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" /> |
|
|
<img :src="message.image || '/LOGO.png'" :alt="message.title" class="w-full h-full object-cover" /> |
|
|
</div> |
|
|
</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> |
|
|
<span>{{ formatDate(message.createTime) }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</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> |
|
|
</div> |
|
|
</section> |
|
|
</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 class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary"></div> |
|
|
</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> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 左右切换控制器 --> |
|
|
|
|
|
<div class="absolute top-1/2 -left-5 transform -translate-y-1/2 z-10"> |
|
|
|
|
|
|
|
|
</SwiperSlide> |
|
|
|
|
|
</Swiper> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 外部自定义导航按钮 --> |
|
|
<button |
|
|
<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> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="absolute top-1/2 -right-5 transform -translate-y-1/2 z-10"> |
|
|
|
|
|
|
|
|
|
|
|
<button |
|
|
<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> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 指示器 --> |
|
|
|
|
|
<div class="flex justify-center mt-6 gap-2"> |
|
|
|
|
|
|
|
|
<!-- 外部自定义分页器 --> |
|
|
|
|
|
<div class="flex justify-center mt-8 gap-4"> |
|
|
<button |
|
|
<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> |
|
|
></button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
@ -539,7 +610,7 @@ onMounted(async() => { |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<button class="flex items-center text-primary-light hover:text-primary-dark transition-colors" @click="prepareComment(forum.id)"> |
|
|
<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"> |
|
|
<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" /> |
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" /> |
|
|
</svg> |
|
|
</svg> |
|
@ -552,7 +623,7 @@ onMounted(async() => { |
|
|
<div class="border-t border-background-light"> |
|
|
<div class="border-t border-background-light"> |
|
|
<div class="p-6"> |
|
|
<div class="p-6"> |
|
|
<h4 class="text-lg font-bold text-text mb-4 flex items-center justify-between"> |
|
|
<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"> |
|
|
<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"> |
|
|
<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" /> |
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> |
|
@ -581,7 +652,7 @@ onMounted(async() => { |
|
|
</svg> |
|
|
</svg> |
|
|
</div> |
|
|
</div> |
|
|
<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> |
|
|
<p class="text-xs text-text-secondary">{{ formatDate(comment.createTime) }}</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
@ -594,7 +665,7 @@ onMounted(async() => { |
|
|
<div class="bg-background-dark rounded-lg p-4"> |
|
|
<div class="bg-background-dark rounded-lg p-4"> |
|
|
<textarea |
|
|
<textarea |
|
|
v-model="newMessage.content" |
|
|
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" |
|
|
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" |
|
|
rows="3" |
|
|
></textarea> |
|
|
></textarea> |
|
@ -625,24 +696,21 @@ onMounted(async() => { |
|
|
</section> |
|
|
</section> |
|
|
|
|
|
|
|
|
<!-- 3. 信息公示 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"> |
|
|
<div class="container mx-auto"> |
|
|
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp"> |
|
|
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp"> |
|
|
{{ t('community.announcements.title') }} |
|
|
{{ t('community.announcements.title') }} |
|
|
</h2> |
|
|
</h2> |
|
|
|
|
|
|
|
|
<!-- 加载中状态 --> |
|
|
|
|
|
<div v-if="messageLoading" class="flex justify-center items-center py-12"> |
|
|
<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 class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 无数据状态 --> |
|
|
|
|
|
<div v-else-if="messageList.length === 0" class="text-center py-10"> |
|
|
<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" /> |
|
|
<Icon icon="carbon:no-content" class="mx-auto mb-4" width="48" height="48" /> |
|
|
<p class="text-text-secondary">暂无信息公示数据</p> |
|
|
<p class="text-text-secondary">暂无信息公示数据</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 信息公示列表 --> |
|
|
|
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto mt-8"> |
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto mt-8"> |
|
|
<div |
|
|
<div |
|
|
v-for="message in messageList" |
|
|
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" |
|
|
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 class="flex items-start gap-4"> |
|
|
<!-- 如果有图片则显示 --> |
|
|
|
|
|
<div v-if="message.image" class="w-16 h-16 rounded-lg overflow-hidden flex-shrink-0"> |
|
|
<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" /> |
|
|
<img :src="message.image" :alt="message.title" class="w-full h-full object-cover" /> |
|
|
</div> |
|
|
</div> |
|
@ -667,27 +734,23 @@ onMounted(async() => { |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</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')})` }"> |
|
|
<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"> |
|
|
<div class="container mx-auto"> |
|
|
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp"> |
|
|
<h2 class="text-3xl font-bold text-text mb-4 text-center wow animate__animated animate__fadeInUp"> |
|
|
{{ t('community.highlights.title') }} |
|
|
{{ t('community.highlights.title') }} |
|
|
</h2> |
|
|
</h2> |
|
|
|
|
|
|
|
|
<!-- 加载中状态 --> |
|
|
|
|
|
<div v-if="communityLoading" class="flex justify-center items-center py-12"> |
|
|
<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 class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 无数据状态 --> |
|
|
|
|
|
<div v-else-if="communityList.length === 0" class="text-center py-10"> |
|
|
<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" /> |
|
|
<Icon icon="carbon:no-content" class="mx-auto mb-4" width="48" height="48" /> |
|
|
<p class="text-text-secondary">暂无社区活动数据</p> |
|
|
<p class="text-text-secondary">暂无社区活动数据</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 社区活动列表 --> |
|
|
|
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8"> |
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8"> |
|
|
<div |
|
|
<div |
|
|
v-for="community in communityList" |
|
|
v-for="community in communityList" |
|
@ -728,4 +791,27 @@ onMounted(async() => { |
|
|
-webkit-box-orient: vertical; |
|
|
-webkit-box-orient: vertical; |
|
|
overflow: hidden; |
|
|
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> |
|
|
</style> |