Hanye官网
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.

index.vue 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <template>
  2. <div class="py-8">
  3. <div class="container-custom">
  4. <h1 class="text-3xl font-bold mb-8">{{ $t('faq.title') }}</h1>
  5. <div class="mb-8">
  6. <div class="relative">
  7. <input
  8. type="text"
  9. v-model="searchQuery"
  10. :placeholder="$t('faq.searchPlaceholder')"
  11. class="w-full px-4 py-3 border border-gray-300 rounded-md pl-10 focus:outline-none focus:ring-2 focus:ring-blue-500"
  12. />
  13. <div class="absolute left-3 top-3 text-gray-400">
  14. <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  15. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
  16. </svg>
  17. </div>
  18. </div>
  19. </div>
  20. <ErrorBoundary :error="error">
  21. <div v-if="isLoading" class="flex justify-center py-12">
  22. <!-- 加载中 -->
  23. <div class="animate-spin h-8 w-8 border-4 border-blue-500 rounded-full border-t-transparent"></div>
  24. </div>
  25. <div v-else>
  26. <div v-if="filteredFaqs.length === 0" class="bg-yellow-50 border border-yellow-200 text-yellow-800 p-4 rounded-md">
  27. 没有找到匹配的问题,请尝试其他关键词。
  28. </div>
  29. <div v-else class="space-y-6">
  30. <div v-for="faq in filteredFaqs" :key="faq.id" class="bg-white border border-gray-200 rounded-lg overflow-hidden hover:shadow-md transition-shadow">
  31. <div class="p-6">
  32. <NuxtLink :to="`/faq/${faq.id}`" class="block">
  33. <h2 class="text-xl font-semibold mb-2 text-blue-700 hover:text-blue-800">{{ faq.question }}</h2>
  34. <p class="text-gray-600 line-clamp-2">{{ faq.answer }}</p>
  35. <div class="mt-4 flex items-center text-blue-600">
  36. <span class="text-sm font-medium">阅读全文</span>
  37. <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  38. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
  39. </svg>
  40. </div>
  41. </NuxtLink>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </ErrorBoundary>
  47. </div>
  48. </div>
  49. </template>
  50. <script setup lang="ts">
  51. /**
  52. * FAQ列表页面
  53. * 展示所有常见问题并支持搜索
  54. */
  55. import { ref, computed, onMounted } from 'vue';
  56. import { useErrorHandler } from '~/composables/useErrorHandler';
  57. // FAQ接口定义
  58. interface Faq {
  59. id: number;
  60. question: string;
  61. answer: string;
  62. category: string;
  63. }
  64. const { error, isLoading, wrapAsync } = useErrorHandler();
  65. const faqs = ref<Faq[]>([]);
  66. const searchQuery = ref('');
  67. /**
  68. * 根据搜索条件过滤FAQ
  69. */
  70. const filteredFaqs = computed(() => {
  71. if (!searchQuery.value.trim()) return faqs.value;
  72. const query = searchQuery.value.toLowerCase();
  73. return faqs.value.filter(faq =>
  74. faq.question.toLowerCase().includes(query) ||
  75. faq.answer.toLowerCase().includes(query)
  76. );
  77. });
  78. /**
  79. * 加载FAQ数据
  80. */
  81. async function loadFaqs() {
  82. await wrapAsync(async () => {
  83. // 模拟API请求延迟
  84. await new Promise(resolve => setTimeout(resolve, 500));
  85. // 模拟数据,实际项目中应从API获取
  86. faqs.value = [
  87. {
  88. id: 1,
  89. question: '如何使用产品?',
  90. answer: '我们的产品设计简单直观,开箱即用。首先,打开包装并检查所有配件是否齐全。然后,按照说明书的步骤进行安装。如有任何问题,可以观看我们网站上的视频教程或联系客服。',
  91. category: '使用指南'
  92. },
  93. {
  94. id: 2,
  95. question: '产品有哪些保修政策?',
  96. answer: '我们为所有产品提供1年的标准保修服务,覆盖制造缺陷和材料问题。部分高端产品可享受最长3年的延长保修服务。保修期内,我们提供免费维修或更换服务。请注意,人为损坏、不当使用或自行拆卸不在保修范围内。',
  97. category: '售后服务'
  98. },
  99. {
  100. id: 3,
  101. question: '如何进行退换货?',
  102. answer: '购买后30天内,如产品未使用且包装完好,可申请无理由退换货。请保留原始包装和购买凭证,联系我们的客服团队安排退换事宜。退款将在收到退回产品并确认状态后的7个工作日内处理。',
  103. category: '售后服务'
  104. },
  105. {
  106. id: 4,
  107. question: '产品支持哪些操作系统?',
  108. answer: '我们的软件产品兼容Windows 10/11、macOS 10.15及以上版本、iOS 14及以上版本和Android 10及以上版本。硬件产品与大多数现代设备兼容,具体请查看产品详情页的技术规格部分。',
  109. category: '技术支持'
  110. },
  111. {
  112. id: 5,
  113. question: '如何联系客服?',
  114. answer: '您可以通过多种方式联系我们的客服团队:拨打服务热线400-123-4567(工作日9:00-18:00);发送邮件至support@example.com(24小时内回复);在官网使用在线客服(工作日9:00-20:00);或填写联系表单,我们会尽快与您联系。',
  115. category: '联系方式'
  116. },
  117. {
  118. id: 6,
  119. question: '是否提供国际配送服务?',
  120. answer: '是的,我们提供国际配送服务,覆盖大部分国家和地区。国际订单的配送时间通常为7-15个工作日,具体取决于目的地和当地海关情况。国际订单可能产生额外的关税和进口费用,这些费用需由收件人承担。',
  121. category: '配送信息'
  122. }
  123. ];
  124. return faqs.value;
  125. });
  126. }
  127. // 页面加载时获取FAQ数据
  128. onMounted(() => {
  129. loadFaqs();
  130. });
  131. // SEO优化
  132. useHead({
  133. title: '常见问题 - Hanye',
  134. meta: [
  135. { name: 'description', content: '浏览我们的常见问题解答,获取产品使用指南、技术支持和售后服务等相关信息。' }
  136. ]
  137. });
  138. </script>
  139. <style scoped>
  140. .line-clamp-2 {
  141. display: -webkit-box;
  142. -webkit-line-clamp: 2;
  143. -webkit-box-orient: vertical;
  144. overflow: hidden;
  145. }
  146. </style>