|
@@ -8,6 +8,7 @@ import {
|
|
|
nextTick,
|
|
|
onBeforeUnmount,
|
|
|
} from "vue";
|
|
|
+import { useMainStore } from "@/stores/store";
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
// VR
|
|
|
import "aframe";
|
|
@@ -37,13 +38,15 @@ import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from "vue-qrcode-reader";
|
|
|
// import "videojs-vr"; // 確保正確引入 VR 插件
|
|
|
// Components
|
|
|
import Navbar from "../components/Navbar.vue";
|
|
|
-import TicketPurchase from "../components/TicketPurchase.vue";
|
|
|
+import Photo from "../components/Photo.vue";
|
|
|
+import Photo101 from "../components/Photo101.vue";
|
|
|
|
|
|
const { t, locale } = useI18n();
|
|
|
|
|
|
const route = useRoute();
|
|
|
const router = useRouter();
|
|
|
const routeParam = ref(null);
|
|
|
+const store = useMainStore();
|
|
|
|
|
|
// AI 客服回覆訊息
|
|
|
let messages = ref([]);
|
|
@@ -1519,6 +1522,37 @@ let videoSrc = ref("");
|
|
|
let hideAnchorPrologue = ref(false); // 顯示開場白 or 點頭影片
|
|
|
let videoIndex = ref(null); // 影片編號
|
|
|
|
|
|
+watch(
|
|
|
+ () => store.funFilterDialog,
|
|
|
+ (val) => {
|
|
|
+ if (!val) {
|
|
|
+ store.assignFilter = "";
|
|
|
+ store.assignGender = "";
|
|
|
+ store.assignRace = "";
|
|
|
+ store.assignBgImg = "";
|
|
|
+
|
|
|
+ parameterRace.value.length = 0;
|
|
|
+ parameterBg.value.length = 0;
|
|
|
+ currentIndex.value = 0;
|
|
|
+ bgCurrentIndex.value = 0;
|
|
|
+ showBg.value = false;
|
|
|
+ } else {
|
|
|
+ // 請求使用者的攝影機(僅限第一次)
|
|
|
+ if (!store.cameraRequested) {
|
|
|
+ store.cameraRequested = true;
|
|
|
+ navigator.mediaDevices
|
|
|
+ .getUserMedia({ video: true })
|
|
|
+ .then((stream) => {
|
|
|
+ vlogVideo.value.srcObject = stream;
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("無法開啟攝影機", error);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
// 選擇類別
|
|
|
async function selectCategory(value, index) {
|
|
|
assignCategory.value = value;
|
|
@@ -1583,6 +1617,8 @@ async function selectCategory(value, index) {
|
|
|
// }
|
|
|
else if (value === "附近有什麼") {
|
|
|
window.open("https://cmm.ai/101-aiv1/#/brand-search", "_blank"); // 另開頁面
|
|
|
+ } else if (value === "趣味濾鏡") {
|
|
|
+ store.funFilterDialog = true;
|
|
|
} else if (value === "秘境花園觀景台") {
|
|
|
messages.value.push({
|
|
|
label: "text",
|
|
@@ -1797,18 +1833,18 @@ const menuList = reactive([
|
|
|
// text: "customer_show",
|
|
|
// value: "叫出真人客服",
|
|
|
// },
|
|
|
- { imgSrc: "素材-11.png", text: "what_around", value: "附近有什麼" },
|
|
|
- // { imgSrc: "素材-11.png", text: "fun_filter", value: "趣味濾鏡" },
|
|
|
- { imgSrc: "素材-06.png", text: "service_information", value: "服務資訊" },
|
|
|
- { imgSrc: "素材-07.png", text: "shopping_discounts", value: "購物及優惠" },
|
|
|
- ],
|
|
|
- [
|
|
|
+ // { imgSrc: "素材-11.png", text: "what_around", value: "附近有什麼" },
|
|
|
{
|
|
|
imgSrc: "素材-08.png",
|
|
|
text: "observation_deck",
|
|
|
value: "秘境花園觀景台",
|
|
|
},
|
|
|
+ { imgSrc: "素材-07.png", text: "shopping_discounts", value: "購物及優惠" },
|
|
|
+ { imgSrc: "素材-06.png", text: "service_information", value: "服務資訊" },
|
|
|
+ ],
|
|
|
+ [
|
|
|
{ imgSrc: "素材-09.png", text: "food_souvenirs", value: "美食/伴手禮" },
|
|
|
+ { imgSrc: "素材-17.png", text: "fun_filter", value: "趣味濾鏡" },
|
|
|
{ imgSrc: "素材-10.png", text: "location_guide", value: "位置導引" },
|
|
|
],
|
|
|
]);
|
|
@@ -2632,6 +2668,224 @@ async function getVideoCache(messages) {
|
|
|
console.log("error", error);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+const getImgUrl = (imgPath) => {
|
|
|
+ return new URL(`../assets/img/${imgPath}`, import.meta.url).href;
|
|
|
+};
|
|
|
+
|
|
|
+let genderList = reactive([
|
|
|
+ {
|
|
|
+ value: "male",
|
|
|
+ icon: "mdi-gender-male",
|
|
|
+ img: "male.png",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "female",
|
|
|
+ icon: "mdi-gender-female",
|
|
|
+ img: "female.png",
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+let filterList = reactive([
|
|
|
+ {
|
|
|
+ text: "taipei_101_postcard",
|
|
|
+ value: "台北101明信片",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "taiwan_landmark_postcard",
|
|
|
+ value: "台灣名勝景點明信片",
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+let imgLoading = ref(false);
|
|
|
+
|
|
|
+// 取得角色清單
|
|
|
+async function getIconImageList(gender) {
|
|
|
+ imgLoading.value = true;
|
|
|
+ let url = `https://cmm.ai/postcard/fs/icon-image-list/${gender}`;
|
|
|
+
|
|
|
+ try {
|
|
|
+ let response = await axios.get(url);
|
|
|
+ let imagePromises = response.data.map((item, index) => {
|
|
|
+ let imageUrl = `https://cmm.ai/postcard/fs/icon-image/${gender}/${item}`;
|
|
|
+ return getIconImage(imageUrl, index); // 取得角色圖片
|
|
|
+ });
|
|
|
+
|
|
|
+ await Promise.all(imagePromises);
|
|
|
+
|
|
|
+ imgLoading.value = false;
|
|
|
+ store.assignGender = gender;
|
|
|
+ } catch (error) {
|
|
|
+ console.log("error", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+let parameterRace = ref([]); // 角色圖片
|
|
|
+
|
|
|
+// 取得角色圖片
|
|
|
+async function getIconImage(url, index) {
|
|
|
+ try {
|
|
|
+ // 設定 responseType 為 arraybuffer 以取得二進位數據
|
|
|
+ let response = await axios.get(url, { responseType: "arraybuffer" });
|
|
|
+
|
|
|
+ let blob = new Blob([response.data], { type: "image/png" }); // 創建 blob
|
|
|
+ let imageUrl = URL.createObjectURL(blob); // 創建圖片 URL
|
|
|
+ parameterRace.value.push({ imgUrl: imageUrl, race: `${index}` });
|
|
|
+ console.log("取得角色圖片 parameterRace.value", parameterRace.value);
|
|
|
+ } catch (error) {
|
|
|
+ console.log("error", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const currentRacePhotos = computed(() => {
|
|
|
+ const start = currentIndex.value;
|
|
|
+ const end = start + perPage.value;
|
|
|
+ return parameterRace.value.slice(start, end);
|
|
|
+});
|
|
|
+
|
|
|
+let currentIndex = ref(0);
|
|
|
+let perPage = ref(2);
|
|
|
+
|
|
|
+function prevRace() {
|
|
|
+ if (currentIndex.value > 0) {
|
|
|
+ currentIndex.value -= perPage.value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function nextRace() {
|
|
|
+ if (currentIndex.value + perPage.value < parameterRace.value.length) {
|
|
|
+ currentIndex.value += perPage.value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 計算頁數
|
|
|
+const totalPages = computed(() =>
|
|
|
+ Math.ceil(parameterRace.value.length / perPage.value)
|
|
|
+);
|
|
|
+
|
|
|
+const currentPage = computed(
|
|
|
+ () => Math.floor(currentIndex.value / perPage.value) + 1
|
|
|
+);
|
|
|
+
|
|
|
+let alertShow = ref(false);
|
|
|
+let showBg = ref(false);
|
|
|
+
|
|
|
+function checkRaceImg() {
|
|
|
+ console.log("checkRaceImg");
|
|
|
+
|
|
|
+ if (store.assignRace && store.assignRace !== "") {
|
|
|
+ alertShow.value = false;
|
|
|
+ showBg.value = true;
|
|
|
+ getTargetImageList(); // 取得背景
|
|
|
+ } else {
|
|
|
+ alertShow.value = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ alertShow.value = false;
|
|
|
+ }, 2000);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleRaceImg(race) {
|
|
|
+ store.assignRace = race;
|
|
|
+}
|
|
|
+
|
|
|
+let bgImgLoading = ref(false);
|
|
|
+let parameterBg = ref([]);
|
|
|
+
|
|
|
+// 取得背景清單
|
|
|
+async function getTargetImageList() {
|
|
|
+ console.log("取得背景清單");
|
|
|
+
|
|
|
+ let race = store.assignRace; // 角色
|
|
|
+ let gender = store.assignGender; // 性別
|
|
|
+
|
|
|
+ bgImgLoading.value = true;
|
|
|
+ let url = `https://cmm.ai/postcard/fs/target-image-list/${gender}/${race}`;
|
|
|
+
|
|
|
+ try {
|
|
|
+ let response = await axios.get(url);
|
|
|
+ console.log("取得背景清單", response);
|
|
|
+
|
|
|
+ let imagePromises = response.data.map((item, index) => {
|
|
|
+ let imageUrl = `https://cmm.ai/postcard/fs/target-image/${gender}/${race}/${item}`;
|
|
|
+ return getTargetImage(imageUrl, item); // 取得角色圖片
|
|
|
+ });
|
|
|
+
|
|
|
+ await Promise.all(imagePromises);
|
|
|
+
|
|
|
+ // 組合陣列
|
|
|
+ parameterBg.value = parameterBg.value.map((item, index) => ({
|
|
|
+ imgUrl: item.imgUrl,
|
|
|
+ name: item.name,
|
|
|
+ title: item.name.replace(/\.[^/.]+$/, ""), // 移除副檔名 .jpg
|
|
|
+ }));
|
|
|
+ bgImgLoading.value = false;
|
|
|
+ } catch (error) {
|
|
|
+ console.log("error", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 取得背景圖片
|
|
|
+async function getTargetImage(url, name) {
|
|
|
+ try {
|
|
|
+ // 設定 responseType 為 arraybuffer 以取得二進位數據
|
|
|
+ let response = await axios.get(url, { responseType: "arraybuffer" });
|
|
|
+ let blob = new Blob([response.data], { type: "image/png" }); // 創建 blob
|
|
|
+ let imageUrl = URL.createObjectURL(blob); // 創建圖片 URL
|
|
|
+ parameterBg.value.push({ imgUrl: imageUrl, name: name });
|
|
|
+ } catch (error) {
|
|
|
+ console.log("error", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleBgImg(item) {
|
|
|
+ store.assignBgImg = item.name;
|
|
|
+}
|
|
|
+
|
|
|
+const bgCurrentPhotos = computed(() => {
|
|
|
+ const start = bgCurrentIndex.value;
|
|
|
+ const end = start + bgPerPage.value;
|
|
|
+ return parameterBg.value.slice(start, end);
|
|
|
+});
|
|
|
+
|
|
|
+let bgCurrentIndex = ref(0);
|
|
|
+let bgPerPage = ref(2);
|
|
|
+
|
|
|
+function prevBg() {
|
|
|
+ if (bgCurrentIndex.value > 0) {
|
|
|
+ bgCurrentIndex.value -= bgPerPage.value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function nextBg() {
|
|
|
+ if (bgCurrentIndex.value + bgPerPage.value < parameterBg.value.length) {
|
|
|
+ bgCurrentIndex.value += bgPerPage.value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 計算頁數
|
|
|
+const bgTotalPages = computed(() =>
|
|
|
+ Math.ceil(parameterBg.value.length / bgPerPage.value)
|
|
|
+);
|
|
|
+
|
|
|
+const bgCurrentPage = computed(
|
|
|
+ () => Math.floor(bgCurrentIndex.value / bgPerPage.value) + 1
|
|
|
+);
|
|
|
+
|
|
|
+let bgAlertShow = ref(false);
|
|
|
+let showPhoto = ref(false); // 顯示拍攝介面
|
|
|
+
|
|
|
+function checkBgImg() {
|
|
|
+ if (store.assignBgImg && store.assignBgImg !== "") {
|
|
|
+ bgAlertShow.value = false;
|
|
|
+ showPhoto.value = true;
|
|
|
+ } else {
|
|
|
+ bgAlertShow.value = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ bgAlertShow.value = false;
|
|
|
+ }, 2000);
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
@@ -4257,6 +4511,303 @@ async function getVideoCache(messages) {
|
|
|
</v-card>
|
|
|
</v-dialog>
|
|
|
|
|
|
+ <!-- 創意濾鏡視窗 -->
|
|
|
+ <v-dialog v-model="store.funFilterDialog" width="1000">
|
|
|
+ <v-card class="pa-5">
|
|
|
+ <v-card-title class="pa-0">
|
|
|
+ <button @click="store.funFilterDialog = false" class="d-flex ml-auto">
|
|
|
+ <v-icon size="small" icon="mdi-close"></v-icon>
|
|
|
+ </button>
|
|
|
+ </v-card-title>
|
|
|
+
|
|
|
+ <v-card-text class="pb-10 px-0">
|
|
|
+ <!-- 選擇濾鏡 -->
|
|
|
+ <div v-if="store.assignFilter === ''" class="px-5 options-btn">
|
|
|
+ <!-- <p class="text-h5 my-10">請選擇濾鏡</p> -->
|
|
|
+ <div v-for="item in filterList">
|
|
|
+ <button @click="store.assignFilter = item.value" class="my-5">
|
|
|
+ <p>{{ t(item.text) }}</p>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 選擇性別 (景點) -->
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ store.funFilterDialog &&
|
|
|
+ store.assignFilter !== '' &&
|
|
|
+ store.assignGender === '' &&
|
|
|
+ store.assignFilter === '台灣名勝景點明信片'
|
|
|
+ "
|
|
|
+ class="options-btn"
|
|
|
+ >
|
|
|
+ <p class="my-10">
|
|
|
+ <!-- {{ t("select_filter") }} -->
|
|
|
+ {{ t("select_gender") }}
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <div class="d-flex flex-column">
|
|
|
+ <div
|
|
|
+ v-for="item in genderList"
|
|
|
+ class="px-5 d-flex flex-column align-center"
|
|
|
+ >
|
|
|
+ <!-- <img
|
|
|
+ @click="store.assignGender = item.value"
|
|
|
+ :src="getImgUrl(item.img)"
|
|
|
+ alt=""
|
|
|
+ /> -->
|
|
|
+
|
|
|
+ <!-- @click="store.assignGender = item.value" -->
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="imgLoading"
|
|
|
+ class="d-flex flex-column align-center justify-center pt-15"
|
|
|
+ >
|
|
|
+ <v-progress-circular
|
|
|
+ :size="70"
|
|
|
+ :width="7"
|
|
|
+ color="white"
|
|
|
+ indeterminate
|
|
|
+ ></v-progress-circular>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <button
|
|
|
+ v-else
|
|
|
+ @click="getIconImageList(item.value)"
|
|
|
+ class="mb-10"
|
|
|
+ :class="{ assign: store.assignGender === item.value }"
|
|
|
+ >
|
|
|
+ <v-icon :icon="item.icon" color="white"></v-icon>
|
|
|
+ <p>{{ t(item.value) }}</p>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 選擇濾鏡 (101) -->
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ store.funFilterDialog &&
|
|
|
+ store.assignFilter !== '' &&
|
|
|
+ store.assignGender === '' &&
|
|
|
+ store.assignFilter === '台北101明信片'
|
|
|
+ "
|
|
|
+ class="options-btn"
|
|
|
+ >
|
|
|
+ <p class="my-10">
|
|
|
+ {{ t("select_filter") }}
|
|
|
+ <!-- {{ t("select_gender") }} -->
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <div class="d-flex w-100">
|
|
|
+ <div
|
|
|
+ v-for="item in genderList"
|
|
|
+ class="w-50 px-2 d-flex flex-column align-center"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ @click="store.assignGender = item.value"
|
|
|
+ :src="getImgUrl(item.img)"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- @click="store.assignGender = item.value" -->
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="imgLoading"
|
|
|
+ class="d-flex flex-column align-center justify-center pt-15"
|
|
|
+ >
|
|
|
+ <v-progress-circular
|
|
|
+ :size="70"
|
|
|
+ :width="7"
|
|
|
+ color="white"
|
|
|
+ indeterminate
|
|
|
+ ></v-progress-circular>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <button
|
|
|
+ v-else
|
|
|
+ @click="getIconImageList(item.value)"
|
|
|
+ class="my-10 gender-btn"
|
|
|
+ :class="{ assign: store.assignGender === item.value }"
|
|
|
+ >
|
|
|
+ <span class="w-100 d-flex justify-center align-center">
|
|
|
+ <v-icon :icon="item.icon" color="white"></v-icon>
|
|
|
+ <p>{{ t(item.value) }}</p>
|
|
|
+ </span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 台北101明信片 -->
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ store.assignGender !== '' && store.assignFilter === '台北101明信片'
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <!-- 拍照介面 -->
|
|
|
+ <div>
|
|
|
+ <Photo101 @closeDialog="store.funFilterDialog = false" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 台灣名勝景點明信片 -->
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ store.assignGender !== '' &&
|
|
|
+ store.assignFilter === '台灣名勝景點明信片'
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div v-if="!showBg" class="menu-content">
|
|
|
+ <p class="text-h5 my-5">{{ t("select_character") }}</p>
|
|
|
+
|
|
|
+ <div class="slider-btn">
|
|
|
+ <button class="prev" @click="prevRace">
|
|
|
+ <img class="arrow" src="../assets/img/arrow_l.png" alt="" />
|
|
|
+ </button>
|
|
|
+ <button class="next" @click="nextRace">
|
|
|
+ <img class="arrow" src="../assets/img/arrow_r.png" alt="" />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ @click="handleRaceImg(item.race)"
|
|
|
+ v-for="item in currentRacePhotos"
|
|
|
+ class="bg-img mt-5"
|
|
|
+ >
|
|
|
+ <v-img
|
|
|
+ cover
|
|
|
+ class="cover"
|
|
|
+ :lazy-src="item.imgUrl"
|
|
|
+ :src="item.imgUrl"
|
|
|
+ >
|
|
|
+ <template v-slot:placeholder>
|
|
|
+ <div class="d-flex align-center justify-center fill-height">
|
|
|
+ <v-progress-circular
|
|
|
+ color="grey-lighten-4"
|
|
|
+ indeterminate
|
|
|
+ ></v-progress-circular>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </v-img>
|
|
|
+
|
|
|
+ <img
|
|
|
+ v-if="item.race === store.assignRace && store.assignRace !== ''"
|
|
|
+ class="icon active"
|
|
|
+ src="../assets/img/confirm.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ v-else
|
|
|
+ class="icon"
|
|
|
+ src="../assets/img/confirm.png"
|
|
|
+ alt=""
|
|
|
+ style="opacity: 0.3"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <span class="page-num">{{ currentPage }} / {{ totalPages }}</span>
|
|
|
+
|
|
|
+ <button @click="checkRaceImg()" class="main-btn">
|
|
|
+ {{ t("confirm") }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 選擇背景 -->
|
|
|
+ <div v-if="showBg && !showPhoto">
|
|
|
+ <div
|
|
|
+ v-if="bgImgLoading"
|
|
|
+ class="d-flex flex-column align-center justify-center py-15"
|
|
|
+ >
|
|
|
+ <v-progress-circular
|
|
|
+ :size="70"
|
|
|
+ :width="7"
|
|
|
+ color="white"
|
|
|
+ indeterminate
|
|
|
+ ></v-progress-circular>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else class="menu-content bg-list">
|
|
|
+ <p class="my-10">{{ t("select_background") }}</p>
|
|
|
+
|
|
|
+ <div class="slider-btn">
|
|
|
+ <button class="prev" @click="prevBg">
|
|
|
+ <img class="arrow" src="../assets/img/arrow_l.png" alt="" />
|
|
|
+ </button>
|
|
|
+ <button class="next" @click="nextBg">
|
|
|
+ <img class="arrow" src="../assets/img/arrow_r.png" alt="" />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ @click="handleBgImg(item)"
|
|
|
+ v-for="item in bgCurrentPhotos"
|
|
|
+ class="bg-img"
|
|
|
+ >
|
|
|
+ <v-img
|
|
|
+ cover
|
|
|
+ class="cover"
|
|
|
+ width="55vw"
|
|
|
+ :lazy-src="item.imgUrl"
|
|
|
+ :src="item.imgUrl"
|
|
|
+ >
|
|
|
+ <template v-slot:placeholder>
|
|
|
+ <div class="d-flex align-center justify-center fill-height">
|
|
|
+ <v-progress-circular
|
|
|
+ color="grey-lighten-4"
|
|
|
+ indeterminate
|
|
|
+ ></v-progress-circular>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </v-img>
|
|
|
+
|
|
|
+ <p>{{ $t(item.title) }}</p>
|
|
|
+
|
|
|
+ <img
|
|
|
+ v-if="item.name === store.assignBgImg"
|
|
|
+ class="icon active"
|
|
|
+ src="../assets/img/confirm.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ v-else
|
|
|
+ class="icon"
|
|
|
+ src="../assets/img/confirm.png"
|
|
|
+ alt=""
|
|
|
+ style="opacity: 0.3"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <span class="page-num"
|
|
|
+ >{{ bgCurrentPage }} / {{ bgTotalPages }}</span
|
|
|
+ >
|
|
|
+
|
|
|
+ <button @click="checkBgImg()" class="main-btn">
|
|
|
+ {{ t("confirm") }}
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <div v-if="bgAlertShow" class="alert-item">
|
|
|
+ <v-alert
|
|
|
+ border="top"
|
|
|
+ type="warning"
|
|
|
+ variant="outlined"
|
|
|
+ class="mt-5"
|
|
|
+ >
|
|
|
+ 尚未選擇背景
|
|
|
+ </v-alert>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 拍照介面 -->
|
|
|
+ <div v-if="showPhoto && store.assignBgImg !== ''">
|
|
|
+ <Photo @closeDialog="store.funFilterDialog = false" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </v-card-text>
|
|
|
+ </v-card>
|
|
|
+ </v-dialog>
|
|
|
+
|
|
|
<!-- 立即前往 -->
|
|
|
<a
|
|
|
:href="clickUrl"
|
|
@@ -5384,6 +5935,172 @@ async function getVideoCache(messages) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+.options-btn {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: auto;
|
|
|
+ font-size: 1.25rem;
|
|
|
+ letter-spacing: 1px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-weight: 600;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ }
|
|
|
+
|
|
|
+ button {
|
|
|
+ display: flex;
|
|
|
+ width: 18rem;
|
|
|
+ padding: 0.8rem;
|
|
|
+ margin-bottom: 2rem;
|
|
|
+ border-radius: 100px;
|
|
|
+ border: 3px solid transparent;
|
|
|
+ background-color: var(--main-color);
|
|
|
+ background-position: center;
|
|
|
+ background-size: cover;
|
|
|
+
|
|
|
+ .v-icon {
|
|
|
+ // position: absolute;
|
|
|
+ margin-right: -15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin: auto;
|
|
|
+ font-size: 1rem;
|
|
|
+ font-weight: 500;
|
|
|
+ letter-spacing: 3px;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.assign {
|
|
|
+ border: 3px solid white;
|
|
|
+ // background-color: #ae774f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .gender-btn {
|
|
|
+ width: 125px;
|
|
|
+ padding: 0.3rem 0.8rem;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.menu-content {
|
|
|
+ height: 950px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ @media (max-width: 600px) {
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.bg-list {
|
|
|
+ .bg-img {
|
|
|
+ color: #fff;
|
|
|
+ background-color: var(--main-color);
|
|
|
+ border: 1px solid var(--main-color);
|
|
|
+ border-radius: 0 0 5px 5px;
|
|
|
+ text-align: center;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .bg-img {
|
|
|
+ margin-top: 2rem;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ p {
|
|
|
+ width: 50vw;
|
|
|
+ margin: 0.5rem auto 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cover {
|
|
|
+ max-width: 100%;
|
|
|
+ width: 12rem;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // p {
|
|
|
+ // margin-top: 0.5rem;
|
|
|
+ // }
|
|
|
+
|
|
|
+ .icon {
|
|
|
+ width: 3.5rem;
|
|
|
+ position: absolute;
|
|
|
+ top: -1.5rem;
|
|
|
+ right: -1.5rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .slider-btn {
|
|
|
+ width: 100%;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 100;
|
|
|
+ // top: 33%;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 60px;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ // @media (max-width: 600px) {
|
|
|
+ // width: 50px;
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ .prev,
|
|
|
+ .next {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ position: absolute;
|
|
|
+ cursor: pointer;
|
|
|
+ border: none;
|
|
|
+ // border-radius: 100px;
|
|
|
+ // background-color: var(--main-color);
|
|
|
+
|
|
|
+ img {
|
|
|
+ filter: invert(65%) sepia(7%) saturate(5329%) hue-rotate(336deg)
|
|
|
+ brightness(112%) contrast(47%);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ img {
|
|
|
+ opacity: 0.7;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .prev {
|
|
|
+ left: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .next {
|
|
|
+ right: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-num {
|
|
|
+ margin: 2rem auto;
|
|
|
+ letter-spacing: 0.2rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .content {
|
|
|
+ @media (max-width: 600px) {
|
|
|
+ min-height: 100vh;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.v-btn {
|
|
|
// &.v-btn--density-default {
|
|
|
// height: auto !important;
|