|
|
- <script setup lang="ts">
- import { useI18n } from 'vue-i18n';
- import { ref, computed, onMounted, watch } from 'vue';
- import { Icon } from '@iconify/vue';
- import { queryQuestionList, type QuestionItem } from '@/api/modules';
-
- // 声明全局变量
- declare global {
- interface Window {
- Typed: any;
- }
- }
-
- const { t } = useI18n();
-
- // 搜索关键词
- const searchQuery = ref('');
-
- // 问题列表
- const questions = ref<QuestionItem[]>([]);
- const loading = ref(true);
-
- // 监听搜索关键词变化
- let searchTimeout: number | null = null;
- watch(searchQuery, (newValue: string) => {
- // 清除之前的定时器
- if (searchTimeout) {
- clearTimeout(searchTimeout);
- }
-
- // 设置新的定时器,实现防抖
- searchTimeout = setTimeout(() => {
- loadQuestions();
- }, 500) as unknown as number;
- });
-
- // 处理搜索按钮点击
- const handleSearch = () => {
- if (searchTimeout) {
- clearTimeout(searchTimeout);
- }
- loadQuestions();
- };
-
- // 加载问题数据
- const loadQuestions = async () => {
- try {
- loading.value = true;
- const data = await queryQuestionList({
- pageSize: 50,
- pageNo: 1,
- title: searchQuery.value || undefined // 添加title参数
- });
- questions.value = data;
- } catch (error) {
- console.error('加载常见问题数据失败:', error);
- } finally {
- loading.value = false;
- }
- };
-
- // 过滤后的问题列表
- const filteredQuestions = computed(() => {
- let result = questions.value;
-
- // 按搜索关键词过滤
- if (searchQuery.value) {
- const query = searchQuery.value.toLowerCase();
- result = result.filter(q =>
- q.question.toLowerCase().includes(query) ||
- q.answer.toLowerCase().includes(query)
- );
- }
-
- return result;
- });
-
- // 展开/折叠问题
- const expandedQuestions = ref<string[]>([]);
-
- const toggleQuestion = (id: string) => {
- const index = expandedQuestions.value.indexOf(id);
- if (index === -1) {
- expandedQuestions.value.push(id);
- } else {
- expandedQuestions.value.splice(index, 1);
- }
- };
-
- const isExpanded = (id: string) => {
- return expandedQuestions.value.includes(id);
- };
-
- // 打字机效果
- const typedElement = ref<HTMLElement | null>(null);
- let typed: any = null;
-
- onMounted(() => {
- loadQuestions();
-
- // 初始化打字机效果
- if (typedElement.value && window.Typed) {
- typed = new window.Typed(typedElement.value, {
- strings: [
- t('faq.hero.subtitle'),
- '有任何疑问?我们随时为您解答',
- '探索 MOSE 的常见问题',
- '快速找到您需要的答案'
- ],
- typeSpeed: 50,
- backSpeed: 30,
- backDelay: 1500,
- loop: true
- });
- }
- });
- </script>
-
- <template>
- <div class="bg-background min-h-screen">
- <!-- Hero Section -->
- <section class="relative py-32 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('faq.hero.title') }}
- </h1>
- <p class="text-lg md:text-xl text-text-secondary mb-8">
- <span ref="typedElement"></span>
- </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-accent 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-primary 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-secondary blur-3xl wow animate__animated animate__pulse animate__infinite animate__delay-md"></div>
- </div>
- </section>
-
- <!-- Search and Filter Section -->
- <section class="py-12 px-6 md:px-12 lg:px-24">
- <div class="container mx-auto">
- <div class="max-w-3xl mx-auto mb-12">
-
- <div class="relative mb-8 search-container">
- <input
- type="text"
- v-model="searchQuery"
- :placeholder="t('faq.search.placeholder')"
- class="w-full py-4 px-6 pr-12 bg-background-light text-text rounded-xl focus:outline-none focus:ring-2 focus:ring-primary"
- @keyup.enter="handleSearch"
- />
- <div
- class="absolute right-4 top-1/2 transform -translate-y-1/2 text-text-secondary hover:text-primary transition-colors btn-hover-scale cursor-pointer"
- @click="handleSearch"
- >
- <Icon icon="carbon:search" width="24" height="24" />
- </div>
- </div>
- </div>
-
- <!-- 加载中状态 -->
- <div v-if="loading" class="flex justify-center items-center py-16 max-w-3xl mx-auto">
- <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
- </div>
-
- <!-- FAQ Questions -->
- <div v-else class="max-w-3xl mx-auto">
- <div v-if="filteredQuestions.length === 0" class="text-center py-8 text-text-secondary wow animate__animated animate__fadeIn">
- {{ t('faq.search.noresults') }}
- </div>
-
- <div v-else class="space-y-4">
- <div
- v-for="question in filteredQuestions"
- :key="question.id"
- class="bg-background-light rounded-xl overflow-hidden wow animate__animated animate__fadeIn"
- >
- <button
- @click="toggleQuestion(question.id)"
- class="w-full px-6 py-4 flex justify-between items-center text-left hover:bg-background-light/80 transition-colors"
- >
- <h3 class="text-lg font-medium text-text">{{ question.question }}</h3>
- <Icon
- :icon="isExpanded(question.id) ? 'carbon:chevron-up' : 'carbon:chevron-down'"
- class="h-5 w-5 text-text-secondary transition-transform duration-300"
- width="20"
- height="20"
- />
- </button>
-
- <div
- v-show="isExpanded(question.id)"
- class="px-6 py-4 border-t border-background"
- >
- <p class="text-text-secondary whitespace-pre-line" v-html="question.answer"></p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <!-- More Questions Section -->
- <section class="py-16 px-6 md:px-12 lg:px-24 bg-background-light">
- <div class="container mx-auto">
- <div class="max-w-3xl mx-auto text-center">
- <h2 class="text-2xl font-bold text-text mb-4">
- {{ t('faq.more.title') || '还有更多问题?' }}
- </h2>
- <div class="flex flex-col sm:flex-row justify-center gap-4 mt-8">
- <router-link
- to="/contact"
- class="px-8 py-3 bg-primary text-text rounded-lg hover:bg-primary-dark transition-colors duration-300 shadow-button btn-hover-glow flex items-center justify-center gap-2"
- >
- <Icon icon="carbon:email" width="20" height="20" />
- {{ t('faq.more.contact') || '联系我们' }}
- </router-link>
- <router-link
- to="/community"
- class="px-8 py-3 bg-transparent border border-primary-light text-primary-light rounded-lg hover:bg-primary-light hover:bg-opacity-10 transition-colors duration-300 btn-hover-shadow flex items-center justify-center gap-2"
- >
- <Icon icon="carbon:group" width="20" height="20" />
- {{ t('faq.more.community') || '加入社区' }}
- </router-link>
- </div>
- </div>
- </div>
- </section>
- </div>
- </template>
-
- <style scoped>
- button {
- outline: none;
- }
-
- .btn-hover-float {
- transition: transform 0.3s ease;
- }
-
- .btn-hover-float:hover {
- transform: translateY(-3px);
- }
-
- .btn-hover-glow {
- position: relative;
- overflow: hidden;
- }
-
- .btn-hover-glow::after {
- content: '';
- position: absolute;
- top: -50%;
- left: -50%;
- width: 200%;
- height: 200%;
- background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0) 70%);
- opacity: 0;
- transform: scale(0.5);
- transition: opacity 0.3s ease, transform 0.3s ease;
- }
-
- .btn-hover-glow:hover::after {
- opacity: 1;
- transform: scale(1);
- }
-
- .btn-hover-shadow {
- transition: box-shadow 0.3s ease;
- }
-
- .btn-hover-shadow:hover {
- box-shadow: 0 4px 12px rgba(var(--primary-light-rgb), 0.15);
- }
- </style>
|