Преглед изворни кода

Merge branch 'dev' of xiongzhu/raex_front into master

panhui пре 4 година
родитељ
комит
e122ae6724

+ 1 - 1
.env.development

@@ -1,4 +1,4 @@
-VUE_APP_BASE_URL=https://test.raex.vip
+VUE_APP_BASE_URL=https://test.raex.vip/
 NODE_ENV=development
 VUE_APP_PUBLIC_PATH=/
 ASSETS_PATH=raex

BIN
src/assets/choose1.png


BIN
src/assets/choose2.png


BIN
src/assets/icon-bianjicangpin.png


BIN
src/assets/icon-dianzan2.png


BIN
src/assets/icon-dianzan3.png


BIN
src/assets/icon-dianzan4.png


BIN
src/assets/icon-fabu.png


BIN
src/assets/icon-fenxiang1.png


BIN
src/assets/icon-fenxiang2.png


BIN
src/assets/icon-jieshaozhanguan.png


BIN
src/assets/icon-liulanliang.png


BIN
src/assets/icon-qiehuanhengping.png


BIN
src/assets/icon-tianjiacangping.png


BIN
src/assets/icon-tianjiacangping1.png


BIN
src/assets/icon-tianjiacangping2.png


BIN
src/assets/icon-tuichu.png


BIN
src/assets/icon-tupian.png


BIN
src/assets/png-zhantai1.png


BIN
src/assets/png-zhongjianlan-bg.jpg


BIN
src/assets/zhanguan-shu.jpg


+ 199 - 0
src/components/asset/showInfo.vue

@@ -0,0 +1,199 @@
+<template>
+    <router-link
+        :to="{
+            path: '/hall',
+            query: {
+                id: info.id
+            }
+        }"
+        class="showInfo"
+    >
+        <div class="bg" :style="{ backgroundImage: `url(${info.headBg}),url(${info.showroomBg})` }"></div>
+        <!-- <van-image radius="6" :src="info.showroomBg" width="100%" height="140" fit="cover" /> -->
+        <div class="collecions">
+            <div class="users">
+                <van-image :src="info.pic" width="120" height="120" radius="8" fit="cover" />
+                <div class="users-text">
+                    <div class="name">
+                        <div>{{ info.nickname }}</div>
+                        <div>的展馆</div>
+                    </div>
+                    <div class="sub">
+                        <span>{{ info.introduction }}</span>
+                    </div>
+                </div>
+            </div>
+            <van-image
+                v-for="(item, index) in collections"
+                :src="item.pic"
+                width="120"
+                height="120"
+                fit="coevr"
+                radius="8"
+                :key="index"
+            />
+        </div>
+        <img src="../../assets/png-zhantai1.png" class="bg-img" alt="" />
+        <div class="text">
+            <div class="text1">{{ info.introduction || '展馆未设置' }}</div>
+            <div class="text2">{{ info.nickname }}</div>
+        </div>
+        <div class="btns" @click.prevent="">
+            <div class="btn">
+                <img src="../../assets/icon-liulanliang.png" alt="" />
+                <span>{{ collections.length }}</span>
+            </div>
+            <div class="btn">
+                <img src="../../assets/icon-fenxiang2.png" alt="" />
+                <span>{{ info.share }}</span>
+            </div>
+            <div class="btn" @click="like(info)">
+                <img v-if="info.liked" src="../../assets/icon-dianzan3.png" alt="" />
+                <img v-else src="../../assets/icon-dianzan2.png" alt="" />
+                <span>{{ info.likes }}</span>
+            </div>
+        </div>
+    </router-link>
+</template>
+
+<script>
+import asset from '../../mixins/asset';
+import product from '../../mixins/product';
+import room from '../../mixins/room';
+
+export default {
+    mixins: [asset, product, room],
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    computed: {
+        collections() {
+            return this.info.collections || [];
+        }
+    },
+    methods: {
+        getDetail(info) {
+            this.$emit('update:info', info);
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.showInfo {
+    padding: 10px 16px;
+    position: relative;
+    display: block;
+
+    & > div {
+        z-index: 1;
+    }
+}
+
+.bg {
+    height: 140px;
+    background-size: auto 140px, auto 140px;
+    background-repeat: no-repeat, repeat-x;
+    background-position: 0 0, 134px 0;
+    z-index: 1;
+    position: relative;
+}
+
+.bg-img {
+    width: 100%;
+    height: 40px;
+    position: absolute;
+    top: 130px;
+    left: 0;
+    right: 0;
+    z-index: 0;
+}
+
+.text {
+    margin-top: 20px;
+    .text1 {
+        font-size: 12px;
+        color: #ffffff;
+        line-height: 17px;
+    }
+
+    .text2 {
+        font-size: 12px;
+        color: #939599;
+        line-height: 12px;
+    }
+}
+
+.btns {
+    .flex();
+    .btn {
+        .flex();
+        img {
+            width: 12px;
+            height: 12px;
+            display: block;
+            margin-right: 3px;
+        }
+        span {
+            font-size: 12px;
+            color: #939599;
+            line-height: 17px;
+        }
+    }
+    .btn + .btn {
+        margin-left: 16px;
+    }
+    position: absolute;
+    right: 16px;
+    bottom: 5px;
+}
+
+.collecions {
+    position: absolute;
+    top: 42px;
+    left: 16px;
+    right: 16px;
+    z-index: 3;
+    width: calc(260% - 124px);
+    .flex();
+    overflow: hidden;
+    transform: scale(0.4);
+    transform-origin: 0 0 0;
+    .van-image {
+        flex-shrink: 0;
+    }
+
+    .users {
+        padding-left: 60px;
+        padding-right: 60px;
+        .flex();
+        .users-text {
+            .flex-col();
+            align-self: stretch;
+            width: 180px;
+            padding-left: 10px;
+        }
+        .name {
+            font-size: 24px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 30px;
+            flex-grow: 1;
+        }
+        .sub {
+            font-size: 12px;
+            color: rgba(255, 255, 255, 0.6);
+            line-height: 17px;
+        }
+    }
+
+    & > .van-image {
+        margin-right: 60px;
+    }
+}
+</style>

+ 19 - 1
src/components/product/ProductBanner.vue

@@ -4,7 +4,7 @@
 
         <div class="detail-info">
             <three-mode :info="info.model3d" v-if="!!info.model3d" :pageType="pageType"></three-mode>
-            <swiper pagination class="mySwiper" v-else-if="banners.length > 0">
+            <swiper pagination @swiper="setSwiperRef" class="mySwiper" v-else-if="banners.length > 0">
                 <swiper-slide v-for="(item, index) in banners" :key="index">
                     <!-- <img :src="item" /> -->
 
@@ -73,7 +73,24 @@ import asset from '../../mixins/asset';
 import Post from '../Post.vue';
 import ThreeMode from './ThreeMode.vue';
 import { ImagePreview } from 'vant';
+import { watch, ref, computed } from 'vue';
+import { useWindowSize } from '@vant/use';
 export default {
+    setup() {
+        const { width, height } = useWindowSize();
+
+        let swiperRef = null;
+
+        const setSwiperRef = swiper => {
+            swiperRef = swiper;
+        };
+
+        watch([width, height], () => {
+            swiperRef.update(true);
+        });
+
+        return { swiperRef: null, setSwiperRef };
+    },
     props: {
         info: {
             type: Object,
@@ -197,6 +214,7 @@ export default {
         padding: 5px;
         overflow: hidden;
         .detail-animate();
+        width: calc(100vw - 124px);
         .swiper-slide {
             display: flex;
             align-items: center;

+ 27 - 21
src/main.js

@@ -121,6 +121,7 @@ const loadSplash = (onload, onerror) =>
         const splash = document.createElement('img');
         splash.className = 'splash-screen';
         splash.onload = () => {
+            console.log('splash onload');
             onload && onload();
             setTimeout(() => {
                 hideSplash();
@@ -133,7 +134,7 @@ const loadSplash = (onload, onerror) =>
         setTimeout(() => {
             hideSplash();
         }, 5000);
-        splash.src = 'https://cdn.raex.vip/splash.jpg?ts=' + new Date().getTime();
+        splash.src = 'https://cdn.raex.vip/splash.jpg';
         document.body.append(splash);
     });
 
@@ -142,15 +143,37 @@ if (navigator.userAgent.includes('#cordova#')) {
         'deviceready',
         function () {
             StatusBar.overlaysWebView(true);
-            window.$vm = app.mount('#app');
+
+            function mountApp() {
+                window.$vm = app.mount('#app');
+                http.http
+                    .get('/appVersion/checkUpdate', {
+                        platform: window.cordova.platformId,
+                        version: navigator.appInfo.version
+                    })
+                    .then(res => {
+                        if (res.needUpdate) {
+                            window.$vm.$dialog.alert({
+                                message: '检测到新版本,请下载更新',
+                                confirmButtonText: '下载更新',
+                                beforeClose(action, done) {
+                                    console.log(action);
+                                    location.href = 'http://download.raex.vip';
+                                }
+                            });
+                        }
+                    });
+            }
             loadSplash(
                 () => {
                     setTimeout(() => {
                         navigator.splashscreen.hide();
                     }, 100);
+                    mountApp();
                 },
                 () => {
                     navigator.splashscreen.hide();
+                    mountApp();
                 }
             ).then(res => {
                 StatusBar.overlaysWebView(false);
@@ -158,7 +181,7 @@ if (navigator.userAgent.includes('#cordova#')) {
                 StatusBar.styleDefault();
             });
 
-            if (/iphone|ipad|ipod/i.test(navigator.userAgent)) {
+            if ('ios' === window.cordova.platformId) {
                 style.setProperty('--safe-top', 'env(safe-area-inset-top)');
                 style.setProperty('--safe-bottom', 'env(safe-area-inset-bottom)');
                 style.setProperty('--safe-left', 'env(safe-area-inset-left)');
@@ -216,24 +239,7 @@ if (navigator.userAgent.includes('#cordova#')) {
                 false
             );
 
-            if (!(/.+\.raex\.vip/.test(location.host) || /192\.168/.test(location.host))) {
-                if (!/iphone|ipad|ipod|Macintosh/i.test(navigator.userAgent)) {
-                    window.$vm.$dialog.alert({
-                        message: '检测到新版本,请下载更新',
-                        confirmButtonText: '下载更新',
-                        beforeClose(action, done) {
-                            console.log(action);
-                            if (/iphone|ipad|ipod|Macintosh/i.test(navigator.userAgent)) {
-                                //location.href = 'https://apps.apple.com/cn/app/id1598469798';
-                            } else {
-                                location.href = 'http://download.raex.vip';
-                            }
-                        }
-                    });
-                }
-            }
-
-            if (window.store && /iphone|ipad|ipod|Macintosh/i.test(navigator.userAgent)) {
+            if ('ios' === window.cordova.platformId) {
                 window.store.register({
                     id: '358',
                     alias: '358',

+ 4 - 1
src/mixins/list.js

@@ -4,7 +4,8 @@ export default {
             empty: false,
             loading: false,
             finished: false,
-            page: 0
+            page: 0,
+            totalElements: 0
         };
     },
     methods: {
@@ -38,6 +39,7 @@ export default {
                     if (!this.finished) {
                         this.page = this.page + 1;
                     }
+                    this.totalElements = Number(res.totalElements);
                 });
             } else {
                 return this.$http.post(this.url, data, { body: 'json' }).then(res => {
@@ -51,6 +53,7 @@ export default {
                     if (!this.finished) {
                         this.page = this.page + 1;
                     }
+                    this.totalElements = Number(res.totalElements);
                 });
             }
         }

+ 43 - 0
src/mixins/room.js

@@ -0,0 +1,43 @@
+export default {
+    methods: {
+        like(info) {
+            this.checkLogin().then(() => {
+                this.$toast.loading({
+                    message: '加载中...',
+                    forbidClick: true
+                });
+                if (!info.liked) {
+                    this.$http
+                        .get(`/newsLike/${info.id}/likeRoom/`)
+                        .then(() => {
+                            if (this.getDetail) {
+                                this.getDetail({
+                                    ...info,
+                                    liked: true
+                                });
+                            }
+                            this.$toast.success('点赞成功');
+                        })
+                        .catch(() => {
+                            this.$toast.clear();
+                        });
+                } else {
+                    this.$http
+                        .get(`/newsLike/${info.id}/unlikeRoom/`)
+                        .then(() => {
+                            if (this.getDetail) {
+                                this.getDetail({
+                                    ...info,
+                                    liked: false
+                                });
+                            }
+                            this.$toast.success('取消成功');
+                        })
+                        .catch(() => {
+                            this.$toast.clear();
+                        });
+                }
+            });
+        }
+    }
+};

+ 46 - 13
src/router/index.js

@@ -116,6 +116,39 @@ const routes = [
             }
         ]
     },
+    {
+        path: '/hall',
+        name: 'hall',
+        component: () => import('../views/hall/Detail.vue'),
+        meta: {
+            pageType: Page.Every,
+            menuPage: true,
+            isHall: true,
+            title: '第九空间'
+        }
+    },
+    {
+        path: '/hallEdit',
+        name: 'hallEdit',
+        component: () => import('../views/hall/Edit.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '第九空间',
+            isHall: true,
+            tabColor: '#181818'
+        }
+    },
+    {
+        path: '/productAdd',
+        name: 'productAdd',
+        component: () => import('../views/hall/ProductAdd.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '第九空间',
+            isHall: true,
+            tabColor: '#181818'
+        }
+    },
     {
         path: '/login',
         name: 'userLogin',
@@ -601,15 +634,14 @@ router.beforeEach((to, from, next) => {
     if (to.query.invitor) {
         sessionStorage.setItem('invitor', to.query.invitor);
     }
-
-    if (!store.state.userInfo && to.meta.pageType !== Page.Login) {
-        store
-            .dispatch('getUserInfo')
-            .then(() => {
-                next(backNext(to));
-            })
-            .catch(() => {
-                if (to.meta.pageType != Page.Every && to.path !== '/collectionDetail' && to.path !== '/castingDetail') {
+    if (to.meta.pageType != Page.Every && to.path !== '/collectionDetail' && to.path !== '/castingDetail') {
+        if (!store.state.userInfo && to.meta.pageType !== Page.Login) {
+            store
+                .dispatch('getUserInfo')
+                .then(() => {
+                    next(backNext(to));
+                })
+                .catch(() => {
                     Dialog.confirm({
                         title: '提示',
                         message: '用户未登录,是否立即登录'
@@ -624,12 +656,13 @@ router.beforeEach((to, from, next) => {
                         .catch(() => {
                             next(false);
                         });
-                } else {
-                    next(backNext(to));
-                }
-            });
+                });
+        } else {
+            next(backNext(to));
+        }
     } else {
         next(backNext(to));
+        !!store.state.userInfo || store.dispatch('getUserInfo');
     }
 });
 router.afterEach((to, from) => {

+ 342 - 0
src/views/Hall.vue

@@ -0,0 +1,342 @@
+<template>
+    <swiper
+        :style="{
+            '--swiper-navigation-color': '#fff',
+            '--swiper-pagination-color': '#fff'
+        }"
+        :speed="600"
+        :parallax="true"
+        :slidesPerView="'auto'"
+        class="mySwiper"
+        :class="{ horizontal: !isVertical, windowHorizontal: !windowVertical }"
+        :direction="isVertical ? 'horizontal' : 'vertical'"
+    >
+        <div class="top"></div>
+        <div class="bottom" @click="isVertical = !isVertical">
+            <div class="btn">
+                <img src="../assets/icon-qiehuanhengping.png" alt="" />
+                <span>切换{{ isVertical || windowVertical ? '横屏' : '竖屏' }}</span>
+            </div>
+        </div>
+        <div class="parallax-bg" data-swiper-parallax="-50%">
+            <div
+                class="parallax-bg-img"
+                :style="{
+                    'background-image': `url(${require('../assets/zhanguan-shu.jpg')})`
+                }"
+            ></div>
+        </div>
+        <swiper-slide class="user">
+            <div class="icon" data-swiper-parallax="-300">
+                <van-image
+                    src="https://raex-meta.oss-cn-shenzhen.aliyuncs.com/nft/2022-02-07-01-15-56Liekxwjf.jpg"
+                    :width="isVertical && windowVertical ? 110 : 120"
+                    :height="isVertical && windowVertical ? 110 : 120"
+                    fit="coevr"
+                    radius="8"
+                />
+            </div>
+            <div data-swiper-parallax="-200">
+                <div class="name">
+                    <div>奶盖</div>
+                    <div>的展馆</div>
+                </div>
+            </div>
+            <div class="sub-box" data-swiper-parallax="-100">
+                <div class="sub">介绍一下展馆主题吧</div>
+            </div>
+        </swiper-slide>
+        <swiper-slide class="imgs" v-for="i in 10" :key="i">
+            <div class="icon" data-swiper-parallax="-20">
+                <van-image
+                    src="https://raex-meta.oss-cn-shenzhen.aliyuncs.com/nft/2022-02-07-01-15-56Liekxwjf.jpg"
+                    :width="isVertical && windowVertical ? 110 : 120"
+                    :height="isVertical && windowVertical ? 110 : 120"
+                    fit="coevr"
+                    radius="8"
+                />
+            </div>
+            <div class="icon" data-swiper-parallax="-40">
+                <van-image
+                    src="https://raex-meta.oss-cn-shenzhen.aliyuncs.com/nft/2022-02-07-01-15-56Liekxwjf.jpg"
+                    :width="isVertical && windowVertical ? 110 : 120"
+                    :height="isVertical && windowVertical ? 110 : 120"
+                    fit="coevr"
+                    radius="8"
+                />
+            </div>
+            <div class="icon" data-swiper-parallax="-100">
+                <van-image
+                    src="https://raex-meta.oss-cn-shenzhen.aliyuncs.com/nft/2022-02-07-01-15-56Liekxwjf.jpg"
+                    :width="isVertical && windowVertical ? 110 : 120"
+                    :height="isVertical && windowVertical ? 110 : 120"
+                    fit="coevr"
+                    radius="8"
+                />
+            </div>
+            <div class="icon" data-swiper-parallax="-200">
+                <van-image
+                    src="https://raex-meta.oss-cn-shenzhen.aliyuncs.com/nft/2022-02-07-01-15-56Liekxwjf.jpg"
+                    :width="isVertical && windowVertical ? 110 : 120"
+                    :height="isVertical && windowVertical ? 110 : 120"
+                    fit="coevr"
+                    radius="8"
+                />
+            </div>
+        </swiper-slide>
+    </swiper>
+</template>
+
+<script>
+import { Swiper, SwiperSlide } from 'swiper/vue';
+
+import 'swiper/swiper.min.css';
+import 'swiper/swiper-bundle.min.css';
+// import required modules
+import SwiperCore, { Pagination, Parallax, Navigation } from 'swiper';
+SwiperCore.use([Pagination, Parallax, Navigation]);
+import { watch, ref, computed } from 'vue';
+import { useWindowSize } from '@vant/use';
+export default {
+    components: {
+        Swiper,
+        SwiperSlide
+    },
+    setup() {
+        const { width, height } = useWindowSize();
+
+        console.log(width.value); // -> 窗口宽度
+        console.log(height.value); // -> 窗口高度
+
+        const windowVertical = computed(() => {
+            if (width.value > height.value) {
+                return false;
+            } else {
+                return true;
+            }
+        });
+
+        return { windowVertical };
+    },
+    data() {
+        return {
+            isVertical: true
+        };
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.user {
+    width: 128px;
+    padding: 6.3vh 100px 0 30px;
+    .icon {
+        .van-image {
+            transition: transform ease-in-out 0.3s;
+        }
+    }
+
+    .name {
+        font-size: 24px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 30px;
+        padding-top: 6px;
+    }
+    .sub {
+        padding-top: 20px;
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.6);
+        line-height: 17px;
+    }
+}
+
+.swiper {
+    width: 100%;
+    height: 100%;
+    background: #000;
+}
+
+.parallax-bg {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 500%;
+    height: 100%;
+    .parallax-bg-img {
+        width: 100%;
+        height: 100%;
+        -webkit-background-size: contain;
+        background-size: contain;
+        transition: transform ease-in-out 0.3s;
+    }
+}
+
+.imgs {
+    width: 100vw;
+    height: calc(25.2vh + 230px);
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    flex-wrap: wrap;
+    .icon {
+        padding: 6.3vh 0;
+        img {
+            width: 110px;
+            height: 110px;
+            display: block;
+        }
+        .van-image {
+            transition: transform ease-in-out 0.3s;
+        }
+    }
+}
+
+.bottom {
+    position: absolute;
+    bottom: 120px;
+    left: 30px;
+    z-index: 20;
+    .btn {
+        transition: transform ease-in-out 0.3s;
+    }
+    img {
+        width: 48px;
+        height: 48px;
+        display: block;
+    }
+    span {
+        font-size: 12px;
+        color: #ffffff;
+        line-height: 17px;
+        margin-top: 4px;
+    }
+}
+
+.mySwiper {
+    padding-top: 7.72vh;
+}
+/deep/.swiper-wrapper {
+    height: calc(100vh - 7.72vh);
+}
+
+.windowHorizontal {
+    padding-top: 7.72vw;
+    .user {
+        width: 298px;
+        height: 120px;
+        display: flex;
+        flex-direction: row;
+        position: relative;
+        padding: 6.3vh 60px;
+
+        .sub-box {
+            position: absolute;
+            bottom: 60px;
+            left: 190px;
+            .sub {
+                padding-top: 0;
+            }
+        }
+        .name {
+            margin-left: 10px;
+            padding-top: 0;
+        }
+    }
+    .imgs {
+        box-sizing: border-box;
+        height: calc(12.6vh + 120px);
+        .icon {
+            padding: 6.3vh;
+        }
+    }
+
+    /deep/.swiper-wrapper {
+        height: calc(100vh - 7.72vw);
+    }
+
+    .bottom {
+        bottom: 60px;
+        left: 60px;
+    }
+}
+
+.horizontal {
+    padding-top: 0;
+    padding-right: 7.72vh;
+    .parallax-bg {
+        width: 100%;
+        height: 600%;
+    }
+    .parallax-bg-img {
+        width: 600vh;
+        height: 100vw;
+        transform: rotate(90deg) translateX(-100vw);
+        transform-origin: left bottom;
+    }
+
+    .imgs {
+        width: calc(12.6vw + 120px);
+        height: 100vh;
+        box-sizing: border-box;
+        .icon {
+            padding: 6.3vw;
+        }
+    }
+
+    .user {
+        padding: 60px 6.3vw 0 30px;
+        height: 298px;
+        width: 120px;
+        .van-image {
+            transform: rotate(90deg);
+        }
+        .name {
+            width: 168px;
+            padding-top: 0;
+            transform: rotate(90deg) translate(-50px, -50px);
+            transform-origin: left bottom;
+        }
+        .sub {
+            width: 168px;
+            padding-top: 0;
+            transform-origin: left bottom;
+            transform: rotate(90deg) translate(-65px, 0px);
+        }
+    }
+
+    .imgs {
+        justify-content: space-around;
+        .van-image {
+            transform: rotate(90deg);
+        }
+    }
+
+    /deep/.swiper-wrapper {
+        height: 100vh;
+        align-items: flex-end;
+    }
+
+    .bottom {
+        top: 60px;
+        left: 49px;
+        .btn {
+            transform: rotate(90deg) translateX(-10px);
+        }
+    }
+    // .user {
+    //     padding: calc(21vw - 110px) 100px 0 30px;
+    // }
+    // /deep/.swiper-wrapper {
+    //     height: calc(100vw - 20vw);
+    // }
+    // &.mySwiper {
+    //     padding-top: 20vw;
+    // }
+    // .imgs {
+    //     height: 50vw;
+    // }
+}
+</style>

+ 74 - 8
src/views/Store.vue

@@ -6,6 +6,14 @@
                     <div class="btn" :class="{ active: active === 'explore' }" @click="changeActive('explore')">
                         我拥有的
                     </div>
+                    <div
+                        class="btn"
+                        v-if="showRoom"
+                        :class="{ active: active === 'showRoom' }"
+                        @click="changeActive('showRoom')"
+                    >
+                        我的展馆
+                    </div>
                     <div
                         class="btn"
                         v-if="!$store.state.reviewPay"
@@ -62,10 +70,12 @@
             class="box-list"
             :style="{
                 backgroundImage:
-                    active !== 'coupon' && showList.length > 0 ? `url(${require('../assets/png-zhantai.png')})` : '',
+                    active !== 'coupon' && active !== 'showRoom' && showList.length > 0
+                        ? `url(${require('../assets/png-zhantai.png')})`
+                        : '',
                 paddingBottom: showList.length % 3 === 0 ? '35.73vw' : '20px'
             }"
-            :class="{ couponList: active === 'coupon' }"
+            :class="{ couponList: active === 'coupon', roomList: active === 'showRoom' }"
             v-model:loading="loading"
             :finished="finished"
             finished-text=""
@@ -73,6 +83,7 @@
         >
             <template v-for="(item, index) in showList" :key="index">
                 <coupon-info :info="item" v-if="active == 'coupon'"></coupon-info>
+                <show-info v-model:info="list[index]" v-if="active == 'showRoom'"></show-info>
                 <asset-info :info="item" v-else></asset-info>
             </template>
 
@@ -100,6 +111,7 @@
 
 <script>
 import AssetInfo from '../components/asset/assetInfo.vue';
+import ShowInfo from '../components/asset/showInfo.vue';
 import CouponInfo from '../components/CouponInfo.vue';
 import asset from '../mixins/asset';
 import coupon from '../mixins/coupon';
@@ -109,7 +121,8 @@ export default {
     inject: ['bar', 'setKeeps', 'scrollWrapper', 'changeScroll', 'bodyScroll'],
     components: {
         AssetInfo,
-        CouponInfo
+        CouponInfo,
+        ShowInfo
     },
     data() {
         return {
@@ -128,7 +141,8 @@ export default {
             name1: '',
             name: '',
             scrollTop: 0,
-            sortDes: ''
+            sortDes: '',
+            showRoom: false
         };
     },
     computed: {
@@ -166,6 +180,24 @@ export default {
                         }
                     ];
                 }
+            } else if (this.active === 'showRoom') {
+                return [
+                    {
+                        label: '全部',
+                        value: '',
+                        type: ''
+                    },
+                    {
+                        label: '展览中',
+                        value: true,
+                        type: ''
+                    },
+                    {
+                        label: '未展览',
+                        value: false,
+                        type: ''
+                    }
+                ];
             } else if (this.active === 'creator') {
                 return [
                     {
@@ -246,13 +278,30 @@ export default {
             this.list = list;
             this.$toast.clear();
         });
+        if (this.isLogin) {
+            this.$http
+                .post(
+                    '/asset/all',
+                    {
+                        query: {
+                            type: 'SHOWROOM'
+                        }
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    if (!res.empty) {
+                        this.showRoom = true;
+                    }
+                });
+        }
     },
     beforeRouteLeave(to, from, next) {
         this.$el.parentNode.childNodes[1].className = this.$el.parentNode.childNodes[1].className.replace(
             / bgBack/,
             ''
         );
-        if (to.path === '/assetDetail') {
+        if (to.path === '/assetDetail' || to.path === '/hall') {
             this.scrollTop = this.scrollWrapper.value.scrollTop;
             this.setKeeps(['index', 'store']);
         } else {
@@ -298,7 +347,15 @@ export default {
                 }
             };
             this.$http
-                .post(this.active === 'coupon' ? '/userCoupon/all' : '/asset/all', form, { body: 'json' })
+                .post(
+                    this.active === 'coupon'
+                        ? '/userCoupon/all'
+                        : this.active === 'showRoom'
+                        ? '/showroom/all'
+                        : '/asset/all',
+                    form,
+                    { body: 'json' }
+                )
                 .then(res => {
                     this.list = [...this.list, ...res.content];
                     this.empty = res.empty;
@@ -313,7 +370,8 @@ export default {
             let form = {};
             if (this.active == 'explore') {
                 form = {
-                    status: this.status
+                    status: this.status,
+                    type: 'BLIND_BOX,DEFAULT'
                 };
                 if (this.type === 'NORMAL') {
                     form = {
@@ -328,6 +386,10 @@ export default {
                         consignment: true
                     };
                 }
+            } else if (this.active == 'showRoom') {
+                form = {
+                    publish: this.type
+                };
             } else if (this.active === 'creator') {
                 form = {
                     status: this.status
@@ -341,6 +403,7 @@ export default {
             return form;
         },
         changeActive(active) {
+            this.list = [];
             this.active = active;
             this.loading = true;
             setTimeout(() => {
@@ -390,7 +453,7 @@ export default {
         }
 
         .btn + .btn {
-            margin-left: 30px;
+            margin-left: 20px;
         }
     }
 
@@ -461,6 +524,9 @@ export default {
     &.couponList {
         padding: 8px 8px 100px;
     }
+    &.roomList {
+        padding: 10px 0 100px;
+    }
 }
 
 .tab {

+ 810 - 0
src/views/hall/Detail.vue

@@ -0,0 +1,810 @@
+<template>
+    <div class="mySwiper">
+        <div class="swiper-content" :class="{ windowHorizontal: !windowVertical, horizontal: !isVertical }">
+            <div class="top">
+                <div class="top-btn left" @click="back">
+                    <img src="../../assets/icon-tuichu.png" alt="" />
+                    <span>退出展馆</span>
+                </div>
+                <div class="top-right">
+                    <div class="top-btn submit" v-if="!isVertical || !windowVertical">
+                        <img src="../../assets/icon-tupian.png" alt="" />
+                        <span>{{ assets.length }}</span>
+                    </div>
+                    <div
+                        class="top-btn submit"
+                        @click="like(info)"
+                        v-if="(!isVertical || !windowVertical) && info.publish"
+                    >
+                        <img v-if="info.liked" src="../../assets/icon-dianzan3.png" alt="" />
+                        <img v-else src="../../assets/icon-dianzan4.png" alt="" />
+                        <span>{{ info.likes }}</span>
+                    </div>
+                    <div @click="share" class="top-btn submit" v-if="(!isVertical || !windowVertical) && info.publish">
+                        <img src="../../assets/icon-fenxiang1.png" alt="" />
+                        <span>分享</span>
+                    </div>
+                    <div class="top-btn submit" @click="submit" v-if="isMine">
+                        <img src="../../assets/icon-fabu.png" alt="" />
+                        <span>发布</span>
+                    </div>
+                </div>
+            </div>
+            <div class="bottom">
+                <div class="btn" @click="addCollections" v-if="isMine">
+                    <img src="../../assets/icon-bianjicangpin.png" alt="" />
+                    <span>编辑藏品</span>
+                </div>
+                <div class="btn" v-if="inApp" @click="isVertical = !isVertical">
+                    <img src="../../assets/icon-qiehuanhengping.png" alt="" />
+                    <span>切换{{ isVertical || windowVertical ? '横屏' : '竖屏' }}</span>
+                </div>
+            </div>
+            <div class="btns" v-if="isVertical && windowVertical && info.publish">
+                <div class="btn">
+                    <img src="../../assets/icon-tupian.png" alt="" />
+                    <span>{{ assets.length }}</span>
+                </div>
+                <div class="btn" @click="like(info)">
+                    <img v-if="info.liked" src="../../assets/icon-dianzan3.png" alt="" />
+                    <img v-else src="../../assets/icon-dianzan4.png" alt="" />
+                    <span>{{ info.likes }}</span>
+                </div>
+                <div class="btn" @click="share">
+                    <img src="../../assets/icon-fenxiang1.png" alt="" />
+                    <span>分享</span>
+                </div>
+            </div>
+            <post ref="post" :info="info"></post>
+
+            <div class="user-bg">
+                <div
+                    class="user-bg-img"
+                    :style="{
+                        'background-image': getBg()
+                    }"
+                ></div>
+                <div class="user">
+                    <div class="icon">
+                        <van-image
+                            :src="info.pic || require('../../assets/icon-tianjiacangping.png')"
+                            :width="picWidth"
+                            :height="picWidth"
+                            fit="cover"
+                            radius="8"
+                        />
+                        <van-uploader v-if="isMine" class="avatar" :after-read="afterRead" result-type="file" />
+                    </div>
+                    <div class="user-content">
+                        <div class="name">
+                            <div>{{ info.nickname }}</div>
+                            <div>的展馆</div>
+                        </div>
+                    </div>
+                    <div class="sub-box">
+                        <div class="sub" @click="goEdit">
+                            <span>{{ info.introduction || '介绍一下展馆主题吧' }}</span>
+                            <img src="../../assets/icon-jieshaozhanguan.png" v-if="isMine" alt="" />
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="img-bg">
+                <div class="bg" :style="{ 'background-image': `url(${info.showroomBg})` }"></div>
+                <div class="imgs" v-if="assets.length === 0 && isMine">
+                    <div class="icon">
+                        <van-image
+                            :src="require('../../assets/icon-tianjiacangping1.png')"
+                            @click="addCollections"
+                            :width="picWidth"
+                            :height="picWidth"
+                            fit="coevr"
+                            radius="8"
+                        />
+                    </div>
+                </div>
+                <div class="imgs" v-for="(item, index) in showList" :key="index" :style="getStyle(item.length)">
+                    <div class="icon" v-for="(img, imgIndex) in item" :key="imgIndex" @click="goCollection(img)">
+                        <van-image :src="img.pic" :width="picWidth" :height="picWidth" fit="coevr" radius="8" />
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+// import required modules
+import { watch, ref, computed } from 'vue';
+import { useWindowSize } from '@vant/use';
+import product from '../../mixins/product';
+import room from '../../mixins/room';
+import Post from './Post.vue';
+let fromRoute = null;
+let inApp = /#cordova#/i.test(navigator.userAgent);
+export default {
+    name: 'Hall',
+    inject: ['setKeeps'],
+    components: {
+        Post
+    },
+    setup() {
+        const { width, height } = useWindowSize();
+
+        console.log(width.value); // -> 窗口宽度
+        console.log(height.value); // -> 窗口高度
+
+        const windowVertical = computed(() => {
+            if (width.value > height.value) {
+                return false;
+            } else {
+                return true;
+            }
+        });
+
+        return { windowVertical, width, height };
+    },
+    mixins: [product, room],
+    data() {
+        return {
+            isVertical: true,
+            roomId: 0,
+            info: {},
+            assets: [],
+            distances: [0, 0, 0, 0],
+            swiperRef: null,
+            inApp,
+            isEdit: false
+        };
+    },
+    computed: {
+        showList() {
+            let assets = [...this.assets];
+            let list = [];
+            for (let i = 0; i <= Math.floor(assets.length / this.groupNum); i++) {
+                list.push(assets.slice(i * this.groupNum, (i + 1) * this.groupNum));
+            }
+            return list.filter(item => {
+                return item.length > 0;
+            });
+        },
+        groupNum() {
+            if (!this.isVertical) {
+                return 4;
+            } else if (!this.windowVertical) {
+                return 4;
+            } else {
+                return 18;
+            }
+        },
+        isMine() {
+            return this.isLogin && this.$store.state.userInfo.id === this.info.userId;
+        },
+        bgParallax() {
+            return (
+                '-' +
+                ((this.isVertical ? this.width : this.height) * ((this.showList.length || 1) - 1) +
+                    (this.isVertical && this.windowVertical ? 280 : 418))
+            );
+        },
+        picWidth() {
+            if (!this.isVertical) {
+                return '35vw';
+            } else if (!this.windowVertical) {
+                return '35vh';
+            } else {
+                return '15vh';
+            }
+        }
+    },
+    mounted() {
+        if (this.$route.query.id) {
+            this.roomId = this.$route.query.id;
+            this.getDetail();
+        }
+        this.emitter.on('setIntroduction', e => {
+            this.info.introduction = e;
+            this.isEdit = true;
+        });
+        this.emitter.on('setAssets', assets => {
+            this.assets = assets;
+            this.isEdit = true;
+        });
+    },
+    beforeRouteEnter(to, from) {
+        fromRoute = from;
+    },
+    methods: {
+        getStyle(num = 1) {
+            if (!this.isVertical) {
+                return {
+                    height: num * 49 + 'vw',
+                    paddingBottom: num == 4 ? '26.5vw' : '10vw'
+                };
+            } else if (!this.windowVertical) {
+                return {
+                    width: num * 49 + 'vh',
+                    paddingRight: num == 4 ? '26.5vh' : '10vh'
+                };
+            } else {
+                return {
+                    width: Math.round(num / 2) * 22 + 'vh',
+                    paddingRight: Math.round(num / 2) == 9 ? '23vh' : '10vh'
+                };
+            }
+        },
+        getBg() {
+            if (!this.isVertical || !this.windowVertical) {
+                return `url(${this.info.headBg})`;
+            } else {
+                return '';
+            }
+        },
+        getImgWidth(num = 1) {
+            if (!this.isVertical) {
+                return num * 49 + 'vw';
+            } else if (!this.windowVertical) {
+                return num * 49 + 'vh';
+            } else {
+                return Math.round(num / 2) * 22 + 'vh';
+            }
+        },
+        getRight(num = 1) {
+            if (!this.isVertical) {
+                return '36vw';
+            } else if (!this.windowVertical) {
+                return num == 4 ? '26.5vh' : '10vh';
+            } else {
+                return Math.round(num / 2) == 9 ? '23vh' : '10vh';
+            }
+        },
+        share() {
+            this.getDetail().then(res => {
+                this.$refs.post.init();
+            });
+        },
+        getDetail() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            return this.$http.get('/showroom/get/' + this.roomId).then(res => {
+                this.$toast.clear();
+                this.info = res;
+                this.assets =
+                    res.collections.map(item => {
+                        return {
+                            ...item,
+                            id: item.collectionId
+                        };
+                    }) || [];
+                // this.assets = [...res.collections, ...res.collections, ...res.collections, ...res.collections];
+                return Promise.resolve(res);
+            });
+        },
+        back() {
+            let _this = this;
+            this.$dialog.confirm({ title: '提示', message: '确定要退出展馆吗?' }).then(() => {
+                this.isEdit = false;
+                if (_this.isMine) {
+                    _this.backPage();
+                } else {
+                    _this.$router.push('/home');
+                }
+            });
+        },
+        backPage() {
+            if (this.$store.state.loginBackUrl) {
+                this.$router.replace(this.$store.state.loginBackUrl);
+            } else if (
+                !fromRoute.name ||
+                fromRoute.name === 'hall' ||
+                fromRoute.name === 'userRegister' ||
+                fromRoute.name === 'userLogin'
+            ) {
+                this.$router.replace('/home');
+            } else {
+                this.$router.back();
+            }
+        },
+        afterRead(e) {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.updateFile(e, 500).then(img => {
+                this.$toast.clear();
+                this.info.pic = img;
+            });
+        },
+        addCollections() {
+            this.$router.push(
+                '/productAdd?ids=' +
+                    this.assets
+                        .map(item => {
+                            return item.id;
+                        })
+                        .join(',') +
+                    '&maxCollection=' +
+                    this.info.maxCollection
+            );
+        },
+        setSwiperRef(ref) {
+            console.log(ref);
+            this.swiperRef = ref;
+        },
+        submit() {
+            let form = {
+                ...this.info,
+                collections: [...this.assets].map(item => {
+                    return {
+                        showroomId: this.roomId,
+                        collectionId: item.id
+                    };
+                }),
+                publish: true
+            };
+
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.$http
+                .post('/showroom/update', form, { body: 'json' })
+                .then(res => {
+                    this.$toast.success('保存成功');
+                    setTimeout(() => {
+                        this.getDetail().then(res => {
+                            this.emitter.emit('updateList', res);
+                        });
+                        this.backPage();
+                    }, 1000);
+                })
+                .catch(e => {
+                    this.$toast(e.error);
+                });
+        },
+        goEdit() {
+            if (this.isMine) {
+                this.$router.push('/hallEdit?message=' + (this.info.introduction || ''));
+            }
+        },
+        goCollection(info) {
+            if (!this.isMine) {
+                this.$router.push('/productDetail/' + info.collectionId);
+            }
+        }
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.path === '/store' && this.isEdit) {
+            next(false);
+            setTimeout(() => {
+                this.back();
+            }, 100);
+        } else {
+            if (!to.meta.isHall) {
+                this.setKeeps(['Hall'], false);
+            } else {
+                this.setKeeps(['Hall']);
+            }
+            next();
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.mySwiper {
+    background-color: #1c1c1c;
+    overflow: auto;
+    width: 100vw;
+    height: 100vh;
+}
+.swiper-content {
+    position: relative;
+    .flex();
+    align-items: stretch;
+    & > div {
+        flex-shrink: 0;
+    }
+    height: 100vh;
+}
+.user-bg {
+    background-size: 100% 100%;
+    z-index: 1;
+    position: relative;
+    .user-bg-img {
+        position: absolute;
+        z-index: 0;
+        width: 100%;
+        height: 100%;
+        background-size: auto 100%;
+    }
+}
+.user {
+    width: 130px;
+    padding: 23vh 0 0 30px;
+    position: absolute;
+    left: 0;
+    background-image: none;
+    .icon {
+        position: relative;
+        .van-image {
+            transition: transform ease-in-out 0.3s;
+        }
+        .avatar {
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            opacity: 0;
+        }
+    }
+
+    .name {
+        font-size: 24px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 30px;
+        padding-top: 6px;
+        & > div {
+            display: -webkit-box;
+            -webkit-box-orient: vertical;
+            -webkit-line-clamp: 2;
+            overflow: hidden;
+        }
+    }
+    .sub {
+        padding-top: 20px;
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.6);
+        line-height: 17px;
+
+        .flex();
+        img {
+            width: 16px;
+            height: 16px;
+            display: block;
+            margin-left: 6px;
+        }
+    }
+    .user-content {
+        flex-grow: 1;
+        overflow: hidden;
+    }
+}
+
+.mySwiper {
+    width: 100%;
+    height: 100%;
+    background: #000;
+}
+.img-bg {
+    .flex();
+    align-items: flex-start;
+    position: relative;
+    overflow: hidden;
+
+    .bg {
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        z-index: 0;
+        background-size: auto 100%;
+    }
+}
+.imgs {
+    // box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    // align-items: center;
+    flex-wrap: wrap;
+    // padding: 0 10vw;
+    // width: 259vh;
+    height: 45vh;
+    padding: 0 10vh 0 23vh;
+    margin-top: 20vh;
+    min-width: calc(100vw - 33vh);
+    .icon {
+        padding: 3vh 0;
+
+        .flex();
+        justify-content: center;
+        width: 22vh;
+        box-sizing: border-box;
+        img {
+            width: 110px;
+            height: 110px;
+            display: block;
+        }
+        .van-image {
+            transition: transform ease-in-out 0.3s;
+        }
+    }
+}
+
+.bottom {
+    position: fixed;
+    bottom: 120px;
+    left: 30px;
+    z-index: 20;
+    .bottom(0px);
+    .flex();
+    .btn {
+        transition: transform ease-in-out 0.3s;
+    }
+
+    .btn + .btn {
+        margin-left: 40px;
+    }
+    img {
+        width: 48px;
+        height: 48px;
+        display: block;
+    }
+    span {
+        font-size: 12px;
+        color: #ffffff;
+        line-height: 17px;
+        margin-top: 4px;
+    }
+}
+
+.btns {
+    .bottom(0px);
+    background-color: #181818;
+    height: 56px;
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 21;
+    .flex();
+
+    .btn {
+        .flex();
+        width: 33%;
+        justify-content: center;
+        img {
+            width: 18px;
+            height: 18px;
+            display: block;
+        }
+        span {
+            font-size: 14px;
+            color: #ffffff;
+            line-height: 24px;
+            margin-left: 3px;
+        }
+    }
+}
+
+.top {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 20;
+    right: 0;
+    height: 44px;
+
+    .flex();
+    justify-content: space-between;
+    .top-btn {
+        .flex();
+        padding: 2px 10px;
+        border-radius: 100px;
+        min-width: 76px;
+        box-sizing: border-box;
+        justify-content: center;
+        img {
+            width: 18px;
+            height: 18px;
+        }
+
+        span {
+            font-size: 14px;
+            color: #ffffff;
+            line-height: 24px;
+            margin-left: 4px;
+        }
+
+        &.submit {
+            background-color: fade(#fff, 30%);
+            margin-right: 16px;
+        }
+    }
+
+    .top-right {
+        .flex();
+    }
+}
+.windowHorizontal {
+    .user {
+        width: 95vh;
+        display: flex;
+        flex-direction: row;
+        position: relative;
+        padding: 22vh 0 0 60px;
+        box-sizing: border-box;
+        .sub-box {
+            position: absolute;
+            bottom: 0px;
+            left: calc(35vh + 70px);
+            .sub {
+                padding-top: 0;
+            }
+        }
+        .name {
+            margin-left: 10px;
+            padding-top: 0;
+            font-size: 6.4vh;
+            line-height: 8vh;
+            & > div {
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+        }
+    }
+    .imgs {
+        height: 44.6vh;
+        flex-direction: row;
+        padding: 0 23vh;
+        min-width: calc(100vw - 128vh);
+        .icon {
+            // padding: 15vh 0;
+            padding: 0 0;
+            width: 49vh;
+            padding-bottom: 4vh;
+        }
+    }
+
+    .bottom {
+        bottom: 60px;
+        left: 60px;
+    }
+
+    .parallax-bg-img {
+        width: 100%;
+        height: 100%;
+        transition: transform ease-in-out 0.3s;
+        background-size: 410px 100%, 100vw 100%;
+        background-repeat: no-repeat, repeat-x;
+        background-position: 0 0, 410px 0;
+    }
+}
+
+.horizontal {
+    padding-top: 0;
+    // padding-right: 32px;
+    flex-direction: column;
+    .user-content {
+        overflow: inherit;
+    }
+    .parallax-bg {
+        width: 100%;
+        height: 600%;
+    }
+    .parallax-bg-img {
+        width: 600vh;
+        height: 100vw;
+        transform: rotate(90deg) translateX(-100vw);
+        transform-origin: left bottom;
+    }
+    .user-bg-img {
+        height: 100vw;
+        width: calc(95vw + 1px);
+        transform: rotate(90deg) translateX(-100vw);
+        transform-origin: left bottom;
+    }
+
+    .bg {
+        width: 600vh;
+        height: 100vw;
+        transform: rotate(90deg) translateX(-100vw);
+        transform-origin: left bottom;
+    }
+
+    // .user-bg {
+    //     transform: rotate(90deg) translate(-50%, 55%);
+    //     transform-origin: bottom;
+    // }
+
+    .user {
+        padding: 60px calc(100vw - 35vw - 23vw) 0;
+        height: 95vw;
+        width: 32vw;
+        position: relative;
+        box-sizing: border-box;
+        .van-image {
+            transform: rotate(90deg);
+        }
+        .name {
+            font-size: 6.4vw;
+            line-height: 8vw;
+            width: 168px;
+            padding-top: 0;
+            transform: rotate(90deg) translate(-13vw, -13vw);
+            transform-origin: left bottom;
+        }
+        .sub {
+            width: 168px;
+            padding-top: 0;
+            transform-origin: left bottom;
+            transform: rotate(90deg) translate(-17.3vw, 0px);
+        }
+    }
+    .img-bg {
+        flex-direction: column;
+        align-items: flex-end;
+        padding-right: 18vw;
+    }
+    .imgs {
+        width: 44.6vw;
+        padding: 23vw 0;
+        margin-top: 0;
+        .icon {
+            height: 49vw;
+            width: auto;
+        }
+        .van-image {
+            transform: rotate(90deg);
+        }
+    }
+
+    .bottom {
+        top: 60px;
+        left: 49px;
+        .flex-col();
+        .btn {
+            transform: rotate(90deg) translateX(-10px);
+        }
+        .btn + .btn {
+            margin-left: 0;
+            margin-top: 40px;
+        }
+    }
+
+    .top {
+        // transform: rotate(90deg) translate(calc(100vh - 100vw), 3px);
+        // width: 100vh;
+        // transform-origin: bottom;
+        top: 0;
+        bottom: 0;
+        left: auto;
+        height: 100vh;
+        width: 40px;
+        flex-direction: column;
+        right: 5px;
+        .top-btn {
+            height: auto;
+            white-space: nowrap;
+
+            &.left {
+                transform: rotate(90deg) translateX(50%);
+            }
+        }
+
+        .top-right {
+            transform: rotate(90deg) translateX(-50%);
+        }
+    }
+    // .user {
+    //     padding: calc(21vw - 110px) 100px 0 30px;
+    // }
+    // /deep/.swiper-wrapper {
+    //     height: calc(100vw - 20vw);
+    // }
+    // &.mySwiper {
+    //     padding-top: 20vw;
+    // }
+    // .imgs {
+    //     height: 50vw;
+    // }
+}
+</style>

+ 73 - 0
src/views/hall/Edit.vue

@@ -0,0 +1,73 @@
+<template>
+    <div class="edit">
+        <div class="edit-title">展馆主题</div>
+        <van-field
+            label=" "
+            label-width="0"
+            v-model="message"
+            rows="4"
+            autosize
+            type="textarea"
+            maxlength="20"
+            placeholder="介绍一下展馆主题吧"
+            show-word-limit
+            :border="false"
+        />
+
+        <div class="btn">
+            <van-button type="primary" round block @click="save">保存</van-button>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            message: ''
+        };
+    },
+    mounted() {
+        if (this.$route.query.message) {
+            this.message = this.$route.query.message;
+        }
+    },
+    methods: {
+        save() {
+            this.emitter.emit('setIntroduction', this.message);
+            this.$router.back();
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.edit {
+    background-color: #1c1c1c;
+}
+
+.edit-title {
+    font-size: 16px;
+    font-weight: bold;
+    color: #ffffff;
+    line-height: 24px;
+    padding: 13px 16px;
+    background-color: #222426;
+    border-bottom: 1px solid #303133;
+}
+
+.van-field {
+    background-color: #222426;
+    color: #ffffff;
+    /deep/.van-field__label {
+        margin-right: 0;
+    }
+    /deep/.van-field__control {
+        color: #fff;
+    }
+}
+
+.btn {
+    margin: 80px 50px;
+}
+</style>

+ 427 - 0
src/views/hall/Post.vue

@@ -0,0 +1,427 @@
+<template>
+    <div ref="share">
+        <van-overlay :show="show" @click="show = false" z-index="99">
+            <div class="wrapper">
+                <div class="img" ref="wrap" v-if="img" @click.stop="preview(0, [img])">
+                    <img :src="img" />
+                </div>
+                <template v-if="!img">
+                    <div class="content" ref="post">
+                        <!-- @load="loadImg" -->
+                        <!-- <img crossOrigin="anonymous" :src="banners" class="detailImg" /> -->
+                        <van-image :src="detailImg || info.headBg" class="detailImg" />
+                        <div class="collecions">
+                            <div class="users">
+                                <van-image :src="userImg || info.pic" width="120" height="120" radius="8" fit="cover" />
+                                <div class="users-text">
+                                    <div class="name">
+                                        <div>{{ info.nickname }}</div>
+                                        <div>的展馆</div>
+                                    </div>
+                                    <div class="sub">
+                                        <span>{{ info.introduction }}</span>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="info">
+                            <div class="left">
+                                <div class="name van-multi-ellipsis--l2">
+                                    {{ info.introduction }}
+                                </div>
+                                <div class="minter-content">
+                                    <van-image width="18" height="18" round :src="userImg || info.pic" fit="cover" />
+                                    <div class="text1">{{ info.nickname }}</div>
+                                </div>
+                            </div>
+                            <div class="right">
+                                <div class="code-box">
+                                    <vue-qrcode
+                                        :value="url"
+                                        :options="{ width: 60, margin: 0 }"
+                                        class="code"
+                                    ></vue-qrcode>
+                                </div>
+                                <div class="text1">扫码查看展厅</div>
+                            </div>
+                        </div>
+                    </div>
+                </template>
+
+                <div class="btn" @click.stop="" v-if="cordova">
+                    <van-button type="primary" round @click="save">点击保存到本地</van-button>
+                </div>
+                <div class="tips" v-else>长按图片保存</div>
+            </div>
+        </van-overlay>
+    </div>
+</template>
+<script>
+import vueQrcode from '@chenfengyuan/vue-qrcode';
+import html2canvas from 'html2canvas';
+import resolveUrl from 'resolve-url';
+import axios from 'axios';
+import { isBefore, format } from 'date-fns';
+import { abs } from 'mathjs';
+import { ImagePreview } from 'vant';
+export default {
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {
+                    pic: []
+                };
+            }
+        },
+        pageUrl: {
+            type: String,
+            default: 'productDetail'
+        },
+        noButton: {
+            type: Boolean,
+            default: false
+        }
+    },
+    data() {
+        return {
+            show: false,
+            share: null,
+            img: '',
+            detailImg: '',
+            userImg: '',
+            cordova: window.cordova,
+            shareBg: ''
+        };
+    },
+    computed: {
+        url() {
+            return resolveUrl(this.$baseUrl, '9th/hall?id=' + this.info.id);
+        },
+        isBuy() {
+            return this.info.stock && this.info.onShelf && this.info.salable;
+        },
+        time() {
+            if (this.info.startTime) {
+                if (isBefore(new Date(this.info.startTime), new Date())) {
+                    return format(new Date(this.info.startTime), 'mm月dd日');
+                }
+            }
+
+            return '';
+        },
+        collections() {
+            return this.info.collections || [];
+        }
+    },
+    components: {
+        vueQrcode
+    },
+    methods: {
+        init() {
+            this.show = true;
+            if (!this.img) {
+                this.$toast.loading({
+                    message: '加载中...',
+                    forbidClick: true
+                });
+                this.$nextTick(() => {
+                    this.getImgBase64(this.info.headBg, 'detailImg');
+                    this.getImgBase64(this.info.pic + '?x-oss-process=image/resize,m_fill,h_200,w200', 'userImg');
+                    setTimeout(() => {
+                        this.loadImg();
+                    }, 1500);
+                });
+            }
+        },
+        loadImg() {
+            html2canvas(this.$refs.post, {
+                useCORS: true,
+                allowTaint: true,
+                backgroundColor: null,
+                scale: 3
+            }).then(canvas => {
+                this.$toast.clear();
+                this.img = canvas.toDataURL('image/png');
+            });
+        },
+        getImgBase64(img2, key) {
+            let img = new Image();
+            img.crossOrigin = 'anonymous';
+            let _this = this;
+            img.onload = function () {
+                let src = _this.image2Base64(img);
+                _this[key] = src;
+            };
+            img.src = img2;
+        },
+        image2Base64(img) {
+            let canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            let ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0, img.width, img.height);
+            let dataURL = canvas.toDataURL('image/png');
+            return dataURL;
+        },
+        preview(index = 0, list = []) {
+            console.log('266716');
+            ImagePreview({
+                images: [...list],
+                startPosition: index
+            });
+        },
+        save() {
+            if (window.cordova) {
+                let _this = this;
+                imageSaver.saveBase64Image(
+                    { data: this.img },
+                    function (filePath) {
+                        _this.$toast('图片已保存至文件夹');
+                        _this.show = false;
+                        console.log('File saved on ' + filePath);
+                    },
+                    function (msg) {
+                        _this.$dialog.alert({
+                            title: '提示',
+                            message: msg + ',请尝试截图保存分享'
+                        });
+                        (1).then(() => {
+                            _this.preview(0, [_this.img]);
+                        });
+                    }
+                );
+            }
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.wrapper {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    height: 100%;
+}
+
+.content {
+    width: 260px;
+    background: @bg;
+    border-radius: 20px;
+    overflow: hidden;
+    position: relative;
+}
+
+.img {
+    img {
+        width: 260px;
+        display: block;
+    }
+}
+
+.info {
+    padding: 10px;
+
+    .flex();
+    align-items: stretch;
+    .left {
+        flex-grow: 1;
+        .name {
+            font-size: 14px;
+            color: #000000;
+            line-height: 20px;
+            min-height: 40px;
+        }
+        .minter-content {
+            margin-top: 8px;
+            .flex();
+            font-size: 12px;
+            color: #939599;
+            .text1 {
+                margin-left: 5px;
+            }
+        }
+    }
+
+    .right {
+        margin-left: 12px;
+        .code-box {
+            padding: 5px;
+            background-color: #f5f7fa;
+            border-radius: 6px;
+            width: 70px;
+            box-sizing: border-box;
+            .code {
+                display: block;
+            }
+        }
+        .text1 {
+            font-size: 12px;
+            color: #939599;
+            line-height: 12px;
+            transform: scale(0.8);
+        }
+    }
+}
+
+.code {
+    border-radius: 6px;
+}
+
+.tips {
+    font-size: 13px;
+    color: @text3;
+    line-height: 22px;
+    margin-top: 30px;
+}
+
+.share {
+    position: fixed;
+    right: 16px;
+    bottom: 20vh;
+    width: 48px;
+    height: 48px;
+    background: linear-gradient(135deg, @prim 0%, @warn 100%);
+    z-index: 20;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    border-radius: 100px;
+    justify-content: center;
+    span {
+        font-size: 12px;
+        color: #333230;
+        line-height: 17px;
+    }
+    img {
+        display: block;
+    }
+}
+
+.detailImg {
+    width: 260px;
+    height: 260px;
+    display: block;
+}
+.tabs {
+    .flex();
+    margin-top: 6px;
+    span {
+        font-size: 12px;
+        color: #939599;
+        line-height: 22px;
+        padding: 0 10px;
+        background: @bg3;
+        border-radius: 4px;
+        margin-right: 6px;
+    }
+}
+
+.status {
+    font-size: 14px;
+    color: #939599;
+    line-height: 24px;
+    padding-top: 11px;
+}
+
+.sold {
+    background-color: #1c1e25;
+    font-size: @font1;
+    color: #939599;
+    padding: 0 17px;
+    border-radius: 13px;
+    line-height: 24px;
+    position: absolute;
+    top: 16px;
+    left: 16px;
+    z-index: 3;
+
+    &.xianliang {
+        position: absolute;
+        top: 16px;
+        left: 16px;
+        font-size: @font1;
+        color: @prim;
+        display: flex;
+        align-items: center;
+        // border-radius: 13px !important;
+        z-index: 4;
+        padding: 0 10px !important;
+
+        img {
+            width: 18px;
+            height: 18px;
+            margin-right: 3px;
+        }
+    }
+}
+
+.btn {
+    padding: 30px;
+}
+
+.assignmentPost {
+    width: 300px;
+    height: 500px;
+    background: #ffffff;
+    border-radius: 30px;
+    position: relative;
+    .qrcode {
+        background-color: @bg3;
+        padding: 6px;
+        position: absolute;
+        left: 50%;
+        transform: translateX(-50%);
+        bottom: 94px;
+        border-radius: 6px;
+        z-index: 20;
+        /deep/canvas {
+            display: block;
+        }
+    }
+}
+
+.collecions {
+    position: absolute;
+    top: 50px;
+    left: 0;
+    right: 0;
+    z-index: 3;
+    width: 200%;
+    .flex();
+    overflow: hidden;
+    transform: scale(0.8);
+    transform-origin: 0 0 0;
+    .van-image {
+        flex-shrink: 0;
+    }
+
+    .users {
+        padding-left: 60px;
+        .flex();
+        .users-text {
+            .flex-col();
+            align-self: stretch;
+            width: 180px;
+            padding-left: 10px;
+        }
+        .name {
+            font-size: 24px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 30px;
+            flex-grow: 1;
+        }
+        .sub {
+            font-size: 12px;
+            color: rgba(255, 255, 255, 0.6);
+            line-height: 17px;
+        }
+    }
+
+    & > .van-image {
+        margin-right: 60px;
+    }
+}
+</style>

+ 251 - 0
src/views/hall/ProductAdd.vue

@@ -0,0 +1,251 @@
+<template>
+    <div class="page">
+        <div class="page-top">
+            <div class="title">
+                <div class="text1">编辑藏品</div>
+                <div class="text2">在展馆的藏品需为展示/正在寄售的状态</div>
+            </div>
+
+            <div class="sub">
+                <div class="text1">符合条件</div>
+                <div class="text2">{{ totalElements }}个</div>
+            </div>
+        </div>
+
+        <van-list v-model:loading="loading" :finished="finished" finished-text="" @load="getData">
+            <van-empty
+                v-if="empty"
+                description=" 你还没有藏品哦~"
+                :image="require(`../../assets/kong_png_yongyoude hei.png`)"
+            />
+            <div class="list">
+                <div
+                    class="box"
+                    v-for="(item, index) in list"
+                    :class="{ active: chooseIds.includes(item.id) }"
+                    :key="index"
+                    @click="choose(item.id)"
+                >
+                    <div class="box-img">
+                        <van-image
+                            :src="getImg(changeImgs(item.pic))"
+                            :width="80"
+                            :height="80"
+                            fit="coevr"
+                            radius="8"
+                        />
+                        <img
+                            v-if="chooseIds.includes(item.id)"
+                            class="choose-img"
+                            src="../../assets/choose2.png"
+                            alt=""
+                        />
+                        <img v-else class="choose-img" src="../../assets/choose1.png" alt="" />
+                        <div class="num" v-if="chooseIds.includes(item.id)">{{ chooseIds.indexOf(item.id) + 1 }}</div>
+                    </div>
+                </div>
+            </div>
+        </van-list>
+
+        <div class="btns">
+            <van-button color="#939599" @click="$router.back()" plain round>取消</van-button>
+            <van-button round type="primary" @click="sure">确认</van-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import list from '../../mixins/list';
+import product from '../../mixins/product';
+export default {
+    data() {
+        return {
+            info: {},
+            url: '/collection/all',
+            list: [],
+            chooseIds: [],
+            maxCollection: 20
+        };
+    },
+    mixins: [list, product],
+    computed: {
+        chooseList() {
+            let list = [...this.list];
+            let chooseIds = [...this.chooseIds];
+            return chooseIds
+                .map(item => {
+                    return (
+                        list.find(child => {
+                            return child.id === item;
+                        }) || item
+                    );
+                })
+                .filter(item => {
+                    return !!item.pic;
+                })
+                .map(item => {
+                    return {
+                        ...item,
+                        pic: this.getImg(this.changeImgs(item.pic))
+                    };
+                });
+        }
+    },
+    mounted() {
+        if (this.$route.query.ids) {
+            this.chooseIds = this.$route.query.ids.split(',');
+        }
+        if (this.$route.query.maxCollection) {
+            this.maxCollection = Number(this.$route.query.maxCollection);
+        }
+    },
+    methods: {
+        beforeData() {
+            return {
+                query: {
+                    ownerId: this.$store.state.userInfo.id
+                },
+                size: 99
+            };
+        },
+        sure() {
+            if (this.chooseIds.length > 0) {
+                this.emitter.emit('setAssets', this.chooseList);
+                this.$router.back();
+            } else {
+                this.$toast('请选择藏品');
+            }
+        },
+        choose(id) {
+            let chooseIds = [...this.chooseIds];
+            if (chooseIds.includes(id)) {
+                chooseIds.splice(chooseIds.indexOf(id), 1);
+            } else if (chooseIds.length >= this.maxCollection) {
+                this.$toast('最多选择' + this.maxCollection + '张藏品');
+            } else {
+                chooseIds.push(id);
+            }
+            this.chooseIds = chooseIds;
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.page {
+    background-color: #1c1c1c;
+}
+
+.page-top {
+    background-color: #222426;
+    padding: 10px 16px 12px;
+    .flex();
+    align-items: flex-end;
+    .title {
+        flex-grow: 1;
+        .text1 {
+            font-size: 16px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 24px;
+        }
+        .text2 {
+            font-size: 12px;
+            color: #939599;
+            line-height: 22px;
+        }
+    }
+
+    .sub {
+        .flex();
+        .text1 {
+            font-size: 12px;
+            color: #939599;
+            line-height: 22px;
+        }
+
+        .text2 {
+            font-size: 12px;
+            color: #ffffff;
+            line-height: 17px;
+            background: #f5f7fa22;
+            border-radius: 10px;
+            padding: 0 18px;
+            margin-left: 3px;
+        }
+    }
+}
+
+.list {
+    .flex();
+    flex-wrap: wrap;
+    padding-bottom: 80px;
+    .box {
+        padding: 10px 16px;
+        width: 33%;
+        box-sizing: border-box;
+        position: relative;
+
+        .choose-img {
+            width: 24px;
+            height: 24px;
+            position: absolute;
+            right: 0px;
+            top: 0px;
+            z-index: 2;
+        }
+
+        .box-img {
+            position: relative;
+            width: 80px;
+            height: 80px;
+            margin: auto;
+        }
+
+        &.active {
+            .box-img {
+                &::after {
+                    content: '';
+                    position: absolute;
+                    left: 0;
+                    top: 0;
+                    right: 0;
+                    bottom: 0;
+                    z-index: 1;
+                    background-color: rgba(0, 0, 0, 0.3);
+                }
+            }
+        }
+
+        .num {
+            font-size: 12px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 17px;
+            position: absolute;
+            left: 5px;
+            top: 0px;
+            z-index: 2;
+        }
+    }
+}
+
+.btns {
+    position: fixed;
+    bottom: 0;
+    right: 0;
+    left: 0;
+    .flex();
+    padding: 9px 16px;
+    background-color: #222426;
+    z-index: 20;
+    .bottom(9px);
+    .van-button {
+        flex-grow: 1;
+        box-sizing: border-box;
+    }
+    .van-button + .van-button {
+        margin-left: 20px;
+    }
+}
+</style>