Browse Source

2025年06月04日:01)完成 “文章详情” 和 “常见问题” 静态页面开发;02)完成 “@/utils/request.ts” 文件内容填充。

yankun 2 months ago
parent
commit
7bd3ccd7b1

+ 9 - 0
src/apis/system.ts

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+
+
+export const getInfo = (params: Object) => request({
+  url: '/api/cate/getCateListProduct',
+  method: 'get',
+  params: params
+})

+ 3 - 3
src/locale/index.ts

@@ -5,7 +5,7 @@ import zh from './lang/zh'
 
 
 // 获取当前语言
 // 获取当前语言
 export function getCurrentLang(): string | null {
 export function getCurrentLang(): string | null {
-  return !!localStorage.getItem('locale') && localStorage.getItem('locale') !== 'null' && localStorage.getItem('locale') !== 'undefine' ? localStorage.getItem('locale') : 'zhCN'
+  return !!localStorage.getItem('locale') && localStorage.getItem('locale') !== 'null' && localStorage.getItem('locale') !== 'undefine' ? localStorage.getItem('locale') : 'zh-CN'
 }
 }
 
 
 
 
@@ -13,10 +13,10 @@ export function getCurrentLang(): string | null {
 const i18n = createI18n({
 const i18n = createI18n({
   legacy: false,
   legacy: false,
   locale: (getCurrentLang() as string),
   locale: (getCurrentLang() as string),
-  fallbackLocale: 'zhCN',
+  fallbackLocale: 'zh-CN',
   messages: {
   messages: {
     en: en,
     en: en,
-    zhCN: zh,
+    "zh-CN": zh,
   },
   },
 });
 });
 
 

+ 22 - 1
src/locale/lang/en.ts

@@ -28,7 +28,8 @@ export default {
     "澳大利亚": "Australia",
     "澳大利亚": "Australia",
     "意大利": "Italy",
     "意大利": "Italy",
     "囧二": "Guang Er",
     "囧二": "Guang Er",
-    
+    updateTimeTxt: 'Updated on {updateTime}'
+
   },
   },
   textLink: {
   textLink: {
     "常见问题": "FAQ",
     "常见问题": "FAQ",
@@ -63,5 +64,25 @@ export default {
     "如果你想买其他东西,没有比 Vava buy 更好的了": "If you want to buy anything else, there's no better option than Vava Buy",
     "如果你想买其他东西,没有比 Vava buy 更好的了": "If you want to buy anything else, there's no better option than Vava Buy",
     "非常易于使用,包装很精美,会收获很多惊喜": "Very easy to use, with exquisite packaging, and you will receive many surprises",
     "非常易于使用,包装很精美,会收获很多惊喜": "Very easy to use, with exquisite packaging, and you will receive many surprises",
     "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。": "We use cookies to provide a better online experience. By visiting and using VAVA BUY.com, you are agreeing to our use of cookies. Please read our terms and conditions, usage terms, and privacy policy.",
     "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。": "We use cookies to provide a better online experience. By visiting and using VAVA BUY.com, you are agreeing to our use of cookies. Please read our terms and conditions, usage terms, and privacy policy.",
+  },
+  questionPage: {
+    bannerTitle: 'FAQ',
+    bannerDesc: 'We will be here to answer all your questions',
+    bannerSearchPlaceholder: 'Please enter the key words of your question...',
+    bannerSearchBtn: 'Search',
+    searchResultTitle: 'Search results ({count} items)',
+    questionCategoryMenuBtn: 'Classification',
+    questionCategoryCountTxt: '{count} questions',
+    questionDrawerTitle: 'Problem classification',
+    questionTagHot: 'Hot',
+    questionTagNew: 'New',
+    questionReadCount: 'Read {count} times',
+    questionDetailBackbtn: 'Back',
+    contactTitle: "Didn't find the answer you need?",
+    contactDesc: 'Our customer service team is always at your service',
+    contactForPhoneTitle: 'Telephone support',
+    contactForPhoneWorkTime: 'Monday to Sunday 9:00-18:00',
+    contactForEmailTitle: 'Email',
+    contactForEmailWorkTime: 'We will reply within 24 hours',
   }
   }
 }
 }

+ 21 - 0
src/locale/lang/zh.ts

@@ -28,6 +28,7 @@ export default {
     "澳大利亚": "澳大利亚",
     "澳大利亚": "澳大利亚",
     "意大利": "意大利",
     "意大利": "意大利",
     "囧二": "囧二",
     "囧二": "囧二",
+    updateTimeTxt: '更新于 {updateTime}'
   },
   },
   textLink: {
   textLink: {
     "常见问题": "常见问题",
     "常见问题": "常见问题",
@@ -62,5 +63,25 @@ export default {
     "如果你想买其他东西,没有比 Vava buy 更好的了": "如果你想买其他东西,没有比 Vava buy 更好的了",
     "如果你想买其他东西,没有比 Vava buy 更好的了": "如果你想买其他东西,没有比 Vava buy 更好的了",
     "非常易于使用,包装很精美,会收获很多惊喜": "非常易于使用,包装很精美,会收获很多惊喜",
     "非常易于使用,包装很精美,会收获很多惊喜": "非常易于使用,包装很精美,会收获很多惊喜",
     "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。": "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。",
     "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。": "我们使用 cookie 来提供更好的在线体验。 访问和使用 VAVA BUY.com,即表示您同意我们使用 Cookie。 通过阅读我们的条款和条件、使用条款、 和隐私政策。",
+  },
+  questionPage: {
+    bannerTitle: '常见问题',
+    bannerDesc: '我们将在这里为您解答所有疑问',
+    bannerSearchPlaceholder: '请输入您的问题关键词...',
+    bannerSearchBtn: '搜索',
+    searchResultTitle: '搜索结果 ({count}条)',
+    questionCategoryMenuBtn: '分类',
+    questionCategoryCountTxt: '{count}个问题',
+    questionDrawerTitle: '常见问题分类',
+    questionTagHot: '热门',
+    questionTagNew: '新',
+    questionReadCount: '阅读 {count} 次',
+    questionDetailBackbtn: '返回列表',
+    contactTitle: '没有找到您需要的答案?',
+    contactDesc: '我们的客服团队随时为您服务',
+    contactForPhoneTitle: '电话支持',
+    contactForPhoneWorkTime: '周一至周日 9:00-18:00',
+    contactForEmailTitle: '电子邮件',
+    contactForEmailWorkTime: '我们会在24小时内回复',
   }
   }
 }
 }

BIN
src/public/images/icons/menu_icon.png


+ 3 - 2
src/router/index.ts

@@ -10,10 +10,11 @@ const routes: Array<RouteRecordRaw> = [
     path: '/',
     path: '/',
     name: 'layout',
     name: 'layout',
     component: Layout,
     component: Layout,
-    redirect: '/home',
+    // redirect: '/home',
     children: [
     children: [
       {
       {
-        path: 'home',
+        // path: 'home',
+        path: '',
         name: 'home',
         name: 'home',
         component: Home
         component: Home
       },
       },

+ 2 - 2
src/stores/useSystemStore.ts

@@ -21,13 +21,13 @@ const useSystemStore = defineStore('system', {
   state: (): ISystemState => ({
   state: (): ISystemState => ({
     locale: getCurrentLang() as string,
     locale: getCurrentLang() as string,
     localeList: [
     localeList: [
-      { name: '简体中文', value: 'zhCN' },
+      { name: '简体中文', value: 'zh-CN' },
       { name: 'English', value: 'en' },
       { name: 'English', value: 'en' },
     ]
     ]
   }),
   }),
 
 
   getters: {
   getters: {
-    localeInfo: function(): ILocale {
+    localeInfo: function (): ILocale {
       const result = this.localeList.find((item: ILocale) => (item.value == this.locale))
       const result = this.localeList.find((item: ILocale) => (item.value == this.locale))
       return result ? result : this.localeList[0]
       return result ? result : this.localeList[0]
     }
     }

+ 35 - 13
src/utils/request.ts

@@ -1,25 +1,47 @@
-import axios from "axios";
+import axios from 'axios'
 
 
 
 
 export const BASE_URL = import.meta.env.VITE_BASE_URL
 export const BASE_URL = import.meta.env.VITE_BASE_URL
 
 
 
 
-const instance = axios.create({
+//用来拦截用的
+axios.defaults.headers.post["Content-Type"] = "application/json;charset=utf-8";
+
+const http = axios.create({
   baseURL: BASE_URL,
   baseURL: BASE_URL,
   timeout: 1000 * 60 * 5,
   timeout: 1000 * 60 * 5,
 })
 })
 
 
 
 
-
+ 
 // 请求拦截器
 // 请求拦截器
-
-
-
-
+http.interceptors.request.use(
+  config => {
+    let token = localStorage.getItem('token')
+    if (token) {
+      config.headers.token = token
+    }
+    return config
+  },
+  err => {
+    return Promise.reject(err)
+  }
+)
+ 
 // 响应拦截器
 // 响应拦截器
-
-
-
-
-
-export default instance
+http.interceptors.response.use(
+  res => {
+    if (res.data.code == 1) {
+      return Promise.resolve(res.data)
+    }
+    else{
+      return Promise.reject(res.data)
+    }
+  },
+  err => {
+    return Promise.reject(err)
+  }
+)
+ 
+
+export default http

+ 13 - 4
src/views/ArticleDetails/index.vue

@@ -10,7 +10,11 @@
         <span class="author-name">{{ article.author.name }}</span>
         <span class="author-name">{{ article.author.name }}</span>
       </div> -->
       </div> -->
       <div class="publish-time">
       <div class="publish-time">
-        {{ formatDate(article.publishTime) }}
+        <span>{{
+          $t('system["updateTimeTxt"]', {
+            updateTime: formatDate(article.publishTime, locale),
+          })
+        }}</span>
       </div>
       </div>
     </div>
     </div>
 
 
@@ -26,8 +30,13 @@
   </section>
   </section>
 </template>
 </template>
 
 
-<script setup>
+<script setup lang="ts">
+import { storeToRefs } from 'pinia'
 import { ref } from 'vue'
 import { ref } from 'vue'
+import useSystemStore from '@/stores/useSystemStore'
+
+const systemStore = useSystemStore()
+const { locale } = storeToRefs(systemStore)
 
 
 // 模拟文章数据
 // 模拟文章数据
 const article = ref({
 const article = ref({
@@ -91,9 +100,9 @@ const article = ref({
 })
 })
 
 
 // 格式化日期
 // 格式化日期
-const formatDate = (dateString) => {
+const formatDate = (dateString: string, lang: string) => {
   const options = { year: 'numeric', month: 'long', day: 'numeric' }
   const options = { year: 'numeric', month: 'long', day: 'numeric' }
-  return new Date(dateString).toLocaleDateString(undefined, options)
+  return new Date(dateString).toLocaleDateString(lang, options as Object)
 }
 }
 </script>
 </script>
 
 

+ 19 - 0
src/views/FAQ/css/styles@768.less

@@ -1,6 +1,9 @@
 @media screen and (max-width: 768px) {
 @media screen and (max-width: 768px) {
   .question-banner {
   .question-banner {
 
 
+    margin-bottom: 8px;
+    margin-bottom: 0.5rem;
+
     h1 {
     h1 {
       font-size: 32px;
       font-size: 32px;
       font-size: 2rem;
       font-size: 2rem;
@@ -10,4 +13,20 @@
       font-size: 1rem;
       font-size: 1rem;
     }
     }
   }
   }
+
+  .question-main-768 {
+    display: block;
+  }
+
+  .question-main-normal {
+    display: none;
+  }
+
+  .detail-content h3 {
+    font-size: 1.375rem !important;
+  }
+
+  .detail-content h4 {
+    font-size: 1.125rem !important;
+  }
 }
 }

+ 233 - 0
src/views/FAQ/hooks/useData.ts

@@ -0,0 +1,233 @@
+import { ref, computed } from 'vue'
+
+
+function useData() {
+
+  // 问题分类
+  const categoryList = ref([
+    { id: 1, name: '账号问题', count: 12 },
+    { id: 2, name: '支付问题', count: 8 },
+    { id: 3, name: '订单问题', count: 15 },
+    { id: 4, name: '产品使用', count: 23 },
+    { id: 5, name: '售后服务', count: 7 },
+    { id: 6, name: '其他问题', count: 5 },
+  ])
+  // 当前选中的分类 ID
+  const activeCategory = ref<string | number>(1)
+
+
+  // 模拟问题数据
+  const questions = ref([
+    {
+      id: 101,
+      categoryId: 1,
+      title: '如何注册账号?',
+      preview: '详细说明注册账号的步骤和注意事项...',
+      content: `
+      <h3>注册账号步骤</h3>
+      <ol>
+        <li>点击网站右上角的"注册"按钮</li>
+        <li>填写您的手机号码或电子邮箱</li>
+        <li>设置登录密码(6-20位字符,包含字母和数字)</li>
+        <li>输入收到的验证码</li>
+        <li>阅读并同意用户协议</li>
+        <li>点击"立即注册"完成注册</li>
+      </ol>
+      <p><strong>注意事项:</strong></p>
+      <ul>
+        <li>请使用常用手机号或邮箱,以便接收重要通知</li>
+        <li>密码请勿设置过于简单</li>
+        <li>如未收到验证码,请检查垃圾邮件或60秒后重新获取</li>
+      </ul>
+    `,
+      updateTime: '2023-05-15',
+      views: 1245,
+      isHot: true,
+      isNew: false,
+    },
+    {
+      id: 102,
+      categoryId: 1,
+      title: '忘记密码怎么办?',
+      preview: '密码找回的几种方法和步骤说明...',
+      content: `
+      <h3>找回密码方法</h3>
+      <p>如果您忘记了密码,可以通过以下方式找回:</p>
+      
+      <h4>方法一:通过手机找回</h4>
+      <ol>
+        <li>在登录页面点击"忘记密码"</li>
+        <li>选择"通过手机找回"</li>
+        <li>输入注册时使用的手机号码</li>
+        <li>获取并输入短信验证码</li>
+        <li>设置新密码并确认</li>
+      </ol>
+      
+      <h4>方法二:通过邮箱找回</h4>
+      <ol>
+        <li>在登录页面点击"忘记密码"</li>
+        <li>选择"通过邮箱找回"</li>
+        <li>输入注册时使用的邮箱地址</li>
+        <li>登录邮箱查收重置密码邮件</li>
+        <li>点击邮件中的链接设置新密码</li>
+      </ol>
+      
+      <p>如果以上方法都无法解决您的问题,请联系客服人员。</p>
+    `,
+      updateTime: '2023-06-02',
+      views: 876,
+      isHot: true,
+      isNew: false,
+    },
+    {
+      id: 201,
+      categoryId: 2,
+      title: '支持哪些支付方式?',
+      preview: '介绍平台目前支持的支付渠道...',
+      content: `
+      <h3>支持的支付方式</h3>
+      <p>我们目前支持以下支付方式:</p>
+      
+      <div class="payment-method">
+        <h4>1. 在线支付</h4>
+        <ul>
+          <li>微信支付</li>
+          <li>支付宝</li>
+          <li>银联在线支付</li>
+          <li>Apple Pay</li>
+        </ul>
+      </div>
+      
+      <div class="payment-method">
+        <h4>2. 银行卡支付</h4>
+        <p>支持以下银行的储蓄卡和信用卡:</p>
+        <ul>
+          <li>中国工商银行</li>
+          <li>中国建设银行</li>
+          <li>中国银行</li>
+          <li>招商银行</li>
+          <li>交通银行等主流银行</li>
+        </ul>
+      </div>
+      
+      <p><strong>注意:</strong>部分银行可能有支付限额,请以银行规定为准。</p>
+    `,
+      updateTime: '2023-04-28',
+      views: 1532,
+      isHot: false,
+      isNew: false,
+    },
+    {
+      id: 301,
+      categoryId: 3,
+      title: '如何查询订单状态?',
+      preview: '订单状态查询的几种途径和方法...',
+      content: `
+      <h3>查询订单状态</h3>
+      <p>您可以通过以下方式查询订单状态:</p>
+      
+      <h4>方法一:网站查询</h4>
+      <ol>
+        <li>登录您的账号</li>
+        <li>点击右上角"我的订单"</li>
+        <li>在订单列表中找到相应订单</li>
+        <li>点击"查看详情"查看订单状态</li>
+      </ol>
+      
+      <h4>方法二:手机APP查询</h4>
+      <ol>
+        <li>打开APP并登录</li>
+        <li>点击底部导航栏"我的"</li>
+        <li>选择"我的订单"</li>
+        <li>查看相应订单状态</li>
+      </ol>
+      
+      <h4>方法三:联系客服查询</h4>
+      <p>如果您无法通过以上方式查询,可以联系客服提供订单号查询。</p>
+      
+      <p><strong>常见订单状态说明:</strong></p>
+      <ul>
+        <li><span class="status waiting">待付款</span> - 订单已生成,等待支付</li>
+        <li><span class="status paid">已支付</span> - 付款成功,等待处理</li>
+        <li><span class="status shipped">已发货</span> - 商品已发出</li>
+        <li><span class="status completed">已完成</span> - 订单交易完成</li>
+        <li><span class="status cancelled">已取消</span> - 订单已取消</li>
+      </ul>
+    `,
+      updateTime: '2023-05-20',
+      views: 2104,
+      isHot: true,
+      isNew: true,
+    },
+  ])
+  // 当前查看的问题详情
+  const currentQuestion = ref(null)
+
+
+  // 搜索查询词
+  const searchQuery = ref('')
+  // 搜索结果
+  const searchResults = ref<Array<typeof questions.value[0]>>([])
+
+
+  // 获取分类名称
+  const getCategoryName = (id: string | number) => {
+    const category = categoryList.value.find((c) => (c.id === id))
+    return category ? category.name : '所有问题'
+  }
+
+  // 切换分类
+  const changeCategory = (categoryId: string | number) => {
+    activeCategory.value = categoryId
+    currentQuestion.value = null
+    searchResults.value = []
+  }
+
+  // 获取当前分类下的问题
+  const questionList = computed(() => {
+    return questions.value.filter((q: any) => q.categoryId === activeCategory.value)
+  })
+
+  // 显示问题详情
+  const showQuestionDetail = (question: any) => {
+    currentQuestion.value = question
+  }
+
+  // 搜索问题
+  const searchQuestions = () => {
+    if (!searchQuery.value.trim()) {
+      searchResults.value = []
+      return
+    }
+
+    const query = searchQuery.value.toLowerCase()
+    searchResults.value = questions.value.filter((q) => {
+      return q.title.toLowerCase().includes(query) || q.preview.toLowerCase().includes(query)
+    })
+    currentQuestion.value = null
+  }
+
+  // 返回问题列表
+  const backToList = () => {
+    currentQuestion.value = null
+  }
+
+  return {
+    categoryList,
+    activeCategory,
+    questionList,
+    currentQuestion,
+    questions,
+    searchQuery,
+    searchResults,
+    getCategoryName,
+    changeCategory,
+    showQuestionDetail,
+    searchQuestions,
+    backToList,
+  }
+}
+
+
+
+export default useData

+ 303 - 261
src/views/FAQ/index.vue

@@ -2,15 +2,15 @@
   <div class="question-container">
   <div class="question-container">
     <!-- 顶部横幅 -->
     <!-- 顶部横幅 -->
     <div class="question-banner">
     <div class="question-banner">
-      <h1>常见问题</h1>
-      <p>我们将在这里为您解答所有疑问</p>
+      <h1>{{ $t('questionPage["bannerTitle"]') }}</h1>
+      <p>{{ $t('questionPage["bannerDesc"]') }}</p>
 
 
       <!-- 搜索框 -->
       <!-- 搜索框 -->
       <div class="question__search-box">
       <div class="question__search-box">
         <input
         <input
           type="text"
           type="text"
           v-model="searchQuery"
           v-model="searchQuery"
-          placeholder="请输入您的问题关键词..."
+          :placeholder="$t(`questionPage['bannerSearchPlaceholder']`)"
           @keyup.enter="searchQuestions"
           @keyup.enter="searchQuestions"
         />
         />
         <button @click="searchQuestions">
         <button @click="searchQuestions">
@@ -25,33 +25,168 @@
               d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"
               d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"
             />
             />
           </svg>
           </svg>
-          搜索
+          {{ $t(`questionPage['bannerSearchBtn']`) }}
         </button>
         </button>
       </div>
       </div>
     </div>
     </div>
 
 
+    <!-- 主要内容区--移动端 -->
+    <section class="width-1200 question-main-768">
+      <div class="question-main__container question-main__container-768">
+        <!-- 问题列表&内容 -->
+        <div class="question-content">
+          <template v-if="!currentQuestion">
+            <!-- 搜索结果列表 -->
+            <div v-if="searchResults.length > 0" class="search-results question-list">
+              <h2>
+                <span>{{
+                  $t('questionPage["searchResultTitle"]', { count: searchResults.length })
+                }}</span>
+                <div class="category-menu-btn" @click="showCategoryDrawer">
+                  <span>{{ $t('questionPage["questionCategoryMenuBtn"]') }}</span>
+                  <img src="@/public/images/icons/menu_icon.png" alt="" />
+                </div>
+              </h2>
+              <div
+                v-for="item in searchResults"
+                :key="item.id"
+                class="question-item"
+                @click="showQuestionDetail(item)"
+              >
+                <div class="question-title">
+                  {{ item.title }}
+                </div>
+                <div class="question-preview">{{ item.preview }}</div>
+              </div>
+            </div>
+
+            <!-- 问题列表 -->
+            <div v-else class="question-list">
+              <h2>
+                <span>{{ getCategoryName(activeCategory) }}</span>
+                <div class="category-menu-btn" @click="showCategoryDrawer">
+                  <span>{{ $t('questionPage["questionCategoryMenuBtn"]') }}</span>
+                  <img src="@/public/images/icons/menu_icon.png" alt="" />
+                </div>
+              </h2>
+
+              <div
+                v-for="question in questionList"
+                :key="question.id"
+                class="question-item"
+                @click="showQuestionDetail(question)"
+              >
+                <div class="question-title">
+                  {{ question.title }}
+                  <div v-if="question.isHot" class="question-tag hot-tag">
+                    {{ $t('questionPage["questionTagHot"]') }}
+                  </div>
+                  <div v-if="question.isNew" class="question-tag new-tag">
+                    {{ $t('questionPage["questionTagNew"]') }}
+                  </div>
+                </div>
+                <div class="question-preview">{{ question.preview }}</div>
+              </div>
+            </div>
+          </template>
+
+          <!-- 问题详情 -->
+          <div v-else class="question-detail">
+            <div class="detail-footer">
+              <button class="back-btn" @click="backToList">
+                <svg
+                  xmlns="http://www.w3.org/2000/svg"
+                  width="16"
+                  height="16"
+                  fill="currentColor"
+                  viewBox="0 0 16 16"
+                >
+                  <path
+                    fill-rule="evenodd"
+                    d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"
+                  />
+                </svg>
+                {{ $t('questionPage["questionDetailBackbtn"]') }}
+              </button>
+
+              <!-- <div class="feedback">
+                <span>这篇回答对您有帮助吗?</span>
+                <button class="feedback-btn yes">有帮助</button>
+                <button class="feedback-btn no">没帮助</button>
+              </div> -->
+            </div>
+
+            <div class="detail-header">
+              <h2>{{ currentQuestion.title }}</h2>
+              <div class="meta">
+                <span>{{
+                  $t('system["updateTimeTxt"]', {
+                    updateTime: formatDate(currentQuestion.updateTime, locale),
+                  })
+                }}</span>
+                <span>{{
+                  $t('questionPage["questionReadCount"]', { count: currentQuestion.views })
+                }}</span>
+              </div>
+            </div>
+
+            <div class="detail-content" v-html="currentQuestion.content"></div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 分类导航侧边抽屉 -->
+      <a-drawer
+        :open="visible"
+        :closable="false"
+        :title="$t(`questionPage['questionDrawerTitle']`)"
+        placement="right"
+        width="70%"
+        getContainer=".question-main__container-768"
+        class=""
+        @close="closeCategoryDrawer"
+      >
+        <div class="question-sidebar">
+          <div
+            v-for="category in categoryList"
+            :key="category.id"
+            class="category-item"
+            :class="{ active: activeCategory === category.id }"
+            @click="changeCategory(category.id)"
+          >
+            {{ category.name }}
+            <span class="count">{{
+              $t('questionPage["questionCategoryCountTxt"]', { count: category.count })
+            }}</span>
+          </div>
+        </div>
+      </a-drawer>
+    </section>
+
     <!-- 主要内容区 -->
     <!-- 主要内容区 -->
-    <div class="question-main__container width-1200">
-      <!-- 左侧导航 -->
+    <div class="question-main__container question-main-normal width-1200">
+      <!-- 左侧分类导航 -->
       <div class="question-sidebar">
       <div class="question-sidebar">
         <div
         <div
-          v-for="category in categories"
+          v-for="category in categoryList"
           :key="category.id"
           :key="category.id"
           class="category-item"
           class="category-item"
           :class="{ active: activeCategory === category.id }"
           :class="{ active: activeCategory === category.id }"
           @click="changeCategory(category.id)"
           @click="changeCategory(category.id)"
         >
         >
           {{ category.name }}
           {{ category.name }}
-          <span class="count">{{ category.count }}个问题</span>
+          <span class="count">{{
+            $t('questionPage["questionCategoryCountTxt"]', { count: category.count })
+          }}</span>
         </div>
         </div>
       </div>
       </div>
 
 
       <!-- 右侧内容 -->
       <!-- 右侧内容 -->
       <div class="question-content">
       <div class="question-content">
         <template v-if="!currentQuestion">
         <template v-if="!currentQuestion">
-          <!-- 搜索结果提示 -->
+          <!-- 搜索结果列表 -->
           <div v-if="searchResults.length > 0" class="search-results">
           <div v-if="searchResults.length > 0" class="search-results">
-            <h3>搜索结果 ({{ searchResults.length }}条)</h3>
+            <h3>{{ $t('questionPage["searchResultTitle"]', { count: searchResults.length }) }}</h3>
             <div
             <div
               v-for="item in searchResults"
               v-for="item in searchResults"
               :key="item.id"
               :key="item.id"
@@ -67,15 +202,19 @@
             <h2>{{ getCategoryName(activeCategory) }}</h2>
             <h2>{{ getCategoryName(activeCategory) }}</h2>
 
 
             <div
             <div
-              v-for="question in filteredQuestions"
+              v-for="question in questionList"
               :key="question.id"
               :key="question.id"
               class="question-item"
               class="question-item"
               @click="showQuestionDetail(question)"
               @click="showQuestionDetail(question)"
             >
             >
               <div class="question-title">
               <div class="question-title">
                 {{ question.title }}
                 {{ question.title }}
-                <div v-if="question.isHot" class="question-tag hot-tag">热门</div>
-                <div v-if="question.isNew" class="question-tag new-tag">新</div>
+                <div v-if="question.isHot" class="question-tag hot-tag">
+                  {{ $t('questionPage["questionTagHot"]') }}
+                </div>
+                <div v-if="question.isNew" class="question-tag new-tag">
+                  {{ $t('questionPage["questionTagNew"]') }}
+                </div>
               </div>
               </div>
               <div class="question-preview">{{ question.preview }}</div>
               <div class="question-preview">{{ question.preview }}</div>
             </div>
             </div>
@@ -87,8 +226,14 @@
           <div class="detail-header">
           <div class="detail-header">
             <h2>{{ currentQuestion.title }}</h2>
             <h2>{{ currentQuestion.title }}</h2>
             <div class="meta">
             <div class="meta">
-              <span>更新于 {{ formatDate(currentQuestion.updateTime) }}</span>
-              <span>阅读 {{ currentQuestion.views }} 次</span>
+              <span>{{
+                $t('system["updateTimeTxt"]', {
+                  updateTime: formatDate(currentQuestion.updateTime, locale),
+                })
+              }}</span>
+              <span>{{
+                $t('questionPage["questionReadCount"]', { count: currentQuestion.views })
+              }}</span>
             </div>
             </div>
           </div>
           </div>
 
 
@@ -108,7 +253,7 @@
                   d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"
                   d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"
                 />
                 />
               </svg>
               </svg>
-              返回列表
+              {{ $t('questionPage["questionDetailBackbtn"]') }}
             </button>
             </button>
 
 
             <!-- <div class="feedback">
             <!-- <div class="feedback">
@@ -123,8 +268,8 @@
 
 
     <!-- 联系客服 -->
     <!-- 联系客服 -->
     <div class="contact-section width-1200">
     <div class="contact-section width-1200">
-      <h3>没有找到您需要的答案?</h3>
-      <p>我们的客服团队随时为您服务</p>
+      <h3>{{ $t('questionPage["contactTitle"]') }}</h3>
+      <p>{{ $t('questionPage["contactDesc"]') }}</p>
       <div class="contact-methods">
       <div class="contact-methods">
         <div class="contact-method">
         <div class="contact-method">
           <svg
           <svg
@@ -139,9 +284,9 @@
             />
             />
           </svg>
           </svg>
           <div>
           <div>
-            <strong>电话支持</strong>
+            <strong>{{ $t('questionPage["contactForPhoneTitle"]') }}</strong>
             <p>400-888-9999</p>
             <p>400-888-9999</p>
-            <p>周一至周日 9:00-18:00</p>
+            <p>{{ $t('questionPage["contactForPhoneWorkTime"]') }}</p>
           </div>
           </div>
         </div>
         </div>
 
 
@@ -158,28 +303,9 @@
             />
             />
           </svg>
           </svg>
           <div>
           <div>
-            <strong>电子邮件</strong>
+            <strong>{{ $t('questionPage["contactForEmailTitle"]') }}</strong>
             <p>support@example.com</p>
             <p>support@example.com</p>
-            <p>我们会在24小时内回复</p>
-          </div>
-        </div>
-
-        <div class="contact-method">
-          <svg
-            xmlns="http://www.w3.org/2000/svg"
-            width="24"
-            height="24"
-            fill="currentColor"
-            viewBox="0 0 16 16"
-          >
-            <path
-              d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"
-            />
-          </svg>
-          <div>
-            <strong>在线客服</strong>
-            <p>点击右下角"在线咨询"</p>
-            <p>工作时间实时沟通</p>
+            <p>{{ $t('questionPage["contactForEmailWorkTime"]') }}</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -187,222 +313,46 @@
   </div>
   </div>
 </template>
 </template>
 
 
-<script setup>
-import { ref, computed } from 'vue'
-
-// 问题分类
-const categories = ref([
-  { id: 1, name: '账号问题', count: 12 },
-  { id: 2, name: '支付问题', count: 8 },
-  { id: 3, name: '订单问题', count: 15 },
-  { id: 4, name: '产品使用', count: 23 },
-  { id: 5, name: '售后服务', count: 7 },
-  { id: 6, name: '其他问题', count: 5 },
-])
-
-// 模拟问题数据
-const questions = ref([
-  {
-    id: 101,
-    categoryId: 1,
-    title: '如何注册账号?',
-    preview: '详细说明注册账号的步骤和注意事项...',
-    content: `
-      <h3>注册账号步骤</h3>
-      <ol>
-        <li>点击网站右上角的"注册"按钮</li>
-        <li>填写您的手机号码或电子邮箱</li>
-        <li>设置登录密码(6-20位字符,包含字母和数字)</li>
-        <li>输入收到的验证码</li>
-        <li>阅读并同意用户协议</li>
-        <li>点击"立即注册"完成注册</li>
-      </ol>
-      <p><strong>注意事项:</strong></p>
-      <ul>
-        <li>请使用常用手机号或邮箱,以便接收重要通知</li>
-        <li>密码请勿设置过于简单</li>
-        <li>如未收到验证码,请检查垃圾邮件或60秒后重新获取</li>
-      </ul>
-    `,
-    updateTime: '2023-05-15',
-    views: 1245,
-    isHot: true,
-    isNew: false,
-  },
-  {
-    id: 102,
-    categoryId: 1,
-    title: '忘记密码怎么办?',
-    preview: '密码找回的几种方法和步骤说明...',
-    content: `
-      <h3>找回密码方法</h3>
-      <p>如果您忘记了密码,可以通过以下方式找回:</p>
-      
-      <h4>方法一:通过手机找回</h4>
-      <ol>
-        <li>在登录页面点击"忘记密码"</li>
-        <li>选择"通过手机找回"</li>
-        <li>输入注册时使用的手机号码</li>
-        <li>获取并输入短信验证码</li>
-        <li>设置新密码并确认</li>
-      </ol>
-      
-      <h4>方法二:通过邮箱找回</h4>
-      <ol>
-        <li>在登录页面点击"忘记密码"</li>
-        <li>选择"通过邮箱找回"</li>
-        <li>输入注册时使用的邮箱地址</li>
-        <li>登录邮箱查收重置密码邮件</li>
-        <li>点击邮件中的链接设置新密码</li>
-      </ol>
-      
-      <p>如果以上方法都无法解决您的问题,请联系客服人员。</p>
-    `,
-    updateTime: '2023-06-02',
-    views: 876,
-    isHot: true,
-    isNew: false,
-  },
-  {
-    id: 201,
-    categoryId: 2,
-    title: '支持哪些支付方式?',
-    preview: '介绍平台目前支持的支付渠道...',
-    content: `
-      <h3>支持的支付方式</h3>
-      <p>我们目前支持以下支付方式:</p>
-      
-      <div class="payment-method">
-        <h4>1. 在线支付</h4>
-        <ul>
-          <li>微信支付</li>
-          <li>支付宝</li>
-          <li>银联在线支付</li>
-          <li>Apple Pay</li>
-        </ul>
-      </div>
-      
-      <div class="payment-method">
-        <h4>2. 银行卡支付</h4>
-        <p>支持以下银行的储蓄卡和信用卡:</p>
-        <ul>
-          <li>中国工商银行</li>
-          <li>中国建设银行</li>
-          <li>中国银行</li>
-          <li>招商银行</li>
-          <li>交通银行等主流银行</li>
-        </ul>
-      </div>
-      
-      <p><strong>注意:</strong>部分银行可能有支付限额,请以银行规定为准。</p>
-    `,
-    updateTime: '2023-04-28',
-    views: 1532,
-    isHot: false,
-    isNew: false,
-  },
-  {
-    id: 301,
-    categoryId: 3,
-    title: '如何查询订单状态?',
-    preview: '订单状态查询的几种途径和方法...',
-    content: `
-      <h3>查询订单状态</h3>
-      <p>您可以通过以下方式查询订单状态:</p>
-      
-      <h4>方法一:网站查询</h4>
-      <ol>
-        <li>登录您的账号</li>
-        <li>点击右上角"我的订单"</li>
-        <li>在订单列表中找到相应订单</li>
-        <li>点击"查看详情"查看订单状态</li>
-      </ol>
-      
-      <h4>方法二:手机APP查询</h4>
-      <ol>
-        <li>打开APP并登录</li>
-        <li>点击底部导航栏"我的"</li>
-        <li>选择"我的订单"</li>
-        <li>查看相应订单状态</li>
-      </ol>
-      
-      <h4>方法三:联系客服查询</h4>
-      <p>如果您无法通过以上方式查询,可以联系客服提供订单号查询。</p>
-      
-      <p><strong>常见订单状态说明:</strong></p>
-      <ul>
-        <li><span class="status waiting">待付款</span> - 订单已生成,等待支付</li>
-        <li><span class="status paid">已支付</span> - 付款成功,等待处理</li>
-        <li><span class="status shipped">已发货</span> - 商品已发出</li>
-        <li><span class="status completed">已完成</span> - 订单交易完成</li>
-        <li><span class="status cancelled">已取消</span> - 订单已取消</li>
-      </ul>
-    `,
-    updateTime: '2023-05-20',
-    views: 2104,
-    isHot: true,
-    isNew: true,
-  },
-])
-
-// 当前选中的分类ID
-const activeCategory = ref(1)
-
-// 当前查看的问题详情
-const currentQuestion = ref(null)
-
-// 搜索查询词
-const searchQuery = ref('')
-
-// 搜索结果
-const searchResults = ref([])
-
-// 获取当前分类下的问题
-const filteredQuestions = computed(() => {
-  return questions.value.filter((q) => q.categoryId === activeCategory.value)
-})
-
-// 获取分类名称
-const getCategoryName = (id) => {
-  const category = categories.value.find((c) => c.id === id)
-  return category ? category.name : '所有问题'
-}
-
-// 切换分类
-const changeCategory = (categoryId) => {
-  activeCategory.value = categoryId
-  currentQuestion.value = null
-  searchResults.value = []
+<script setup lang="ts">
+import { useI18n } from 'vue-i18n'
+import { storeToRefs } from 'pinia'
+import { ref } from 'vue'
+import useSystemStore from '@/stores/useSystemStore'
+import useData from './hooks/useData'
+
+const { t } = useI18n()
+const systemStore = useSystemStore()
+const { locale } = storeToRefs(systemStore)
+
+const {
+  categoryList,
+  activeCategory,
+  questionList,
+  currentQuestion,
+  questions,
+  searchQuery,
+  searchResults,
+  getCategoryName,
+  changeCategory,
+  showQuestionDetail,
+  searchQuestions,
+  backToList,
+} = useData()
+
+const visible = ref<boolean>(false)
+
+const showCategoryDrawer = () => {
+  visible.value = true
 }
 }
 
 
-// 显示问题详情
-const showQuestionDetail = (question) => {
-  currentQuestion.value = question
-}
-
-// 返回问题列表
-const backToList = () => {
-  currentQuestion.value = null
-}
-
-// 搜索问题
-const searchQuestions = () => {
-  if (!searchQuery.value.trim()) {
-    searchResults.value = []
-    return
-  }
-
-  const query = searchQuery.value.toLowerCase()
-  searchResults.value = questions.value.filter((q) => {
-    return q.title.toLowerCase().includes(query) || q.preview.toLowerCase().includes(query)
-  })
-  currentQuestion.value = null
+const closeCategoryDrawer = () => {
+  visible.value = false
 }
 }
 
 
 // 格式化日期
 // 格式化日期
-const formatDate = (dateString) => {
+const formatDate = (dateString: string, lang: string) => {
   const options = { year: 'numeric', month: 'long', day: 'numeric' }
   const options = { year: 'numeric', month: 'long', day: 'numeric' }
-  return new Date(dateString).toLocaleDateString('zh-CN', options)
+  return new Date(dateString).toLocaleDateString(lang, options as Object)
 }
 }
 </script>
 </script>
 
 
@@ -424,8 +374,6 @@ const formatDate = (dateString) => {
 
 
 .question-banner {
 .question-banner {
   width: 100%;
   width: 100%;
-  background: linear-gradient(135deg, #1976d2, var(--color-active));
-  background: var(--color-active);
   background: rgba(0, 0, 0, 1);
   background: rgba(0, 0, 0, 1);
   color: white;
   color: white;
   padding: 40px 15px;
   padding: 40px 15px;
@@ -547,19 +495,19 @@ const formatDate = (dateString) => {
       font-size: 1.25rem;
       font-size: 1.25rem;
       margin-bottom: 15px;
       margin-bottom: 15px;
       margin-bottom: 0.9375rem;
       margin-bottom: 0.9375rem;
-      color: #1976d2;
+      color: var(--color-active);
     }
     }
   }
   }
 
 
   .question-list {
   .question-list {
     h2 {
     h2 {
-      font-size: 24px;
-      font-size: 1.5rem;
       margin-bottom: 20px;
       margin-bottom: 20px;
       margin-bottom: 1.25rem;
       margin-bottom: 1.25rem;
-      padding-bottom: 10px;
-      padding-bottom: 0.625rem;
+      padding: 10px 0;
+      padding: 0.625rem 0;
       border-bottom: 1px solid #eee;
       border-bottom: 1px solid #eee;
+      font-size: 24px;
+      font-size: 1.5rem;
     }
     }
   }
   }
 
 
@@ -616,14 +564,16 @@ const formatDate = (dateString) => {
       border-bottom: 1px solid #eee;
       border-bottom: 1px solid #eee;
 
 
       h2 {
       h2 {
-        font-size: 24px;
-        font-size: 1.8rem;
+        font-size: 28px;
+        font-size: 1.75rem;
         margin-bottom: 10px;
         margin-bottom: 10px;
         margin-bottom: 0.625rem;
         margin-bottom: 0.625rem;
+        text-align: center;
       }
       }
 
 
       .meta {
       .meta {
         display: flex;
         display: flex;
+        justify-content: center;
         gap: 15px;
         gap: 15px;
         gap: 0.9375rem;
         gap: 0.9375rem;
         color: #757575;
         color: #757575;
@@ -690,6 +640,98 @@ const formatDate = (dateString) => {
   }
   }
 }
 }
 
 
+.question-main-768 {
+  display: none;
+  padding-bottom: 0;
+}
+
+.question-main__container-768 {
+  flex-direction: column;
+  align-items: center;
+
+  .question-sidebar {
+    width: 100%;
+  }
+
+  .question-content {
+    width: 100%;
+    border-radius: 0px;
+    border-radius: 0rem;
+    padding: 0px 0;
+    padding: 0rem 0;
+    box-shadow: none;
+  }
+
+  .question-list {
+    h2 {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 8px;
+      margin-bottom: 0.5rem;
+      color: var(--color-active);
+      font-size: 18px;
+      font-size: 1.125rem;
+    }
+
+    .category-menu-btn {
+      display: flex;
+      align-items: center;
+      color: #333;
+      font-size: 16px;
+      font-size: 1rem;
+      cursor: pointer;
+    }
+
+    .category-menu-btn img {
+      width: 28px;
+      width: 1.75rem;
+      height: 28px;
+      height: 1.75rem;
+      margin-left: 6px;
+      margin-left: 0.375rem;
+    }
+  }
+
+  :deep(.ant-drawer-body) {
+    padding: 15px 12px;
+    padding: 0.9375rem 0.75rem;
+  }
+
+  .question-detail {
+    .detail-header {
+      margin-bottom: 24px;
+      margin-bottom: 1.5rem;
+      padding-bottom: 15px;
+      padding-bottom: 0.9375rem;
+      border-bottom: 1px solid #eee;
+
+      h2 {
+        padding-top: 15px;
+        padding-top: 0.9375rem;
+        margin-bottom: 4px;
+        margin-bottom: 0.25rem;
+        font-size: 24px;
+        font-size: 1.5rem;
+      }
+    }
+
+    .detail-footer {
+      margin-top: 0;
+      padding-top: 0;
+      border-bottom: 1px solid #eee;
+      border-top: 0;
+
+      .back-btn {
+        margin: 12px 0;
+        margin: 0.75rem 0;
+        color: var(--color-active);
+        background-color: rgba(0, 0, 0, 0.02125);
+      }
+    }
+  }
+}
+
 .contact-section {
 .contact-section {
   margin-top: 32px;
   margin-top: 32px;
   margin-top: 2rem;
   margin-top: 2rem;
@@ -737,7 +779,7 @@ const formatDate = (dateString) => {
     box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
     box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
 
 
     svg {
     svg {
-      color: #1976d2;
+      color: var(--color-active);
       margin-top: 3px;
       margin-top: 3px;
     }
     }
 
 

+ 5 - 1
src/views/Home/modules/Banners/index.vue

@@ -13,7 +13,7 @@
           $t('paragraph["连接全球优质商品,一键下单无忧,实时查看订单进程,享受便捷购物体验。"]')
           $t('paragraph["连接全球优质商品,一键下单无忧,实时查看订单进程,享受便捷购物体验。"]')
         }}
         }}
       </div>
       </div>
-      <div class="banners__content-btn">
+      <div class="banners__content-btn" @click="goRegister">
         <span>{{ $t('system["立即免费注册"]') }}</span>
         <span>{{ $t('system["立即免费注册"]') }}</span>
       </div>
       </div>
     </div>
     </div>
@@ -22,6 +22,10 @@
 
 
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
+// 注册跳转
+const goRegister = function () {
+  window.open('https://vavabuy.net/#/pages/login/register', '__blank')
+}
 </script>
 </script>
 
 
 
 

+ 6 - 1
src/views/Home/modules/WrapTwo/index.vue

@@ -33,7 +33,7 @@
         </div>
         </div>
       </div>
       </div>
       <div class="wrap__two-foot">
       <div class="wrap__two-foot">
-        <div class="wrap__two-btn">{{ $t('system["立即免费注册"]') }}</div>
+        <div class="wrap__two-btn" @click="goRegister">{{ $t('system["立即免费注册"]') }}</div>
       </div>
       </div>
     </div>
     </div>
   </section>
   </section>
@@ -63,6 +63,11 @@ const stepList = reactive<IStep[]>([
     desc: '合并包裹并节省高达80%的运费',
     desc: '合并包裹并节省高达80%的运费',
   },
   },
 ])
 ])
+
+// 注册跳转
+const goRegister = function () {
+  window.open('https://vavabuy.net/#/pages/login/register', '__blank')
+}
 </script>
 </script>
 
 
 
 

+ 1 - 1
src/views/Layout/modules/Header/hooks/useLinkList.ts

@@ -40,7 +40,7 @@ function useLinkList() {
     },
     },
     {
     {
       text: '在 VAVA BUY 购物',
       text: '在 VAVA BUY 购物',
-      url: 'https://www.baidu.com'
+      url: 'https://vavabuy.net'
     },
     },
   ])
   ])
 
 

+ 6 - 1
src/views/Layout/modules/Header/index.vue

@@ -43,7 +43,7 @@
               </a-menu>
               </a-menu>
             </template>
             </template>
           </a-dropdown>
           </a-dropdown>
-          <div class="login-btn">
+          <div class="login-btn" @click="goLogin">
             <span>{{ $t('system["登录"]') }}</span>
             <span>{{ $t('system["登录"]') }}</span>
           </div>
           </div>
         </div>
         </div>
@@ -168,6 +168,11 @@ const goHome = function () {
     path: '/',
     path: '/',
   })
   })
 }
 }
+
+// 登录跳转
+const goLogin = function () {
+  window.open('https://vavabuy.net/#/pages/login/login', '__blank')
+}
 </script>
 </script>
 
 
 
 

BIN
vava_buy_official.zip