SyuanYu преди 8 месеца
родител
ревизия
d387e20592

+ 3 - 3
src/components/Chat.vue

@@ -515,7 +515,7 @@ let shoppingList = reactive([
 ]);
 
 // 購物品牌查詢
-let shoppingBrandList = reactive([
+let brandList = reactive([
   {
     value: "國際珠寶腕錶",
     text: "shopping_discounts_info.brands.jewely",
@@ -1927,7 +1927,7 @@ function handleShoppingDialog(value) {
     messages.value.push({
       label: "shopping_brand",
       author: "ai",
-      body: shoppingBrandList,
+      body: brandList,
     });
   } else if (value === "國際貴賓卡專屬禮遇") {
     messages.value.push({
@@ -2453,7 +2453,7 @@ let dialog = ref(false);
         </button>
       </div> -->
 
-      <!-- <v-btn class="mt-5 ms-5" @click="dialog = true"> 購票測試介面 </v-btn> -->
+      <v-btn class="mt-5 ms-5" @click="dialog = true"> 購票測試介面 </v-btn>
 
       <v-dialog v-model="dialog" width="600">
         <v-card class="py-5">

+ 5 - 6
src/components/Navbar.vue

@@ -9,7 +9,9 @@ console.log("currentLanguage", currentLanguage);
 <template>
   <div class="navbar">
     <div class="d-flex align-center w-100">
-      <img src="../assets/img/logo.svg" alt="" class="logo" />
+      <router-link to="/">
+        <img src="../assets/img/logo.svg" alt="" class="logo" />
+      </router-link>
       <h1>{{ t("title") }}</h1>
     </div>
 
@@ -27,7 +29,6 @@ console.log("currentLanguage", currentLanguage);
 <style lang="scss" scoped>
 .navbar {
   height: 7vh;
-  // height: 50px;
   position: sticky;
   z-index: 1000;
   top: 0;
@@ -35,12 +36,10 @@ console.log("currentLanguage", currentLanguage);
   justify-content: space-between;
   padding: 10px;
   background-color: #fafcf7;
-
-  // @media (max-width: 375px) {
-  //   height: 9vh;
-  // }
+  box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15);
 
   .logo {
+    width: 100%;
     max-width: 80px;
   }
 

+ 113 - 0
src/components/TicketPurchase.vue

@@ -0,0 +1,113 @@
+<script setup>
+import { ref, reactive, onMounted, watch } from "vue";
+// FullCalendar
+import FullCalendar from "@fullcalendar/vue3";
+import dayGridPlugin from "@fullcalendar/daygrid";
+import interactionPlugin from "@fullcalendar/interaction";
+import zhTwLocale from "@fullcalendar/core/locales/zh-tw";
+
+let dialog = ref(false);
+
+// 日期選擇器設定
+const calendarOptions = ref({
+  editable: true,
+  selectable: true,
+  locale: zhTwLocale,
+  plugins: [dayGridPlugin, interactionPlugin],
+  initialView: "dayGridMonth",
+  headerToolbar: {
+    start: "prev",
+    center: "title",
+    end: "next",
+  },
+  selectAllow: function (info) {
+    return info.start >= getDateWithoutTime(new Date()); // 過去日期設為禁用
+  },
+  dayCellContent: function (args) {
+    const dayText = args.dayNumberText.trim();
+    const cleanedText = dayText.replace("日", ""); // 移除 "日"
+    return cleanedText;
+  },
+  datesSet: function (arg) {
+    console.log("切換日期:", arg.startStr, arg.endStr);
+    // 其他處理
+  },
+  // validRange: function (nowDate) {
+  //   console.log("nowDate", nowDate);
+  //   return {
+  //     start: nowDate,
+  //   };
+  // },
+});
+
+function getDateWithoutTime(dt) {
+  dt.setHours(0, 0, 0, 0);
+  return dt;
+}
+</script>
+
+<template>
+  <v-btn class="mt-5 ms-5" @click="dialog = true"> 購票測試介面 </v-btn>
+
+  <v-dialog v-model="dialog" width="600">
+    <v-card class="py-5">
+      <v-card-title>【台北101觀景台】2024快速通行門票 </v-card-title>
+
+      <v-card-text>
+        <img
+          class="w-100 mb-7"
+          src="https://cdn.fontrip.com/fontour/file/show/3m3RR/1024x684.jpg"
+          alt=""
+        />
+
+        <p class="pt-5 mb-3 border-t-sm font-weight-bold">請選擇預約日期</p>
+
+        <!-- 日期選擇器 -->
+        <FullCalendar :options="calendarOptions" />
+
+        <p class="mb-5 font-weight-bold">可預約時段 (尚餘數量)</p>
+
+        <v-menu class="time-menu">
+          <template v-slot:activator="{ props }">
+            <v-btn v-bind="props">
+              請選擇預約時段
+              <v-icon icon="mdi-menu-down" size="x-large" class="ms-1"></v-icon
+            ></v-btn>
+          </template>
+          <v-list>
+            <v-list-item v-for="(item, index) in 6" :key="index" :value="index">
+              <v-list-item-title class="d-flex justify-space-between">
+                <span>
+                  <p>平日</p>
+                  <small class="time">0{{ item }}:30</small>
+                </span>
+                <p class="quota">393</p>
+              </v-list-item-title>
+            </v-list-item>
+          </v-list>
+        </v-menu>
+
+        <p class="mt-10 mb-5 font-weight-bold">請選擇商品規格數量或參與人數</p>
+      </v-card-text>
+
+      <v-card-actions>
+        <v-btn class="ms-auto" text="Ok" @click="dialog = false"></v-btn>
+      </v-card-actions>
+    </v-card>
+  </v-dialog>
+</template>
+
+<style lang="scss">
+.time-menu {
+  .time {
+    display: block;
+    margin-top: -5px;
+    color: #969696;
+  }
+
+  .quota {
+    font-size: 12px;
+    color: #b28850;
+  }
+}
+</style>

+ 9 - 0
src/language/en.json

@@ -113,5 +113,14 @@
     "supermarket": "Supermarket",
     "din_tai_fung": "Din Tai Fung",
     "all_brands": "All Brands"
+  },
+  "external": {
+    "gifts": "Gifts",
+    "dining": "Dining",
+    "accommodation": "Accommodation",
+    "hairdressing": "Hairdressing",
+    "car_supplies": "Car Supplies",
+    "entertainment": "Entertainment",
+    "pet_supplies": "Pet Supplies"
   }
 }

+ 9 - 0
src/language/ja.json

@@ -113,5 +113,14 @@
     "supermarket": "超市",
     "din_tai_fung": "鼎泰豐",
     "all_brands": "全館品牌"
+  },
+  "external": {
+    "gifts": "伴手禮",
+    "dining": "餐飲",
+    "accommodation": "住宿",
+    "hairdressing": "美髮",
+    "car_supplies": "汽車用品",
+    "entertainment": "休閒娛樂",
+    "pet_supplies": "寵物用品"
   }
 }

+ 9 - 0
src/language/ko.json

@@ -113,5 +113,14 @@
     "supermarket": "超市",
     "din_tai_fung": "鼎泰豐",
     "all_brands": "全館品牌"
+  },
+  "external": {
+    "gifts": "伴手禮",
+    "dining": "餐飲",
+    "accommodation": "住宿",
+    "hairdressing": "美髮",
+    "car_supplies": "汽車用品",
+    "entertainment": "休閒娛樂",
+    "pet_supplies": "寵物用品"
   }
 }

+ 9 - 0
src/language/zh.json

@@ -113,5 +113,14 @@
     "supermarket": "超市",
     "din_tai_fung": "鼎泰豐",
     "all_brands": "全館品牌"
+  },
+  "external": {
+    "gifts": "伴手禮",
+    "dining": "餐飲",
+    "accommodation": "住宿",
+    "hairdressing": "美髮",
+    "car_supplies": "汽車用品",
+    "entertainment": "休閒娛樂",
+    "pet_supplies": "寵物用品"
   }
 }

+ 51 - 45
src/router/index.js

@@ -1,6 +1,7 @@
 import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
 import HomeView from '../views/HomeView.vue'
-import ArTourView from '../views/ArTourView.vue'
+import BrandSearch from '../views/BrandSearch.vue'
+// import ArTourView from '../views/ArTourView.vue'
 
 const router = createRouter({
   history: createWebHashHistory(),
@@ -10,52 +11,57 @@ const router = createRouter({
       name: 'home',
       component: HomeView,
     },
-    // 定位點網址設定
-    {
-      path: '/b1-1',
-      component: HomeView,
-    },
-    {
-      path: '/b1-2',
-      component: HomeView,
-    },
-    {
-      path: '/b1-3',
-      component: HomeView,
-    },
-    {
-      path: '/b1-4',
-      component: HomeView,
-    },
-    {
-      path: '/b1-5',
-      component: HomeView,
-    },
     {
-      path: '/1f-6',
-      component: HomeView,
-    },
-    {
-      path: '/1f-7',
-      component: HomeView,
-    },
-    {
-      path: '/2f-8',
-      component: HomeView,
-    },
-    {
-      path: '/89f-9',
-      component: HomeView,
-    },
-    {
-      path: '/88f-10',
-      component: HomeView,
-    },
-    {
-      path: '/ar-tour',
-      name: 'ar-tour',
-      component: ArTourView
+      path: '/brand-search',
+      name: 'BrandSearch',
+      component: BrandSearch,
     },
+    // 定位點網址設定
+    // {
+    //   path: '/b1-1',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/b1-2',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/b1-3',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/b1-4',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/b1-5',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/1f-6',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/1f-7',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/2f-8',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/89f-9',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/88f-10',
+    //   component: HomeView,
+    // },
+    // {
+    //   path: '/ar-tour',
+    //   name: 'ar-tour',
+    //   component: ArTourView
+    // },
   ]
 })
 

+ 0 - 12
src/stores/counter.js

@@ -1,12 +0,0 @@
-import { ref, computed } from 'vue'
-import { defineStore } from 'pinia'
-
-export const useCounterStore = defineStore('counter', () => {
-  const count = ref(0)
-  const doubleCount = computed(() => count.value * 2)
-  function increment() {
-    count.value++
-  }
-
-  return { count, doubleCount, increment }
-})

+ 16 - 0
src/stores/store.js

@@ -0,0 +1,16 @@
+import { defineStore } from 'pinia'
+
+export const useMainStore = defineStore('mainStore', {
+  state: () => ({
+  }),
+  getters: {
+    isMobile: () => {
+      // 判斷是否為手機裝置
+      return /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
+        window.navigator.userAgent
+      );
+    },
+  },
+  actions: {
+  },
+})

+ 257 - 0
src/views/BrandSearch.vue

@@ -0,0 +1,257 @@
+<script setup>
+import { ref, reactive, watch } from "vue";
+import { useMainStore } from "../stores/store";
+// i18n
+import { useI18n } from "vue-i18n";
+// Axios
+import axios from "axios";
+// Components
+import Navbar from "../components/Navbar.vue";
+
+const { t } = useI18n();
+const store = useMainStore();
+let loading = ref(false);
+let pageNum = ref(1); // 當前頁數(預設第一頁)
+let pageAmount = ref(10); // 每頁顯示筆數
+let totalPages = ref(1); // 總頁數
+
+let assignBrand = ref("");
+let searchKeyword = ref("");
+
+// 按鈕篩選
+function filterBrand(val) {
+  console.log("searchKeyword", searchKeyword);
+  pageNum.value = 1;
+  assignBrand.value = val;
+  getBrand();
+}
+
+watch(pageNum, () => {
+  getBrand();
+});
+
+let data = reactive({
+  list: [],
+});
+
+// 取得館外品牌
+async function getBrand() {
+  loading.value = true;
+
+  let keyword = "館外";
+  let url = `https://cmm.ai:9101/find_brand?language=ch&page_num=${pageNum.value}&page_amount=${pageAmount.value}`;
+
+  if (searchKeyword.value !== "") {
+    url += `&search_name=${searchKeyword.value}`;
+  }
+
+  // 指定類別
+  if (assignBrand.value !== "") {
+    keyword += `,${assignBrand.value}`;
+  }
+
+  url += `&keyword=${keyword}`;
+
+  try {
+    const response = await axios.get(url);
+    data.list = response.data.data;
+    totalPages.value = getTotalPages(response.data.all_num, pageAmount.value); // 計算頁數
+    loading.value = false;
+    console.log("館外品牌", response.data.data);
+  } catch (error) {
+    console.error(error);
+  }
+}
+
+getBrand();
+
+// 計算頁數
+function getTotalPages(totalRecords, recordsPerPage) {
+  return Math.ceil(totalRecords / recordsPerPage);
+}
+
+// 截斷文字
+const truncateText = (text, maxLength) => {
+  text = text.replace(/\s+/g, "");
+  if (text.length <= maxLength) {
+    return text;
+  }
+  return text.substring(0, maxLength) + "...";
+};
+
+let brandList = reactive([
+  {
+    value: "伴手禮",
+    text: "external.gifts",
+  },
+  {
+    value: "餐飲",
+    text: "external.dining",
+  },
+  {
+    value: "住宿",
+    text: "external.accommodation",
+  },
+  {
+    value: "美髮",
+    text: "external.hairdressing",
+  },
+  {
+    value: "汽車用品",
+    text: "external.car_supplies",
+  },
+  {
+    value: "休閒娛樂",
+    text: "external.entertainment",
+  },
+  {
+    value: "寵物用品",
+    text: "external.pet_supplies",
+  },
+]);
+</script>
+<template>
+  <Navbar />
+
+  <div class="brand-list">
+    <v-text-field
+      v-model="searchKeyword"
+      append-inner-icon="mdi-magnify"
+      density="compact"
+      label="搜尋品牌"
+      variant="outlined"
+      hide-details
+      single-line
+      @click:append-inner="onClick"
+      class="border-sm rounded"
+    ></v-text-field>
+
+    <v-row class="mt-3 px-1">
+      <v-col
+        cols="6"
+        v-for="(item, index) in brandList"
+        :key="index"
+        class="pa-2"
+      >
+        <button @click="filterBrand(item.value)" class="rounded brand-btn">
+          {{ t(item.text) }}
+        </button>
+      </v-col>
+    </v-row>
+
+    <div v-if="loading" class="d-flex justify-center pt-15">
+      <v-progress-circular color="primary" indeterminate></v-progress-circular>
+    </div>
+
+    <v-row v-else class="content mt-0">
+      <v-col
+        cols="12"
+        class="card"
+        v-for="(item, index) in data.list"
+        :key="index"
+      >
+        <a :href="item.info.url" target="_blank">
+          <img class="card-img" :src="item.info.img" :alt="item.info.name" />
+        </a>
+        <h2>{{ item.info.name }}</h2>
+        <p>{{ truncateText(item.info.content, 100) }}</p>
+        <div class="d-flex align-center mt-3 mb-5">
+          <img src="../assets/img/location-dot-solid.svg" width="15" alt="" />
+          <p class="ms-2">{{ item.info.address }}</p>
+        </div>
+        <div class="cta">
+          <a :href="item.info.url" target="_blank">
+            <button>立即前往</button>
+          </a>
+        </div>
+      </v-col>
+    </v-row>
+
+    <v-pagination
+      v-if="!loading"
+      color="primary"
+      v-model="pageNum"
+      class="my-10"
+      :length="totalPages"
+    ></v-pagination>
+  </div>
+</template>
+
+<style lang="scss">
+.brand-list {
+  width: 90%;
+  margin: 30px auto;
+
+  .brand-btn {
+    width: 100%;
+    padding: 0.7rem;
+    color: var(--main-color);
+    background-color: #f5f2eb;
+    letter-spacing: 1px;
+    transition: all .3s;
+
+    &:hover {
+      color: #fff;
+      background-color: var(--main-color);
+    }
+  }
+
+  .content {
+    text-align: center;
+
+    .card {
+      border-bottom: 1px solid #cea84d;
+      padding: 2rem 1rem;
+
+      &:last-child {
+        border-bottom: none !important;
+      }
+    }
+
+    .card {
+      letter-spacing: 0.05rem;
+
+      h2 {
+        margin: 0.5rem 0;
+        font-size: 1.2rem;
+        font-weight: bold;
+        text-align: left;
+      }
+
+      p {
+        text-align: left;
+      }
+
+      .card-img {
+        width: 100%;
+        height: 220px;
+        object-fit: contain;
+      }
+
+      .cta {
+        text-align: right;
+
+        button {
+          padding: 10px 20px;
+          border-radius: 100px;
+          color: #fff;
+          text-align: center;
+          background-color: #b07843;
+          letter-spacing: 0.05rem;
+          text-decoration: none;
+          transition: all 0.3s;
+        }
+      }
+    }
+  }
+
+  .v-pagination {
+    margin: auto;
+    max-width: 300px;
+  }
+
+  .v-btn--icon.v-btn--density-default {
+    width: 35px !important;
+  }
+}
+</style>

+ 4668 - 12
src/views/HomeView.vue

@@ -1,26 +1,4682 @@
 <script setup>
-import Chat from "../components/Chat.vue";
+import { ref, reactive, onMounted, watch, nextTick } from "vue";
+import { useRoute } from "vue-router";
+// VR
+import "aframe";
+// i18n
+import { useI18n } from "vue-i18n";
+// Axios
+import axios from "axios";
+// Moment
+import moment from "moment";
+// Animate
+import "animate.css";
+// Swiper
+import { Swiper, SwiperSlide } from "swiper/vue";
+import { Navigation, Autoplay } from "swiper/modules";
+import "swiper/css";
+import "swiper/css/navigation";
+// Recorder
+import Recorder from "recorder-core";
+import "recorder-core/src/engine/mp3";
+import "recorder-core/src/engine/mp3-engine";
+// QR Code
+import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from "vue-qrcode-reader";
+// Components
 import Navbar from "../components/Navbar.vue";
+import TicketPurchase from "../components/TicketPurchase.vue";
+
+const { t, locale } = useI18n();
+
+const route = useRoute();
+const routeParam = ref(null);
+
+let qrCodeDialog = ref(false);
+let qrCodeLoading = ref(true);
+let location = ref(""); // 當前位置
+
+// QR Code 掃描
+function onDetect(detectedCodes) {
+  console.log("detectedCodes", detectedCodes);
+
+  const url = new URL(detectedCodes[0].rawValue);
+  location.value = url.searchParams.get("location");
+
+  let val;
+  let lang = getLang();
+
+  if (lang === "en") {
+    switch (location.value) {
+      case "B1 鼎泰豐":
+        val = "b1 Din Tai Fung";
+        break;
+      case "B1 中環":
+        val = "b1 Centre";
+        break;
+      case "B1 2號電梯":
+        val = "b1 Elevator No.2";
+        break;
+      case "B1 4號電梯":
+        val = "b1 Elevator No.4";
+        break;
+      case "B1 3號電梯":
+        val = "b1 Elevator No.3";
+        break;
+      case "1F 信義環":
+        val = "1f South Xinyi";
+        break;
+      case "1F 3號電梯":
+        val = "1f Elevator No.3";
+        break;
+      case "2F 3號電梯":
+        val = "2f Elevator No.3";
+        break;
+      case "88F 觀景台":
+        val = "88f Observatory";
+        break;
+      case "89F 觀景台":
+        val = "89f Observatory";
+        break;
+
+      default:
+        break;
+    }
+  } else if (lang === "ch") {
+    val = location.value;
+  }
+
+  if (location.value && location.value !== "") {
+    qrCodeDialog.value = false;
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: `${t("current_location")}:${val}`,
+    });
+
+    changeLocation(location.value); // 選擇導覽位置
+  } else {
+    qrCodeDialog.value = false;
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: "讀取錯誤,請重新掃描。",
+    });
+  }
+}
+
+// 判斷 vue-qrcode-reader 是否加載完成
+function onInit(capabilities) {
+  qrCodeLoading.value = false;
+}
+
+onMounted(() => {
+  // 取得當前路由參數
+  routeParam.value = route.path.replace("/", "");
+  console.log("網址參數", routeParam.value);
+  window.addEventListener("resize", handleResize);
+});
+
+const userMessage = ref("");
+let modules = [Navigation, Autoplay]; // Swiper
+
+// AI 客服回覆訊息
+let messages = ref([]);
+
+watch(messages.value, (val) => {
+  console.log("messages", val);
+  scrollToBottom();
+  updateMenuHeight();
+});
+
+let ad = ref({}); // 彈跳視窗廣告
+let qaQuery = reactive([]);
+
+const chatArea = ref(null); // 對話框
+
+// 滾動到對話框底部
+const scrollToBottom = () => {
+  setTimeout(() => {
+    // chatArea.value.scrollTop = chatArea.value.scrollHeight;
+
+    window.scrollTo({
+      top: document.body.scrollHeight,
+      behavior: "smooth", // 平滑滾動
+    });
+  }, 100);
+
+  // let list = messages.value;
+  // const item = list[list.length - 1];
+  // if (item.label === "text") {
+  //   setTimeout(() => {
+  //     chatArea.value.scrollTop = chatArea.value.scrollHeight;
+  //   }, 100);
+  // }
+};
+
+// 對話選項(按鈕)
+function setBtnValue(val) {
+  console.log("value", val);
+  userMessage.value = val;
+  sendMessage("text");
+}
+
+// 傳送訊息 (如 type="text" 代表為純文字訊息,不需語音回覆)
+async function sendMessage(type = "") {
+  if (userMessage.value === "") {
+    return;
+  }
+
+  console.log("sendMessage", userMessage.value);
+  qaQuery.push(userMessage.value);
+
+  let url = "https://devbox10.itri-nlp.tw:38125/v1/qa/";
+
+  try {
+    // 使用者訊息
+    messages.value.push({
+      label: "text",
+      body: userMessage.value,
+      author: "user",
+    });
+
+    userMessage.value = "";
+    // hideMenu.value = true;
+
+    axios
+      .post(
+        url,
+        new URLSearchParams({
+          query: JSON.stringify(qaQuery), // 使用者問句
+          language: selectLang.value, // 語系
+          category: assignCategory.value, // 類別
+          subtype: assignSubtype.value, // 詳細類別(非必填)
+          from_loc: "", // 定位點
+          to_loc: "", // 導覽點
+        }),
+        {
+          headers: {
+            "Content-Type": "application/x-www-form-urlencoded",
+          },
+        }
+      )
+      .then((response) => {
+        // if (showAnchor.value) {
+        //   getVideo(response.data);
+        // }
+
+        // AI 客服回傳訊息
+        messages.value.push({
+          label: "text",
+          author: "ai",
+          body: response.data.response,
+        });
+
+        console.log("response", response);
+
+        if (type !== "text") {
+          handleTTS(response.data.response); // 取得語音回覆
+        }
+
+        if (response.data.data.length) {
+          let info = {
+            buttonList: [], // 按鈕
+            ticketList: [], // 票券
+          };
+          let labelContent;
+
+          response.data.data.map((item) => {
+            if (item.type === "button") {
+              console.log("按鈕");
+              info.buttonList.push(item);
+              labelContent = "ticket";
+            } else if (item.type === "ticket") {
+              console.log("票");
+              info.ticketList.push(item);
+              labelContent = "ticket";
+            } else if (item.type === "brand") {
+              console.log("品牌");
+              info.ticketList.push(item);
+              labelContent = "brand";
+            }
+          });
+
+          console.log("info", info);
+          console.log("labelContent", labelContent);
+
+          setTimeout(() => {
+            messages.value.push({
+              label: labelContent,
+              author: "ai",
+              body: info,
+            });
+          }, 10);
+        }
+      })
+      .catch((error) => {
+        console.error("Error:", error);
+      });
+
+    console.log("messages.value", messages.value);
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// let isTTSVideo = ref(false); // API 是否回傳影片
+// let ttsVideo = ref(null); // 影片 dom
+// let ttsVideoSrc = ref(""); // 影片路徑
+// let videoPause = ref(false); // 暫停按鈕
+let hideMenu = ref(false); // 底部選單
+let showInput = ref(false); // 輸入框
+
+// 取得 mp4
+// async function getVideo(data) {
+//   console.log("getVideo data", data);
+//   // let url = `https://cmm.ai:9101/tts?message=${data.response}&type=101`;
+//   let url = `https://bf18-61-230-0-215.ngrok-free.app/tts?message=${data.response}&type=101`;
+
+//   try {
+//     const response = await axios.post(url);
+//     console.log("response", response);
+
+//     if (response.status === 200) {
+//       video.value.pause();
+//       videoPause.value = false;
+
+//       // ttsVideoSrc.value = `https://cmm.ai:9101/${response.data.url}`;
+//       // ttsVideoSrc.value = `https://bf18-61-230-0-215.ngrok-free.app/${response.data.url}`;
+//       ttsVideoSrc.value = response.data.url;
+//       await ttsVideo.value.load();
+//       await ttsVideo.value.play();
+
+//       // AI 客服回傳訊息
+//       // messages.value.splice(-1, 1);
+
+//       messages.value.push({
+//         type: data.type,
+//         body: data.response,
+//         author: data.author,
+//       });
+
+//       // isTTSVideo.value = true;
+
+//       // 判斷影片是否結束
+//       const videoPromise = new Promise((resolve, reject) => {
+//         ttsVideo.value.onended = () => resolve(true);
+//       });
+
+//       const videoCompleted = await videoPromise; // 影片結束
+
+//       if (videoCompleted) {
+//         console.log("影片結束");
+//         // isTTSVideo.value = false; // 切換為初始影片
+//         hideAnchorPrologue.value = false; // 切換開場白影片
+//       }
+
+//       console.log("videoCompleted", videoCompleted);
+//     }
+//   } catch (error) {
+//     console.log("error", error);
+//   }
+// }
+
+// 影片暫停/播放
+// function handleVideo(isTTS) {
+//   if (videoPause.value) {
+//     if (isTTS) {
+//       ttsVideo.value.play();
+//     } else {
+//       video.value.play();
+//     }
+//     videoPause.value = false;
+//   } else {
+//     if (isTTS) {
+//       ttsVideo.value.pause();
+//     } else {
+//       video.value.pause();
+//     }
+//     videoPause.value = true;
+//   }
+// }
+
+function getLang() {
+  let lang = localStorage.getItem("lang");
+  let langVal = "";
+
+  switch (lang) {
+    case "zh-tw":
+      langVal = "ch";
+      break;
+    case "en-us":
+      langVal = "en";
+      break;
+
+    default:
+      break;
+  }
+
+  return langVal;
+}
+
+let showAd = ref(false);
+
+// 取得廣告
+async function setAd() {
+  let lang = getLang();
+  console.log("lang", lang);
+  let url = `https://cmm.ai:9101/ad?language=${lang}`;
+
+  try {
+    const response = await axios.get(url);
+    console.log("Ad response", response);
+
+    ad.value = response.data.data.body;
+    console.log("Ad", ad.value);
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+let video = ref(null);
+
+function videoPlay() {
+  video.value.load();
+  video.value.play();
+}
+
+// 底部選單
+const menu = ref(null);
+const menuHeight = ref(0);
+
+// let isRotate = ref(false);
+let isLanguagePage = ref(true);
+let selectLang = ref("");
+let chatLoading = ref(true);
+
+watch(isLanguagePage, (val) => {
+  if (!val) {
+    setTimeout(updateMenuHeight, 500);
+  }
+});
+
+const handleResize = () => {
+  updateMenuHeight();
+};
+
+// 取得底部選單高度
+const updateMenuHeight = () => {
+  nextTick(() => {
+    if (menu.value) {
+      menuHeight.value = menu.value.clientHeight;
+      chatLoading.value = false;
+    }
+  });
+};
+
+function chooseLang(lang) {
+  console.log("選擇語言:", lang);
+  selectLang.value = lang;
+  isLanguagePage.value = false;
+  locale.value = lang; // i18n locale
+  localStorage.setItem("lang", lang);
+
+  messages.value.push({
+    label: "text",
+    author: "ai",
+    body: t("prologue"),
+  });
+
+  messages.value.push({
+    label: "text",
+    author: "ai",
+    body: t("service"),
+  });
+
+  // messages.value.push({
+  //   label: "text",
+  //   author: "ai",
+  //   body: "請選擇問題類型:",
+  // });
+
+  // messages.value.push({
+  //   label: "btn-list",
+  //   author: "ai",
+  //   body: "",
+  // });
+
+  setAd();
+  handleClick();
+
+  console.log(" messages.value", messages.value);
+  setTimeout(() => {
+    showAd.value = true;
+    // videoPlay();
+  }, 500);
+}
+
+let assignSubtype = ref("");
+let assignCategory = ref("");
+let assignCategoryIndex = ref(null);
+
+// 美食伴手禮
+let diningList = reactive([
+  {
+    value: "特色/高空餐廳",
+    text: "food_souvenirs_info.signature",
+  },
+  {
+    value: "輕食/CAFÉ",
+    text: "food_souvenirs_info.light",
+  },
+  {
+    value: "美食街",
+    text: "food_souvenirs_info.courts",
+  },
+  {
+    value: "伴手禮",
+    text: "food_souvenirs_info.souvenir",
+  },
+]);
+
+// 秘境花園觀景台
+let observationList = reactive([
+  {
+    value: "線上購票",
+    text: "observatory_info.tickets.title",
+  },
+  {
+    value: "參觀資訊",
+    text: "observatory_info.visitor.title",
+  },
+  // {
+  //   value: "實境景色",
+  //   text: "observatory_info.view",
+  // },
+  {
+    value: "前往秘境花園觀景台",
+    text: "observatory_info.garden",
+  },
+]);
+
+// 購物及優惠
+let shoppingList = reactive([
+  {
+    value: "購物品牌查詢",
+    text: "shopping_discounts_info.brands.title",
+  },
+  {
+    value: "國際貴賓卡專屬禮遇",
+    text: "shopping_discounts_info.tourist_card.title",
+  },
+]);
+
+// 購物品牌查詢
+let brandList = reactive([
+  {
+    value: "國際珠寶腕錶",
+    text: "shopping_discounts_info.brands.jewely",
+  },
+  {
+    value: "國際精品",
+    text: "shopping_discounts_info.brands.boutique",
+  },
+  {
+    value: "美妝保養品",
+    text: "shopping_discounts_info.brands.skincare",
+  },
+  {
+    value: "流行服飾",
+    text: "shopping_discounts_info.brands.apparel",
+  },
+  {
+    value: "生活居家/3C",
+    text: "shopping_discounts_info.brands.lifestyle",
+  },
+  {
+    value: "文化創意",
+    text: "shopping_discounts_info.brands.cultural",
+  },
+  {
+    value: "特色品牌",
+    text: "shopping_discounts_info.brands.signature",
+  },
+  {
+    value: "館外店家",
+    text: "shopping_discounts_info.brands.outside",
+  },
+]);
+
+// 服務資訊
+let serviceList = reactive([
+  {
+    title: "service_info.business_hours",
+    depiction: "service_info.business_hours_1",
+  },
+  {
+    title: "service_info.tax_refund",
+    depiction: "service_info.tax_refund_1",
+  },
+  {
+    title: "service_info.toilets",
+    depiction: "service_info.toilets_1",
+  },
+  {
+    title: "service_info.charge",
+    depiction: "service_info.charge_1",
+  },
+  // {
+  //   title: "AI 天燈",
+  //   depiction: "https://cmm.ai/101-postcard/#/skylanternhome",
+  // },
+]);
+
+// 定位點
+let locationList = reactive([
+  {
+    location: "B1 鼎泰豐", // 編號 1
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "退稅/外幣兌換櫃台",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "鼎泰豐",
+    //   "捷運",
+    //   "超市",
+    //   "美食街",
+    //   "退稅/外幣兌換櫃台",
+    //   "計程車乘車處",
+    //   "無障礙廁所",
+    //   "客服(停車折抵)",
+    //   "哺乳室",
+    //   "飲水機",
+    //   "伴手禮區",
+    //   "廁所",
+    //   "置物櫃",
+    // ],
+  },
+  {
+    location: "B1 中環", // 編號 2
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "美食街",
+    //   "伴手禮區",
+    //   "鼎泰豐",
+    //   "捷運",
+    //   "超市",
+    //   "計程車乘車處",
+    //   "無障礙廁所",
+    // ],
+  },
+  {
+    location: "B1 2號電梯", // 編號 3
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "客服(退稅櫃台/外幣兌換)",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "客服(退稅櫃台/外幣兌換)",
+    //   "計程車乘車處",
+    //   "無障礙廁所",
+    //   "超市",
+    //   "鼎泰豐",
+    //   "捷運",
+    //   "伴手禮區",
+    //   "廁所",
+    //   "置物櫃",
+    //   "美食街",
+    //   "客服(停車折抵)",
+    //   "哺乳室",
+    //   "飲水機",
+    //   "廁所",
+    // ],
+  },
+  {
+    location: "B1 4號電梯", // 編號 4
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "退稅/外幣兌換櫃台",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "廁所",
+    //   "置物櫃",
+    //   "客服(停車折抵)",
+    //   "哺乳室",
+    //   "飲水機",
+    //   "退稅/外幣兌換櫃台",
+    //   "計程車乘車處",
+    //   "無障礙廁所",
+    //   "伴手禮區",
+    //   "捷運",
+    //   "鼎泰豐",
+    //   "美食街",
+    //   "超市",
+    // ],
+  },
+  {
+    location: "B1 3號電梯", // 編號 5
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "客服(退稅櫃台/外幣兌換)",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "廁所",
+    //   "無障礙廁所",
+    //   "計程車乘車處",
+    //   "客服(退稅櫃台/外幣兌換)",
+    //   "飲水機",
+    //   "哺乳室",
+    //   "置物櫃",
+    //   "客服(停車折抵)",
+    //   "美食街",
+    //   "伴手禮區",
+    //   "鼎泰豐",
+    //   "捷運",
+    //   "超市",
+    // ],
+  },
+  {
+    location: "1F 信義環", // 編號 6
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "退稅/外幣兌換櫃台",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "鼎泰豐",
+        text: "din_tai_fung",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "廁所",
+    //   "ATM",
+    //   "置物櫃",
+    //   "飲水機",
+    //   "無障礙廁所",
+    //   "哺乳室",
+    //   "客服(停車折抵)",
+    //   "退稅/外幣兌換櫃台",
+    //   "伴手禮區",
+    //   "美食街",
+    //   "捷運",
+    //   "鼎泰豐",
+    //   "超市",
+    // ],
+  },
+  {
+    location: "1F 3號電梯", // 編號 7
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+      {
+        value: "退稅/外幣兌換櫃台",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "美食街",
+        text: "food_court",
+      },
+      {
+        value: "超市",
+        text: "supermarket",
+      },
+      {
+        value: "捷運",
+        text: "metro_station",
+      },
+      {
+        value: "伴手禮區",
+        text: "snackable_souvenirs",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "廁所",
+    //   "置物櫃",
+    //   "飲水機",
+    //   "無障礙廁所",
+    //   "哺乳室",
+    //   "客服(停車折抵)",
+    //   "退稅/外幣兌換櫃台",
+    //   "計程車乘車處",
+    //   "美食街",
+    //   "超市",
+    //   "捷運",
+    //   "伴手禮區",
+    // ],
+  },
+  {
+    location: "2F 3號電梯", // 編號 8
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "觀景台售票處",
+        text: "observatory_ticket_office",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "置物櫃",
+        text: "items_and_luggage_storage",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "無障礙廁所",
+        text: "accessible_facilities",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+      {
+        value: "計程車乘車處",
+        text: "taxi_station",
+      },
+      {
+        value: "退稅/外幣兌換櫃台",
+        text: "tax_refund_currency_exchange",
+      },
+      {
+        value: "客服(停車折抵)",
+        text: "service_counter_parking_discount",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "觀景台售票處",
+    //   "廁所",
+    //   "置物櫃",
+    //   "飲水機",
+    //   "無障礙廁所",
+    //   "哺乳室",
+    //   "計程車乘車處",
+    //   "退稅/外幣兌換櫃台",
+    //   "客服(停車折抵)",
+    // ],
+  },
+  {
+    location: "89F 觀景台", // 編號 9
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "客服",
+        text: "service_counter",
+      },
+      {
+        value: "91F戶外區",
+        text: "91f_outdoor_area",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "101F排隊處",
+        text: "101f_queue_area",
+      },
+    ],
+    // navigation: [
+    //   "景觀餐廳櫃台",
+    //   "ATM",
+    //   "客服",
+    //   "91F戶外區",
+    //   "廁所",
+    //   "101F排隊處",
+    // ],
+  },
+  {
+    location: "88F 觀景台", // 編號 10
+    navigation: [
+      {
+        value: "景觀餐廳櫃台",
+        text: "high_rise_restaurant_reception",
+      },
+      {
+        value: "ATM",
+        text: "atm",
+      },
+      {
+        value: "廁所",
+        text: "restroom",
+      },
+      {
+        value: "飲水機",
+        text: "ice_warmed_water_dispenser",
+      },
+      {
+        value: "哺乳室",
+        text: "nursing_room",
+      },
+    ],
+    // navigation: ["景觀餐廳櫃台", "ATM", "廁所", "飲水機", "哺乳室"],
+  },
+]);
+
+// 平面圖
+let mapList = reactive([
+  {
+    title: "B1 平面圖",
+  },
+  {
+    title: "1F 平面圖",
+  },
+  {
+    title: "2F 平面圖",
+  },
+]);
+
+let assignLocation = ref("當前位置"); // 指定定位點
+let assignNavigationList = ref(null); // 指定導覽點列表
+// let assignLocationFloor = ref(null); // 指定定位點樓層
+// let assignNavigation = ref(null); // 指定導覽點
+// let navigationBtn = reactive(["B1", "1F", "2F", "4F", "5F", "89F", "91F"]);
+
+let arVideo = ref(null);
+let arVideoDialog = ref(false);
+
+// 取得 AR 導覽影片
+async function getArviews(route, text, type = "") {
+  let url;
+  let lang = getLang();
+  console.log("text >>>", text);
+
+  if (type === "garden") {
+    console.log("route", route);
+    let start;
+    // if (route === "B1 鼎泰豐旁 數位屏幕") {
+    //   start = "B1 鼎泰豐";
+    // } else if (route === "B1 松智藍梯梯廳") {
+    //   start = "B1 3號電梯";
+    // }
+
+    switch (route) {
+      case "B1 鼎泰豐旁 數位屏幕":
+        start = "B1 鼎泰豐";
+        break;
+      case "B1 中環WOW屏幕":
+        start = "B1 中環";
+        break;
+      case "B1 信義橘梯梯廳":
+        start = "B1 2號電梯";
+        break;
+      case "B1 信義綠梯梯廳":
+        start = "B1 4號電梯";
+        break;
+      case "B1 松智藍梯梯廳":
+        start = "B1 3號電梯";
+        break;
+      case "1F 信義綠梯出入口":
+        start = "1F 信義環";
+        break;
+      case "1F 松智梯廳":
+        start = "1F 3號電梯";
+        break;
+      case "2F 松智藍梯梯廳":
+        start = "2F 3號電梯";
+        break;
+      default:
+        break;
+    }
+
+    url = `https://cmm.ai:9101/arviews?language=${lang}&start=${start}&end=觀景台售票處`;
+  } else {
+    url = `https://cmm.ai:9101/arviews?language=${lang}&start=${assignLocation.value}&end=${route}`;
+  }
+
+  console.log("url", url);
+
+  messages.value.push({
+    label: "text",
+    author: "ai",
+    body: text,
+  });
+
+  try {
+    const response = await axios.get(url);
+    console.log("AR 導覽影片", response);
+
+    messages.value.push({
+      label: "ar_views",
+      author: "ai",
+      body: response.data,
+    });
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// 取得定位點 & 導覽點
+function changeLocation(item) {
+  assignLocation.value = item;
+
+  console.log("定位點:", item);
+
+  let assign = locationList.filter((e) => e.location === item);
+  console.log("assign", assign);
+
+  assignNavigationList.value = assign[0].navigation;
+
+  // assignLocation.value = item.location;
+  // assignNavigationList.value = item.navigation;
+
+  console.log("assignNavigationList.value", assignNavigationList.value);
+
+  messages.value.push({
+    label: "text",
+    author: "ai",
+    body: t("select_navigation_location"),
+  });
+
+  messages.value.push({
+    label: "navigation",
+    author: "ai",
+    body: assignNavigationList.value,
+  });
+}
+
+// 顯示平面圖
+function assignMapImg(item) {
+  console.log("顯示平面圖 item", item);
+  let name;
+  if (item.title === "B1 平面圖") {
+    name = "All_b1";
+  } else if (item.title === "1F 平面圖") {
+    name = "All_1";
+  } else if (item.title === "2F 平面圖") {
+    name = "All_2";
+  }
+
+  messages.value.push({
+    label: "map_img",
+    author: "ai",
+    body: name,
+  });
+}
+
+// 動態引入視頻文件
+const videoSources = ref([]); // 開場白影片(中)
+const videoSourcesEn = ref([]); // 開場白影片(英)
+const videoMuteSources = ref([]); // 點頭影片(靜音)
+const videoSpeakSources = ref([]); // 動嘴型影片
+
+const loadVideoSources = async () => {
+  // 本地端影片路徑
+  // const start1 = await import("@/assets/video/start_1.mp4");
+  // const start2 = await import("@/assets/video/start_2.mp4");
+  // const mute_1 = await import("@/assets/video/mute_1.mp4");
+  // const mute_2 = await import("@/assets/video/mute_2.mp4");
+  // const speak_1 = await import("@/assets/video/speak_1.mp4");
+  // const speak_2 = await import("@/assets/video/speak_2.mp4");
+  // videoSpeakSources.value = [speak_1.default, speak_2.default];
+
+  videoSources.value = [
+    "https://cmm.ai/101-ai-chatbot-new/video/start_1.mp4",
+    "https://cmm.ai/101-ai-chatbot-new/video/start_2.mp4",
+  ];
+  videoSourcesEn.value = [
+    "https://cmm.ai/101-ai-chatbot-new/video/start_en_1.mp4",
+    "https://cmm.ai/101-ai-chatbot-new/video/start_en_2.mp4",
+  ];
+  videoMuteSources.value = [
+    "https://cmm.ai/101-ai-chatbot-new/video/mute_1.mp4",
+    "https://cmm.ai/101-ai-chatbot-new/video/mute_2.mp4",
+  ];
+  videoSpeakSources.value = [
+    "https://cmm.ai/101-ai-chatbot-new/video/speak_1.mp4",
+    "https://cmm.ai/101-ai-chatbot-new/video/speak_2.mp4",
+  ];
+};
+
+let videoSrc = ref("");
+let hideAnchorPrologue = ref(false); // 顯示開場白 or 點頭影片
+let videoIndex = ref(null); // 影片編號
+
+// 選擇類別
+async function selectCategory(value, index) {
+  assignCategory.value = value;
+  assignCategoryIndex.value = index;
+  console.log("selectCategory index", assignCategoryIndex.value);
+  console.log("selectCategory value", assignCategory.value);
+
+  if (value === "叫出真人客服") {
+    showAnchor.value = true;
+
+    if (currentAudio.value && isAudioPlaying.value) {
+      // currentAudio.value.addEventListener("ended", onAudioEnded); // 監聽音訊播放結束
+      // setTimeout(() => {
+      //   video.value.play();
+      // }, 0);
+      // return;
+      handleVoice("pause"); // 暫停音訊
+    }
+
+    // 隨機取得影片路徑
+    await loadVideoSources();
+
+    // 主播開場白只顯示一次
+    if (!hideAnchorPrologue.value) {
+      let lang = getLang();
+      let sources;
+
+      if (lang === "ch") {
+        sources = videoSources.value;
+      } else if (lang === "en") {
+        sources = videoSourcesEn.value;
+      }
+
+      const randomIndex = Math.floor(Math.random() * sources.length);
+      videoSrc.value = sources[randomIndex];
+      hideAnchorPrologue.value = true;
+      videoIndex.value = randomIndex + 1;
+
+      // const randomIndex = Math.floor(Math.random() * videoSources.value.length);
+      // videoSrc.value = videoSources.value[randomIndex];
+      // hideAnchorPrologue.value = true;
+      // videoIndex.value = randomIndex + 1;
+    } else {
+      const randomIndex = Math.floor(
+        Math.random() * videoMuteSources.value.length
+      );
+      videoSrc.value = videoMuteSources.value[randomIndex];
+      videoIndex.value = randomIndex + 1;
+    }
+
+    // 播放影片
+    setTimeout(() => {
+      videoPlay();
+    }, 0);
+
+    // const randomIndex = Math.floor(Math.random() * videoSources.value.length);
+    // videoSrc.value = videoSources.value[randomIndex];
+  }
+  //  else if (value === "隱藏真人客服") {
+  //   showAnchor.value = false;
+  //   video.value.pause();
+  //   menuList[0][0].text = "customer_show";
+  //   menuList[0][0].value = "叫出真人客服";
+  // }
+  else if (value === "秘境花園觀景台") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.tickets.purchase"),
+    });
+
+    messages.value.push({
+      label: "observation_deck",
+      author: "ai",
+      body: observationList,
+    });
+  } else if (value === "位置導引") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("qr_code_scan_prompt"),
+    });
+
+    // messages.value.push({
+    //   label: "map_img",
+    //   author: "ai",
+    //   body: mapList,
+    // });
+
+    messages.value.push({
+      label: "location",
+      author: "ai",
+      body: locationList,
+    });
+  } else if (value === "美食/伴手禮") {
+    getAd("美食伴手禮");
+
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("food_souvenirs_info.searching"),
+    });
+
+    messages.value.push({
+      label: "dining",
+      author: "ai",
+      body: diningList,
+    });
+  } else if (value === "購物及優惠") {
+    getAd("購物及優惠");
+
+    messages.value.push({
+      label: "shopping",
+      author: "ai",
+      body: shoppingList,
+    });
+  } else if (value === "服務資訊") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("service_info.inquiry_prompt"),
+    });
+
+    messages.value.push({
+      label: "service",
+      author: "ai",
+      body: serviceList,
+    });
+  }
+}
+
+let secondaryAd = ref({}); // 隨機廣告
+let secondaryAdShow = ref(false);
+
+// 取得隨機廣告 (美食伴手禮/購物及優惠)
+async function getAd(type) {
+  let lang = getLang();
+  let url = `https://cmm.ai:9101/ad/${type}?language=${lang}`;
+
+  try {
+    const response = await axios.get(url);
+    console.log("response", response);
+    secondaryAd.value = response.data.data;
+    // secondaryAdShow.value = true; // 取消蓋版廣告
+
+    messages.value.push({
+      label: "brand",
+      author: "ai",
+      body: [
+        {
+          info: response.data.data,
+        },
+      ],
+    });
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// 服務資訊回覆
+function handleService(title, depiction) {
+  messages.value.push({
+    label: "text",
+    author: "user",
+    body: title,
+  });
+
+  if (title !== "AI 天燈") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: depiction,
+    });
+  } else {
+    window.location.href = depiction;
+    // window.open(depiction, "_blank"); // 另開天燈頁面
+  }
+}
+
+// 參觀資訊回覆
+function handleVisit(title, depiction) {
+  messages.value.push({
+    label: "text",
+    author: "user",
+    body: title,
+  });
+
+  messages.value.push({
+    label: "text",
+    author: "ai",
+    body: depiction,
+  });
+}
+
+// 計算使用次數
+async function handleClick() {
+  let url = "https://cmm.ai:9101/click";
+  try {
+    const response = await axios.get(url);
+    console.log("Click", response);
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+let langList = reactive([
+  {
+    lang: "中文",
+    value: "zh-tw",
+  },
+  {
+    lang: "English",
+    value: "en-us",
+  },
+  // {
+  //   lang: "日本語",
+  //   value: "ja-jp",
+  // },
+  // {
+  //   lang: "한국어",
+  //   value: "ko-kr",
+  // },
+]);
+
+const btnList = reactive([
+  {
+    title: "observation_deck",
+    value: "秘境花園觀景台",
+  },
+  {
+    title: "location_guide",
+    value: "位置導引",
+  },
+  {
+    title: "food_souvenirs",
+    value: "美食伴手禮",
+  },
+  {
+    title: "shopping_discounts",
+    value: "購物及優惠",
+  },
+  {
+    title: "service_information",
+    value: "服務資訊",
+  },
+]);
+
+function getImageUrl(name) {
+  return new URL(`../assets/img/icon/${name}`, import.meta.url).href;
+}
+
+let showAnchor = ref(false); // AI 主播影片
+let videoContent = ref(null); // 主播影片區塊
+
+// 動態更改主播區塊位置
+// watch(showAnchor, () => {
+//   console.log("showAnchor", showAnchor.value);
+//   nextTick(() => {
+//     changeAnchorTop();
+//   });
+// });
+
+// watch(hideMenu, () => {
+//   nextTick(() => {
+//     changeAnchorTop();
+//   });
+// });
+
+// function changeAnchorTop() {
+//   const menuOffsetTop = menu.value.offsetTop;
+//   videoContent.value.style.top = `${menuOffsetTop - 170}px`;
+// }
+
+const menuList = reactive([
+  [
+    {
+      imgSrc: "素材-05.png",
+      text: "customer_show",
+      value: "叫出真人客服",
+    },
+    { imgSrc: "素材-06.png", text: "service_information", value: "服務資訊" },
+    { imgSrc: "素材-07.png", text: "shopping_discounts", value: "購物及優惠" },
+  ],
+  [
+    {
+      imgSrc: "素材-08.png",
+      text: "observation_deck",
+      value: "秘境花園觀景台",
+    },
+    { imgSrc: "素材-09.png", text: "food_souvenirs", value: "美食/伴手禮" },
+    { imgSrc: "素材-10.png", text: "location_guide", value: "位置導引" },
+  ],
+]);
+
+// 美食伴手禮 or 購物及優惠類別篩選
+async function findBrand(value) {
+  console.log("findBrand", value);
+
+  if (value === "館外店家") {
+    value = "館外";
+  }
+
+  let lang = getLang();
+  let url = `https://cmm.ai:9101/find_brand?keyword=${value}&language=${lang}`;
+
+  try {
+    const response = await axios.get(url);
+    console.log("response", response);
+
+    // response.data.data.map(
+    //   (item) => (item.info.tags = JSON.parse(item.info.tags))
+    // );
+
+    messages.value.push({
+      label: "brand",
+      author: "ai",
+      body: response.data.data,
+    });
+
+    assignCategoryIndex.value = null;
+    assignCategory.value = "";
+
+    // messages.value.push({
+    //   label: "text",
+    //   author: "ai",
+    //   body: "請選擇問題類型:",
+    // });
+
+    // messages.value.push({
+    //   label: "btn-list",
+    //   author: "ai",
+    //   body: "",
+    // });
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// 處理電話格式
+// function getPhoneNumber(phoneString) {
+//   const parts = phoneString.split("\n");
+//   return parts[1];
+// }
+
+// 取得線上購票
+async function getStaticTickets(type) {
+  let url = `https://cmm.ai:9101/static_tickets?is_Chinese=${type}`;
+
+  let info = {
+    buttonList: [], // 按鈕
+    ticketList: [], // 票券
+  };
+
+  try {
+    const response = await axios.get(url);
+    console.log("線上購票", response.data.result);
+
+    response.data.result.map((item) => info.ticketList.push(item));
+    console.log("info", info);
+
+    messages.value.push({
+      label: "ticket",
+      author: "ai",
+      body: info,
+    });
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// 秘境花園觀景台對話
+function handleObservationDialog(value) {
+  console.log("value", value);
+
+  if (value === "線上購票") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.tickets.id_card"),
+    });
+
+    messages.value.push({
+      label: "check",
+      author: "ai",
+      body: [
+        {
+          value: "是",
+          text: "observatory_info.tickets.yes",
+        },
+        {
+          value: "否",
+          text: "observatory_info.tickets.no",
+        },
+      ],
+    });
+  } else if (value === "是" || value === "否") {
+    if (value === "是") {
+      getStaticTickets("1");
+    } else if (value === "否") {
+      getStaticTickets("0");
+    }
+
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.tickets.ticket_type"),
+    });
+  } else if (value === "參觀資訊") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.visitor.question"),
+    });
+
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.visitor.faq"),
+    });
+
+    messages.value.push({
+      label: "visit",
+      author: "ai",
+      body: visitList,
+    });
+  } else if (value === "實境景色") {
+    // window.location.href = "https://www.youtube.com/watch?v=RVV00FZbeH0";
+    window.open("https://www.youtube.com/watch?v=RVV00FZbeH0", "_blank"); // 另開頁面
+  } else if (value === "前往秘境花園觀景台") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("select_location"),
+    });
+
+    messages.value.push({
+      label: "garden_route",
+      author: "ai",
+      body: [
+        "B1 鼎泰豐旁 數位屏幕",
+        "B1 中環WOW屏幕",
+        "B1 信義橘梯梯廳",
+        "B1 信義綠梯梯廳",
+        "B1 松智藍梯梯廳",
+        "1F 信義綠梯出入口",
+        "1F 松智梯廳",
+        "2F 松智藍梯梯廳",
+      ],
+    });
+  }
+}
+
+// 購物及優惠對話
+function handleShoppingDialog(value) {
+  console.log("value", value);
+
+  if (value === "購物品牌查詢") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: "請選擇品牌類別",
+    });
+
+    messages.value.push({
+      label: "shopping_brand",
+      author: "ai",
+      body: brandList,
+    });
+  } else if (value === "國際貴賓卡專屬禮遇") {
+    messages.value.push({
+      label: "text",
+      author: "user",
+      body: "國際貴賓卡專屬禮遇",
+    });
+
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("shopping_discounts_info.tourist_card.content"),
+    });
+  } else if (value === "參觀資訊") {
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.visitor.question"),
+    });
+
+    messages.value.push({
+      label: "text",
+      author: "ai",
+      body: t("observatory_info.visitor.faq"),
+    });
+
+    messages.value.push({
+      label: "visit",
+      author: "ai",
+      body: visitList,
+    });
+  }
+}
+
+let visitList = reactive([
+  {
+    title: "observatory_info.visitor.events_q",
+    depiction: "observatory_info.visitor.events_a",
+  },
+  {
+    title: "observatory_info.visitor.ball_q",
+    depiction: "observatory_info.visitor.ball_a",
+  },
+  {
+    title: "observatory_info.visitor.accessible_q",
+    depiction: "observatory_info.visitor.accessible_a",
+  },
+]);
+
+// 判斷價格是否包含 $ 符號
+function formatPrice(price) {
+  if (price === "") {
+    return "";
+  } else {
+    if (price.includes("$")) {
+      return price;
+    } else {
+      return `$${price}`;
+    }
+  }
+}
+
+let currentAudio = ref(null); // 當前音訊
+let audioDuration = ref(null); // 音訊秒數
+
+// 文字轉語音 (TTS)
+async function handleTTS(message) {
+  console.log("handleTTS", message);
+  let audioLang; // 音訊語言
+  let lang = localStorage.getItem("lang");
+  console.log("lang", lang);
+
+  switch (lang) {
+    case "zh-tw":
+      audioLang = "cmn-TW";
+      break;
+    case "en-us":
+      audioLang = "en-US";
+      break;
+    case "ja-jp":
+      audioLang = "ja-JP";
+      break;
+    case "ko-kr":
+      audioLang = "ko-KR";
+      break;
+    default:
+      break;
+  }
+
+  // let url = `https://bf18-61-230-0-215.ngrok-free.app/ttsTry/tts_try?message=${message}&type=101`;
+  let url = `https://bf18-61-230-0-215.ngrok-free.app/gcp/text-to-speech?language_code=${audioLang}&gender=female`;
+
+  const formData = new FormData();
+  formData.append("text", message);
+
+  try {
+    const response = await axios.post(url, formData, { responseType: "blob" });
+    console.log("TTS response", response);
+
+    const blob = new Blob([response.data], { type: "audio/mp3" });
+    const audioUrl = URL.createObjectURL(blob);
+    console.log("audioUrl", audioUrl);
+    cutVideo();
+
+    // 取得 mp3 音訊秒數
+    // audio.addEventListener("loadedmetadata", function () {
+    //   audioDuration.value = audio.duration;
+    //   cutVideo();
+    // });
+
+    // 暫停當前音訊
+    if (currentAudio.value) {
+      currentAudio.value.pause();
+      currentAudio.value.currentTime = 0;
+    }
+
+    // 播放音檔
+    currentAudio.value = new Audio(audioUrl);
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+let videoLoading = ref(false);
+let isAudioPlaying = ref(false); // 音訊播放狀態
+
+// 取得語音回覆 mp4
+async function cutVideo() {
+  videoSrc.value = videoSpeakSources.value[videoIndex.value - 1];
+  video.value.load(); // 重新讀取影片
+
+  // let duration = Math.floor(audioDuration.value); // 音訊秒數
+
+  // 影片和音訊加載完成後播放
+  video.value.oncanplay = () => {
+    setTimeout(() => {
+      // 監聽音訊播放結束
+      currentAudio.value.addEventListener("ended", onAudioEnded);
+
+      // 監聽音訊播放狀態
+      currentAudio.value.addEventListener("play", onAudioPlay);
+      currentAudio.value.addEventListener("pause", onAudioPause);
+
+      video.value.play(); // 播放影片
+      currentAudio.value.currentTime = 0; // 重置時間
+      currentAudio.value.play(); // 播放音訊
+      isVideoPause.value = true;
+      videoLoading.value = false;
+    }, 500);
+  };
+
+  // video.value.currentTime = 0;
+  // video.value.play(); // 播放影片
+  // currentAudio.value.play(); // 播放音訊
+  // isVideoPause.value = true;
+  // videoLoading.value = false;
+
+  // setTimeout(()=>{
+  //   video.value.play(); // 播放影片
+  // },300)
+
+  // // 監聽音訊播放狀態
+  // currentAudio.value.addEventListener("play", onAudioPlay);
+  // currentAudio.value.addEventListener("pause", onAudioPause);
+
+  // 監聽音訊播放結束
+  // currentAudio.value.addEventListener("ended", onAudioEnded);
+
+  // if (video.value.currentTime >= duration) {
+  //   video.value.pause();
+  // }
+}
+
+// 音訊結束後暫停影片播放
+const onAudioEnded = () => {
+  video.value.pause();
+};
+
+// 判斷音訊是否為播放狀態
+const onAudioPlay = () => {
+  isAudioPlaying.value = true;
+  console.log("isAudioPlaying.value", isAudioPlaying.value);
+};
+
+const onAudioPause = () => {
+  isAudioPlaying.value = false;
+  console.log("isAudioPlaying.value", isAudioPlaying.value);
+};
+
+const audioURL = ref(null);
+const audioFile = ref(null); // 音訊檔案
+
+let recordTime = ref(0); // 錄音時間
+let isRecording = ref(false); // 錄音狀態
+let timer;
+
+// 語音轉文字
+async function handleAudioToText() {
+  isRecording.value = false;
+  let audioLang; // 音訊語言
+  let lang = localStorage.getItem("lang");
+  console.log("lang", lang);
+
+  switch (lang) {
+    case "zh-tw":
+      audioLang = "cmn-Hant-TW";
+      break;
+    case "en-us":
+      audioLang = "en-US";
+      break;
+    case "ja-jp":
+      audioLang = "ja-JP";
+      break;
+    case "ko-kr":
+      audioLang = "ko-KR";
+      break;
+    default:
+      break;
+  }
+
+  // let url = `http://172.104.93.163:9880/whisper/${audioLang}/`;
+  // let url = `https://bf18-61-230-0-215.ngrok-free.app/whisper/${audioLang}/`;
+  let url = `https://bf18-61-230-0-215.ngrok-free.app/gcp/speech-to-text?language_code=${audioLang}`;
+
+  const formData = new FormData();
+  formData.append("file", audioFile.value);
+
+  try {
+    console.log("audioFile.value", audioFile.value);
+    const response = await axios.post(url, formData);
+    console.log("語音轉文字 response", response);
+    // showAnchor.value = false; // 關閉主播視窗
+
+    userMessage.value = response.data[0];
+    // handleTTS(userMessage.value); // 取得語音回覆
+
+    if (response.data[0] && response.data[0] !== "") {
+      sendMessage(); // 傳送使用者訊息
+    } else {
+      if (showAnchor.value) {
+        alert("語音辨識有誤,請重新錄製。");
+        videoLoading.value = false;
+        return;
+      } else {
+        messages.value.push({
+          label: "text",
+          author: "user",
+          body: "語音辨識有誤,請重新錄製。",
+        });
+      }
+    }
+  } catch (error) {
+    console.log("error", error);
+  }
+}
+
+// 語音轉文字 (使用 recorder-core 錄音)
+let rec, wave;
+
+// 調用 open 請求錄音權限
+let recOpen = function (success) {
+  rec = Recorder({
+    type: "mp3",
+    sampleRate: 16000,
+    bitRate: 16,
+    onProcess: function (
+      buffers,
+      powerLevel,
+      bufferDuration,
+      bufferSampleRate,
+      newBufferIdx,
+      asyncEnd
+    ) {
+      wave &&
+        wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate);
+    },
+  });
+
+  rec.open(
+    function () {
+      if (Recorder.WaveView) wave = Recorder.WaveView({ elem: ".recwave" });
+      success && success();
+    },
+    function (msg, isUserNotAllow) {
+      // 使用者未授權或不支援
+      console.log((isUserNotAllow ? "UserNotAllow," : "") + "無法錄音:" + msg);
+    }
+  );
+};
+
+/** 開始錄音 **/
+function recStart() {
+  togglePause("pause"); // 暫停影片音訊
+  // 需先呼叫 recOpen() 開啟錄音後才能調用 start、stop 方法
+  console.log("開始錄音");
+
+  recOpen(function () {
+    isRecording.value = true;
+
+    // 開始計時
+    timer = setInterval(() => {
+      recordTime.value += 1;
+    }, 1000);
+
+    rec.start();
+  });
+}
+
+/** 結束錄音 **/
+function recStop() {
+  videoLoading.value = true;
+  rec.stop(
+    function (blob, duration) {
+      // 利用 URL 產生本地檔案位址,不用時需要 revokeObjectURL
+      let localUrl = (window.URL || webkitURL).createObjectURL(blob); // 該 url 只能本地端使用 (例如給 audio.src 進行播放,或是給 a.href download 進行下載)
+      console.log(blob, localUrl, "時長:" + duration + "ms");
+      // rec.close(); // 釋放錄音資源 (若不釋放系統或瀏覽器將持續提示在錄音中)
+      // rec = null;
+
+      // 將 Blob 轉換為 File 對象
+      audioFile.value = new File([blob], "recording.mp3", {
+        type: "audio/mp3",
+      });
+
+      console.log("audioFile", audioFile.value);
+
+      // 自動播放(測試用)
+      // const audio = document.createElement("audio");
+      // audio.src = localUrl;
+      // audio.autoplay = true;
+      // audio
+      //   .play()
+      //   .then(() => {
+      //     console.log("Audio is playing automatically.");
+      //   })
+      //   .catch((error) => {
+      //     console.error("Error playing audio:", error);
+      //   });
+
+      rec.close(); // 釋放錄音資源 (若不釋放系統或瀏覽器將持續提示在錄音中)
+      rec = null;
+
+      if (recordTime.value !== 0) {
+        handleAudioToText(); // 語音轉文字
+      } else {
+        isRecording.value = false;
+      }
+
+      clearInterval(timer); // 清空計時秒數
+      recordTime.value = 0;
+    },
+    function (msg) {
+      console.log("錄音失敗:" + msg);
+      rec.close(); // 可以透過 stop 方法的第 3 個參數來自動呼叫 close
+      rec = null;
+    }
+  );
+}
+
+// 關閉主播視窗 (結束錄音)
+function closeRec() {
+  video.value.pause();
+  isVideoPause.value = true;
+  recordTime.value = 0;
+  clearInterval(timer); // 清空計時秒數
+  if (isRecording.value) {
+    recStop();
+  }
+  showAnchor.value = false;
+}
+
+// watch(showAnchor, (val) => {
+//   if (val) {
+//     isVideoPause.value = true;
+//   }
+// });
+
+let isVideoPause = ref(true);
+
+// AI 主播影片播放 & 暫停
+function togglePause(val) {
+  if (val === "pause") {
+    // video.value.pause();
+    isVideoPause.value = false;
+
+    if (video.value) {
+      video.value.pause();
+    }
+    if (currentAudio.value) {
+      currentAudio.value.pause(); // 暫停音訊
+    }
+  } else {
+    // video.value.play();
+    isVideoPause.value = true;
+
+    if (video.value) {
+      video.value.play();
+    }
+    if (currentAudio.value) {
+      currentAudio.value.play(); // 播放音訊
+      currentAudio.value.addEventListener("ended", onAudioEnded);
+    }
+  }
+}
+
+// 語音暫停
+function handleVoice(state) {
+  if (currentAudio.value) {
+    if (state === "pause") {
+      currentAudio.value.pause();
+      isVideoPause.value = false;
+    } else {
+      currentAudio.value.play();
+      isVideoPause.value = true;
+    }
+  }
+}
 </script>
 
-<template>
-  <!-- <Navbar /> -->
-  <Chat />
+<template>
+  <Navbar v-if="!isLanguagePage" />
+
+  <div v-if="isLanguagePage" class="lang-content">
+    <div class="btn-list">
+      <button
+        v-for="(item, index) in langList"
+        :key="index"
+        @click="chooseLang(item.value)"
+        class="main-btn"
+      >
+        {{ item.lang }}
+      </button>
+    </div>
+  </div>
+
+  <div v-else-if="!isLanguagePage && !showAnchor" class="main-containar">
+    <!-- <div class="video-content">
+      <video
+        ref="video"
+        preload
+        playsinline
+        :style="{ opacity: !isTTSVideo ? '1' : '0' }"
+      >
+        <source src="../assets/video/start_1.mp4" type="video/mp4" />
+        Your browser does not support the video tag.
+      </video>
+
+      <video
+        ref="ttsVideo"
+        preload
+        playsinline
+        :style="{ opacity: isTTSVideo ? '1' : '0' }"
+      >
+        <source :src="ttsVideoSrc" type="video/mp4" />
+
+        Your browser does not support the video tag.
+      </video>
+
+      <button @click="handleVideo(isTTSVideo)" class="control-btn">
+        <img v-if="!videoPause" src="../assets/img/pause-button.png" alt="" />
+        <img v-else src="../assets/img/play-button.png" alt="" />
+      </button>
+    </div> -->
+
+    <!-- <Navbar /> -->
+    <div v-if="chatLoading" class="d-flex justify-center pt-5">
+      <v-progress-circular color="primary" indeterminate></v-progress-circular>
+    </div>
+
+    <div
+      v-else
+      class="chat-content"
+      :class="{ 'hide-menu': hideMenu }"
+      :style="{ paddingBottom: !hideMenu ? menuHeight + 'px' : '50px' }"
+    >
+      <!-- <div class="headline">
+        <h1>{{ t("title") }}</h1>
+        <button @click="isRotate = !isRotate">
+          <img
+            :class="{ rotate: isRotate }"
+            src="../assets/img/angles-up-solid.svg"
+            alt=""
+          />
+        </button>
+      </div> -->
+
+      <!-- 購票介面 -->
+      <TicketPurchase />
+
+      <router-link
+        to="/brand-search"
+        style="color: #fff; text-decoration: none"
+        class="ps-3"
+        >館外品牌測試頁面</router-link
+      >
+
+      <!-- 語音暫停按鈕 -->
+      <div v-if="currentAudio" class="voice-btn">
+        <button v-if="isAudioPlaying" @click="togglePause('pause')">
+          <img src="../assets/img/pause-button.png" alt="" />
+          <p>語音</p>
+        </button>
+
+        <button v-else @click="togglePause('play')">
+          <img src="../assets/img/play-button.png" alt="" />
+          <p>語音</p>
+        </button>
+      </div>
+
+      <section
+        ref="chatArea"
+        class="chat-area"
+        :class="{ 'hide-menu': hideMenu }"
+      >
+        <div v-for="message in messages" class="message-content">
+          <p
+            v-if="message.label === 'text'"
+            class="message animate__animated"
+            :class="{
+              'message-out': message.author === 'user',
+              'message-in': message.author !== 'user',
+              animate__fadeInRight: message.author === 'user',
+              animate__fadeInLeft: message.author !== 'user',
+            }"
+            v-html="message.body"
+          ></p>
+
+          <!-- 問題類別 -->
+          <!-- <div v-else-if="message.label === 'btn-list'">
+            <ul class="btn-list">
+              <li v-for="(btn, index) in btnList">
+                <button
+                  :class="{ active: index === assignCategoryIndex }"
+                  @click="selectCategory(btn.value, index)"
+                >
+                  {{ t(`${btn.title}`) }}
+                </button>
+              </li>
+            </ul>
+          </div> -->
+
+          <!-- 秘境花園觀景台 -->
+          <div v-else-if="message.label === 'observation_deck'">
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="handleObservationDialog(item.value)">
+                    {{ t(item.text) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 確認按鈕 -->
+          <div v-else-if="message.label === 'check'">
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="handleObservationDialog(item.value)">
+                    {{ t(item.text) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 參觀資訊 -->
+          <div v-else-if="message.label === 'visit'">
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button
+                    @click="handleVisit(t(item.title), t(item.depiction))"
+                  >
+                    {{ t(item.title) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 位置導引 (定位點) -->
+          <div v-else-if="message.label === 'location'">
+            <!-- <v-select
+              @update:modelValue="changeLocation"
+              v-model="assignLocation"
+              label="當前位置"
+              :items="locationList"
+              item-title="location"
+              item-value="location"
+              variant="outlined"
+              density="comfortable"
+              hide-details
+              color="primary"
+              class="mt-5 me-15"
+              :menu-props="{ maxHeight: '155px' }"
+            ></v-select> -->
+
+            <!-- 掃描 QR Code -->
+            <v-btn @click="qrCodeDialog = true" color="primary" class="mt-5">
+              {{ t("tap_to_start_scan") }}
+            </v-btn>
+
+            <v-dialog v-model="qrCodeDialog" width="auto">
+              <v-card max-width="400">
+                <v-card-text>
+                  <div v-if="qrCodeLoading" class="d-flex justify-center pt-5">
+                    <v-progress-circular
+                      color="primary"
+                      indeterminate
+                    ></v-progress-circular>
+                  </div>
+
+                  <qrcode-stream
+                    v-show="!qrCodeLoading"
+                    @detect="onDetect"
+                    @camera-on="onInit"
+                  ></qrcode-stream>
+                </v-card-text>
+
+                <template v-slot:actions>
+                  <v-btn
+                    class="ms-auto"
+                    text="關閉"
+                    @click="qrCodeDialog = false"
+                  ></v-btn>
+                </template>
+              </v-card>
+            </v-dialog>
+
+            <!-- <div class="d-flex">
+              <v-menu location="top">
+                <template v-slot:activator="{ props }">
+                  <v-btn class="mt-5 py-2" color="primary" dark v-bind="props">
+                    <p class="me-2">{{ assignLocation }}</p>
+                    <svg
+                      xmlns="http://www.w3.org/2000/svg"
+                      width="18"
+                      height="18"
+                      fill="currentColor"
+                      class="bi bi-caret-down-fill pt-1"
+                      viewBox="0 0 16 16"
+                    >
+                      <path
+                        d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"
+                      />
+                    </svg>
+                  </v-btn>
+                </template>
+
+                <v-list style="max-height: 155px; overflow-y: auto">
+                  <v-list-item
+                    v-for="(item, index) in locationList"
+                    :key="index"
+                  >
+                    <v-list-item-title @click="changeLocation(item)">
+                      {{ index + 1 }}. {{ item.location }}
+                    </v-list-item-title>
+                  </v-list-item>
+                </v-list>
+              </v-menu>
+
+              <v-menu location="top">
+                <template v-slot:activator="{ props }">
+                  <v-btn
+                    class="ms-5 mt-5 py-2"
+                    color="primary"
+                    dark
+                    v-bind="props"
+                  >
+                    <p class="me-2">查看平面圖</p>
+                    <svg
+                      xmlns="http://www.w3.org/2000/svg"
+                      width="18"
+                      height="18"
+                      fill="currentColor"
+                      class="bi bi-caret-down-fill pt-1"
+                      viewBox="0 0 16 16"
+                    >
+                      <path
+                        d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"
+                      />
+                    </svg>
+                  </v-btn>
+                </template>
+
+                <v-list style="max-height: 155px; overflow-y: auto">
+                  <v-list-item v-for="(item, index) in mapList" :key="index">
+                    <v-list-item-title @click="assignMapImg(item)">
+                      {{ item.title }}
+                    </v-list-item-title>
+                  </v-list-item>
+                </v-list>
+              </v-menu>
+            </div> -->
+          </div>
+
+          <!-- 定位點平面圖 -->
+          <!-- <div v-else-if="message.label === 'map_img'" class="mt-5">
+            <img
+              class="map-img"
+              :class="{ 'show-anchor': showAnchor }"
+              :src="`../src/assets/img/map/${message.body}.webp`"
+              alt=""
+            />
+          </div> -->
+
+          <!-- 位置導引 (導覽點) -->
+          <div v-else-if="message.label === 'navigation'">
+            <!-- <v-select
+              @update:modelValue="changeLocation"
+              v-model="assignNavigation"
+              label="導覽位置"
+              :items="assignNavigationList"
+              variant="solo"
+              hide-details
+              class="bg-white mt-4"
+            ></v-select> -->
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button
+                    @click="
+                      getArviews(item.value, t(`navigation.${item.text}`))
+                    "
+                  >
+                    {{ t(`navigation.${item.text}`) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 秘境花園觀景台 -->
+          <div v-else-if="message.label === 'garden_route'">
+            <!-- <v-select
+              @update:modelValue="changeLocation"
+              v-model="assignNavigation"
+              label="導覽位置"
+              :items="assignNavigationList"
+              variant="solo"
+              hide-details
+              class="bg-white mt-4"
+            ></v-select> -->
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="getArviews(item, item, 'garden')">
+                    {{ item }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- AR 導覽影片 -->
+          <div v-else-if="message.label === 'ar_views'">
+            <div
+              class="message animate__animated"
+              :class="{
+                'message-out': message.author === 'user',
+                'message-in': message.author !== 'user',
+                animate__fadeInRight: message.author === 'user',
+                animate__fadeInLeft: message.author !== 'user',
+              }"
+            >
+              <p v-html="message.body.words"></p>
+
+              <button @click="arVideoDialog = true" class="ar-link my-3">
+                進行 AR 導覽
+              </button>
+
+              <v-dialog v-model="arVideoDialog" width="auto">
+                <v-card class="ar-card">
+                  <v-card-title class="mt-3"> AR 導覽 </v-card-title>
+
+                  <v-card-text class="pa-0">
+                    <a-scene>
+                      <a-assets>
+                        <video
+                          id="vr-video"
+                          ref="arVideo"
+                          :src="message.body.url"
+                          autoplay
+                          crossorigin="anonymous"
+                          ecrossorigin="anonymous"
+                        ></video>
+                      </a-assets>
+
+                      <a-sky src="#vr-video"></a-sky>
+                    </a-scene>
+                  </v-card-text>
+
+                  <template v-slot:actions>
+                    <v-btn
+                      class="ms-auto"
+                      text="關閉"
+                      @click="arVideoDialog = false"
+                    ></v-btn>
+                  </template>
+                </v-card>
+              </v-dialog>
+            </div>
+          </div>
+
+          <!-- 美食伴手禮 -->
+          <div v-else-if="message.label === 'dining'">
+            <!-- <ul class="btn-options">
+              <li v-for="item in message.body">
+                <button @click="findBrand(item.value)">
+                  {{ t(item.text) }}
+                </button>
+              </li>
+            </ul> -->
+
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="findBrand(item.value)">
+                    {{ t(item.text) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 購物及優惠 -->
+          <div v-else-if="message.label === 'shopping'">
+            <!-- <ul class="btn-options">
+              <li v-for="item in message.body">
+                <button @click="handleShoppingDialog(item.value)">
+                  {{ t(item.text) }}
+                </button>
+              </li>
+            </ul> -->
+
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="handleShoppingDialog(item.value)">
+                    {{ t(item.text) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 購物品牌查詢 -->
+          <div v-else-if="message.label === 'shopping_brand'">
+            <!-- <ul class="btn-options">
+              <li v-for="item in message.body">
+                <button @click="findBrand(item.value)">
+                  {{ item.value }}
+                </button>
+              </li>
+            </ul> -->
+
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button @click="findBrand(item.value)">
+                    {{ t(item.text) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 服務資訊 (常見問題) -->
+          <div v-else-if="message.label === 'service'">
+            <swiper
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="btn-container">
+                  <button
+                    @click="handleService(t(item.title), t(item.depiction))"
+                  >
+                    {{ t(item.title) }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 推薦資訊 -->
+          <div v-else-if="message.label === 'ticket'" class="ticket-item">
+            <!-- 按鈕 -->
+            <swiper
+              v-if="message.body.buttonList.length"
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+              :style="{
+                marginBottom: message.body.ticketList.length ? '35px' : '0px',
+              }"
+            >
+              <swiper-slide v-for="item in message.body.buttonList">
+                <div class="btn-container">
+                  <button @click="setBtnValue(item.info.value)">
+                    {{ item.info.key }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+
+            <!-- 票券 -->
+            <swiper
+              v-if="message.body.ticketList.length"
+              :slidesPerView="1"
+              :navigation="true"
+              :modules="modules"
+              class="ticket-slide"
+            >
+              <swiper-slide v-for="item in message.body.ticketList">
+                <div class="slide-item">
+                  <img
+                    class="cover-img"
+                    :src="item.info.img || item.info.cover_img"
+                    alt=""
+                  />
+                  <section>
+                    <h3 class="title">
+                      {{ item.info.name || item.info.title }}
+                    </h3>
+                    <div class="price-info">
+                      <span>{{ item.info.floor || item.info.price }}</span>
+                      <div class="link-btn">
+                        <a
+                          :href="item.info.website_url || item.info.url"
+                          target="_blank"
+                        >
+                          {{ t("ctaGoUrl") }}
+                        </a>
+                      </div>
+                    </div>
+                    <p class="description">
+                      {{ item.info.content || item.info.description }}
+                    </p>
+                  </section>
+                </div>
+              </swiper-slide>
+            </swiper>
+          </div>
+
+          <!-- 品牌資訊 -->
+          <div v-else-if="message.label === 'brand'" class="ticket-item">
+            <!-- 按鈕 -->
+            <swiper
+              v-if="message.body.buttonList?.length"
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+              class="btn-swiper"
+              :style="{
+                marginBottom: message.body.ticketList.length ? '35px' : '0px',
+              }"
+            >
+              <swiper-slide v-for="item in message.body.buttonList">
+                <div class="btn-container">
+                  <button @click="setBtnValue(item.info.value)">
+                    {{ item.info.key }}
+                  </button>
+                </div>
+              </swiper-slide>
+            </swiper>
+
+            <!-- 票券 -->
+            <swiper
+              v-if="message.body.ticketList?.length"
+              :slidesPerView="1"
+              :navigation="true"
+              :modules="modules"
+              class="ticket-slide"
+            >
+              <swiper-slide v-for="item in message.body.ticketList">
+                <div class="slide-item">
+                  <img
+                    class="cover-img aa"
+                    :src="item.info.img || item.info.cover_img"
+                    alt=""
+                  />
+                  <section>
+                    <h3 class="title">
+                      {{ item.info.name || item.info.title }}
+                    </h3>
+                    <div class="price-info">
+                      <span>{{ item.info.floor || item.info.price }}</span>
+                      <div class="link-btn">
+                        <a :href="item.info.url" target="_blank">
+                          {{ t("ctaGoUrl") }}
+                        </a>
+                      </div>
+                    </div>
+                    <p class="description">
+                      {{ item.info.content || item.info.description }}
+                    </p>
+                  </section>
+                </div>
+              </swiper-slide>
+            </swiper>
+
+            <!-- 美食/伴手禮 -->
+            <swiper
+              v-if="message.body.length"
+              :slidesPerView="1"
+              :navigation="true"
+              :modules="modules"
+              class="ticket-slide"
+            >
+              <swiper-slide v-for="item in message.body">
+                <div class="slide-item">
+                  <img
+                    class="cover-img"
+                    :src="item.info.img || item.info.cover_img"
+                    alt=""
+                  />
+                  <section>
+                    <h3 class="title">
+                      {{ item.info.name || item.info.title }}
+                    </h3>
+
+                    <div
+                      v-if="item.info.phone !== ''"
+                      class="d-flex align-center mt-3 mb-5"
+                    >
+                      <img
+                        src="../assets/img/phone-solid.svg"
+                        width="15"
+                        alt=""
+                      />
+                      <p class="ms-2">
+                        {{ item.info.phone }}
+                      </p>
+                    </div>
+
+                    <div class="price-info">
+                      <span>{{ item.info.floor || item.info.price }}</span>
+                      <div class="link-btn">
+                        <a :href="item.info.url" target="_blank">
+                          {{ t("ctaGoUrl") }}
+                        </a>
+                      </div>
+                    </div>
+
+                    <p class="description">
+                      {{ item.info.content || item.info.description }}
+                    </p>
+                  </section>
+                </div>
+              </swiper-slide>
+            </swiper>
+
+            <!-- <swiper
+              v-if="message.body.length"
+              :slidesPerView="'auto'"
+              :spaceBetween="20"
+              :modules="modules"
+            >
+              <swiper-slide v-for="item in message.body">
+                <img
+                  class="cover-img"
+                  :src="item.info.img || item.info.cover_img"
+                  alt=""
+                />
+                <section>
+                  <h3 class="title">{{ item.info.name || item.info.title }}</h3>
+
+                  <div
+                    v-if="item.info.phone !== ''"
+                    class="d-flex align-center mt-3 mb-5"
+                  >
+                    <img
+                      src="../assets/img/phone-solid.svg"
+                      width="15"
+                      alt=""
+                    />
+                    <p class="ms-2">
+                      {{ getPhoneNumber(item.info.phone) }}
+                    </p>
+                  </div>
+
+                  <div class="price-info">
+                    <span>{{ item.info.floor || item.info.price }}</span>
+                    <div class="link-btn">
+                      <a :href="item.info.url" target="_blank">
+                        {{ t("ctaGoUrl") }}
+                      </a>
+                    </div>
+                  </div>
+
+                  <p class="description">
+                    {{ item.info.content || item.info.description }}
+                  </p>
+                </section>
+              </swiper-slide>
+            </swiper> -->
+          </div>
+
+          <!-- 推薦資訊 -->
+          <div v-else-if="message.label === 'recommend'" class="recommend-item">
+            <img class="cover-img" :src="message.body.cover_img" alt="" />
+            <section>
+              <h3 class="title">{{ message.body.title }}</h3>
+              <p class="description">{{ message.body.description }}</p>
+              <div class="link-btn">
+                <a
+                  :href="message.body.store_info_url || message.body.url"
+                  target="_blank"
+                >
+                  {{ t("ctaBuyNow") }}
+                </a>
+                <a :href="message.body.website_url" target="_blank"> 官網 </a>
+              </div>
+
+              <p class="date">{{ message.body.date }} 限時搶購</p>
+            </section>
+          </div>
+
+          <!-- 店家資訊 -->
+          <div v-else-if="message.label === 'store'" class="store-item">
+            <p class="headline">店家資訊</p>
+            <div class="cover-img">
+              <img :src="message.body.cover_img" alt="" />
+              <h3 class="title">{{ message.body.title }}</h3>
+            </div>
+            <section>
+              <div class="info">
+                <p>
+                  <img
+                    src="../assets/img/location-dot-solid.svg"
+                    width="15"
+                    alt=""
+                  />
+                  {{ message.body.location }}
+                </p>
+                <p>
+                  <img src="../assets/img/phone-solid.svg" width="15" alt="" />
+                  {{ message.body.contact }}
+                </p>
+              </div>
+              <p class="description">{{ message.body.description }}</p>
+            </section>
+          </div>
+
+          <!-- 套票資訊 -->
+          <div v-else-if="message.label === 'ticket'" class="ticket-item">
+            <img class="cover-img" :src="message.body.cover_img" alt="" />
+            <section>
+              <h3 class="title">{{ message.body.title }}</h3>
+              <div class="link-btn">
+                <a :href="message.body.store_info_url" target="_blank">
+                  線上預約
+                </a>
+              </div>
+              <p class="description">{{ message.body.description }}</p>
+              <span class="price-item">{{ message.body.price }}</span>
+            </section>
+          </div>
+        </div>
+
+        <!-- 對話輸入框 -->
+        <!-- <form
+          @submit.prevent="sendMessage('out')"
+          class="chat-inputs"
+          :class="{ 'd-none': !hideMenu }"
+        >
+          <button @click="hideMenu = false" class="menu-btn">
+            <img src="../assets/img/icon/素材-02.png" alt="" width="50" />
+          </button>
+
+          <input
+            v-model="userMessage"
+            type="text"
+            placeholder="Type a message..."
+          />
+          <button type="submit" class="submit">
+            <img width="20" src="../assets/img/paper-plane-solid.svg" alt="" />
+          </button>
+        </form> -->
+      </section>
+
+      <!-- 廣告輪播 -->
+      <!-- <div class="slider-content">
+        <swiper
+          :slidesPerView="1"
+          :autoplay="{
+            delay: 5000,
+            disableOnInteraction: false,
+          }"
+          :modules="modules"
+        >
+          <swiper-slide>
+            <img src="../assets/img/banner-1.jpg" alt="" />
+          </swiper-slide>
+          <swiper-slide>
+            <img src="../assets/img/banner-2.jpg" alt="" />
+          </swiper-slide>
+        </swiper>
+      </div> -->
+
+      <!-- AI 主播影片 -->
+      <!-- <div
+        ref="videoContent"
+        v-show="showAnchor"
+        class="video-content"
+        :class="{ 'video-down': hideMenu }"
+      >
+        <div v-show="!isTTSVideo">
+          <video ref="video" preload playsinline>
+            <source src="../assets/video/start_1.mp4" type="video/mp4" />
+            Your browser does not support the video tag.
+          </video>
+        </div>
+
+        <div v-show="isTTSVideo">
+          <video ref="ttsVideo" preload playsinline>
+            <source :src="ttsVideoSrc" type="video/mp4" />
+
+            Your browser does not support the video tag.
+          </video>
+        </div>
+      </div> -->
+    </div>
+
+    <!-- 底部選單 -->
+    <div ref="menu" class="menu">
+      <!-- AI 主播影片 -->
+      <!-- <div
+        v-show="showAnchor"
+        class="video-content"
+        :class="{ 'video-down': hideMenu }"
+      >
+        <div v-show="!isTTSVideo">
+          <video ref="video" preload playsinline>
+            <source src="../assets/video/start_1.mp4" type="video/mp4" />
+            Your browser does not support the video tag.
+          </video>
+        </div>
+
+        <div v-show="isTTSVideo">
+          <video ref="ttsVideo" preload playsinline>
+            <source
+              :src="`https://bf18-61-230-0-215.ngrok-free.app/${ttsVideoSrc}`"
+              type="video/mp4"
+            />
+
+            Your browser does not support the video tag.
+          </video>
+        </div>
+      </div> -->
+
+      <div class="menu-table" :class="{ 'hide-table': hideMenu }">
+        <table class="mt-3">
+          <tbody>
+            <tr v-for="(row, rowIndex) in menuList" :key="rowIndex">
+              <td v-for="(item, itemIndex) in row" :key="itemIndex">
+                <button @click="selectCategory(item.value, itemIndex)">
+                  <img :src="getImageUrl(item.imgSrc)" alt="" class="icon" />
+                  <p>{{ t(`${item.text}`) }}</p>
+                </button>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+
+      <!-- <table class="mt-3">
+        <tbody>
+          <tr v-for="(row, rowIndex) in menuList" :key="rowIndex">
+            <td v-for="(item, itemIndex) in row" :key="itemIndex">
+              <button @click="selectCategory(item.value, itemIndex)">
+                <img :src="getImageUrl(item.imgSrc)" alt="" class="icon" />
+                <p>{{ t(`${item.text}`) }}</p>
+              </button>
+            </td>
+          </tr>
+        </tbody>
+      </table> -->
+
+      <div class="d-flex align-center position-relative">
+        <div class="position-absolute">
+          <button
+            v-if="!showInput"
+            @click="
+              hideMenu = true;
+              showInput = true;
+            "
+            class="ms-3 pt-1"
+          >
+            <img src="../assets/img/icon/素材-04.png" alt="" width="35" />
+          </button>
+
+          <button
+            v-else
+            @click="
+              hideMenu = false;
+              showInput = false;
+            "
+          >
+            <img
+              src="../assets/img/icon/素材-02.png"
+              alt=""
+              width="50"
+              class="pt-2"
+            />
+          </button>
+        </div>
+
+        <div class="w-100 d-flex align-center justify-center">
+          <button
+            v-if="!showInput"
+            @click="
+              hideMenu = true;
+              showInput = true;
+            "
+            class="d-flex align-center question-btn"
+          >
+            <img
+              class="me-2"
+              src="../assets/img/icon/素材-03.png"
+              alt=""
+              width="45"
+            />
+            {{ t("question") }}
+          </button>
+
+          <!-- 對話輸入框 -->
+          <form
+            v-else
+            @submit.prevent="sendMessage('text')"
+            class="chat-inputs"
+            :class="{ 'd-none': !showInput }"
+          >
+            <!-- <button @click="hideMenu = false" class="menu-btn">
+              <img src="../assets/img/icon/素材-02.png" alt="" width="50" />
+            </button> -->
+
+            <input
+              v-model="userMessage"
+              type="text"
+              placeholder="Type a message..."
+            />
+            <button type="submit" class="submit">
+              <img
+                width="20"
+                src="../assets/img/paper-plane-solid.svg"
+                alt=""
+              />
+            </button>
+          </form>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- AI 主播語音轉文字 -->
+  <div v-else class="anchor-voice">
+    <div v-show="showAnchor" class="video-content">
+      <div>
+        <video ref="video" preload playsinline>
+          <source :src="videoSrc" type="video/mp4" />
+          <!-- <source src="../assets/video/start_1.mp4" type="video/mp4" /> -->
+          Your browser does not support the video tag.
+        </video>
+
+        <div v-if="videoLoading" class="video-progress">
+          <v-progress-circular
+            color="primary"
+            indeterminate
+          ></v-progress-circular>
+        </div>
+      </div>
+
+      <!-- <div v-show="isTTSVideo">
+        <video ref="ttsVideo" preload playsinline>
+          <source
+            :src="` ${ttsVideoSrc}`"
+            type="video/mp4"
+          />
+
+          Your browser does not support the video tag.
+        </video>
+      </div> -->
+    </div>
+
+    <div class="control-item">
+      <!-- <p class="text-center">連接中…</p> -->
+
+      <div class="d-flex flex-column align-center">
+        <audio v-if="audioURL" :src="audioURL" controls></audio>
+        <!-- <p
+          v-if="!isRecording"
+          class="mb-3 text-center"
+          v-html="t('system_construction')"
+        ></p> -->
+        <p v-if="!isRecording" class="mb-3">點選以進行錄音</p>
+        <p v-else class="mb-3">錄音中:{{ recordTime }} 秒</p>
+        <!-- 錄音按鈕 -->
+        <v-btn
+          v-if="!isRecording"
+          @click="recStart"
+          icon="mdi-circle"
+          size="large"
+        >
+          <v-icon icon="mdi-circle" color="red" size="large"></v-icon>
+        </v-btn>
+
+        <v-btn
+          v-else
+          @click="recStop"
+          icon="mdi-circle"
+          size="large"
+          color="success"
+        >
+          <v-icon icon="mdi-square" size="large"></v-icon>
+        </v-btn>
+      </div>
+
+      <div class="d-flex justify-space-between mt-3 mx-10">
+        <!-- 暫停按鈕 -->
+        <v-btn
+          v-if="isVideoPause"
+          @click="togglePause('pause')"
+          icon="mdi-pause"
+          size="large"
+          color="grey-darken-3"
+        ></v-btn>
+
+        <v-btn
+          v-else
+          @click="togglePause('play')"
+          icon="mdi-play"
+          size="large"
+          color="grey-darken-3"
+        ></v-btn>
+
+        <!-- 關閉按鈕 -->
+        <v-btn
+          @click="closeRec()"
+          icon="mdi-close-thick"
+          size="large"
+          color="red"
+        ></v-btn>
+      </div>
+    </div>
+  </div>
+
+  <!-- 主要廣告 -->
+  <v-dialog v-model="showAd">
+    <div class="ad-content">
+      <button @click="showAd = false" class="close-btn">
+        <svg
+          xmlns="http://www.w3.org/2000/svg"
+          width="28"
+          height="28"
+          fill="currentColor"
+          class="bi bi-x-circle"
+          viewBox="0 0 16 16"
+        >
+          <path
+            d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"
+          />
+          <path
+            d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"
+          />
+        </svg>
+      </button>
+
+      <img class="cover-img" :src="ad.cover_img" alt="" />
+      <section>
+        <h2 class="title">{{ ad.title }}</h2>
+        <span></span>
+        <p v-html="ad.description"></p>
+
+        <div v-if="ad.included.length" class="product">
+          <p>訂單內含商品</p>
+          <ul>
+            <li v-for="(product, index) in ad.included" :key="index">
+              {{ product }}
+            </li>
+          </ul>
+        </div>
+
+        <div v-if="ad.branch.length" class="branch">
+          <p>分店資訊</p>
+          <ul>
+            <li v-for="(name, index) in ad.branch" :key="index">
+              {{ name }}
+            </li>
+          </ul>
+        </div>
+
+        <!-- <p class="date">{{ item.body.date }}</p> -->
+
+        <span v-if="ad.location !== ''" class="info justify-end">
+          <svg
+            xmlns="http://www.w3.org/2000/svg"
+            width="20"
+            height="20"
+            viewBox="0 0 384 512"
+          >
+            <path
+              d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"
+            />
+          </svg>
+          <p>{{ ad.location }}</p>
+        </span>
+      </section>
+    </div>
+  </v-dialog>
+
+  <!-- 隨機廣告 -->
+  <v-dialog v-model="secondaryAdShow">
+    <div class="ad-content">
+      <button @click="secondaryAdShow = false" class="close-btn">
+        <svg
+          xmlns="http://www.w3.org/2000/svg"
+          width="28"
+          height="28"
+          fill="currentColor"
+          class="bi bi-x-circle"
+          viewBox="0 0 16 16"
+        >
+          <path
+            d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"
+          />
+          <path
+            d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"
+          />
+        </svg>
+      </button>
+
+      <img class="cover-img" :src="secondaryAd.img" alt="" />
+      <section>
+        <h2 class="title">{{ secondaryAd.name }}</h2>
+
+        <span class="price">
+          <p>{{ formatPrice(secondaryAd.price) }}</p>
+          <a :href="secondaryAd.url">前往官網</a>
+        </span>
+
+        <p class="mb-5" v-html="secondaryAd.content"></p>
+
+        <span v-if="secondaryAd.phone !== ''" class="info">
+          <img
+            src="../assets/img/phone-solid.svg"
+            width="15"
+            alt=""
+            style="
+              filter: invert(50%) sepia(21%) saturate(1061%) hue-rotate(348deg)
+                brightness(96%) contrast(92%);
+            "
+          />
+          <p class="ms-1">{{ secondaryAd.phone }}</p>
+        </span>
+
+        <span v-if="secondaryAd.address !== ''" class="info">
+          <svg
+            xmlns="http://www.w3.org/2000/svg"
+            width="20"
+            height="20"
+            viewBox="0 0 384 512"
+            class="mt-1"
+          >
+            <path
+              d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"
+            />
+          </svg>
+          <p>{{ secondaryAd.address }}</p>
+        </span>
+      </section>
+    </div>
+  </v-dialog>
+
+  <!-- <div
+    v-show="showAd"
+    v-for="(item, index) in ad"
+    :key="index"
+    class="ad-content"
+  >
+    <div>
+      <button @click="showAd = false" class="close-btn">
+        <svg
+          xmlns="http://www.w3.org/2000/svg"
+          width="28"
+          height="28"
+          fill="currentColor"
+          class="bi bi-x-circle"
+          viewBox="0 0 16 16"
+        >
+          <path
+            d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"
+          />
+          <path
+            d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"
+          />
+        </svg>
+      </button>
+      <img class="cover-img" :src="item.body.cover_img" alt="" />
+      <section>
+        <h2 class="title">{{ item.body.title }}</h2>
+        <span></span>
+        <p>
+          {{ item.body.description }}
+        </p>
+
+        <div v-if="item.body.included.length" class="product">
+          <p>訂單內含商品</p>
+          <ul>
+            <li v-for="(product, index) in item.body.included" :key="index">
+              {{ product }}
+            </li>
+          </ul>
+        </div>
+
+        <div v-if="item.body.branch.length" class="branch">
+          <p>分店資訊</p>
+          <ul>
+            <li v-for="(name, index) in item.body.branch" :key="index">
+              {{ name }}
+            </li>
+          </ul>
+        </div>
+
+        <span v-if="item.body.location !== ''" class="map">
+          <svg
+            xmlns="http://www.w3.org/2000/svg"
+            width="20"
+            height="20"
+            viewBox="0 0 384 512"
+          >
+            <path
+              d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"
+            />
+          </svg>
+          <p>{{ item.body.location }}</p>
+        </span>
+      </section>
+    </div>
+  </div> -->
 </template>
 
-<!-- <style scoped>
-main {
-  height: 150vh;
-  min-height: -webkit-fill-available;
+<style lang="scss">
+.main-btn {
+  padding: 16px 70px;
+  font-size: 22px;
+  font-weight: 600;
+  border: none;
+  border-radius: 100px;
+  letter-spacing: 2px;
+  color: white;
+  background-color: var(--main-color);
+  cursor: pointer;
+  transition: all 0.3s;
+  &:hover {
+    background-color: #c19c75;
+  }
+}
+
+.lang-content {
+  width: 100%;
+  height: 100vh;
+  padding: 0 20vw;
   display: flex;
-  flex-direction: column;
-  justify-content: center;
   align-items: center;
-  background-color: var(--sub-color);
+  justify-content: center;
   background-color: rgba(0, 0, 0, 0.6);
   background-blend-mode: multiply;
   background-image: url("@/assets/img/banner.jpg");
   background-size: cover;
   background-position: center center;
+
+  .main-btn {
+    margin-bottom: 40px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .btn-list {
+    max-width: 400px;
+    display: flex;
+    flex-direction: column;
+  }
+}
+
+.main-containar {
+  width: 100%;
+  background-color: var(--sub-color);
+  // height: 150vh;
+  // min-height: -webkit-fill-available;
+  // display: flex;
+  // flex-direction: column;
+  // padding-bottom: 70vh;
+  // min-height: 100%;
+  // overflow-x: hidden;
+  // overflow-y: scroll;
+
+  .video-content {
+    width: 25vw;
+    position: absolute;
+    right: -5px;
+    top: -45vw;
+
+    @media (max-width: 360px) {
+      width: 22vw;
+      top: -40vw;
+    }
+
+    video {
+      // position: fixed;
+      // top: 50px;
+      // left: 0;
+      // right: 0;
+      // z-index: 10;
+      width: 100%;
+      height: auto;
+    }
+
+    .control-btn {
+      width: 33px;
+      height: 33px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      position: absolute;
+      z-index: 50;
+      top: 70px;
+      right: 7px;
+      background: var(--main-color);
+      border: none;
+      border-radius: 100px;
+
+      img {
+        width: 25px;
+        filter: invert(100%) sepia(0%) saturate(0%) hue-rotate(93deg)
+          brightness(103%) contrast(103%); // 改成白色
+      }
+    }
+  }
+
+  .chat-content {
+    width: 100%;
+    position: relative;
+    z-index: 200;
+    letter-spacing: 1px;
+    background-color: var(--sub-color);
+
+    &.hide-menu {
+      min-height: 90vh;
+    }
+
+    .headline {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 10px 25px;
+      border-radius: 15px 15px 0 0;
+      background-color: var(--main-color);
+
+      h1 {
+        font-size: 1.125rem;
+        font-weight: 500;
+        color: white;
+
+        @media (max-width: 375px) {
+          font-size: 0.875rem;
+        }
+      }
+
+      button {
+        padding-top: 3px;
+        display: flex;
+        align-items: center;
+        border: none;
+        background-color: transparent;
+        cursor: pointer;
+
+        img {
+          width: 25px;
+          height: 20px;
+          transition: all 0.3s;
+          transform: rotate(0deg);
+
+          &.rotate {
+            transform: rotate(180deg);
+          }
+        }
+      }
+    }
+
+    .chat-area {
+      // display: flex;
+      // flex-direction: column;
+      min-height: 60vh;
+      background: var(--sub-color);
+      padding: 0.5em 1em 1.5em;
+
+      .btn-list {
+        margin-top: 20px;
+        display: flex;
+        flex-wrap: wrap;
+        list-style: none;
+
+        button {
+          margin-right: 15px;
+          margin-bottom: 15px;
+          padding: 5px 15px;
+          color: white;
+          border: 2px solid white;
+          letter-spacing: 2px;
+          font-weight: bold;
+          text-shadow: 1px 1px 1px #939393;
+
+          &.active {
+            color: var(--sub-color);
+            background-color: white;
+            text-shadow: none;
+          }
+        }
+      }
+    }
+
+    .message-content {
+      display: flex;
+      flex-direction: column;
+      // margin-top: 20px;
+
+      .message {
+        max-width: 45%;
+        border-radius: 20px;
+        padding: 0.8em 1.2em;
+        white-space: pre-line;
+
+        &:first-child {
+          margin-top: 0;
+        }
+
+        @media (max-width: 600px) {
+          max-width: 75%;
+          font-size: 0.875em;
+        }
+
+        &.message-out {
+          margin-left: auto;
+          background: var(--bg-grey);
+          color: white;
+        }
+
+        &.message-in {
+          margin-right: auto;
+          background: #f1f0f0;
+          color: black;
+        }
+
+        &.message-in,
+        &.message-out {
+          margin-top: 20px;
+        }
+      }
+    }
+
+    .branch {
+      ul,
+      li,
+      p {
+        margin: 10px 0;
+        font-size: 14px;
+      }
+    }
+
+    .recommend-item {
+      width: 350px;
+      border-radius: 10px;
+      background-color: white;
+    }
+
+    .recommend-item,
+    .ticket-item {
+      .cover-img {
+        width: 100%;
+        height: 22.5vh;
+        object-fit: contain;
+        overflow: hidden;
+        border-radius: 10px 10px 0 0;
+      }
+
+      section {
+        padding: 15px 25px;
+        letter-spacing: 1px;
+
+        .title {
+          margin-bottom: 0;
+          font-weight: 600;
+          font-size: 1.25rem;
+          text-align: left;
+          // 超過則省略
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-line-clamp: 1;
+          -webkit-box-orient: vertical;
+          line-break: after-white-space;
+        }
+
+        .description {
+          line-height: 1.8;
+          // text-align: justify;
+          font-size: 0.875rem;
+        }
+
+        .date {
+          color: #646464;
+          font-size: 0.875rem;
+          text-align: center;
+        }
+      }
+
+      .link-btn {
+        display: flex;
+        justify-content: center;
+        a {
+          display: block;
+          width: 100%;
+          max-width: 200px;
+          margin: 25px 3px;
+          padding: 8px;
+          text-align: center;
+          border-radius: 20px;
+          color: white;
+          background-color: var(--main-color);
+          text-decoration: none;
+          transition: all 0.3s;
+
+          &:hover {
+            opacity: 0.8;
+          }
+        }
+      }
+    }
+
+    .store-item {
+      width: 350px;
+
+      .cover-img {
+        position: relative;
+        margin-bottom: -5px;
+
+        img {
+          width: 100%;
+          height: 200px;
+          object-fit: cover;
+        }
+
+        .title {
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+          color: white;
+          font-size: 1.25rem;
+          letter-spacing: 2px;
+          text-shadow: 2px 2px 4px #333;
+        }
+      }
+
+      .headline {
+        color: white;
+        justify-content: center;
+      }
+
+      section {
+        padding: 20px;
+        letter-spacing: 1px;
+        border-radius: 0 0 10px 10px;
+        background-color: white;
+
+        .info {
+          margin-bottom: 15px;
+          p {
+            display: flex;
+            align-items: center;
+            img {
+              margin-right: 10px;
+            }
+
+            &:last-child {
+              margin-top: 3px;
+            }
+          }
+        }
+      }
+    }
+
+    .ticket-item {
+      width: 100%;
+      margin-top: 20px;
+
+      h3 {
+        margin-bottom: 10px;
+        text-align: center;
+      }
+
+      .ticket-slide {
+        width: 80%;
+        position: relative;
+
+        .slide-item {
+          max-width: 60vw;
+          border-radius: 10px;
+          background-color: white;
+        }
+
+        .swiper-button-prev {
+          display: none;
+        }
+      }
+
+      .title,
+      .description {
+        // 超過則省略
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        // -webkit-line-clamp: 3;
+        -webkit-box-orient: vertical;
+        line-break: after-white-space;
+      }
+
+      .title {
+        -webkit-line-clamp: 3;
+      }
+
+      .description {
+        -webkit-line-clamp: 5;
+      }
+
+      section {
+        margin-top: -6px;
+        border-radius: 0 0 10px 10px;
+        background-color: white;
+
+        .link-btn {
+          a {
+            max-width: 150px;
+            margin: 0;
+            padding: 8px 12px;
+            font-size: 0.75rem;
+          }
+        }
+
+        .price-item {
+          display: block;
+          margin-top: 10px;
+          text-align: end;
+        }
+
+        .price-info {
+          margin: 20px 0;
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+
+          @media (max-width: 575px) {
+            font-size: 0.875rem;
+            // flex-direction: column;
+            // align-items: start;
+          }
+
+          span {
+            display: block;
+            margin: 10px 0;
+            padding-right: 5px;
+            font-size: 1rem;
+            font-weight: 600;
+            color: var(--main-color);
+          }
+        }
+      }
+    }
+  }
+}
+
+.btn-options {
+  // max-width: 85%;
+  margin-top: 15px;
+  display: flex;
+  flex-wrap: wrap;
+  list-style: none;
+
+  li {
+    margin-top: 15px;
+    margin-right: 20px;
+
+    button {
+      display: block;
+      width: 100%;
+      padding: 8px 16px;
+      border-radius: 5px;
+      color: white;
+      border: none;
+      background-color: var(--main-color);
+      letter-spacing: 2px;
+      transition: all 0.3s;
+      font-size: 0.875rem;
+
+      &:hover {
+        opacity: 0.8;
+      }
+    }
+  }
+}
+
+.btn-swiper {
+  .swiper-slide {
+    width: auto;
+    // max-width: 185px;
+
+    .btn-container {
+      display: flex;
+      justify-content: center;
+
+      button {
+        display: block;
+        width: 100%;
+        padding: 10px 20px;
+        border-radius: 5px;
+        color: white;
+        border: none;
+        background-color: var(--main-color);
+        letter-spacing: 2px;
+        transition: all 0.3s;
+        font-size: 0.875rem;
+
+        &:hover {
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+}
+
+.ad-content {
+  // width: 90%;
+  max-height: 95vh;
+  padding: 35px;
+  overflow-y: auto;
+  // position: absolute;
+  // z-index: 500;
+  border-radius: 10px;
+  background-color: #fff;
+  // box-shadow: 2px 2px 14px #5f5f5f;
+
+  .close-btn {
+    position: absolute;
+    top: 7px;
+    right: 5px;
+    border: none;
+    background-color: transparent;
+    transition: all 0.3s;
+    cursor: pointer;
+
+    svg {
+      filter: invert(57%) sepia(45%) saturate(391%) hue-rotate(350deg)
+        brightness(93%) contrast(84%);
+    }
+
+    &:hover {
+      opacity: 0.8;
+    }
+  }
+
+  .ar-link {
+    display: flex;
+    justify-content: center;
+  }
+
+  section {
+    p {
+      // padding: 0 10px;
+      line-height: 1.7;
+      letter-spacing: 2px;
+    }
+
+    .title {
+      margin: 15px auto;
+      color: var(--main-color);
+      font-weight: 600;
+      font-size: 1.375em;
+      text-align: center;
+      letter-spacing: 2px;
+    }
+
+    .product,
+    .branch {
+      margin-top: 20px;
+      background-color: #f1e9dc;
+
+      p {
+        padding: 10px 0;
+        font-weight: 500;
+        font-size: 0.875em;
+        text-align: center;
+        border-bottom: 2px solid #fff;
+      }
+
+      ul {
+        padding: 10px;
+        list-style: none;
+
+        li {
+          padding-bottom: 5px;
+          letter-spacing: 1px;
+          font-weight: 500;
+          font-size: 0.875em;
+        }
+      }
+    }
+
+    .date {
+      margin: 20px 0;
+      text-align: center;
+    }
+
+    .info {
+      display: flex;
+      align-items: center;
+      margin-top: 5px;
+
+      p {
+        padding-left: 10px;
+        letter-spacing: 2px;
+        // font-weight: 500;
+        // color: var(--main-color);
+      }
+
+      svg {
+        filter: invert(57%) sepia(45%) saturate(391%) hue-rotate(350deg)
+          brightness(93%) contrast(84%);
+      }
+    }
+  }
+
+  .cover-img {
+    width: 100%;
+    max-height: 250px;
+    object-fit: cover;
+  }
+
+  .price {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    justify-content: space-between;
+    margin: 10px 0;
+
+    p {
+      font-size: 1.25rem;
+      font-weight: 500;
+      color: var(--main-color);
+    }
+
+    a {
+      max-width: 150px;
+      margin: 10px 0;
+      padding: 8px 25px;
+      display: inline-block;
+      text-decoration: none;
+      text-align: center;
+      border-radius: 20px;
+      letter-spacing: 1px;
+      color: white;
+      background-color: var(--main-color);
+    }
+  }
+}
+
+.slider-content {
+  width: 100%;
+
+  img {
+    width: 100%;
+    margin-bottom: -5px;
+  }
+}
+
+.branch {
+  margin-top: 30px;
+  ul {
+    padding: 0;
+    list-style: none;
+
+    li {
+      letter-spacing: 1px;
+    }
+  }
+}
+
+.video-progress {
+  position: absolute;
+  left: 50%;
+  top: 40%;
+  transform: translate(-50%, -50%);
+}
+
+.dialog-content {
+  position: absolute;
+  top: 60px;
+  left: 0;
+  z-index: 100;
+}
+
+.vr-content {
+  width: 700px;
+  height: 700px;
+}
+
+.ar-link {
+  display: inline-block;
+  padding: 7px 17px;
+  color: #fff;
+  background-color: var(--main-color);
+  border-radius: 5px;
+  text-decoration: none;
+}
+
+.ar-card {
+  width: 85vw;
+  height: 100vh;
+
+  .v-card-title {
+    text-align: center;
+  }
+
+  #vr-video {
+    height: 77vh;
+  }
+}
+
+.btn-swiper {
+  margin-top: 20px;
+}
+
+.v-expansion-panel-text {
+  font-size: 0.875rem;
+  line-height: 1.7;
+}
+
+// 對話輸入框
+.chat-inputs {
+  width: 100%;
+  display: flex;
+  padding: 10px 20px;
+  background-color: white;
+
+  input {
+    width: 100%;
+    border: none;
+    margin-left: 2rem;
+
+    &:focus-visible {
+      outline: none;
+    }
+  }
+
+  .menu-btn {
+    position: absolute;
+    top: 2px;
+    left: 0;
+  }
+
+  button.submit {
+    border: none;
+    background: white;
+    cursor: pointer;
+    &:hover {
+      img {
+        opacity: 0.8;
+      }
+    }
+
+    img {
+      padding-top: 5px;
+      transition: all 0.3s;
+      filter: invert(75%) sepia(20%) saturate(459%) hue-rotate(360deg)
+        brightness(100%) contrast(85%);
+    }
+  }
+
+  ::placeholder {
+    font-size: 1rem;
+    font-weight: 500;
+    color: var(--sub-color);
+    opacity: 1; /* Firefox */
+  }
+
+  ::-ms-input-placeholder {
+    /* Edge 12 -18 */
+    color: var(--sub-color);
+  }
+}
+
+// 底部選單
+.menu {
+  position: fixed;
+  z-index: 300;
+  left: 0;
+  bottom: 0px;
+  right: 0;
+  color: var(--text-color);
+  background-color: white;
+
+  &.hide-menu table {
+    height: 0;
+    z-index: -1;
+  }
+
+  .icon {
+    width: 80px;
+
+    @media (max-width: 414px) {
+      width: 60px;
+    }
+
+    @media (max-width: 375px) {
+      width: 45px;
+    }
+  }
+
+  .menu-table {
+    height: 100%;
+    transition: all 0.3s;
+
+    &.hide-table {
+      height: 0;
+
+      table {
+        display: none;
+        height: 0;
+      }
+    }
+
+    table {
+      width: 95%;
+      height: 100%;
+      margin: auto;
+      border-collapse: collapse;
+      position: relative;
+      transition: all 0.3s;
+
+      &::before,
+      &::after {
+        content: "";
+        display: inline-block;
+        width: 10px;
+        height: 100%;
+        background-color: #fff;
+        position: absolute;
+        bottom: 0%;
+
+        @media (max-width: 390px) {
+          width: 8px;
+        }
+      }
+
+      &::before {
+        left: -5px;
+      }
+
+      &::after {
+        right: -5px;
+      }
+
+      tr {
+        td {
+          width: 50px;
+          padding: 1rem 0;
+          text-align: center;
+          border: 1px solid #ccc;
+
+          @media (max-width: 414px) {
+            width: 100px;
+            padding: 1rem 0;
+          }
+
+          @media (max-width: 390px) {
+            padding: 0.5rem 0;
+          }
+
+          p {
+            padding: 0 0.3rem;
+            letter-spacing: 0.03rem;
+
+            @media (max-width: 430px) {
+              // width: 115px;
+              font-size: 0.875rem;
+            }
+          }
+        }
+
+        &:first-child {
+          td {
+            border-top: 0px solid transparent;
+          }
+        }
+
+        &:last-child {
+          td {
+            border-bottom: 0px solid transparent;
+          }
+        }
+      }
+    }
+  }
+
+  .question-btn {
+    color: var(--main-color);
+    font-size: 1.25rem;
+    font-weight: 500;
+    letter-spacing: 0.1rem;
+
+    @media (max-width: 414px) {
+      font-size: 1rem;
+    }
+  }
+}
+
+.anchor-voice {
+  height: 94vh;
+  color: white;
+  background-color: black;
+
+  .video-content {
+    height: 70vh;
+    overflow: hidden;
+
+    @media (max-width: 375px) {
+      height: 65vh;
+    }
+
+    video {
+      width: 100%;
+
+      @media (max-width: 375px) {
+        margin-top: -50px;
+      }
+    }
+  }
+
+  .control-item {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    height: 24vh;
+
+    @media (max-width: 375px) {
+      height: 29vh;
+    }
+  }
+
+  // .v-btn.v-btn--density-default {
+  //   height: 55px !important;
+  // }
+}
+
+.map-img {
+  max-width: 100%;
+
+  &.show-anchor {
+    max-width: 70%;
+  }
+}
+
+.voice-btn {
+  position: fixed;
+  right: 5px;
+  top: 55px;
+  z-index: 100;
+
+  button {
+    display: flex;
+    align-items: center;
+
+    img {
+      width: 22px;
+      filter: invert(49%) sepia(66%) saturate(368%) hue-rotate(348deg)
+        brightness(91%) contrast(92%);
+    }
+
+    p {
+      margin-left: 5px;
+      font-size: 0.85rem;
+      color: var(--main-color);
+    }
+  }
+}
+
+.v-btn {
+  // &.v-btn--density-default {
+  //   height: auto !important;
+  // }
+
+  p {
+    font-size: 0.875rem;
+  }
+}
+
+.v-field__outline {
+  --v-field-border-width: 0 !important;
+}
+
+.swiper {
+  // width: 300px;
+  margin-left: 0;
+}
+
+.a-modal {
+  position: relative !important;
+  top: 50% !important;
+  z-index: 15000 !important;
+}
+
+html.a-fullscreen {
+  position: relative !important;
+}
+
+a-video-controls {
+  position: absolute;
+  bottom: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.fc-direction-ltr {
+  height: 500px;
+}
+
+.fc {
+  .fc-scrollgrid,
+  .fc-scrollgrid table,
+  .fc-daygrid-body {
+    height: 94%;
+    width: 100% !important;
+  }
+
+  .fc-toolbar.fc-header-toolbar {
+    padding: 5px;
+    margin-bottom: 0;
+    letter-spacing: 1px;
+    background-color: #f2f2f2;
+    border-radius: 5px 5px 0 0;
+  }
+
+  .fc-toolbar-title {
+    font-size: 1.125em;
+  }
+
+  .fc-day-past {
+    &.fc-day-other {
+      a {
+        text-decoration: none;
+      }
+    }
+
+    a {
+      color: #cccccc;
+      text-decoration: line-through;
+    }
+  }
+
+  .fc-button .fc-icon {
+    color: #969696;
+    font-size: 1em !important;
+    vertical-align: baseline !important;
+  }
+
+  .fc-icon-chevron-left::before {
+    content: "<";
+  }
+
+  .fc-icon-chevron-right::before {
+    content: ">";
+  }
+
+  .fc-button-primary {
+    border: none;
+    background-color: transparent;
+
+    &:hover,
+    &:focus,
+    &:not(:disabled):active:focus {
+      box-shadow: none;
+      background-color: transparent;
+    }
+
+    &:disabled {
+      display: none;
+    }
+  }
+
+  .fc-daygrid-day-top {
+    justify-content: center;
+  }
+
+  .fc-day-today.fc-daygrid-day,
+  .fc-day-future.fc-daygrid-day {
+    cursor: pointer;
+  }
 }
-</style> -->
+</style>

+ 26 - 0
src/views/HomeView_back.vue

@@ -0,0 +1,26 @@
+<script setup>
+import Chat from "../components/Chat.vue";
+import Navbar from "../components/Navbar.vue";
+</script>
+
+<template>
+  <!-- <Navbar /> -->
+  <Chat />
+</template>
+
+<!-- <style scoped>
+main {
+  height: 150vh;
+  min-height: -webkit-fill-available;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  background-color: var(--sub-color);
+  background-color: rgba(0, 0, 0, 0.6);
+  background-blend-mode: multiply;
+  background-image: url("@/assets/img/banner.jpg");
+  background-size: cover;
+  background-position: center center;
+}
+</style> -->