panhui 4 سال پیش
والد
کامیت
19936aa4c8

BIN
src/main/nine-space/src/assets/01.png


BIN
src/main/nine-space/src/assets/02.png


BIN
src/main/nine-space/src/assets/creatorBg.png


+ 21 - 0
src/main/nine-space/src/components/ImgContent.vue

@@ -0,0 +1,21 @@
+<template>
+    <van-image :src="src" :fit="fit">
+        <template v-slot:loading>
+            <loading></loading>
+        </template>
+    </van-image>
+</template>
+
+<script>
+import { Image } from 'vant';
+import Loading from './Loading.vue';
+export default {
+    props: ['src', 'fit'],
+    components: {
+        'van-image': Image,
+        Loading
+    }
+};
+</script>
+
+<style lang="less" scoped></style>

+ 69 - 231
src/main/nine-space/src/components/Loading.vue

@@ -1,243 +1,81 @@
 <template>
-    <div class="loader">
-        <!-- <span class="text">Loading</span> -->
-        <span class="spinner"></span>
+    <div class="loading-content">
+        <div class="loading">
+            <img class="img1" src="../assets/01.png" alt="" />
+            <img class="img2" src="../assets/02.png" alt="" />
+        </div>
     </div>
 </template>
 
-<style lang="less" scoped>
-.loader {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    -webkit-transform: translate(-50%, -50%);
-    -moz-transform: translate(-50%, -50%);
-    -mos-transform: translate(-50%, -50%);
-    -o-transform: translate(-50%, -50%);
-    transform: translate(-50%, -50%);
-    text-align: center;
-    /* disable selection and cursor changes */
-    -webkit-touch-callout: none;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-    cursor: default;
-}
+<script>
+export default {};
+</script>
 
-/* Text align it the center of screen and connect the looped animation for 2.5 seconds */
-.loader .text {
-    position: absolute;
-    top: 18px;
-    left: 4px;
-    z-index: 5;
-    font-size: 20px;
-    text-transform: uppercase;
-    -webkit-animation: text 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -moz-animation: text 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -ms-animation: text 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -o-animation: text 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    animation: text 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-}
-
-/* Create a container for animation*/
-.spinner {
-    position: relative;
-    width: 50px;
-    height: 50px;
-    color: #fff;
-}
-
-.spinner:before,
-.spinner:after {
-    content: '';
+<style lang="less" scoped>
+.loading-content {
+    display: flex;
+    justify-content: center;
+    width: 100%;
     position: relative;
-    display: block;
-}
-
-/* Create cube and set animation*/
-.spinner:before {
-    -webkit-animation: spinner 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -moz-animation: spinner 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -ms-animation: spinner 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -o-animation: spinner 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    animation: spinner 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    width: 50px;
-    height: 50px;
-    background-color: #ffb178;
 }
 
-/* Create shadow and set animation*/
-.spinner:after {
-    -webkit-animation: shadow 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -moz-animation: shadow 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -ms-animation: shadow 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    -o-animation: shadow 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
-    animation: shadow 2.5s cubic-bezier(0.75, 0, 0.5, 1) infinite normal;
+.loading {
     position: relative;
-    bottom: -17.5px;
-    height: 2.5px;
-    border-radius: 50%;
-    background-color: #322b27;
-}
-
-/* Animation keys */
-/* from cube to circle */
-@-webkit-keyframes spinner {
-    50% {
-        -webkit-border-radius: 50%;
-        -webkit-transform: scale(0.5) rotate(360deg);
-        background-color: #fffecb;
-    }
-    100% {
-        -webkit-transform: scale(1) rotate(720deg);
-        background-color: #ffb178;
-    }
-}
-
-@-moz-keyframes spinner {
-    50% {
-        -moz-border-radius: 50%;
-        -moz-transform: scale(0.5) rotate(360deg);
-        background-color: #fffecb;
-    }
-    100% {
-        -moz-transform: scale(1) rotate(720deg);
-        background-color: #ffb178;
-    }
-}
-
-@-mos-keyframes spinner {
-    50% {
-        -mos-border-radius: 50%;
-        -mos-transform: scale(0.5) rotate(360deg);
-        background-color: #fffecb;
-    }
-    100% {
-        -mos-transform: scale(1) rotate(720deg);
-        background-color: #ffb178;
-    }
-}
-
-@-o-keyframes spinner {
-    50% {
-        -o-border-radius: 50%;
-        -o-transform: scale(0.5) rotate(360deg);
-        background-color: #fffecb;
-    }
-    100% {
-        -o-transform: scale(1) rotate(720deg);
-        background-color: #ffb178;
-    }
-}
-
-@keyframes spinner {
-    50% {
-        border-radius: 50%;
-        transform: scale(0.5) rotate(360deg);
-        background-color: #fffecb;
-    }
-    100% {
-        transform: scale(1) rotate(720deg);
-        background-color: #ffb178;
-    }
-}
-
-/* animation shadow */
-@-webkit-keyframes shadow {
-    50% {
-        -webkit-transform: scale(0.5);
-        background-color: #322b27;
-    }
-}
-
-@-moz-keyframes shadow {
-    50% {
-        -moz-transform: scale(0.5);
-        background-color: #322b27;
-    }
-}
-
-@-mos-keyframes shadow {
-    50% {
-        -mos-transform: scale(0.5);
-        background-color: #322b27;
-    }
-}
-
-@-o-keyframes shadow {
-    50% {
-        -o-transform: scale(0.5);
-        background-color: #322b27;
-    }
-}
-
-@keyframes shadow {
-    50% {
-        transform: scale(0.5);
-        background-color: #322b27;
-    }
-}
-
-/* animation text */
-@-webkit-keyframes text {
-    0% {
-        -webkit-transform: scale(1, 1);
-    }
-    50% {
-        -webkit-transform: scale(0.5, 0.5);
-    }
-    100% {
-        -webkit-transform: scale(1, 1);
-    }
-}
-
-@-moz-keyframes text {
-    0% {
-        -moz-transform: scale(1, 1);
-    }
-    50% {
-        -moz-transform: scale(0.5, 0.5);
-    }
-    100% {
-        -moz-transform: scale(1, 1);
-    }
-}
-
-@-mos-keyframes text {
-    0% {
-        -mos-transform: scale(1, 1);
-    }
-    50% {
-        -mos-transform: scale(0.5, 0.5);
-    }
-    100% {
-        -mos-transform: scale(1, 1);
-    }
-}
-
-@-o-keyframes text {
-    0% {
-        -o-transform: scale(1, 1);
-    }
-    50% {
-        -o-transform: scale(0.5, 0.5);
-    }
-    100% {
-        -o-transform: scale(1, 1);
-    }
-}
-
-@keyframes text {
-    0% {
-        transform: scale(1, 1);
-    }
-    50% {
-        transform: scale(0.5, 0.5);
-    }
-    100% {
-        transform: scale(1, 1);
+    overflow: hidden;
+    box-sizing: border-box;
+    border-width: 0;
+    width: 60%;
+    .img1 {
+        position: absolute;
+        left: -1px;
+        top: -1px;
+        right: -1px;
+        bottom: -1px;
+        z-index: 2;
+        display: block;
+        width: calc(100% + 4px);
+        height: calc(100% + 4px);
+    }
+
+    .img2 {
+        position: relative;
+        z-index: 0;
+        display: block;
+        width: 100%;
+        height: auto;
+    }
+
+    @keyframes flipYLight {
+        0% {
+            left: -40%;
+            opacity: 0.5;
+            width: 10px;
+        }
+        50% {
+            left: 20%;
+            opacity: 0;
+            width: 35px;
+        }
+        100% {
+            left: 90%;
+            opacity: 0.5;
+            width: 10px;
+        }
+    }
+
+    &::after {
+        content: '';
+        background-color: #fff;
+        position: absolute;
+        background: #fff;
+        width: 25px;
+        height: 100vw;
+        top: 0;
+        left: 45px;
+        opacity: 1;
+        transform: skewX(-25deg);
+        z-index: 1;
+        animation: flipYLight 1.5s linear infinite;
     }
 }
 </style>

+ 8 - 1
src/main/nine-space/src/components/product/ProductBanner.vue

@@ -22,7 +22,7 @@
                         :src="getImg(item.url, '', 1200)"
                         width="calc(100vw - 134px)"
                         height="calc(100vw - 134px)"
-                        fit="scale-down"
+                        fit="cover"
                     />
                 </swiper-slide>
             </swiper>
@@ -141,6 +141,7 @@ export default {
     .mySwiper {
         border-radius: @radius;
         border: 2px solid #ffffff;
+        padding: 5px;
         .detail-animate();
         .swiper-slide {
             display: flex;
@@ -156,6 +157,12 @@ export default {
     }
 }
 
+.swiper-video {
+    width: calc(100vw - 134px);
+    height: calc(100vw - 134px);
+    display: block;
+}
+
 .share-content {
     display: flex;
     margin-top: 20px;

+ 6 - 37
src/main/nine-space/src/components/product/productSmall.vue

@@ -1,30 +1,22 @@
 <template>
-    <router-link
-        :to="{
-            path: '/productDetail',
-            query: {
-                id: info.id
-            }
-        }"
-        class="product"
-    >
-        <van-image width="100%" height="140px" :radius="30" :src="getImg(changeImgs(info.pic))" fit="cover" />
+    <div class="product" @click="goNext(info)">
+        <van-image width="100%" height="140px" :radius="30" :src="getImg(info.pic)" fit="cover" />
 
         <div class="content">
             <div class="name van-ellipsis">
                 {{ info.name }}
             </div>
             <div class="text van-ellipsis">
-                {{ info.name }}
+                {{ info.remark }}
             </div>
         </div>
-    </router-link>
+    </div>
 </template>
 
 <script>
-import product from '../../mixins/product';
+import banner from '../../mixins/banner';
 export default {
-    mixins: [product],
+    mixins: [banner],
     props: {
         info: {
             type: Object,
@@ -32,29 +24,6 @@ export default {
                 return {};
             }
         }
-    },
-    methods: {
-        likeProduct() {
-            if (!this.info.liked) {
-                this.$http.get(`/collection/${this.info.id}/like`).then(() => {
-                    this.$emit('update:info', {
-                        ...this.info,
-                        liked: true,
-                        likes: this.info.likes + 1
-                    });
-                    this.$toast.success('收藏成功');
-                });
-            } else {
-                this.$http.get(`/collection/${this.info.id}/unlike`).then(() => {
-                    this.$emit('update:info', {
-                        ...this.info,
-                        liked: false,
-                        likes: this.info.likes - 1
-                    });
-                    this.$toast.success('取消收藏');
-                });
-            }
-        }
     }
 };
 </script>

+ 4 - 3
src/main/nine-space/src/main.js

@@ -17,10 +17,10 @@ import Driver from './components/Driver.vue';
 import common from './mixins/common';
 import VueClipboard from 'vue-clipboard2';
 import queryString from 'query-string';
-// import VConsole from 'vconsole';
-// const vConsole = new VConsole();
 store.commit('setFirstUrl', location.href);
 
+import ImgContent from './components/ImgContent.vue';
+
 http.http
     .get('/wx/jsapiSign', { url: location.href })
     .then(res => {
@@ -55,7 +55,7 @@ http.http
             });
         });
     })
-    .catch(e => {});
+    .catch(e => { });
 
 createApp(App)
     .use(Vant)
@@ -67,6 +67,7 @@ createApp(App)
     .component('page-title', PageTitle)
     .component('like-button', LikeButton)
     .component('driver', Driver)
+    .component('van-image', ImgContent)
     .use(store)
     .use(router)
     .mount('#app');

+ 2 - 2
src/main/nine-space/src/styles/app.less

@@ -30,7 +30,7 @@
     --van-uploader-upload-background-color: transparent;
     --van-uploader-file-background-color: transparent;
     --van-active-color: @bg3;
-    --van-image-placeholder-background-color: @bg3;
+    --van-image-placeholder-background-color: @bg2;
     --van-search-background-color: #181818;
     --van-search-content-background-color: #0f0f0f;
     // --van-picker-background-color: @bg;
@@ -169,4 +169,4 @@ input:-webkit-autofill {
             }
         }
     }
-}
+}

+ 162 - 1
src/main/nine-space/src/utils/data.json

@@ -1 +1,162 @@
-{"v":"5.5.8","fr":30,"ip":0,"op":75,"w":821,"h":444,"nm":"第九空间-加载","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":8,"nm":"第九空间-加载_[00000-00074].png","cl":"png","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[410.5,222,0],"ix":2},"a":{"a":0,"k":[410.5,222,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":75,"st":0,"bm":0}],"markers":[]}
+{
+  "v": "5.8.1",
+  "fr": 30,
+  "ip": 0,
+  "op": 75,
+  "w": 821,
+  "h": 444,
+  "nm": "第九空间-加载",
+  "ddd": 0,
+  "assets": [
+    {
+      "id": "image_0",
+      "w": 821,
+      "h": 444,
+      "u": "images/",
+      "p": "img_0.png",
+      "e": 0
+    },
+    {
+      "id": "image_1",
+      "w": 738,
+      "h": 269,
+      "u": "images/",
+      "p": "img_1.png",
+      "e": 0
+    },
+    {
+      "id": "comp_0",
+      "nm": "第九空间-加载 (1)",
+      "fr": 30,
+      "layers": [
+        {
+          "ddd": 0,
+          "ind": 1,
+          "ty": 2,
+          "nm": "圆角矩形 1",
+          "refId": "image_0",
+          "sr": 1,
+          "ks": {
+            "o": { "a": 0, "k": 100, "ix": 11 },
+            "r": { "a": 0, "k": 0, "ix": 10 },
+            "p": {
+              "a": 1,
+              "k": [
+                {
+                  "i": { "x": 0, "y": 1 },
+                  "o": { "x": 0.409, "y": 0 },
+                  "t": 0,
+                  "s": [155.5, 171, 0],
+                  "to": [3.79, 0, 0],
+                  "ti": [-124.71, 0, 0]
+                },
+                { "t": 74, "s": [988.5, 199, 0] }
+              ],
+              "ix": 2,
+              "l": 2
+            },
+            "a": { "a": 0, "k": [410.5, 222, 0], "ix": 1, "l": 2 },
+            "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 }
+          },
+          "ao": 0,
+          "hasMask": true,
+          "masksProperties": [
+            {
+              "inv": false,
+              "mode": "a",
+              "pt": {
+                "a": 0,
+                "k": {
+                  "i": [
+                    [-4.507, -3.192],
+                    [0, 0],
+                    [3.192, -4.507],
+                    [0, 0],
+                    [4.507, 3.192],
+                    [0, 0],
+                    [-3.192, 4.507],
+                    [0, 0]
+                  ],
+                  "o": [
+                    [0, 0],
+                    [4.507, 3.192],
+                    [0, 0],
+                    [-3.192, 4.507],
+                    [0, 0],
+                    [-4.507, -3.192],
+                    [0, 0],
+                    [3.192, -4.507]
+                  ],
+                  "v": [
+                    [316.435, 63.822],
+                    [380.086, 108.906],
+                    [382.466, 122.847],
+                    [81.901, 547.183],
+                    [67.961, 549.563],
+                    [4.31, 504.478],
+                    [1.93, 490.538],
+                    [302.495, 66.202]
+                  ],
+                  "c": true
+                },
+                "ix": 1
+              },
+              "o": { "a": 0, "k": 100, "ix": 3 },
+              "x": { "a": 0, "k": 0, "ix": 4 },
+              "nm": "蒙版 1"
+            }
+          ],
+          "ip": 0,
+          "op": 74,
+          "st": 0,
+          "bm": 0
+        },
+        {
+          "ddd": 0,
+          "ind": 2,
+          "ty": 2,
+          "nm": "图层 2",
+          "refId": "image_1",
+          "sr": 1,
+          "ks": {
+            "o": { "a": 0, "k": 100, "ix": 11 },
+            "r": { "a": 0, "k": 0, "ix": 10 },
+            "p": { "a": 0, "k": [404, 234.5, 0], "ix": 2, "l": 2 },
+            "a": { "a": 0, "k": [369, 134.5, 0], "ix": 1, "l": 2 },
+            "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 }
+          },
+          "ao": 0,
+          "ip": 0,
+          "op": 300,
+          "st": 0,
+          "bm": 0
+        }
+      ]
+    }
+  ],
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 4,
+      "ty": 0,
+      "nm": "图层 2",
+      "refId": "comp_0",
+      "sr": 1,
+      "ks": {
+        "o": { "a": 0, "k": 100, "ix": 11 },
+        "r": { "a": 0, "k": 0, "ix": 10 },
+        "p": { "a": 0, "k": [410.5, 222, 0], "ix": 2, "l": 2 },
+        "a": { "a": 0, "k": [410.5, 222, 0], "ix": 1, "l": 2 },
+        "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 }
+      },
+      "ao": 0,
+      "w": 821,
+      "h": 444,
+      "ip": 0,
+      "op": 300,
+      "st": 0,
+      "bm": 0
+    }
+  ],
+  "markers": []
+}

+ 3 - 9
src/main/nine-space/src/views/Home.vue

@@ -63,15 +63,9 @@ export default {
                 message: '加载中...',
                 forbidClick: true
             });
-            Promise.all([
-                this.getProduct().then(res => {
-                    this.banners = res;
-                }),
-                this.getProduct('LIST').then(res => {
-                    this.products = res;
-                })
-            ]).then(() => {
-                this.$toast.clear();
+            this.getBanner();
+            this.getProduct('LIST').then(res => {
+                this.products = res;
             });
         },
         getProduct(type = 'BANNER') {

+ 8 - 5
src/main/nine-space/src/views/Mine.vue

@@ -1,7 +1,14 @@
 <template>
     <div class="mine">
         <div class="userInfo" v-if="isLogin">
-            <van-image width="100%" height="35vw" :src="userInfo.bg" loading-icon="" fit="cover" class="top-img" />
+            <van-image
+                width="100%"
+                height="35vw"
+                :src="userInfo.bg || require('../assets/creatorBg.png')"
+                loading-icon=""
+                fit="cover"
+                class="top-img"
+            />
             <div class="userInfo-content">
                 <div class="userInfo-top">
                     <van-image
@@ -332,10 +339,6 @@ export default {
         top: 0;
         left: 0;
         z-index: 1;
-        /deep/.van-image__loading {
-            background: linear-gradient(131deg, #fffbb2 0%, #ffd5b7 100%);
-            filter: blur(0px);
-        }
     }
 }
 .userInfo-content {

+ 9 - 2
src/main/nine-space/src/views/creator/Detail.vue

@@ -1,7 +1,14 @@
 <template>
     <div class="mine">
         <div class="userInfo">
-            <van-image width="100%" height="35vw" loading-icon="" :src="info.bg" fit="cover" class="top-img" />
+            <van-image
+                width="100%"
+                height="35vw"
+                loading-icon=""
+                :src="info.bg || require('../../assets/creatorBg.png')"
+                fit="cover"
+                class="top-img"
+            />
             <div class="userInfo-content">
                 <div class="userInfo-top">
                     <van-image
@@ -237,7 +244,7 @@ export default {
         z-index: 1;
 
         /deep/.van-image__loading {
-            background: linear-gradient(131deg, #fffbb2 0%, #ffd5b7 100%);
+            // background: linear-gradient(131deg, #fffbb2 0%, #ffd5b7 100%);
             filter: blur(0px);
         }
     }

+ 23 - 16
src/main/nine-space/src/views/product/Detail.vue

@@ -13,14 +13,14 @@
 
             <div class="price-line" v-if="info.salable">
                 <div class="text" v-if="info.number">编号 {{ info.number }}</div>
-                <div class="text" v-if="info.salable && info.stock > 0">
-                    <span>已售 {{ info.sale }}</span>
-                    <span>剩余 {{ info.stock }}</span>
-                </div>
                 <div class="text total" v-if="info.total > 1">
                     <span>限量</span>
                     <span>{{ info.total }}份</span>
                 </div>
+                <div class="text" v-if="info.salable && info.stock > 0">
+                    <span>已售 {{ info.sale }}</span>
+                    <span>剩余 {{ info.stock }}</span>
+                </div>
             </div>
             <!-- <div class="title">{{ info.name }}</div> -->
             <div class="info-bottom">
@@ -252,6 +252,9 @@ import 'swiper/swiper-bundle.min.css';
 import SwiperCore, { Pagination } from 'swiper';
 
 SwiperCore.use([Pagination]);
+
+let inWeixin = /micromessenger/i.test(navigator.userAgent);
+
 export default {
     components: {
         HashCode,
@@ -271,7 +274,8 @@ export default {
             init: [],
             init2: null,
             list: [],
-            activeNames: ['1', '2', '3', '4', '5', '6', 'hashCode', '8']
+            activeNames: ['1', '2', '3', '4', '5', '6', 'hashCode', '8'],
+            inWeixin
         };
     },
     computed: {
@@ -329,17 +333,20 @@ export default {
                 .then(res => {
                     console.log(res);
                     this.info = res;
-                    wx.updateAppMessageShareData({
-                        title: '第九空间-' + res.name,
-                        desc: '全球首个基于区块链的游戏资产集换中心',
-                        link: location.origin + '/9th/productDetail?id=' + res.id,
-                        imgUrl: this.getImg(this.changeImgs(this.banners), '', 600)
-                    });
-                    wx.updateTimelineShareData({
-                        title: '第九空间-' + res.name,
-                        link: location.origin + '/9th/productDetail?id=' + res.id,
-                        imgUrl: this.getImg(this.changeImgs(this.banners), '', 600)
-                    });
+                    if (this.inWeixin) {
+                        wx.updateAppMessageShareData({
+                            title: '第九空间-' + res.name,
+                            desc: '全球首个基于区块链的游戏资产集换中心',
+                            link: location.origin + '/9th/productDetail?id=' + res.id,
+                            imgUrl: this.getImg(this.changeImgs(this.banners), '', 300)
+                        });
+                        wx.updateTimelineShareData({
+                            title: '第九空间-' + res.name,
+                            link: location.origin + '/9th/productDetail?id=' + res.id,
+                            imgUrl: this.getImg(this.changeImgs(this.banners), '', 300)
+                        });
+                        console.log(wx);
+                    }
                     if (res.assetId) {
                         this.$http.get('/asset/get/' + res.assetId).then(res => {
                             console.log(res);

+ 0 - 3
src/main/nine-space/src/views/user/Point.vue

@@ -41,7 +41,6 @@
                 </div>
                 <div class="text3">-320</div>
             </div> -->
-            <lottie :options="defaultOptions" :height="50" :width="400" v-on:animCreated="handleAnimation" />
             <van-empty :image="require('../../assets/kong_png_yongyoude  (1).png')" description="暂时没有任何记录哦~" />
         </div>
     </div>
@@ -49,10 +48,8 @@
 
 <script>
 import { ref } from 'vue';
-import Lottie from 'vue-lottie';
 const animationData = require('../../utils/data.json');
 export default {
-    components: { Lottie },
     setup() {
         const showPopover = ref(false);