panhui %!s(int64=3) %!d(string=hai) anos
pai
achega
f21dcac7d8
Modificáronse 75 ficheiros con 27359 adicións e 560 borrados
  1. BIN=BIN
      ._.DS_Store
  2. 1 1
      .env.development
  3. 18100 1
      package-lock.json
  4. 1 0
      package.json
  5. BIN=BIN
      public/._.DS_Store
  6. BIN=BIN
      src/._.DS_Store
  7. 5 1
      src/App.vue
  8. BIN=BIN
      src/assets/._.DS_Store
  9. BIN=BIN
      src/assets/._bg-01.png
  10. BIN=BIN
      src/assets/._icon_gouxuan_pre.png
  11. BIN=BIN
      src/assets/auction1.png
  12. BIN=BIN
      src/assets/auction2.png
  13. BIN=BIN
      src/assets/auction3.png
  14. BIN=BIN
      src/assets/icon-miaoshu(1).png
  15. BIN=BIN
      src/assets/icon-miaoshu1.png
  16. BIN=BIN
      src/assets/icon-paimaijilu-bai.png
  17. BIN=BIN
      src/assets/icon-paimaijilu.png
  18. BIN=BIN
      src/assets/icon-paipingxinxi-bai.png
  19. BIN=BIN
      src/assets/icon-sosuo1.png
  20. BIN=BIN
      src/assets/icon_close_tips.png
  21. BIN=BIN
      src/assets/icon_jiage_bai.png
  22. BIN=BIN
      src/assets/icon_jiage_hei.png
  23. BIN=BIN
      src/assets/icon_xiangqingye_bangzhu.png
  24. BIN=BIN
      src/assets/info_icon_paimaidingdan.png
  25. BIN=BIN
      src/assets/info_icon_time.png
  26. BIN=BIN
      src/assets/info_icon_time1.png
  27. BIN=BIN
      src/assets/nav_logo_2.png
  28. BIN=BIN
      src/assets/paimai.png
  29. BIN=BIN
      src/assets/png-paimaizhong.png
  30. BIN=BIN
      src/assets/shuzi.png
  31. BIN=BIN
      src/assets/suishi.png
  32. BIN=BIN
      src/assets/svgs/._.DS_Store
  33. BIN=BIN
      src/assets/yikou.png
  34. BIN=BIN
      src/assets/zhengji.png
  35. 8 1
      src/components/AppBar.vue
  36. 6 0
      src/components/asset/assetInfo.vue
  37. 449 0
      src/components/auction/Post.vue
  38. 1187 0
      src/components/auction/asset.vue
  39. 344 0
      src/components/auction/banner.vue
  40. 713 0
      src/components/auction/deposit.vue
  41. 258 0
      src/components/auction/help.vue
  42. 204 0
      src/components/auction/info.vue
  43. 156 0
      src/components/auction/records.vue
  44. 134 0
      src/components/auction/rule.vue
  45. 3 3
      src/components/level/Level.vue
  46. 465 0
      src/components/order/OrderInfoAuction.vue
  47. 3 0
      src/main.js
  48. 8 0
      src/mixins/asset.js
  49. 74 0
      src/mixins/auction.js
  50. 37 0
      src/mixins/auctionOrder.js
  51. 7 1
      src/mixins/common.js
  52. 17 0
      src/mixins/imgInfo.js
  53. 3 2
      src/mixins/list.js
  54. 2 0
      src/mixins/product.js
  55. 1 1
      src/plugins/colors.js
  56. 79 0
      src/router/index.js
  57. 8 0
      src/styles/app.less
  58. 4 0
      src/styles/common/common.less
  59. 30 25
      src/styles/font.less
  60. BIN=BIN
      src/views/._.DS_Store
  61. 74 10
      src/views/Mine.vue
  62. 22 9
      src/views/Store.vue
  63. BIN=BIN
      src/views/asset/._.DS_Store
  64. 612 0
      src/views/asset/AuctionPublish.vue
  65. 257 160
      src/views/asset/Detail.vue
  66. 849 0
      src/views/auction/Detail.vue
  67. 276 0
      src/views/auction/Home.vue
  68. 412 0
      src/views/auction/List.vue
  69. 299 0
      src/views/auction/Offer.vue
  70. 426 0
      src/views/auction/Search.vue
  71. 677 0
      src/views/auction/Submit.vue
  72. 441 0
      src/views/order/AuctionDetail.vue
  73. 324 0
      src/views/order/AuctionOrders.vue
  74. 56 18
      src/views/pay/BankPay.vue
  75. 327 327
      yarn.lock

BIN=BIN
._.DS_Store


+ 1 - 1
.env.development

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

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 18100 - 1
package-lock.json


+ 1 - 0
package.json

@@ -32,6 +32,7 @@
         "query-string": "^7.0.1",
         "queue": "^6.0.2",
         "register-service-worker": "^1.7.1",
+        "smoothscroll-polyfill": "^0.4.4",
         "swiper": "^6.8.1",
         "three": "^0.136.0",
         "v-charts": "^1.19.0",

BIN=BIN
public/._.DS_Store


BIN=BIN
src/._.DS_Store


+ 5 - 1
src/App.vue

@@ -25,7 +25,8 @@ export default {
             scrollWrapper: computed(() => this.$el),
             changeScroll: this.changeScroll,
             keeps: computed(() => this.keeps),
-            bodyScroll: computed(() => this.bodyScroll)
+            bodyScroll: computed(() => this.bodyScroll),
+            changeTab: this.changeTab
         };
     },
     computed: {
@@ -76,6 +77,9 @@ export default {
         scrollEvent() {
             // console.log(this.$el.scrollTop);
             this.bodyScroll = this.$el.scrollTop;
+        },
+        changeTab(color) {
+            this.$refs.bar.getColor(color);
         }
     }
 };

BIN=BIN
src/assets/._.DS_Store


BIN=BIN
src/assets/._bg-01.png


BIN=BIN
src/assets/._icon_gouxuan_pre.png


BIN=BIN
src/assets/auction1.png


BIN=BIN
src/assets/auction2.png


BIN=BIN
src/assets/auction3.png


BIN=BIN
src/assets/icon-miaoshu(1).png


BIN=BIN
src/assets/icon-miaoshu1.png


BIN=BIN
src/assets/icon-paimaijilu-bai.png


BIN=BIN
src/assets/icon-paimaijilu.png


BIN=BIN
src/assets/icon-paipingxinxi-bai.png


BIN=BIN
src/assets/icon-sosuo1.png


BIN=BIN
src/assets/icon_close_tips.png


BIN=BIN
src/assets/icon_jiage_bai.png


BIN=BIN
src/assets/icon_jiage_hei.png


BIN=BIN
src/assets/icon_xiangqingye_bangzhu.png


BIN=BIN
src/assets/info_icon_paimaidingdan.png


BIN=BIN
src/assets/info_icon_time.png


BIN=BIN
src/assets/info_icon_time1.png


BIN=BIN
src/assets/nav_logo_2.png


BIN=BIN
src/assets/paimai.png


BIN=BIN
src/assets/png-paimaizhong.png


BIN=BIN
src/assets/shuzi.png


BIN=BIN
src/assets/suishi.png


BIN=BIN
src/assets/svgs/._.DS_Store


BIN=BIN
src/assets/yikou.png


BIN=BIN
src/assets/zhengji.png


+ 8 - 1
src/components/AppBar.vue

@@ -113,13 +113,19 @@ export default {
                 this.title = '';
             }
         },
-        getColor() {
+        getColor(color = '') {
             if (this.$route.meta.tabColor) {
                 if (window.cordova && StatusBar && StatusBar.isVisible) {
                     StatusBar.backgroundColorByHexString(this.$route.meta.tabColor);
                     StatusBar.styleLightContent();
                 }
                 this.tabColor = this.$route.meta.tabColor;
+            } else if (color) {
+                if (window.cordova && StatusBar && StatusBar.isVisible) {
+                    StatusBar.backgroundColorByHexString(color);
+                    StatusBar.styleLightContent();
+                }
+                this.tabColor = color;
             } else {
                 if (window.cordova && StatusBar && StatusBar.isVisible) {
                     StatusBar.backgroundColorByHexString('#ffffff');
@@ -129,6 +135,7 @@ export default {
             }
         },
         onSelect(val) {
+            console.log(val);
             if (val.value === 'back') {
                 this.$router.go(-1);
             } else if (val.value === 'reload') {

+ 6 - 0
src/components/asset/assetInfo.vue

@@ -29,6 +29,12 @@
                 src="../../assets/png-jinzhanshi.png"
                 alt=""
             />
+            <img
+                v-else-if="info.status === 'AUCTIONING'"
+                class="status-img"
+                src="../../assets/png-paimaizhong.png"
+                alt=""
+            />
             <!-- <img v-if="info.consignment" class="status-img" src="../../assets/png-jishouzhong.png" alt="" />
             <div class="status" v-else-if="info.status === 'NORMAL'">
                 {{ info.publicShow ? '仅展示' : '未展示' }}

+ 449 - 0
src/components/auction/Post.vue

@@ -0,0 +1,449 @@
+<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="assignmentPost" v-if="assignment && pageUrl === 'productDetail'" ref="post">
+                        <van-image class="assignmentPostBg" width="300" height="500" :src="shareBg" />
+                        <div class="qrcode">
+                            <vue-qrcode :value="url" :options="{ width: 82, margin: 0 }"></vue-qrcode>
+                        </div>
+                    </div>
+                    <div class="content" v-else ref="post">
+                        <!-- @load="loadImg" -->
+                        <!-- <img crossOrigin="anonymous" :src="banners" class="detailImg" /> -->
+                        <van-image :src="detailImg" class="detailImg" fit="cover" />
+                        <div class="info">
+                            <div class="name van-multi-ellipsis--l2">
+                                {{ info.name }}
+                            </div>
+                            <div class="tabs">
+                                <span>拍卖</span>
+                                <span v-if="info.category">{{ info.category }}</span>
+                                <span v-if="info.number">编号{{ info.number }}</span>
+                            </div>
+                            <template v-if="pageUrl !== 'assetDetail'">
+                                <div class="text" v-if="isBuy">
+                                    <div class="price">
+                                        <img src="@assets/jiage_huang.png" alt="" />
+                                        <span>{{ info.price }}</span>
+                                    </div>
+                                    <div class="text1" v-if="info.stock && !time">
+                                        <span>已售 {{ Math.max(Math.min(info.sale, info.total), 0) }}</span>
+                                        <span>剩余 {{ Math.min(Math.max(info.stock, 0), info.total) }}</span>
+                                    </div>
+                                </div>
+                            </template>
+                            <template v-else>
+                                <div class="text" v-if="info.consignment">
+                                    <div class="price">
+                                        <img src="@assets/jiage_huang.png" alt="" />
+                                        <span>{{ info.sellPrice || 0 }}</span>
+                                    </div>
+                                </div>
+
+                                <div class="status" v-else-if="info.status == 'NORMAL'">
+                                    {{ info.publicShow ? '仅展示' : '未展示' }}
+                                </div>
+                            </template>
+                        </div>
+                        <div class="minter">
+                            <div class="minter-content">
+                                <van-image width="26" height="26" round :src="userImg" fit="cover" />
+                                <div class="text1">{{ info.minter }}</div>
+                                <div class="text2">铸造者</div>
+                            </div>
+
+                            <vue-qrcode :value="url" :options="{ width: 70, margin: 3 }" class="code"></vue-qrcode>
+                        </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 class="share" v-if="!noButton" @click="init">
+            <img src="@assets/svgs/icon-share.svg" alt="" />
+            <span>分享</span>
+        </div>
+    </div>
+</template>
+<script>
+import vueQrcode from '@chenfengyuan/vue-qrcode';
+import html2canvas from 'html2canvas';
+import auction from '../../mixins/auction';
+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 {
+    mixins: [auction],
+    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() {
+            let pageUrl = this.pageUrl;
+            let id = this.info.id;
+            if (pageUrl === 'assetDetail') {
+                id = this.info.publicCollectionId;
+                pageUrl = 'productDetail';
+            }
+
+            if (pageUrl === 'productDetail' && !this.assignment) {
+                pageUrl = 'productDetail/' + id;
+            }
+            if (this.isLogin && this.assignment && pageUrl === 'productDetail') {
+                return resolveUrl(
+                    this.$baseUrl,
+                    '9th/productTasks?id=' + id + '&invitor=' + this.$store.state.userInfo.id
+                );
+            } else if (this.isLogin) {
+                return resolveUrl(
+                    this.$baseUrl,
+                    '9th/' + pageUrl + '?id=' + id + '&invitor=' + this.$store.state.userInfo.id
+                );
+            } else {
+                return resolveUrl(this.$baseUrl, '9th/' + pageUrl + '?id=' + id);
+            }
+        },
+        banners() {
+            return this.getImg(this.changeImgs(this.info.pic || []), '', 900);
+        },
+        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 '';
+        }
+    },
+    components: {
+        vueQrcode
+    },
+    methods: {
+        init() {
+            this.show = true;
+            if (!this.img) {
+                this.$toast.loading({
+                    message: '加载中...',
+                    forbidClick: true
+                });
+                this.$nextTick(() => {
+                    if (this.assignment && this.pageUrl === 'productDetail') {
+                        this.getImgBase64(this.info.shareBg, 'shareBg');
+                    } else {
+                        this.getImgBase64(this.banners, 'detailImg');
+                        this.getImgBase64(this.info.minterAvatar, 'userImg');
+                    }
+                    setTimeout(() => {
+                        this.loadImg();
+                    }, 1000);
+                });
+            }
+        },
+        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: 80vw;
+    background: @bg;
+    border-radius: 30px;
+    overflow: hidden;
+    position: relative;
+}
+
+.img {
+    img {
+        width: 80vw;
+        display: block;
+    }
+}
+
+.info {
+    padding: 12px 10px 7px;
+    .name {
+        font-size: 18px;
+        font-weight: bold;
+        color: @text0;
+        line-height: 24px;
+    }
+    .text {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-end;
+        margin-top: 6px;
+
+        .price {
+            img {
+                width: 10px;
+                height: 11px;
+            }
+            span {
+                font-size: 24px;
+                font-family: OSP-DIN, OSP;
+                color: @prim;
+                line-height: 36px;
+            }
+        }
+        .text1 {
+            font-size: 14px;
+            color: @text3;
+            line-height: 24px;
+            span + span {
+                margin-left: 10px;
+            }
+        }
+    }
+}
+
+.code {
+    border-radius: 6px;
+}
+
+.minter {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px 16px 12px 10px;
+    border-top: 2px solid @bg3;
+
+    .minter-content {
+        /deep/.van-image {
+            img {
+                display: block;
+            }
+        }
+        .text1 {
+            font-size: @font1;
+            color: @text0;
+            line-height: 17px;
+            margin-top: 1px;
+        }
+        .text2 {
+            font-size: @font1;
+            color: @text3;
+            line-height: 17px;
+        }
+    }
+}
+
+.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: 80vw;
+    height: 80vw;
+    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;
+        }
+    }
+}
+</style>

+ 1187 - 0
src/components/auction/asset.vue

@@ -0,0 +1,1187 @@
+<template>
+    <div class="goods">
+        <van-collapse v-model="activeNames">
+            <van-collapse-item name="1" class="goods-info">
+                <template #title>
+                    <div class="page-title">
+                        <img src="@assets/fenxiang-icon.png" alt="" />
+                        用户信息
+                    </div>
+                </template>
+                <div class="user">
+                    <van-cell
+                        class="creator"
+                        :to="{
+                            path: '/creatorDetail',
+                            query: {
+                                id: info.minterId
+                            }
+                        }"
+                    >
+                        <template #icon>
+                            <van-image
+                                width="32"
+                                height="32"
+                                :src="info.minterAvatar || require('@assets/svgs/img_default_photo.svg')"
+                                fit="cover"
+                                radius="100"
+                            />
+                        </template>
+                        <template #title>
+                            <div class="text1">{{ info.minter }}</div>
+                            <div class="text2">铸造者</div>
+                        </template>
+                    </van-cell>
+                    <van-cell
+                        v-if="info.ownerId !== info.minterId"
+                        class="creator"
+                        :to="{
+                            path: '/creatorDetail',
+                            query: {
+                                id: info.ownerId,
+                                type: 'DEFAULT'
+                            }
+                        }"
+                    >
+                        <template #icon>
+                            <van-image
+                                width="32"
+                                height="32"
+                                class="user-img"
+                                :src="info.ownerAvatar || require('@assets/svgs/img_default_photo.svg')"
+                                fit="cover"
+                                radius="100"
+                            />
+                        </template>
+                        <template #title>
+                            <div class="text1 van-ellipsis">{{ info.owner }}</div>
+                            <div class="text2">持有者</div>
+                        </template>
+                    </van-cell>
+                </div>
+            </van-collapse-item>
+
+            <van-collapse-item name="2" class="goods-info">
+                <template #title>
+                    <div class="page-title"><img src="@assets/icon-miaoshu.png" alt="" />作品描述</div>
+                </template>
+                <swiper v-if="boxs.length > 0" :slidesPerView="'auto'" :spaceBetween="20" class="detail-swiper">
+                    <swiper-slide v-for="(item, index) in boxs" :key="index">
+                        <van-image
+                            width="100%"
+                            height="130"
+                            :src="getImg(item, '', 1000)"
+                            fit="cover"
+                            radius="12"
+                            @click="preview(index, boxs)"
+                        />
+                    </swiper-slide>
+                </swiper>
+                <div v-if="info.detail" class="page-text page-detail" v-html="info.detail"></div>
+            </van-collapse-item>
+            <van-collapse-item name="3" class="goods-info top1">
+                <template #title>
+                    <div class="page-title"><img src="@assets/icon-lianshangxinxi.png" alt="" /> 类型</div>
+                </template>
+                <div class="top1">
+                    <div v-if="info.category" class="category">
+                        <span>{{ info.category }}</span>
+                    </div>
+                    <div v-else class="tips">铸造者未设置</div>
+                </div>
+            </van-collapse-item>
+            <van-collapse-item name="4" class="goods-info">
+                <template #title>
+                    <div class="page-title">
+                        <img src="@assets/qiaoqiaohua-icon-weidakai.png" alt="" /> 悄悄话<span>(灰色表示已使用)</span>
+                    </div>
+                </template>
+                <div class="qiaohua" v-if="init2">
+                    <img class="img" :src="init2.icon[0]" alt="" />
+                    <div class="text4" :class="{ prim: init2.opened }">
+                        {{ init2.opened ? '已打开' : '未打开' }}
+                    </div>
+                </div>
+                <div class="tips" v-else>铸造者未设置</div>
+            </van-collapse-item>
+            <van-collapse-item name="5" class="goods-info">
+                <template #title>
+                    <div class="titleIcon page-title">
+                        <img src="@assets/icon-lianshangxinxi(1).png" alt="" />
+                        持有特权
+                        <span>(灰色表示已使用)</span>
+                    </div>
+                </template>
+                <div class="prive" v-if="init.length > 0">
+                    <div v-for="(item, index) in init" :key="index">
+                        <div class="prive1">
+                            <img class="img" :src="item.icon[0]" alt="" />
+                            <div class="prive2">{{ item.name }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div v-if="init.length === 0" class="tips">铸造者未设置</div>
+            </van-collapse-item>
+            <van-collapse-item name="6" class="goods-info">
+                <template #title>
+                    <div class="page-title"><img src="@assets/icon-lianshangxinxi(2).png" alt="" />作品特性</div>
+                </template>
+                <div class="specific-list" v-if="properties.length > 0">
+                    <div class="specific-item" v-for="(item, index) in properties" :key="index">
+                        <div class="text1">{{ item.name }}</div>
+                        <div class="text2">{{ item.value }}</div>
+                    </div>
+                </div>
+                <div v-else class="textName">铸造者未设置</div>
+            </van-collapse-item>
+            <hash-code :info="info"></hash-code>
+            <van-collapse-item name="8" class="goods-info">
+                <template #title>
+                    <div class="page-title"><img src="@assets/info_icon_jiaoyijilu1.png" alt="" />交易记录</div>
+                </template>
+                <div v-if="list.length > 0">
+                    <div class="content" v-for="item in list" :key="item.id">
+                        <!-- <img class="img" :src="list.avatar" alt="" /> -->
+                        <div class="user-detail">
+                            <div class="text1 van-ellipsis">{{ item.fromUser || '保密' }}</div>
+                            <div class="text2" v-if="item.price">{{ item.operation }}¥{{ item.price }}</div>
+                            <div class="text2" v-else>{{ item.operation }}</div>
+                            <div class="text3 van-ellipsis">{{ item.toUser || '保密' }}</div>
+                            <div class="text4">{{ item.createdAt.substr(0, 16) }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div v-else class="textName">暂无购买记录</div>
+            </van-collapse-item>
+        </van-collapse>
+    </div>
+</template>
+
+<script>
+import { ImagePreview } from 'vant';
+import product from '../../mixins/product';
+import coupon from '../../mixins/coupon';
+import HashCode from '../../components/product/HashCode.vue';
+import { Swiper, SwiperSlide } from 'swiper/vue';
+import { mapState } from 'vuex';
+
+import 'swiper/swiper.min.css';
+import 'swiper/swiper-bundle.min.css';
+
+import SwiperCore, { Pagination } from 'swiper';
+
+SwiperCore.use([Pagination]);
+
+let inWeixin = /micromessenger/i.test(navigator.userAgent);
+
+export default {
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    components: {
+        HashCode,
+        Swiper,
+        SwiperSlide
+    },
+    mixins: [product, coupon],
+    data() {
+        return {
+            activeName: '1',
+            liked: false,
+            btn: null,
+            blindBoxItems: [],
+            init: [],
+            init2: null,
+            list: [],
+            activeNames: ['1', '2', '3', '4', '5', '6', 'hashCode', '8'],
+            inWeixin,
+            limit: {},
+            couponList: [],
+            assignments: [],
+            noPay: false,
+            collectionId: 0,
+            createrId: 0
+        };
+    },
+    computed: {
+        ...mapState(['userInfo']),
+        banners() {
+            return this.info.pic || [];
+        },
+        properties() {
+            return this.info.properties || [];
+        },
+        isBuy() {
+            return this.info.stock > 0 && this.info.onShelf && this.info.salable;
+        },
+        boxs() {
+            let list = [...this.blindBoxItems];
+            return list.map(item => {
+                return this.changeImgs(item.pic);
+            });
+        }
+    },
+    methods: {
+        getInit() {
+            return this.getProduct();
+        },
+        preview(index = 0, list = []) {
+            ImagePreview({
+                images: [...list].map(item => {
+                    return item;
+                }),
+                startPosition: index
+            });
+        },
+        appointment() {
+            if (this.info.appointment) {
+                return;
+            }
+            this.$http
+                .post('/collection/appointment?id=' + this.info.id)
+                .then(res => {
+                    this.getProduct();
+                    this.$toast.success('预约成功');
+                })
+                .catch(e => {
+                    if (e.error) {
+                        this.$toast.warning(e.error);
+                    }
+                });
+        },
+        getProduct() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            return this.$http
+                .get('/collection/get/' + this.collectionId)
+                .then(res => {
+                    if (this.$store.state.from === 'scanCode') {
+                        res.onShelf = true;
+                        this.checkLogin();
+                    }
+                    console.log(res);
+                    // this.info = res;
+                    //优惠券
+                    if (res.couponPayment) {
+                        this.getCouponList();
+                    }
+                    if (this.inWeixin) {
+                        wx.updateAppMessageShareData({
+                            title: '第九空间-' + res.name,
+                            desc: '全球首个基于区块链的游戏资产集换中心',
+                            link: location.origin + '/9th/productDetail/' + res.id,
+                            imgUrl: this.getImg(this.changeImgs(this.banners), '', 300)
+                        });
+                        wx.updateTimelineShareData({
+                            title: '第九空间-' + res.name,
+                            link: location.origin + '/9th/productDetail/' + 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);
+                            // this.info = {
+                            //     ...res,
+                            //     ...this.info
+                            // };
+                            this.$http
+                                .get('/asset/tokenHistory', {
+                                    tokenId: res.tokenId,
+                                    assetId: res.collectionId
+                                })
+                                .then(res => {
+                                    console.log(res);
+                                    this.list = res;
+                                });
+                        });
+                    }
+                    if (res.privileges) {
+                        this.init2 = res.privileges.find(item => {
+                            return item.name === '悄悄话';
+                        });
+                    }
+                    if (res.privileges) {
+                        this.init = res.privileges.filter(item => {
+                            return item.name !== '悄悄话';
+                        });
+                    }
+                    this.getTime(res.startTime);
+                    if (res.saleTime) {
+                        this.getTime(res.saleTime, 'saleTime');
+                    }
+                    this.$nextTick(() => {
+                        if (this.isBuy) {
+                            this.btn = this.$refs.btn;
+                        }
+                    });
+                    this.$toast.clear();
+
+                    if (res.type === 'BLIND_BOX') {
+                        return this.$http.post(
+                            '/blindBoxItem/all',
+                            {
+                                query: {
+                                    blindBoxId: res.id
+                                }
+                            },
+                            { body: 'json' }
+                        );
+                    } else {
+                        return Promise.resolve();
+                    }
+                })
+                .then(res => {
+                    if (res) {
+                        this.blindBoxItems = res.content;
+                    }
+                })
+                .catch(e => {
+                    this.$toast.clear();
+                    if (e && e.error) {
+                        this.$dialog
+                            .alert({
+                                title: '提示',
+                                message: e.error
+                            })
+                            .then(res => {
+                                this.$router.back();
+                            });
+                    }
+                });
+        },
+        showReason() {
+            this.$dialog.alert({
+                title: '提示',
+                message: '若存在未支付无效订单,请等待订单自动5分钟内取消,退回白名单资格。'
+            });
+        },
+        getCouponList() {
+            if (!this.isLogin) {
+                return;
+            }
+            this.$http
+                .post(
+                    '/userCoupon/all',
+                    {
+                        query: { userId: this.$store.state.userInfo.id, used: false }
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.couponList = [...res.content].filter(item => {
+                        return this.checkTime(item) && this.checkUse(item, this.info.id);
+                    });
+                });
+        },
+        buy() {
+            this.checkLogin().then(() => {
+                if (this.info.couponPayment && this.couponList.length === 0) {
+                    this.$dialog
+                        .alert({
+                            title: '提示',
+                            message: '该藏品为特殊藏品,需要使用优惠券才能兑换'
+                        })
+                        .then(() => {});
+                } else if (!this.usedBuy && this.info.source === 'TRANSFER') {
+                    this.$toast('该通道暂且关闭');
+                }
+                // else if (this.authStatus !== '已认证') {
+                //     this.$dialog
+                //         .alert({
+                //             title: '提示',
+                //             message: '实名认证后才可进行藏品购买'
+                //         })
+                //         .then(() => {
+                //             this.goAuth();
+                //         });
+                // }
+                else if (this.info.minimumCharge && !this.$store.state.userInfo.canSale) {
+                    this.$dialog
+                        .alert({
+                            title: '提示',
+                            message: '未实名或规定时间内绿洲石不满' + this.info.minimumCharge
+                        })
+                        .then(() => {});
+                } else {
+                    this.$router.push({
+                        path: '/submit',
+                        query: {
+                            id: this.collectionId,
+                            invitor: this.$route.query.invitor
+                        }
+                    });
+                }
+            });
+        },
+        goAuth() {
+            if (this.authStatus === '认证中' || this.authStatus === '认证失败') {
+                this.$router.push('/waiting');
+            } else if (this.authStatus === '未认证') {
+                this.$router.push('/Authentication');
+            }
+        },
+        share() {
+            if (this.assignment && !this.isLogin) {
+                this.checkLogin();
+            } else {
+                this.$refs.post.init();
+            }
+        },
+        vipAssignment() {
+            if (this.info.vipSurplus <= 0) {
+                this.$dialog
+                    .alert({
+                        title: '通道已关闭',
+                        message: '您的vip购买次数已经用完啦,请完成邀请任务继续购买吧~'
+                    })
+                    .then(res => {
+                        if (this.info.totalQuota) {
+                            this.share();
+                        }
+                    });
+            } else {
+                this.buy();
+            }
+        },
+        onRefresh() {
+            this.getInit().then(() => {
+                this.isLoading = false;
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.scroll-wrapper {
+    background-color: @bgProductDetail;
+}
+
+/deep/.van-nav-bar {
+    background-color: @bgProductDetail;
+}
+.detail {
+    padding-bottom: 150px;
+    background-color: @bgProductDetail;
+}
+.prive {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    margin-bottom: -12px;
+    .prive1 {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 16px 12px 0;
+        width: 94px;
+        height: 32px;
+        color: #000;
+        background: linear-gradient(48deg, @prim 0%, @warn 100%);
+        border-radius: 4px;
+        &.prim {
+            background: #202122;
+            color: @text3;
+        }
+        .img {
+            text-align: center;
+            width: 18px;
+            height: 18px;
+            margin-right: 4px;
+        }
+        .prive2 {
+            font-size: @font1;
+            text-align: center;
+            margin-left: 2px;
+            color: @btnText;
+        }
+    }
+}
+.info {
+    // height: 164px;
+    background-color: @bgProductDetail;
+    border-radius: 20px 20px 0 0;
+    transform: translateY(-16px);
+    position: relative;
+    z-index: 2;
+    padding: 16px 16px 0;
+    box-sizing: border-box;
+    .name {
+        text-align: center;
+        .name1 {
+            font-size: 14px;
+            font-weight: 400;
+            color: #ffffff;
+            line-height: 24px;
+        }
+        .name2 {
+            font-size: @font2;
+            font-weight: 400;
+            color: @prim;
+            line-height: 24px;
+            background: linear-gradient(135deg, @prim 0%, @warn 100%);
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+        }
+    }
+    .price {
+        font-size: 36px;
+        font-family: OSP;
+        color: @prim;
+        line-height: 36px;
+        transform: translateY(3px);
+
+        .font_family {
+            font-size: 10px;
+            line-height: 24px;
+            vertical-align: middle;
+        }
+    }
+
+    .price-line {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        margin-top: 16px;
+        flex-wrap: wrap;
+        .sub {
+            flex-grow: 1;
+            margin-left: 5px;
+            font-size: @font2;
+            color: #949699;
+            line-height: 16px;
+            span {
+                color: #fff;
+            }
+        }
+
+        .price-sub {
+            font-size: @font2;
+            color: @text3;
+            text-decoration: line-through;
+            margin-left: 10px;
+        }
+
+        .text {
+            font-size: @font1;
+            color: @text3;
+            line-height: 20px;
+            height: 20px;
+            background-color: #27272b;
+            border-radius: 4px;
+            padding: 0 10px;
+            margin-bottom: 6px;
+
+            span + span {
+                margin-left: 10px;
+            }
+
+            &.total {
+                padding: 0 0;
+                border-radius: 4px;
+                overflow: hidden;
+                span {
+                    display: inline-block;
+                    padding: 0 12px;
+                    &:first-child {
+                        background-color: @prim;
+                        color: #fff;
+                    }
+                    &:last-child {
+                        color: @prim;
+                        background-color: #27272b;
+                    }
+                }
+
+                span + span {
+                    margin-left: 0px;
+                }
+            }
+        }
+        .text + .text {
+            margin-left: 10px;
+        }
+    }
+
+    .title {
+        font-size: 20px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 28px;
+        margin-top: 12px;
+    }
+
+    .info-bottom {
+        display: flex;
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        margin-top: 4px;
+        height: 24px;
+        .text1 {
+            font-size: @font1;
+            color: #949699;
+            line-height: 24px;
+        }
+        .van-button {
+            font-size: @font2;
+            color: @prim;
+            line-height: 24px;
+            background: linear-gradient(135deg, @prim 0%, @warn 100%);
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+            border-width: 0px;
+            margin-left: 10px;
+            white-space: nowrap;
+        }
+        .like {
+            position: absolute;
+            right: 0;
+        }
+    }
+}
+/deep/ .van-collapse-item__content {
+    background: #181818 !important;
+    padding: 0 !important;
+}
+.activeName {
+    /deep/ .van-cell__title {
+        font-size: @font2;
+        font-family: PingFangSC-Medium, PingFang SC;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 24px;
+    }
+    /deep/ .van-cell {
+        padding: 0 16px;
+    }
+}
+/deep/.creator {
+    .flex();
+    align-items: center;
+    padding: 24px 16px 24px;
+    .van-cell__title {
+        margin-left: 6px !important;
+        .text1 {
+            color: #fff;
+            font-size: @font1;
+            line-height: 20px;
+        }
+        .text2 {
+            font-size: @font1;
+            color: @text3;
+            line-height: 22px;
+        }
+    }
+
+    .van-cell__value {
+        font-size: @font2;
+    }
+}
+.conName {
+    font-size: @font2;
+    font-weight: 400;
+    color: #939599;
+    line-height: 24px;
+    // padding: 10px 0 0 16px;
+}
+.titleIcon {
+    font-size: @font2;
+    font-weight: bold;
+    color: #ffffff;
+    line-height: 24px;
+    // padding: 30px 0 0 16px;
+    span {
+        font-size: @font2;
+        font-weight: 400;
+        color: #939599;
+        line-height: 24px;
+    }
+}
+
+.info {
+    min-height: 100px;
+}
+
+.top {
+    padding: 20px 16px 0;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    .top1 {
+        display: flex;
+        align-items: center;
+        .text1 {
+            font-size: @font2;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 28px;
+        }
+        .text2 {
+            width: 94px;
+            height: 32px;
+            border: 1px solid yellow;
+            border-radius: 4px;
+            margin-left: 14px;
+            line-height: 32px;
+            text-align: center;
+            color: #ffffff;
+            &.text3 {
+                display: flex;
+                align-items: center;
+                justify-content: center;
+            }
+            .img {
+                width: 18px;
+                height: 18px;
+                margin-right: 4px;
+            }
+            &.prim {
+                color: @text3;
+                border: 1px solid #303133;
+                background: #202122;
+            }
+        }
+        .text4 {
+            color: @prim;
+            &.prim {
+                color: @text3;
+            }
+        }
+    }
+}
+.tips {
+    font-size: @font2;
+    color: @text3;
+    line-height: 24px;
+    // padding-top: 12px;
+}
+.buy {
+    width: 100%;
+    display: block;
+    height: 52px;
+    background: linear-gradient(135deg, @prim 0%, @warn 100%);
+    border-radius: 8px;
+    border-width: 0;
+    color: #000;
+    &:hover {
+        background: linear-gradient(135deg, darken(@prim, 10%), darken(@warn, 10%));
+    }
+
+    &.used {
+        background: linear-gradient(135deg, darken(@prim, 50%), darken(@warn, 50%));
+        color: @text3;
+    }
+}
+
+.goods {
+    // padding: 0 16px 0px;
+    background-color: #1c1c1c;
+
+    .page-title {
+        font-size: @font2;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 24px;
+        display: flex;
+        align-items: center;
+        &:not(:first-child) {
+            padding-top: 16px;
+        }
+        img {
+            width: 18px;
+            height: 18px;
+            margin-right: 6px;
+        }
+        span {
+            color: @text3;
+            font-size: @font1;
+            font-weight: normal;
+        }
+    }
+}
+.qiaohua {
+    border-radius: 4px;
+    background: linear-gradient(45deg, @prim, @warn);
+    position: relative;
+    width: 94px;
+    display: flex;
+    height: 30px;
+    align-items: center;
+    justify-content: center;
+    // margin-top: 12px;
+    .img {
+        width: 18px;
+        height: 18px;
+        position: relative;
+        z-index: 1;
+    }
+    .text4 {
+        color: @prim;
+        &.prim {
+            color: @text3;
+        }
+        margin-left: 4px;
+        position: relative;
+        z-index: 1;
+        font-size: @font1;
+    }
+    &::after {
+        content: '';
+        border-radius: 4px;
+        background-color: @bgProductDetail;
+        position: absolute;
+        top: 1px;
+        left: 1px;
+        right: 1px;
+        bottom: 1px;
+        z-index: 0;
+    }
+}
+.specific-list {
+    // padding: 10px 0 0;
+    display: flex;
+    align-items: center;
+    overflow-x: auto;
+}
+.textName {
+    font-size: @font2;
+    font-weight: 400;
+    color: #939599;
+    line-height: 24px;
+    // padding-top: 10px;
+}
+.specific-item {
+    // width: 94px;
+    // height: 62px;
+    border-radius: 4px;
+    padding: 4px 8px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    position: relative;
+    background: linear-gradient(135deg, @prim, @warn);
+    margin-right: 20px;
+    box-sizing: border-box;
+    min-width: 94px;
+
+    &::after {
+        content: '';
+        position: absolute;
+        top: 1px;
+        left: 1px;
+        right: 1px;
+        bottom: 1px;
+        background-color: @bgProductDetail;
+        border-radius: 4px;
+        z-index: 0;
+    }
+
+    .text1 {
+        font-size: @font1;
+        color: @text3;
+        line-height: 18px;
+        z-index: 1;
+        white-space: nowrap;
+    }
+
+    .text2 {
+        font-size: @font1;
+        color: #ffffff;
+        line-height: 18px;
+        z-index: 1;
+        white-space: nowrap;
+    }
+}
+
+.page-text {
+    font-size: @font2;
+    color: #ffffff;
+    line-height: 28px;
+    word-break: break-all;
+    // margin-top: 10px;
+}
+.btn-list {
+    display: flex;
+    align-items: flex-end;
+    padding: 9px 16px;
+}
+.btn {
+    position: fixed;
+    z-index: 20;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background-color: @bgProductDetail;
+    border-width: 0;
+    // background: #202122ee;
+
+    // filter: blur(19px);
+    // &::after {
+    //     content: '';
+    //     position: absolute;
+    //     left: 0;
+    //     top: 0;
+    //     right: 0;
+    //     bottom: 0;
+    //     filter: blur(19px);
+    //     z-index: 1;
+    // }
+    .btn-list,
+    .status-text {
+        z-index: 2;
+    }
+    .btns {
+        width: 138px;
+        position: relative;
+        min-height: 38px;
+        .van-button--primary {
+            background: linear-gradient(135deg, @prim 0%, @warn 100%);
+            color: @btnText;
+            font-size: @font2;
+            border-width: 0px;
+        }
+        .no-btn {
+            color: #939599;
+            background-color: #303133;
+            border-width: 0;
+
+            .appoint {
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+                span {
+                    font-size: @font2;
+
+                    &:last-child {
+                        font-size: @font1;
+                    }
+                }
+            }
+        }
+
+        .btn-assignments {
+            .flex();
+            width: 186px;
+            position: absolute;
+            right: 0;
+            bottom: 0;
+            .vip {
+                margin-right: 6px;
+            }
+        }
+    }
+}
+
+.share-content {
+    display: flex;
+    margin-top: 20px;
+}
+.share-icon {
+    margin-left: 30px;
+    img {
+        width: 18px;
+        height: 18px;
+        display: inline-block;
+        vertical-align: middle;
+    }
+    span {
+        font-size: @font1;
+        color: #949699;
+        line-height: 24px;
+        vertical-align: middle;
+        margin-left: 2px;
+    }
+}
+.info {
+    .info-title {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+}
+
+.status-text {
+    font-size: @font4;
+    color: #939599;
+    line-height: 28px;
+    text-align: center;
+    padding: 14px 50px !important;
+    border-top: 1px solid #313233;
+}
+
+/deep/.goods-info {
+    .van-cell {
+        // padding: 0 0;
+        &::after {
+            content: none;
+        }
+
+        &:active {
+            background-color: @bgProductDetail;
+        }
+    }
+}
+/deep/.van-collapse-item--border::after {
+    content: none;
+}
+/deep/.van-hairline--top-bottom::after,
+.van-hairline-unset--top-bottom::after {
+    border-width: 0;
+}
+
+.user {
+    // padding: 12px 0 0;
+    display: flex;
+    .creator {
+        width: 50%;
+    }
+
+    .user-img {
+        flex-shrink: 0;
+    }
+    /deep/.van-cell {
+        padding: 0;
+    }
+
+    /deep/.van-cell__title {
+        margin-left: 10px;
+        overflow: hidden;
+    }
+}
+
+.price-content {
+    display: flex;
+    align-items: center;
+    .price {
+        font-size: 32px;
+        font-family: OSP-DIN, OSP;
+        color: @prim;
+        line-height: 26px;
+        display: flex;
+        align-items: center;
+        .font_family {
+            font-size: 10px;
+        }
+        img {
+            width: 10px;
+            height: 11px;
+            display: inline-block;
+            margin-top: 8px;
+        }
+    }
+    .price-sub {
+        font-size: @font1;
+        color: @text3;
+        text-decoration: line-through;
+        margin-left: 3px;
+        margin-top: 8px;
+    }
+
+    .sub {
+        font-size: @font1;
+        color: #949699;
+        line-height: 22px;
+        //
+    }
+
+    .price-text {
+        margin-left: 6px;
+        .flex-col();
+        .text1 {
+            .flex();
+            img {
+                width: 18px;
+                height: 18px;
+            }
+            span {
+                font-size: 12px;
+                color: #ffffff;
+                line-height: 17px;
+                margin-left: 2px;
+            }
+        }
+    }
+}
+.category {
+    width: 94px;
+    height: 30px;
+    border-radius: 4px;
+    background: linear-gradient(135deg, @prim, @warn);
+    font-size: @font1;
+    color: #ffffff;
+    line-height: 30px;
+    text-align: center;
+    position: relative;
+    // margin-top: 12px;
+    &::after {
+        content: '';
+        background-color: @bgProductDetail;
+        position: absolute;
+        left: 1px;
+        top: 1px;
+        right: 1px;
+        bottom: 1px;
+        z-index: 0;
+        border-radius: 4px;
+    }
+    span {
+        position: relative;
+        z-index: 1;
+    }
+}
+/deep/.van-collapse-item__content {
+    padding: 12px 16px !important;
+    background-color: #131313 !important;
+}
+
+.user-detail {
+    .flex();
+    width: 100%;
+    font-size: @font1;
+    height: 42px;
+    .text1 {
+        color: @prim;
+        width: 64px;
+        margin-right: 10px;
+        flex-basis: 0;
+        flex-grow: 1;
+    }
+    .text2 {
+        color: @text3;
+        width: 95px;
+        min-width: 95px;
+    }
+    .text3 {
+        color: #fff;
+        width: 64px;
+        margin-right: 10px;
+        flex-basis: 0;
+        flex-grow: 1;
+    }
+    .text4 {
+        color: @text3;
+    }
+
+    & + & {
+        border-top: 1px solid #202122;
+    }
+}
+
+.detail-swiper {
+    .swiper-slide {
+        width: 130px;
+    }
+}
+</style>

+ 344 - 0
src/components/auction/banner.vue

@@ -0,0 +1,344 @@
+<template>
+    <div class="detail-top" v-if="info.auctionType === 'NFT'">
+        <img src="@assets/png-bg-shangping.png" class="bg-img" />
+
+        <div class="detail-info">
+            <three-mode :info="info.model3d" v-if="!!info.model3d" :pageType="pageType"></three-mode>
+            <swiper @swiper="setSwiperRef" class="mySwiper" v-else-if="banners.length > 0">
+                <swiper-slide v-for="(item, index) in banners" :key="index">
+                    <!-- <img :src="item" /> -->
+
+                    <!-- <div class="video-box" v-if="isVideo(item)">
+                        <van-icon color="#fff" size="60" name="play-circle" />
+                    </div> -->
+                    <van-image
+                        v-if="opened === false"
+                        width="calc(100vw - 134px)"
+                        height="calc(100vw - 134px)"
+                        :src="require('../../assets/manghe.png')"
+                        fit="cover"
+                    />
+                    <video
+                        class="swiper-video"
+                        v-else-if="isVideo(item)"
+                        :src="item.url"
+                        controls
+                        :poster="getImg(changeImgs([item]), '', 1200)"
+                        playsinline="true"
+                        webkit-playsinline="true"
+                        autoplay
+                        loop
+                    >
+                        您的浏览器不支持 video 标签。
+                    </video>
+                    <van-image
+                        v-else
+                        @click="preview(index, changeImgs(banners))"
+                        :src="getImg(item.url, '', 1200)"
+                        width="calc(100vw - 134px)"
+                        height="calc(100vw - 134px)"
+                        fit="cover"
+                    />
+                </swiper-slide>
+            </swiper>
+
+            <div class="share-content">
+                <!-- <div class="setAvatar" @click="setAvatar" v-if="pageType == 'asset' && onlyImg">
+                    <img src="../../assets/icon-sheweitouxiang.png" alt="" />
+                    <span>设为头像</span>
+                </div> -->
+
+                <like-button :isLike="info.liked" @click="likeProduct">
+                    {{ info.likes }}
+                </like-button>
+
+                <div class="share-icon shareLeft" @click="share">
+                    <img src="@assets/svgs/icon-fenxiang.svg" alt="" />
+                    <span>分享</span>
+                </div>
+            </div>
+        </div>
+
+        <post ref="post" :info="assetInfo" noButton :pageUrl="pageUrl" />
+    </div>
+    <div class="top-box" v-else>
+        <three-mode :info="info.model3d" v-if="!!info.model3d" :pageType="pageType"></three-mode>
+
+        <swiper
+            v-else
+            :pagination="{ type: 'fraction' }"
+            :space-between="16"
+            class="mySwiper"
+            :autoplay="{ delay: 3500 }"
+        >
+            <swiper-slide v-for="(item, index) in banners" :key="index">
+                <video
+                    class="video"
+                    v-if="isVideo(item)"
+                    :src="item.url"
+                    controls
+                    :poster="getImg(changeImgs([item]), '', 1200)"
+                    playsinline="true"
+                    webkit-playsinline="true"
+                    autoplay
+                    loop
+                >
+                    您的浏览器不支持 video 标签。
+                </video>
+                <van-image width="100vw" height="100vw" :src="getImg(item.url, '', 1200)" fit="cover" />
+            </swiper-slide>
+        </swiper>
+    </div>
+</template>
+
+<script>
+import { Swiper, SwiperSlide } from 'swiper/vue';
+
+import 'swiper/swiper.min.css';
+import 'swiper/swiper-bundle.min.css';
+
+import product from '../../mixins/product';
+import asset from '../../mixins/asset';
+import Post from './Post.vue';
+import ThreeMode from '../product/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,
+            default: () => {
+                return {};
+            }
+        },
+        assetInfo: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        pageType: {
+            type: String,
+            default: 'product'
+        },
+        startTime: {
+            type: String,
+            default: ''
+        },
+        assignment: {
+            type: Boolean,
+            default: false
+        }
+    },
+    mixins: [product, asset],
+    components: {
+        Swiper,
+        SwiperSlide,
+        Post,
+        ThreeMode
+    },
+    computed: {
+        banners() {
+            return this.info.pic || [];
+        },
+        pageUrl() {
+            if (this.pageType === 'product') {
+                return 'productDetail';
+            } else {
+                return 'assetDetail';
+            }
+        },
+        onlyImg() {
+            if (this.banners.length > 0 && !this.info.model3d) {
+                if (this.banners[0].type.indexOf('image') !== -1 || this.banners[0].type.indexOf('png') !== -1) {
+                    return true;
+                }
+            }
+            return false;
+        },
+        shareInfo() {
+            return {
+                ...this.assetInfo,
+                ...this.info
+            };
+        }
+    },
+    methods: {
+        share() {
+            this.$refs.post.init();
+        },
+        preview(index = 0, list = []) {
+            ImagePreview({
+                images: [...list],
+                startPosition: index
+            });
+        },
+        likeProduct() {
+            if (!this.info.liked) {
+                this.$http.get(`/newsLike/${this.info.id}/likeAuction`).then(() => {
+                    this.$emit('getProduct');
+                    setTimeout(() => {
+                        this.$toast.success('收藏成功');
+                    }, 300);
+                });
+            } else {
+                this.$http.get(`/newsLike/${this.info.id}/unlikeAuction`).then(() => {
+                    this.$emit('getProduct');
+                    setTimeout(() => {
+                        this.$toast.success('取消收藏');
+                    }, 300);
+                });
+            }
+        },
+        videoPlay(e) {
+            console.log(this.$refs.swiperVideo[0]);
+            this.$nextTick(() => {
+                this.$refs.swiperVideo[0].play();
+            });
+        },
+        setAvatar() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.updateUser({ avatar: this.banners[0].url, useCollectionPic: true }).then(res => {
+                this.$toast.success('设置成功');
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+@radius: 30px;
+.detail-top {
+    position: relative;
+    padding-bottom: 20px;
+    .detail-info {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding-bottom: 90px;
+    }
+    .bg-img {
+        display: block;
+        width: 100vw;
+    }
+    .mySwiper {
+        border-radius: @radius;
+        border: 2px solid #ffffff;
+        padding: 5px;
+        overflow: hidden;
+        .detail-animate();
+        width: calc(100vw - 124px);
+        .swiper-slide {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            position: relative;
+            overflow: hidden;
+            /deep/ .van-image {
+                border: 2px solid #2f2f2f;
+                border-radius: @radius;
+                overflow: hidden;
+                background-color: @bg;
+            }
+
+            .video {
+                width: 100vw;
+                height: 100vw;
+                display: block;
+                overflow: hidden;
+            }
+        }
+    }
+}
+
+.swiper-video {
+    border: 2px solid #2f2f2f;
+    border-radius: @radius;
+    width: calc(100vw - 134px);
+    height: calc(100vw - 134px);
+    display: block;
+    overflow: hidden;
+}
+
+.share-content {
+    display: flex;
+    margin-top: 20px;
+}
+.share-icon {
+    img {
+        width: 18px;
+        height: 18px;
+        display: inline-block;
+        vertical-align: middle;
+    }
+    span {
+        font-size: @font1;
+        color: #949699;
+        line-height: 24px;
+        vertical-align: middle;
+        margin-left: 2px;
+    }
+
+    &.shareLeft {
+        margin-left: 30px;
+    }
+}
+
+.video-box {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(255, 255, 255, 0.5);
+    .flex();
+    justify-content: center;
+
+    .van-icon {
+        color: rgba(0, 0, 0, 0.5) !important;
+    }
+}
+
+.setAvatar {
+    .flex();
+    img {
+        width: 18px;
+        height: 18px;
+        display: block;
+    }
+
+    span {
+        font-size: 12px;
+        color: #949699;
+        line-height: 24px;
+        margin-left: 3px;
+    }
+}
+
+.top-box {
+    background-color: @bg3;
+}
+</style>

+ 713 - 0
src/components/auction/deposit.vue

@@ -0,0 +1,713 @@
+<template>
+    <van-action-sheet v-model:show="show" title="参拍详情">
+        <div class="content">
+            <div class="collection">
+                <van-image width="80" height="80" radius="8" :src="getImg(changeImgs(info.pic, 600))" fit="cover" />
+                <div class="collection-info">
+                    <div class="name">{{ info.name }}</div>
+                    <div class="time">
+                        <img src="../../assets/info_icon_time.png" alt="" />
+                        <span>{{ timeText }}:<van-count-down :time="time" format="HH 时 mm 分 ss 秒" /></span>
+                    </div>
+                </div>
+            </div>
+
+            <div class="price">
+                <div class="text1">保证金</div>
+                <img src="../../assets/jiage_huang.png" alt="" />
+                <div class="text2">{{ info.deposit }}</div>
+            </div>
+            <div class="tips">若竞拍不成功,保证金将原路退回</div>
+
+            <div v-if="!isNFT" class="address" @click="onAdd">
+                <div class="address-info" v-if="addressInfo.id">
+                    <div class="text1">
+                        <span>收货人</span>
+                        <span>{{ addressInfo.name }} {{ addressInfo.phone }}</span>
+                    </div>
+
+                    <div class="text1">
+                        <span>收货地址</span>
+                        <span
+                            >{{ addressInfo.provinceName }} {{ addressInfo.cityName }} {{ addressInfo.districtName }}
+                            {{ addressInfo.address }}</span
+                        >
+                    </div>
+                </div>
+                <span class="address-info address-info-text" v-else> 选择收货地址 </span>
+                <img src="../../assets/icon_inter.png" alt="" />
+            </div>
+
+            <div class="pay" v-if="!($store.state.review && inIos)">
+                <!-- <div class="pay-item" @click="payType = item.type" v-for="(item, index) in payInfos" :key="index">
+                    <img class="icon" :src="item.icon" alt="" />
+                    <span>{{ item.name }}</span>
+                    <img class="choose-icon" :src="payType === item.type ? icons[1] : icons[0]" alt="" />
+                </div> -->
+
+                <pay-method-pick v-model="payType"></pay-method-pick>
+            </div>
+        </div>
+        <div class="agreement" @click="showRule">竞拍需要同意协议<span>《拍卖服务协议》</span></div>
+        <div class="btn">
+            <a id="pay" :href="hrefUrl"></a>
+            <van-button type="primary" block round @click="submit">同意协议并支付</van-button>
+        </div>
+    </van-action-sheet>
+</template>
+
+<script>
+import auction from '../../mixins/auction';
+import resolveUrl from 'resolve-url';
+import PayMethodPick from '../PayMethodPick.vue';
+let inWeixin = /micromessenger/i.test(navigator.userAgent);
+let inApp = /#cordova#/i.test(navigator.userAgent);
+let inIos = /iPhone|iPad|iPod/i.test(navigator.userAgent);
+export default {
+    components: { PayMethodPick },
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    mixins: [auction],
+    data() {
+        return {
+            show: false,
+            time: 30 * 60 * 60 * 1000,
+            addressInfo: {},
+            payType: null,
+            icons: [require('@assets/svgs/icon_gouxuan_huise.svg'), require('@assets/icon_gouxuan_pre.png')],
+            payInfos: [
+                {
+                    icon: require('@assets/svgs/zhifubao.svg'),
+                    name: '支付宝',
+                    type: 'ALIPAY'
+                },
+                {
+                    icon: require('@assets/svgs/wechat.svg'),
+                    name: '微信',
+                    type: 'WEIXIN'
+                }
+                // {
+                //   icon: require("@assets/svgs/png-decp.svg"),
+                //   name: "DCEP",
+                // },
+            ],
+            enable_wx_lite: false,
+            enable_wx_pub: false,
+            hrefUrl: '',
+            orderId: 0,
+            timer: null
+        };
+    },
+    mounted() {
+        if (this.isLogin) {
+            this.emitter.on('updateChoose', info => {
+                console.log(info);
+                this.addressInfo = info;
+            });
+            this.$http
+                .post(
+                    '/userAddress/all',
+                    {
+                        query: {
+                            userId: this.$store.state.userInfo.id,
+                            del: false,
+                            def: true
+                        },
+                        size: 99
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    if (!res.empty) {
+                        this.addressInfo = res.content[0];
+                    }
+                });
+        }
+    },
+    methods: {
+        getOrder(next = false) {
+            this.$http.get('/auctionOrder/get/' + this.orderId).then(res => {
+                if (this.timer) {
+                    clearTimeout(this.timer);
+                }
+                if (this.timerNum >= 20) {
+                    this.$toast.clear();
+                    this.$dialog
+                        .confirm({
+                            title: '提示',
+                            message: '订单是否已经支付',
+                            confirmButtonText: '已经支付',
+                            cancelButtonText: '未支付'
+                        })
+                        .then(() => {
+                            this.$dialog
+                                .alert({
+                                    title: '正在排队中...',
+                                    message: '您的铸造订单正在排队,下单的藏品后续会直接出现在藏品室哦~'
+                                })
+                                .then(res => {
+                                    this.$router.back();
+                                });
+                        })
+                        .catch(e => {
+                            this.$dialog
+                                .confirm({
+                                    title: '提示',
+                                    message: '订单未支付是否重新支付?',
+                                    confirmButtonText: '重新支付',
+                                    cancelButtonText: '取消订单'
+                                })
+                                .then(() => {
+                                    this.timerNum = 0;
+                                    this.payEvent(false);
+                                })
+                                .catch(() => {
+                                    this.$router.back();
+                                });
+                        });
+                } else if (res.status === 'PROCESSING' || res.status === 'FINISH' || res.status === 'CANCELLED') {
+                    this.$toast.clear();
+                    this.$dialog
+                        .alert({
+                            title: '提示',
+                            message:
+                                res.status === 'CANCELLED' ? '订单支付失败,点击重新下单' : '订单已支付,点击查看订单详情'
+                        })
+                        .then(() => {
+                            location.reload();
+                            // on close
+                        });
+                } else if (next) {
+                    this.timerNum += 1;
+                    this.timer = setTimeout(() => {
+                        this.getOrder(next);
+                    }, 1500);
+                }
+            });
+        },
+        onAdd() {
+            this.$router.push('/mineAddress?page=submit&chooseId=' + this.addressInfo.id);
+        },
+        pay() {
+            this.$router.push('/auctionOffer');
+        },
+        init() {
+            this.time = this.getTime(this.info.endTime);
+            this.show = true;
+        },
+        showRule() {
+            this.$emit('showRule');
+        },
+        paySubmit(saveOrder = true) {
+            return new Promise((resolve, reject) => {
+                if (this.info.deposit && saveOrder) {
+                    this.$toast.clear();
+                    this.$nextTick(() => {
+                        if (window.cordova && window.cordova.platformId === 'ios' && this.$store.state.review) {
+                            resolve();
+                        } else if (this.payType === 'ALIPAY') {
+                            if (this.inWeixin) {
+                                resolve();
+                            } else {
+                                this.$http
+                                    .get(`/payOrder/v2/auction/alipay?id=${this.orderId}`)
+                                    .then(res => {
+                                        this.$toast.clear();
+                                        this.hrefUrl = res;
+                                        resolve();
+                                    })
+                                    .catch(e => {
+                                        if (e && e.error) {
+                                            this.$toast.clear();
+                                            this.$dialog
+                                                .alert({
+                                                    title: '提示',
+                                                    message: this.backReson(e.error)
+                                                })
+                                                .then(res => {
+                                                    this.$router.back();
+                                                });
+                                            reject();
+                                        }
+                                    });
+                            }
+                        } else if (this.payType === 'WEIXIN') {
+                            this.$toast.loading('加载中');
+                            this.$http
+                                .post('/payOrder/weixin', {
+                                    id: this.orderId,
+                                    channel: this.payChannel,
+                                    openId: localStorage.getItem('openId') || 'oWJG55wLnwdVzXoKka1-DzQKOd_Y'
+                                })
+                                .then(res => {
+                                    if ('wx_pub' === this.payChannel) {
+                                        this.weixinOptions = res;
+                                        resolve();
+                                    } else {
+                                        this.$toast.clear();
+                                        this.hrefUrl = res.scheme_code;
+                                        resolve();
+                                    }
+                                    // console.log({
+                                    //     ...res,
+                                    //     package: res.package || res.packageValue
+                                    // });
+                                    // let _this = this;
+                                    // wx.chooseWXPay({
+                                    //     ...res,
+                                    //     package: res.package || res.packageValue,
+                                    //     timestamp: res.timeStamp,
+                                    //     success(res) {
+                                    //         _this.$toast.success('支付成功');
+                                    //         setTimeout(() => {
+                                    //             _this.$router.replace('/orders');
+                                    //         }, 1000);
+                                    //     },
+                                    //     fail(e) {
+                                    //         console.log(e);
+                                    //         _this.$toast('支付失败,请稍后再试');
+                                    //     }
+                                    // });
+                                })
+                                .catch(e => {
+                                    this.$toast.clear();
+                                    this.$dialog
+                                        .alert({
+                                            title: '提示',
+                                            message: this.backReson(e.error || '支付失败请稍后再试')
+                                        })
+                                        .then(res => {
+                                            this.$router.back();
+                                        });
+                                    reject();
+                                });
+                        } else if (this.payType === 'H5PAY') {
+                            resolve();
+                        }
+                    });
+                } else {
+                    resolve();
+                }
+            });
+        },
+        createOrder() {
+            let form = { userId: this.$store.state.userInfo.id, auctionId: this.info.id, type: 'DEPOSIT' };
+            if (!this.isNFT) {
+                form.addressId = this.addressInfo.id;
+            }
+            return this.$http
+                .post('/auctionOrder/createDeposit', form)
+                .then(res => {
+                    return Promise.resolve(res);
+                })
+                .catch(e => {
+                    return Promise.reject(e);
+                });
+        },
+        submit() {
+            if (!this.isNFT && !this.addressInfo.id) {
+                this.$toast('请选择收货地址');
+                return;
+            }
+
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.createOrder()
+                .then(res => {
+                    this.$toast.clear();
+                    this.orderId = res.id;
+                    if (Number(this.info.deposit) != 0) {
+                        this.$router.replace({ query: { ...this.$route.query, orderId: res.id } });
+
+                        this.$nextTick(() => {
+                            if (this.payType === 'SYXPAY') {
+                                this.$toast.clear();
+                                this.$router.push('/bankPay?id=' + this.orderId + '&type=auction&paymentType=DEPOSIT');
+                            } else if (this.$store.state.review) {
+                                window.store.order('358');
+                                this.getOrder(true);
+                            } else if (this.payType === 'ALIPAY') {
+                                if (this.inWeixin) {
+                                    document.location.replace(
+                                        resolveUrl(this.$baseUrl, '/payOrder/v2/auction/alipay_wx?id=' + res.id)
+                                    );
+                                } else {
+                                    this.$http
+                                        .get(`/payOrder/v2/auction/alipay?id=${res.id}`)
+                                        .then(res => {
+                                            this.$toast.clear();
+                                            this.hrefUrl = res;
+                                            this.$nextTick(() => {
+                                                document.getElementById('pay').click();
+                                            });
+
+                                            this.$toast.loading({
+                                                message: '加载中...',
+                                                forbidClick: true
+                                            });
+                                            this.getOrder(true);
+                                        })
+                                        .catch(e => {
+                                            if (e.error) {
+                                                this.$toast(e.error);
+                                            }
+                                        });
+                                }
+                            } else if (this.payType === 'WEIXIN') {
+                                this.$toast.loading('加载中');
+                                this.$http
+                                    .post('/payOrder/auction/weixin', {
+                                        id: res.id,
+                                        channel: this.payChannel,
+                                        openId: localStorage.getItem('openId') || 'oWJG55wLnwdVzXoKka1-DzQKOd_Y'
+                                    })
+                                    .then(res => {
+                                        if ('wx_pub' === this.payChannel) {
+                                            console.log('wxPayParams', res);
+                                            wx.chooseWXPay({
+                                                ...res,
+                                                success(res) {
+                                                    this.$toast.success('支付成功');
+                                                    setTimeout(() => {
+                                                        this.$router.replace('/orders');
+                                                    }, 1000);
+                                                },
+                                                fail(e) {
+                                                    console.log(e);
+                                                    this.$toast('支付失败,请稍后再试');
+                                                }
+                                            });
+                                        } else {
+                                            this.$toast.clear();
+                                            this.hrefUrl = res.scheme_code;
+                                            this.$nextTick(() => {
+                                                document.getElementById('pay').click();
+                                            });
+
+                                            this.$toast.loading({
+                                                message: '加载中...',
+                                                forbidClick: true
+                                            });
+                                            this.getOrder(true);
+                                        }
+                                    })
+                                    .catch(e => {
+                                        this.$toast(e.error || '支付失败请稍后再试');
+                                    });
+                            } else if (this.payType === 'UNION') {
+                                document.location.href = resolveUrl(
+                                    this.$baseUrl,
+                                    '/payOrder/v2/auction/sandQuick?id=' + this.orderId
+                                )
+                                    .replace('www.raex.vip', 'jump.raex.vip')
+                                    .replace('test.raex.vip', 'jumptest.raex.vip')
+                                    .replace(/http:\/\/192\.168.*?\//, 'https://jumptest.raex.vip/');
+                            }
+                        });
+                    } else {
+                        this.$toast.success('支付成功');
+                        setTimeout(() => {
+                            location.reload();
+                        }, 1000);
+                    }
+                })
+                .catch(e => {
+                    if (e) {
+                        this.$toast(e.error);
+                    }
+                });
+        },
+        payEvent(saveOrder = true) {
+            this.paySubmit(saveOrder).then(() => {
+                if (this.info.deposit) {
+                    this.$nextTick(() => {
+                        if (this.payType === 'SYXPAY') {
+                            this.$toast.clear();
+                            this.$router.replace('/bankPay?id=' + this.orderId + '&type=auction');
+                        } else if (this.$store.state.review) {
+                            window.store.order('358');
+                            this.getOrder(true);
+                        } else if (this.payType === 'ALIPAY') {
+                            if (this.inWeixin) {
+                                document.location.replace(
+                                    resolveUrl(this.$baseUrl, '/payOrder/v2/auction/alipay_wx?id=' + this.orderId)
+                                );
+                            } else {
+                                this.$http
+                                    .get(`/payOrder/v2/auction/alipay?id=${this.orderId}`)
+                                    .then(res => {
+                                        this.$toast.clear();
+                                        this.hrefUrl = res;
+                                        this.$nextTick(() => {
+                                            document.getElementById('pay').click();
+                                        });
+
+                                        this.$toast.loading({
+                                            message: '加载中...',
+                                            forbidClick: true
+                                        });
+                                        this.getOrder(true);
+                                    })
+                                    .catch(e => {
+                                        if (e.error) {
+                                            this.$toast(e.error);
+                                        }
+                                    });
+                            }
+                        } else if (this.payType === 'WEIXIN') {
+                            this.$toast.loading('加载中');
+                            this.$http
+                                .post('/payOrder/auction/weixin', {
+                                    id: this.orderId,
+                                    channel: this.payChannel,
+                                    openId: localStorage.getItem('openId') || 'oWJG55wLnwdVzXoKka1-DzQKOd_Y'
+                                })
+                                .then(res => {
+                                    if ('wx_pub' === this.payChannel) {
+                                        console.log('wxPayParams', res);
+                                        wx.chooseWXPay({
+                                            ...res,
+                                            success(res) {
+                                                this.$toast.success('支付成功');
+                                                setTimeout(() => {
+                                                    this.$router.replace('/orders');
+                                                }, 1000);
+                                            },
+                                            fail(e) {
+                                                console.log(e);
+                                                this.$toast('支付失败,请稍后再试');
+                                            }
+                                        });
+                                    } else {
+                                        this.$toast.clear();
+                                        this.hrefUrl = res.scheme_code;
+                                        this.$nextTick(() => {
+                                            document.getElementById('pay').click();
+                                        });
+
+                                        this.$toast.loading({
+                                            message: '加载中...',
+                                            forbidClick: true
+                                        });
+                                        this.getOrder(true);
+                                    }
+                                    // console.log({
+                                    //     ...res,
+                                    //     package: res.package || res.packageValue
+                                    // });
+                                    // let _this = this;
+                                    // wx.chooseWXPay({
+                                    //     ...res,
+                                    //     package: res.package || res.packageValue,
+                                    //     timestamp: res.timeStamp,
+                                    //     success(res) {
+                                    //         _this.$toast.success('支付成功');
+                                    //         setTimeout(() => {
+                                    //             _this.$router.replace('/orders');
+                                    //         }, 1000);
+                                    //     },
+                                    //     fail(e) {
+                                    //         console.log(e);
+                                    //         _this.$toast('支付失败,请稍后再试');
+                                    //     }
+                                    // });
+                                })
+                                .catch(e => {
+                                    this.$toast(e.error || '支付失败请稍后再试');
+                                });
+                        } else if (this.payType === 'UNION') {
+                            document.location.href = resolveUrl(
+                                this.$baseUrl,
+                                '/payOrder/v2/auction/sandQuick?id=' + this.orderId
+                            )
+                                .replace('www.raex.vip', 'jump.raex.vip')
+                                .replace('test.raex.vip', 'jumptest.raex.vip')
+                                .replace(/http:\/\/192\.168.*?\//, 'https://jumptest.raex.vip/');
+                        }
+                    });
+                } else {
+                    this.$toast.success('支付成功');
+                    setTimeout(() => {
+                        location.reload();
+                    }, 1000);
+                }
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.content {
+    padding: 16px;
+}
+
+.collection {
+    .flex();
+    .van-image {
+        flex-shrink: 0;
+    }
+    .collection-info {
+        flex-grow: 1;
+        .flex-col();
+        margin-left: 10px;
+        align-self: stretch;
+
+        .name {
+            font-size: 14px;
+            font-weight: bold;
+            color: #000000;
+            line-height: 20px;
+        }
+
+        .time {
+            .flex();
+            background: #fff7f2;
+            border-radius: 4px;
+            align-self: flex-start;
+            padding: 0 2px;
+            margin-top: 10px;
+            img {
+                width: 18px;
+                height: 18px;
+            }
+            span {
+                margin-left: 2px;
+                .flex();
+                font-size: 12px;
+                color: #ff7f1f;
+                line-height: 22px;
+                .van-count-down {
+                    font-size: 12px;
+                    color: #ff7f1f;
+                    line-height: 22px;
+                }
+            }
+        }
+    }
+}
+
+.price {
+    .flex();
+    align-items: flex-end;
+    padding-top: 16px;
+    .text1 {
+        font-size: 14px;
+        color: #000000;
+        line-height: 14px;
+        font-weight: bold;
+    }
+
+    img {
+        width: 10px;
+        height: 11px;
+        margin-left: 10px;
+    }
+    .text2 {
+        font-size: 32px;
+        font-family: OSP-DIN, OSP;
+        font-weight: normal;
+        color: #3ab200;
+        line-height: 20px;
+    }
+}
+.tips {
+    font-size: 12px;
+    color: #c8c9cc;
+    line-height: 17px;
+    margin-top: 6px;
+}
+
+.address {
+    background-color: #f5f7fa;
+    padding: 16px 10px;
+    border-radius: 12px;
+    margin-top: 16px;
+    .flex();
+
+    .text1 {
+        .flex();
+        align-items: flex-start;
+        span {
+            font-size: 14px;
+            color: #000000;
+            line-height: 24px;
+
+            &:first-child {
+                color: #939599;
+                min-width: 56px;
+                margin-right: 12px;
+                display: inline-block;
+            }
+        }
+    }
+
+    .address-info {
+        flex-grow: 1;
+
+        &.address-info-text {
+            font-size: 14px;
+            color: @text3;
+            line-height: 52px;
+        }
+    }
+
+    .text1 + .text1 {
+        margin-top: 6px;
+    }
+
+    img {
+        width: 24px;
+        height: 24px;
+    }
+}
+
+.agreement {
+    font-size: 12px;
+    color: #939599;
+    line-height: 24px;
+    margin-top: 26px;
+    text-align: center;
+    background-color: #f5f7fa;
+    padding: 7px 0;
+    span {
+        color: #3ab200;
+    }
+}
+.btn {
+    padding: 9px 48px;
+}
+.pay {
+    padding-top: 10px;
+}
+.pay-item {
+    display: flex;
+    align-items: center;
+    height: 48px;
+    border-top: 1px solid @tabBorder;
+    .icon {
+        height: 24px;
+        display: block;
+    }
+    span {
+        font-size: 14px;
+        font-weight: bold;
+        color: @text0;
+        line-height: 24px;
+        flex-grow: 1;
+        padding: 0 10px;
+    }
+    .choose-icon {
+        width: 24px;
+        height: 24px;
+    }
+}
+</style>

+ 258 - 0
src/components/auction/help.vue

@@ -0,0 +1,258 @@
+<template>
+    <van-action-sheet
+        @close="close"
+        :lazy-render="false"
+        :overlay-style="{ zIndex: 18 }"
+        class="help-box"
+        v-model:show="show"
+    >
+        <div class="container" ref="container">
+            <van-tabs v-model:active="active" @click="changeTab" v-show="scrollTop > 10">
+                <van-tab title="特别提醒" name="node1"> </van-tab>
+                <van-tab title="竞拍说明" name="node2"> </van-tab>
+                <van-tab title="竞拍告知" name="node3"> </van-tab>
+                <van-tab title="竞拍公告" name="node4"> </van-tab>
+            </van-tabs>
+            <h3 ref="node1">一、特别提醒</h3>
+            <h4>1.温馨提示</h4>
+            <p>
+                华储艺术品中心(深圳)有限公司举办的拍卖活动均按照本规则进行,参加拍卖活动的相关方务必仔细阅读并予以遵守。
+            </p>
+            <h4>2.特别声明</h4>
+            <p>华储艺术品中心(深圳)有限公司特别声明不能保证拍品的真伪、品质及价值,对拍品不承担瑕疵担保责任。</p>
+            <h3 ref="node2">二、竞拍说明(玩法说明)</h3>
+            <h4>1.什么是增价拍?</h4>
+            <p>
+                增加拍是指由送拍方设置最低成交价和加价幅度,由竞买人按照规定的加价幅度加价,在规定的时间内由最高出价者竞得。
+            </p>
+            <h4>增价拍规则</h4>
+            <p><span>1</span>首次出价不得低于最低成交价。</p>
+            <p><span>2</span>出价最高者领先,价低者竞拍记录出具,出局者可以再次出价。</p>
+            <p><span>3</span>再次出价,须至少增加一个加价幅度出价。</p>
+            <h4>2.什么是一口价?</h4>
+            <p>一口价是送拍方以固定价格出售商品,没有讨价还价的余地,最先付款支付成功的竞买人竞得。</p>
+            <h4>3.保证金的缴纳</h4>
+
+            <p>
+                保证金是买家需要预先缴纳一定金额的资金,作为最终支付竞得拍品的拍品款和相关费用的保证。如果竞拍成功,已缴纳的保证金将自动抵扣相应金额的拍品款。如果买家为竞得拍品,系统将自动将保证金(无息)退回到买家的账户中。
+            </p>
+            <h4>4.保证金的返还</h4>
+            <p><span>1</span>买家未成功竞得拍品:例如在竞拍过程中始终未出价、在竞拍过程中放弃加价等等情况;</p>
+            <p><span>2</span>买家竞拍成功后,平台自动关闭交易,或未履约发货及其他原因导致交易未完成的;</p>
+            <p>
+                <span>3</span
+                >竞拍结束后,系统一般会在1-15个工作日内将款项退还到支付账号中,如您缴纳的竞拍保证金符合退换条件,但是系统未予自动退还,您可以联系本公司客服。
+            </p>
+            <h4>5.保证金的扣除</h4>
+            <p>买家竞拍成功后,如果未按规定时间支付剩余货款,保证金将被扣除。</p>
+            <h4>6.保证金抵拍退款</h4>
+            <p>买家竞拍成功后 买家需在规定时间内缴纳剩余尾款,订单完成后之后,保证金原路退回至买家支付账户。</p>
+            <h4>7.关于退换货</h4>
+            <p>由于拍品的特殊性质,因此不提供退换货服务,请您务必充分评估并谨慎出价。</p>
+            <h3 ref="node3">三、竞拍告知</h3>
+            <h4>1.发货时间</h4>
+            <p>数字艺术品在拍卖付款成功后1个工作日内将移至您的账户。</p>
+            <p>
+                实物商品正常订单付款后一般72小时发货。节假日订单顺延至工作日统一发货。送拍方的仓库可能分布在全国各地,因此一旦出现疫情封控或其他特殊情况需要延后发货的,送拍方将直接联系您沟通具体情况。
+            </p>
+            <h4>2.物流服务</h4>
+            <p>所有实物拍品一般默认快递发货。</p>
+            <h4>3.关于运费</h4>
+            <p>
+                中国大陆地区一般提供包邮服务,不提供的会在详情页注明。
+                国际及港澳台快递费、包装费用均由买受人支付相应费用。
+            </p>
+            <h4>4.运费保险</h4>
+            <p>
+                如拍品物流过程中出现问题,快递公司默认保丢不保损,未选择保价服务的商品,如在运输途中出现破损、缺失、丢失等异常情况,买家将无法享受快递公司的理赔服务。买家接受和认可平台不对运输过程中的任何损失或丢失情况负责任。为避免运输途中出现缺失与损坏,买受人可根据拍品价值及需求提前联系官方咨询保价服务。
+            </p>
+            <h4>5.开具发票</h4>
+            <p>
+                如买家需开具发票,发票中的购买方名称必须与本人名称一致,且须于结清拍品款的当月月底前联系客服办理增值税普通发票开具事宜。逾期恕不办理,请买家务必正确提供开票信息。
+            </p>
+            <h3 ref="node4">四、竞拍公告</h3>
+            <p>
+                1.凡参与一口价购买或增价拍的竞买人,请您先了解本(公告)规则,您一旦参与购买或竞价即视为您已经同意本现则。
+            </p>
+            <p>
+                2.本场竞拍活动是数字艺术品版权(拍品)的拍卖活动,本拍品已经过蚂蚁链技术的加密程序,您竞拍成功后可前往“RAEX绿洲宇宙”手机APP查看、验证和下载。
+            </p>
+            <p>
+                3.本拍品数量为【1】件,作品拍卖展示时,频道内会显著、清晰标准拍品的详细信息,所有拍品的相关内容和版权均由送拍方自行承担责任。
+            </p>
+            <p>
+                4.本拍品的介绍(包括但不限于图片、文字、视频等)及拍品资质文件(包括但不限于来源证明、鉴定证书等),所有拍品的相关内容和版权均由送拍方自行编辑上传并承担责任。
+            </p>
+            <p>
+                5.本拍品由送拍方提供,您将独立承担参与本次拍卖的相关风险,并享有相应权利。如因送拍方或者拍品原创作者发布危害国家利益、违反社会道德、公序良俗及其他可能造成严重负面舆论的言论或行为,导致数字艺术品版权被屏蔽或者限制使用的,您应当自行与送拍方沟通解决。
+            </p>
+            <p>6.“蚂蚁链”仅提供区块链技术服务,不参与作品拍卖的具体环节。 7送拍方应保证本作品版权的合法性和唯一性。</p>
+            <p>
+                8.为防止恶意竞拍扰乱市场秩序的行为,在您参加竞拍活动前,系统需要冻结一定金额的保证金。在竞拍结束后如未成功则自动解冻,无息返还至原支付账户。竞拍成功的用户竞拍结束后72小时内未支付尾款的,保证金将作为违约金不予返还。
+            </p>
+            <p>9.每个拍品每个用户仅限参与一次,名额不可转让、折现、出售。</p>
+            <p>
+                10.考虑到本次拍卖活动中的拍品具有区块链上唯一性的特征,同时鉴于参拍前已向您充分说明拍卖特性,因此拍品不提供退换货服务,请您务必充分评估并谨慎出价。
+            </p>
+            <p>
+                11.买家理解并同意,鉴于网络服务的特殊性,我们对本服务持续提供可能受到多重因素影响,如出现技术升级、网路故障、经营策略调整、配合国家重大技术、法规政策变化,平台可能随时终止、中断提供服务或变更服务形式、规格或其他方面而无须承担责任。
+            </p>
+            <p>12.如您想要通过竞拍方式购买数字艺术品,应当满足以下条件:</p>
+            <p><span>1</span>您已满18周岁未满60周岁,并具有中华人民共和国国籍。</p>
+            <p><span>2</span>您已通过实名制认证。</p>
+            <p>
+                您仅代表您个人而不属于任何组织或企业,您理解及确认我们有权依据国家法律法规、监管政策、活动规则或业务需要对上述条件进行补充或修改,您一旦参拍并购买商品,即表示您承诺符合以上条件并受到本协议及活动细则约束。
+            </p>
+        </div>
+    </van-action-sheet>
+</template>
+
+<script>
+import { ref, watch } from 'vue';
+import { useScrollParent, useEventListener, useToggle } from '@vant/use';
+export default {
+    setup() {
+        const container = ref();
+        const node1 = ref();
+        const node2 = ref();
+        const node3 = ref();
+        const node4 = ref();
+        const scrollParent = useScrollParent(container);
+        const active = ref('');
+        const [state, toggle] = useToggle();
+        const scrollTop = ref(0);
+
+        useEventListener(
+            'scroll',
+            e => {
+                scrollTop.value = container.value.parentNode.scrollTop;
+                if (!state.value) {
+                    if (scrollTop.value > node4.value.offsetTop - 80) {
+                        active.value = 'node4';
+                    } else if (scrollTop.value > node3.value.offsetTop - 80) {
+                        active.value = 'node3';
+                    } else if (scrollTop.value > node2.value.offsetTop - 80) {
+                        active.value = 'node2';
+                    } else {
+                        active.value = 'node1';
+                    }
+                }
+            },
+            { target: scrollParent }
+        );
+
+        let time = null;
+        const changeTab = options => {
+            if (time) {
+                clearTimeout(time);
+                time = null;
+            }
+            toggle(true);
+            let scrollTop = 0;
+            if (options === 'node4') {
+                scrollTop = node4.value.offsetTop - 50;
+            } else if (options === 'node3') {
+                scrollTop = node3.value.offsetTop - 50;
+            } else if (options === 'node2') {
+                scrollTop = node2.value.offsetTop - 50;
+            } else {
+                scrollTop = 0;
+            }
+
+            container.value.parentNode.scroll({
+                top: scrollTop,
+                behavior: 'smooth'
+            });
+
+            time = setTimeout(() => {
+                toggle(false);
+            }, 1500);
+        };
+
+        return { container, node1, node2, node3, node4, active, changeTab, scrollTop };
+    },
+    data() {
+        return {
+            show: false
+        };
+    },
+    methods: {
+        close() {
+            this.$emit('changePopup');
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.container {
+    padding: 16px;
+    position: relative;
+
+    .van-tabs {
+        position: sticky;
+        top: 0;
+        z-index: 20;
+    }
+}
+
+h3 {
+    text-align: center;
+    font-size: 16px;
+    font-weight: bold;
+    color: #000000;
+    line-height: 22px;
+    margin: 16px 0 0;
+}
+h4 {
+    font-size: 14px;
+    color: #000000;
+    line-height: 20px;
+    margin: 12px 0 0;
+}
+p {
+    font-size: 14px;
+    color: #939599;
+    line-height: 22px;
+    margin: 5px 0 0;
+}
+p + h3 {
+    margin: 24px 0 0;
+}
+h3 + p {
+    margin: 12px 0 0;
+}
+p + p {
+    margin: 12px 0 0;
+}
+
+p {
+    span {
+        font-size: 12px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 16px;
+        width: 16px;
+        height: 16px;
+        display: inline-flex;
+        background-color: #939599;
+        text-align: center;
+        border-radius: 16px;
+        align-items: center;
+        justify-content: center;
+        margin-right: 6px;
+    }
+}
+
+/deep/.van-tab {
+    margin-right: 0;
+    flex-grow: 1 !important;
+}
+</style>
+<style lang="less">
+.help-box {
+    .fixedBottom(59px);
+    z-index: 19 !important;
+    height: 50vh;
+}
+</style>

+ 204 - 0
src/components/auction/info.vue

@@ -0,0 +1,204 @@
+<template>
+    <router-link
+        :to="{
+            path: '/auctionDetail',
+            query: {
+                id: info.id
+            }
+        }"
+        class="auction-info"
+        :class="{ isEnd: isEnd }"
+    >
+        <van-image :radius="8" width="128" height="128" :src="getImg(changeImgs(info.pic, 600))" fit="cover" />
+        <div class="content">
+            <div class="text1 van-multi-ellipsis--l2">
+                {{ info.name }}
+            </div>
+            <div class="text2">
+                <div class="time" v-if="!isEnd">
+                    <img src="../../assets/info_icon_time.png" alt="" />
+                    <span
+                        >{{ timeText }}:<van-count-down @finish="finish" :time="time" format="HH 小时 mm 分 ss 秒"
+                    /></span>
+                </div>
+
+                <div class="time" v-else>
+                    <img src="../../assets/info_icon_time1.png" alt="" />
+                    <span>{{ timeText }}</span>
+                </div>
+            </div>
+
+            <div class="text3">
+                <span class="text3-1">{{ priceText }}</span>
+                <div class="price">
+                    <img src="../../assets/icon_jiage_hei.png" alt="" />
+                    <span>{{ showPrice }}</span>
+                </div>
+                <span class="text3-3">出价{{ info.bids }}次</span>
+            </div>
+        </div>
+    </router-link>
+</template>
+
+<script>
+import auction from '../../mixins/auction';
+export default {
+    data() {
+        return {
+            time: 0,
+            isFirst: true
+        };
+    },
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        size: {
+            type: String,
+            default: 'normall'
+        },
+        isLink: {
+            type: Boolean,
+            default: true
+        }
+    },
+    mixins: [auction],
+    mounted() {
+        this.setTime();
+    },
+    methods: {
+        setTime() {
+            let time = 0;
+            if (this.info.status === 'NOTSTARTED') {
+                time = this.getTime(this.info.startTime);
+            } else {
+                time = this.getTime(this.info.endTime);
+            }
+            if (time > 0) {
+                this.time = time;
+            }
+            if (this.isFirst) {
+                setTimeout(() => {
+                    this.isFirst = false;
+                }, 1000);
+            }
+        },
+        finish(e) {
+            if (this.isFirst) {
+                return;
+            }
+            this.$http.get('/auctionActivity/get/' + this.info.id).then(res => {
+                this.$emit('update:info', res);
+                this.$nextTick(() => {
+                    this.setTime();
+                });
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.auction-info {
+    border-radius: 8px;
+    overflow: hidden;
+    background-color: #fff;
+    display: inline-flex;
+    width: calc(100% - 16px);
+    margin: 8px;
+    align-items: stretch;
+    box-sizing: border-box;
+    color: #000;
+    .van-image {
+        flex-shrink: 0;
+    }
+
+    .content {
+        flex-grow: 1;
+        padding: 10px 12px;
+        .flex-col();
+        .text1 {
+            font-size: 14px;
+            font-weight: bold;
+        }
+
+        .text2 {
+            flex-grow: 1;
+            margin-top: 8px;
+
+            .time {
+                .flex();
+                height: 22px;
+                background: #fff7f2;
+                border-radius: 4px;
+                display: inline-flex;
+                padding: 0 4px;
+                img {
+                    width: 18px;
+                    height: 18px;
+                }
+                span {
+                    margin-left: 2px;
+                    .flex();
+                    font-size: 12px;
+                    color: #ff7f1f;
+                    line-height: 22px;
+                    .van-count-down {
+                        font-size: 12px;
+                        color: #ff7f1f;
+                        line-height: 22px;
+                    }
+                }
+            }
+        }
+        .text3 {
+            .flex();
+            .text3-1 {
+                font-size: 10px;
+                font-weight: bold;
+                color: #000000;
+                line-height: 10px;
+            }
+            .price {
+                .flex();
+                img {
+                    width: 8px;
+                    height: 8px;
+                    margin-top: 4px;
+                }
+                span {
+                    font-size: 20px;
+                    font-family: OSP-DIN, OSP;
+                    font-weight: normal;
+                    color: #000000;
+                    line-height: 14px;
+                }
+
+                flex-grow: 1;
+                padding: 0 2px;
+            }
+
+            .text3-3 {
+                font-size: 10px;
+                color: #c8c9cc;
+                line-height: 10px;
+            }
+        }
+    }
+
+    &.isEnd {
+        .text2 {
+            .time {
+                font-size: 12px;
+                background-color: #f2f4f5;
+                span {
+                    color: #939599;
+                }
+            }
+        }
+    }
+}
+</style>

+ 156 - 0
src/components/auction/records.vue

@@ -0,0 +1,156 @@
+<template>
+    <van-overlay :lock-scroll="false" :show="show" z-index="99" @click="show = false">
+        <div class="wrapper">
+            <div class="block" @click.stop>
+                <div class="title">
+                    <img src="../../assets/icon-paimaijilu.png" alt="" />
+                    <span class="text1">拍卖纪录</span>
+                    <span class="text2">共{{ recordNum }}条</span>
+                    <img src="../../assets/icon_close_tips.png" @click="show = false" alt="" class="close" />
+                </div>
+                <van-list class="list" v-model:loading="loading" :finished="finished" finished-text="" @load="getData">
+                    <div class="record-item" v-for="(item, index) in list" :key="index">
+                        <span>{{ item.user }}</span>
+                        <span>{{ index === 0 ? '领先' : '出局' }}</span>
+                        <span>¥{{ item.bidderPrice || 0 }}</span>
+                        <span>{{ showTime(item.createdAt) }}</span>
+                    </div>
+                    <div class="empty" v-if="empty">暂无拍卖纪录</div>
+                </van-list>
+            </div>
+        </div>
+    </van-overlay>
+</template>
+
+<script>
+import list from '../../mixins/list';
+import auction from '../../mixins/auction';
+
+export default {
+    props: {
+        auctionId: {
+            type: Number,
+            default: 0
+        },
+        recordNum: {
+            type: Number,
+            default: 0
+        }
+    },
+    mixins: [list, auction],
+    data() {
+        return {
+            show: false,
+            url: '/auctionRecord/all',
+            size: 10
+        };
+    },
+    methods: {
+        beforeData() {
+            return {
+                query: {
+                    auctionId: this.auctionId,
+                    type: 'BIDDER',
+                    del: false
+                },
+                sort: 'id,desc'
+            };
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.wrapper {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 100%;
+}
+
+.block {
+    width: 300px;
+    height: 340px;
+    background-color: #fff;
+    border-radius: 8px;
+    overflow: auto;
+
+    .empty {
+        font-size: 12px;
+        font-family: PingFangSC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #939599;
+        line-height: 17px;
+    }
+}
+
+.title {
+    .flex();
+    height: 40px;
+    padding: 0 16px;
+    border-bottom: 1px solid #f5f7fa;
+    background-color: #fff;
+    position: sticky;
+    top: 0;
+    img {
+        width: 18px;
+        height: 18px;
+    }
+
+    .text1 {
+        flex-grow: 1;
+        font-size: 14px;
+        font-weight: bold;
+        color: #000000;
+        line-height: 24px;
+        margin: 0 6px;
+    }
+    .close {
+        width: 24px;
+        height: 24px;
+    }
+
+    .text2 {
+        font-size: 12px;
+        color: #c8c9cc;
+        line-height: 17px;
+        margin: 0 6px;
+    }
+}
+
+.list {
+    padding: 0 16px 30px;
+    overflow: hidden;
+}
+
+.record-item {
+    .flex();
+    font-size: 12px;
+    color: #939599;
+    line-height: 17px;
+    margin-top: 10px;
+
+    span {
+        white-space: nowrap;
+        &:first-child {
+            width: 20%;
+            overflow: hidden; //溢出隐藏
+            white-space: nowrap; //禁止换行
+            text-overflow: ellipsis;
+            display: inline-block;
+        }
+
+        &:nth-child(3) {
+            flex-grow: 1;
+        }
+    }
+
+    span + span {
+        margin-left: 18px;
+    }
+
+    &:first-child {
+        color: @prim;
+    }
+}
+</style>

+ 134 - 0
src/components/auction/rule.vue

@@ -0,0 +1,134 @@
+<template>
+    <van-action-sheet
+        class="rule-box"
+        closeable
+        :lazy-render="false"
+        :overlay-style="{ zIndex: 18 }"
+        v-model:show="show"
+        title=" "
+    >
+        <div class="page">
+            <h3>RAEX绿洲宇宙拍卖规则</h3>
+            <p>
+                一、凡参与一口价购买或增价拍的竞买人,请您先了解本(公告)规则,您一旦参与购买或竞价即视为您已经同意本现则。
+            </p>
+            <p>
+                二、本场竞拍活动是数字艺术品版权(拍品)的拍卖活动,本拍品已经过蚂蚁链技术的加密程序,您竞拍成功后可前往“RAEX绿洲宇宙”手机APP查看、验证和下载。
+            </p>
+            <p>
+                三、本拍品数量为【1】件,作品拍卖展示时,频道内会显著、清晰标准拍品的详细信息,所有拍品的相关内容和版权均由送拍方自行承担责任。
+            </p>
+            <p>
+                四、本拍品的介绍(包括但不限于图片、文字、视频等)及拍品资质文件(包括但不限于来源证明、鉴定证书等),所有拍品的相关内容和版权均由送拍方自行编辑上传并承担责任。
+            </p>
+            <p>
+                五、本拍品由送拍方提供,您将独立承担参与本次拍卖的相关风险,并享有相应权利。如因送拍方或者拍品原创作者发布危害国家利益、违反社会道德、公序良俗及其他可能造成严重负面舆论的言论或行为,导致数字艺术品版权被屏蔽或者限制使用的,您应当自行与送拍方沟通解决。
+            </p>
+            <p>
+                六、“蚂蚁链”仅提供区块链技术服务,不参与作品拍卖的具体环节。
+                七、送拍方应保证本作品版权的合法性和唯一性。
+            </p>
+            <p>
+                八、为防止恶意竞拍扰乱市场秩序的行为,在您参加竞拍活动前,系统需要冻结一定金额的保证金。在竞拍结束后如未成功则自动解冻,无息返还至原支付账户。竞拍成功的用户竞拍结束后72小时内未支付尾款的,保证金将作为违约金不予返还。
+            </p>
+            <p>九、每个拍品每个用户仅限参与一次,名额不可转让、折现、出售。</p>
+            <p>
+                十、考虑到本次拍卖活动中的拍品具有区块链上唯一性的特征,同时鉴于参拍前已向您充分说明拍卖特性,因此拍品不提供退换货服务,请您务必充分评估并谨慎出价。
+            </p>
+            <p>
+                十一、买家理解并同意,鉴于网络服务的特殊性,我们对本服务持续提供可能受到多重因素影响,如出现技术升级、网路故障、经营策略调整、配合国家重大技术、法规政策变化,平台可能随时终止、中断提供服务或变更服务形式、规格或其他方面而无须承担责任。
+            </p>
+            <p>十二、如您想要通过竞拍方式购买数字艺术品,应当满足以下条件:</p>
+            <p>1)您已满18周岁未满60周岁,并具有中华人民共和国国籍。 2)您已通过实名制认证。</p>
+            <p>
+                您仅代表您个人而不属于任何组织或企业,您理解及确认我们有权依据国家法律法规、监管政策、活动规则或业务需要对上述条件进行补充或修改,您一旦参拍并购买商品,即表示您承诺符合以上条件并受到本协议及活动细则约束。
+            </p>
+            <p>生效日期:2022年4月25日</p>
+
+            <div class="botton-btn">
+                <van-button @click="show = false" type="primary" block round>知道了</van-button>
+            </div>
+        </div>
+    </van-action-sheet>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            show: false
+        };
+    }
+};
+</script>
+
+<style lang="less">
+.rule-box {
+    height: 100%;
+    max-height: 100%;
+}
+</style>
+<style lang="less" scoped>
+.page {
+    padding: 16px;
+    .bottom(80px);
+}
+h3 {
+    text-align: center;
+    font-size: 16px;
+    font-weight: bold;
+    color: #000000;
+    line-height: 22px;
+    margin: 16px 0 0;
+}
+h4 {
+    font-size: 14px;
+    color: #000000;
+    line-height: 20px;
+    margin: 12px 0 0;
+}
+p {
+    font-size: 14px;
+    color: #939599;
+    line-height: 22px;
+    margin: 5px 0 0;
+}
+p + h3 {
+    margin: 24px 0 0;
+}
+h3 + p {
+    margin: 12px 0 0;
+}
+p + p {
+    margin: 12px 0 0;
+}
+
+p {
+    span {
+        font-size: 12px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 16px;
+        width: 16px;
+        height: 16px;
+        display: inline-flex;
+        background-color: #939599;
+        text-align: center;
+        border-radius: 16px;
+        align-items: center;
+        justify-content: center;
+        margin-right: 6px;
+    }
+}
+
+.botton-btn {
+    position: fixed;
+    padding: 9px 48px;
+    background-color: #fff;
+    .bottom(9px);
+    border-top: 1px solid #f2f3f5;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+</style>

+ 3 - 3
src/components/level/Level.vue

@@ -56,9 +56,9 @@ export default {
     },
     mixins: [level],
     mounted() {
-        this.$nextTick(() => {
-            // document.body.appendChild(this.$refs.overLay);
-        });
+        // this.$nextTick(() => {
+        //     document.getElementById('app').appendChild(this.$refs.overLay);
+        // });
     },
     methods: {
         changeLevel(level) {

+ 465 - 0
src/components/order/OrderInfoAuction.vue

@@ -0,0 +1,465 @@
+<template>
+    <div class="orderInfo" @click="goDetail">
+        <div class="order-top">
+            <span>{{ info.contactName || info.minter }}</span>
+            <span class="status" :style="{ color: statusColor }">{{ status }}</span>
+        </div>
+
+        <div class="auction-info" :class="{ isEnd: isEnd }">
+            <van-image
+                :radius="8"
+                width="80"
+                height="80"
+                :src="getImg(changeImgs(info.pic || info.auctionPic, 600))"
+                fit="cover"
+            />
+            <div class="content">
+                <div class="text1 van-multi-ellipsis--l2">
+                    {{ info.name }}
+                </div>
+                <div class="text2">
+                    <div class="time" v-if="!isEnd">
+                        <img src="../../assets/info_icon_time.png" alt="" />
+                        <span>{{ timeText }}:<van-count-down :time="time" format="HH 小时 mm 分 ss 秒" /></span>
+                    </div>
+                    <div class="time" v-else>
+                        <img src="../../assets/info_icon_time1.png" alt="" />
+                        <span>{{ timeText }}</span>
+                    </div>
+                </div>
+
+                <div class="text3" v-if="type !== 'FIXED_PRICE'">
+                    <span class="text3-1">保证金</span>
+                    <div class="price">
+                        <!-- <img src="../../assets/icon_jiage_hei.png" alt="" /> -->
+                        <span>¥{{ info.deposit }}{{ deposit ? `(${deposit})` : '' }}</span>
+                    </div>
+                    <!-- <span class="text3-3">出价{{ info.bids }}次</span> -->
+                </div>
+            </div>
+        </div>
+        <div class="bottom">
+            <div class="tips">{{ showText }}: {{ info.createdAt || info.createdTime }}</div>
+            <div class="price">
+                <span class="text1">{{ payText }}</span>
+                <span class="text2" :style="{ color: priceColor }">¥{{ info.totalPrice || info.bidderPrice }}</span>
+            </div>
+        </div>
+        <!-- <div class="total-price">
+            <span class="time flex1">{{ info.payTime }}</span>
+            <span>实际支付</span>
+            <span>¥{{ info.gasPrice }}</span>
+        </div> -->
+    </div>
+</template>
+
+<script>
+import auctionOrder from '../../mixins/auctionOrder';
+import auction from '../../mixins/auction';
+import { mapState } from 'vuex';
+export default {
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        isOrder: {
+            type: Boolean,
+            default: false
+        }
+    },
+    data() {
+        return {
+            time: 0
+        };
+    },
+    mixins: [auctionOrder, auction],
+    computed: {
+        ...mapState(['userInfo']),
+        materials() {
+            if (!this.info.material) {
+                return [];
+            } else if (this.info.material.length < 4) {
+                return [...this.info.material] || [];
+            } else {
+                return [...this.info.material].slice(0, 2);
+            }
+        },
+        isLeader() {
+            return this.isLogin && this.info.actPurchasedId === this.userInfo.id;
+        },
+        isbidder() {
+            return this.info.auctionStatus == 'PURCHASED' && this.info.actPurchasedId === this.userInfo.id;
+        },
+        status() {
+            let status = this.getLabelName(this.info.orderStatus || this.info.orderStatus, this.orderStatusOptions);
+            if (!status) {
+                if (this.isbidder) {
+                    status = '竞价成功,去支付';
+                } else if (this.info.auctionStatus === 'PASS') {
+                    status = '已流局';
+                } else if (this.info.auctionStatus === 'ONGOING' && this.isLeader) {
+                    status = '竞价中';
+                } else if (this.info.auctionStatus === 'ONGOING' && !this.isLeader) {
+                    status = '已出局,重新叫价';
+                } else {
+                    status = '已结束';
+                }
+            }
+            return status;
+        },
+        statusColor() {
+            let color = '#3AB200';
+            if (this.isbidder) {
+                color = '#FF4F50';
+            } else if (
+                this.info.auctionStatus === 'ONGOING' &&
+                (this.info.purchaserId === this.userInfo.id || !this.info.purchaserId)
+            ) {
+                color = '#3AB200';
+            } else if (this.info.purchaserId) {
+                color = '#3AB200';
+            } else if (this.isPass) {
+                color = '#939599';
+            } else {
+                color = '#939599';
+            }
+
+            return color;
+        },
+        isEnd() {
+            if (this.info.auctionStatus !== 'NOTSTARTED' && this.info.auctionStatus !== 'ONGOING') {
+                return true;
+            }
+            return false;
+        },
+        payText() {
+            if (this.orderId || this.isOrder) {
+                return '实际支付';
+            } else if (this.info.auctionStatus === 'ONGOING') {
+                return '当前价';
+            } else {
+                return '成交价';
+            }
+        },
+        showText() {
+            if (this.orderId || this.isOrder) {
+                return '订单时间';
+            } else if (this.info.auctionStatus === 'ONGOING') {
+                return '出价时间';
+            } else {
+                return '结束时间';
+            }
+        },
+        isPass() {
+            if (this.info.auctionStatus === 'PASS' && this.info.purchaserId === this.userInfo.id) {
+                return true;
+            } else {
+                return false;
+            }
+        },
+        deposit() {
+            if (this.info.depositStatus === 'REFUNDED') {
+                return '已退';
+            } else if (this.isPass) {
+                return '不退';
+            } else {
+                return '';
+            }
+        },
+        priceColor() {
+            if (this.info.orderId || this.isOrder) {
+                return '#3AB200';
+            } else if (
+                this.info.auctionStatus === 'ONGOING' &&
+                this.info.purchaserId &&
+                this.info.purchaserId === this.userInfo.id
+            ) {
+                return '#F53809';
+            }
+            return '#939599';
+        },
+        type() {
+            return this.info.paymentType || this.info.type;
+        }
+    },
+    mounted() {
+        if (this.info.auctionStatus === 'ONGOING') {
+            this.time = this.getTime(this.info.endTime);
+        }
+    },
+    methods: {
+        delInit() {
+            this.$emit('delFn');
+        },
+        del() {
+            this.Dialog.confirm({
+                title: '确定删除吗?',
+                message: '删除此记录将消失'
+            }).then(() => {
+                this.$http
+                    .post('/order/hide/', {
+                        id: this.info.id
+                    })
+                    .then(() => {
+                        this.$toast.success('删除成功');
+                        setTimeout(() => {
+                            this.delInit();
+                        }, 1000);
+                    });
+            });
+            // this.$http
+            //     .post('/order/hide/', {
+            //         id: this.info.id
+            //     })
+            //     .then(() => {
+            //         this.$toast.success('删除成功');
+            //         setTimeout(() => {
+            //             this.delInit();
+            //         }, 1000);
+            //     });
+        },
+        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('取消收藏');
+                });
+            }
+        },
+        sure() {
+            this.$dialog
+                .confirm({
+                    title: '确定已经收到货了吗?'
+                })
+                .then(() => {
+                    return this.$http.get('/mintOrder/finish/' + this.info.id);
+                })
+                .then(() => {
+                    this.$toast.success('确认成功');
+                    this.$emit('update:info', {
+                        ...this.info,
+                        status: 'FINISH'
+                    });
+                });
+        },
+        goDetail() {
+            if (this.info.orderId || this.isOrder) {
+                this.$router.push({
+                    path: '/auctionOrderDetail',
+                    query: {
+                        id: this.isOrder ? this.info.id : this.info.orderId
+                    }
+                });
+            } else {
+                this.$router.push({
+                    path: '/auctionDetail',
+                    query: {
+                        id: this.info.auctionId
+                    }
+                });
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.orderInfo {
+    background: @bg;
+    border-radius: 12px;
+    color: @text0;
+    padding: 16px 10px 0;
+    margin: 20px 16px 0;
+    display: block;
+}
+.order-top {
+    display: flex;
+    justify-content: space-between;
+    padding-bottom: 10px;
+    span {
+        font-size: 14px;
+        color: @text0;
+        line-height: 22px;
+    }
+
+    .status {
+        color: @prim;
+    }
+}
+
+.order {
+    .flex();
+    .van-image {
+        margin-right: 10px;
+    }
+    position: relative;
+}
+
+.tips {
+    padding: 12px 0;
+    font-size: 12px;
+    color: #c8c9cc;
+    line-height: 24px;
+}
+
+.order-content {
+    position: absolute;
+    right: -8px;
+    top: 28px;
+    .flex();
+    font-size: 12px;
+    color: #c8c9cc;
+    line-height: 24px;
+    img {
+        width: 24px;
+        height: 24px;
+        transform: translateX(-2px);
+    }
+}
+
+.btns {
+    padding: 12px 0;
+    border-top: 1px solid @bg3;
+    .flex();
+    justify-content: flex-end;
+    .sure {
+        border: 1px solid @prim;
+    }
+}
+
+.auction-info {
+    border-radius: 8px;
+    overflow: hidden;
+    background-color: #fff;
+    display: inline-flex;
+    width: calc(100% - 16px);
+    margin: 8px;
+    align-items: stretch;
+    box-sizing: border-box;
+    color: #000;
+    .van-image {
+        flex-shrink: 0;
+    }
+
+    .content {
+        flex-grow: 1;
+        padding: 0 12px;
+        align-self: stretch;
+        .flex-col();
+        .text1 {
+            font-size: 14px;
+            font-weight: bold;
+        }
+
+        .text2 {
+            flex-grow: 1;
+            margin-top: 8px;
+
+            .time {
+                .flex();
+                height: 22px;
+                background: #fff7f2;
+                border-radius: 4px;
+                display: inline-flex;
+                padding: 0 4px;
+                img {
+                    width: 18px;
+                    height: 18px;
+                }
+                span {
+                    margin-left: 2px;
+                    .flex();
+                    font-size: 12px;
+                    color: #ff7f1f;
+                    line-height: 22px;
+                    .van-count-down {
+                        font-size: 12px;
+                        color: #ff7f1f;
+                        line-height: 22px;
+                    }
+                }
+            }
+        }
+        .text3 {
+            .flex();
+            .text3-1 {
+                font-size: 12px;
+                color: #c8c9cc;
+                line-height: 17px;
+            }
+            .price {
+                .flex();
+                margin-left: 10px;
+                img {
+                    width: 8px;
+                    height: 8px;
+                    margin-top: 4px;
+                }
+                span {
+                    font-size: 12px;
+                    color: #c8c9cc;
+                    line-height: 17px;
+                }
+
+                flex-grow: 1;
+                padding: 0 2px;
+            }
+
+            .text3-3 {
+                font-size: 10px;
+                color: #c8c9cc;
+                line-height: 10px;
+            }
+        }
+    }
+
+    &.isEnd {
+        .text2 {
+            .time {
+                background-color: #f2f4f5;
+                span {
+                    color: #939599;
+                }
+            }
+        }
+    }
+}
+
+.bottom {
+    .flex();
+    justify-content: space-between;
+
+    .price {
+        .text1 {
+            font-size: 14px;
+            font-weight: bold;
+            color: #000000;
+            line-height: 24px;
+        }
+
+        .text2 {
+            font-size: 16px;
+            font-weight: bold;
+            color: #939599;
+            line-height: 24px;
+            margin-left: 10px;
+        }
+    }
+}
+</style>

+ 3 - 0
src/main.js

@@ -27,6 +27,9 @@ import duration from 'dayjs/plugin/duration';
 import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
 import customParseFormat from 'dayjs/plugin/customParseFormat';
 import { Toast, Dialog } from 'vant';
+import smoothscroll from 'smoothscroll-polyfill';
+
+smoothscroll.polyfill();
 
 const appHeight = () => {
     const doc = document.documentElement;

+ 8 - 0
src/mixins/asset.js

@@ -29,6 +29,14 @@ export default {
                 {
                     label: '已销毁',
                     value: 'DESTROYED'
+                },
+                {
+                    label: '拍卖中',
+                    value: 'AUCTIONING'
+                },
+                {
+                    label: '已拍卖',
+                    value: 'AUCTIONED'
                 }
             ]
         };

+ 74 - 0
src/mixins/auction.js

@@ -0,0 +1,74 @@
+import imgInfo from './imgInfo';
+export default {
+    mixins: [imgInfo],
+    data() {
+        return {
+            auctionTypeOptions: [
+                { label: '虚拟藏品', value: 'NFT' },
+                { label: '实物', value: 'ENTITY' }
+            ],
+            statusOptions: [
+                { label: '未开始', value: 'NOTSTARTED' },
+                { label: '进行中', value: 'ONGOING' },
+                { label: '成交', value: 'PURCHASED' },
+                { label: '一口价成交', value: 'FIXED_PRICE_PURCHASED' },
+                { label: '流拍', value: 'PASS' },
+                { label: '完成', value: 'FINISH' }
+            ],
+            sourceOptions: [
+                { label: '官方拍卖', value: 'OFFICIAL' },
+                { label: '转让拍卖', value: 'TRANSFER' }
+            ]
+        };
+    },
+    computed: {
+        //是否数字藏品
+        isNFT() {
+            return this.info.auctionType === 'NFT';
+        },
+        timeText() {
+            if (this.info.status === 'NOTSTARTED') {
+                return '距开始';
+            } else if (this.info.status === 'ONGOING') {
+                return '距结束';
+            } else {
+                return '已结束';
+            }
+        },
+        //是否结束
+        isEnd() {
+            if (this.info.status !== 'NOTSTARTED' && this.info.status !== 'ONGOING') {
+                return true;
+            }
+            return false;
+        },
+        priceText() {
+            if (this.info.purchasePrice) {
+                return '当前价';
+            } else if (this.info.startingPrice) {
+                return '起拍价';
+            } else {
+                return '一口价';
+            }
+        },
+        showPrice() {
+            return this.info.purchasePrice || this.info.startingPrice || this.info.fixedPrice || 0;
+        },
+        isLeader() {
+            return this.isLogin && this.info.purchaserId === this.$store.state.userInfo.id;
+        },
+        isbidder() {
+            return this.isLeader && this.info.status === 'PURCHASED';
+        }
+    },
+    methods: {
+        getTime(endTime) {
+            console.log('2726');
+            let time = this.dayjs(endTime).diff(this.dayjs());
+            return time;
+        },
+        showTime(time) {
+            return this.dayjs(time, 'YYYY-MM-DD HH:mm:ss').format('MM-DD HH:mm:ss');
+        }
+    }
+};

+ 37 - 0
src/mixins/auctionOrder.js

@@ -0,0 +1,37 @@
+export default {
+    data() {
+        return {
+            typeOptions: [
+                { label: '默认', value: 'DEFAULT' },
+                { label: '盲盒', value: 'BLIND_BOX' },
+                { label: '拍卖', value: 'AUCTION' },
+                { label: '展厅', value: 'SHOWROOM' }
+            ],
+            sourceOptions: [
+                { label: '官方拍卖', value: 'OFFICIAL' },
+                { label: '转让拍卖', value: 'TRANSFER' }
+            ],
+            paymentTypeOptions: [
+                { label: '保证金', value: 'DEPOSIT' },
+                { label: '竞拍金', value: 'PURCHASE_PRICE', text: '你已竞价成功' },
+                { label: '一口价', value: 'FIXED_PRICE', text: '一口价支付' }
+            ],
+            orderStatusOptions: [
+                { label: '未支付', value: 'NOT_PAID' },
+                { label: '已支付,处理中', value: 'PROCESSING' },
+                { label: '已完成', value: 'FINISH' },
+                { label: '已取消', value: 'CANCELLED' },
+                { label: '退款中', value: 'REFUNDING' },
+                { label: '已退款', value: 'REFUNDED' },
+                { label: '待发货', value: 'DELIVERY' },
+                { label: '待收货', value: 'RECEIVE' },
+                { label: '待空投', value: 'AIR_DROP' }
+            ],
+            payMethodOptions: [
+                { label: '微信', value: 'WEIXIN' },
+                { label: '支付宝', value: 'ALIPAY' },
+                { label: '无GAS费', value: 'FREE' }
+            ]
+        };
+    }
+};

+ 7 - 1
src/mixins/common.js

@@ -181,7 +181,6 @@ export default {
             let info = list.find(item => {
                 return item.value === val;
             });
-
             return info ? info[key] : '';
         },
         scrollRefreash() {
@@ -226,6 +225,13 @@ export default {
         goWin(next) {
             window.location.href = next;
         },
+        getNum(num = 0) {
+            if (num < 10) {
+                return '0' + num;
+            } else {
+                return num;
+            }
+        },
         openScheme(url) {
             const a = document.createElement('a');
             a.href = url;

+ 17 - 0
src/mixins/imgInfo.js

@@ -0,0 +1,17 @@
+export default {
+    methods: {
+        changeImgs(list = []) {
+            // console.log(list);
+            return list.map(item => {
+                if (item.type === 'video/mp4') {
+                    return item.thumb;
+                } else {
+                    return item.url;
+                }
+            });
+        },
+        isVideo(info = {}) {
+            return info.type === 'video/mp4';
+        }
+    }
+};

+ 3 - 2
src/mixins/list.js

@@ -5,7 +5,8 @@ export default {
             loading: false,
             finished: false,
             page: 0,
-            totalElements: 0
+            totalElements: 0,
+            size: 20
         };
     },
     methods: {
@@ -19,7 +20,7 @@ export default {
             this.loading = true;
             this.finished = false;
             this.empty = false;
-            let data = { page: this.page, size: 20, sort: 'createdAt,desc' };
+            let data = { page: this.page, size: this.size, sort: 'createdAt,desc' };
             if (this.beforeData) {
                 data = {
                     ...data,

+ 2 - 0
src/mixins/product.js

@@ -1,5 +1,6 @@
 import { abs } from 'mathjs';
 import { mapState } from 'vuex';
+import imgInfo from './imgInfo';
 export default {
     data() {
         return {
@@ -44,6 +45,7 @@ export default {
             saleTime: ''
         };
     },
+    mixins: [imgInfo],
     computed: {
         ...mapState(['usedBuy']),
         bannerList() {

+ 1 - 1
src/plugins/colors.js

@@ -19,7 +19,7 @@ export default {
             };
         }
         if (process.env.NODE_ENV == 'development') {
-            app.config.globalProperties.$rating = 1000;
+            app.config.globalProperties.$rating = 10;
         } else {
             app.config.globalProperties.$rating = 1000;
         }

+ 79 - 0
src/router/index.js

@@ -372,6 +372,60 @@ const routes = [
             tabColor: '#222426'
         }
     },
+    {
+        path: '/auction',
+        name: 'auction',
+        component: () => import('../views/auction/Home.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
+    {
+        path: '/auctionDetail',
+        name: 'auctionDetail',
+        component: () => import('../views/auction/Detail.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
+    {
+        path: '/auctionList',
+        name: 'auctionList',
+        component: () => import('../views/auction/List.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
+    {
+        path: '/auctionSearch',
+        name: 'auctionSearch',
+        component: () => import('../views/auction/Search.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
+    {
+        path: '/auctionOffer',
+        name: 'auctionOffer',
+        component: () => import('../views/auction/Offer.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
+    {
+        path: '/auctionSubmit',
+        name: 'auctionSubmit',
+        component: () => import('../views/auction/Submit.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '拍卖'
+        }
+    },
     {
         path: '/productSearch',
         name: 'productSearch',
@@ -431,6 +485,15 @@ const routes = [
             pageType: Page.Every
         }
     },
+    {
+        path: '/auctionPublish',
+        name: 'auctionPublish',
+        component: () => import('../views/asset/AuctionPublish.vue'),
+        meta: {
+            pageType: Page.Every,
+            title: '第九空间'
+        }
+    },
     {
         path: '/consignmentAgreement',
         name: 'consignmentAgreement',
@@ -493,6 +556,22 @@ const routes = [
         component: () => import('../views/order/ActivityDetail.vue'),
         meta: {}
     },
+    {
+        path: '/auctionOrders',
+        name: 'auctionOrders',
+        component: () => import('../views/order/AuctionOrders.vue'),
+        meta: {
+            title: '第九空间'
+        }
+    },
+    {
+        path: '/auctionOrderDetail',
+        name: 'auctionOrderDetail',
+        component: () => import('../views/order/AuctionDetail.vue'),
+        meta: {
+            title: '第九空间'
+        }
+    },
     {
         path: '/activityList',
         name: 'activityList',

+ 8 - 0
src/styles/app.less

@@ -280,3 +280,11 @@ input:-webkit-autofill {
         height: 2px;
     }
 }
+
+.van-action-sheet {
+    .van-action-sheet__header {
+        border-bottom: 1px solid #f2f4f5;
+        text-align: left;
+        padding: 0 16px;
+    }
+}

+ 4 - 0
src/styles/common/common.less

@@ -192,6 +192,10 @@
     padding-bottom: calc(@height + constant(safe-area-inset-bottom));
     padding-bottom: calc(@height + env(safe-area-inset-bottom));
 }
+.fixedBottom(@height:0px) {
+    bottom: calc(@height + constant(safe-area-inset-bottom));
+    bottom: calc(@height + env(safe-area-inset-bottom));
+}
 @keyframes zoomOutUp {
     40% {
         -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);

+ 30 - 25
src/styles/font.less

@@ -1,53 +1,58 @@
 @font-face {
-  font-family: 'ZhenyanGB';
-  src: url(https://cdn.raex.vip/font/RuiZiZhenYanTiMianFeiShangYong-2.ttf);
+    font-family: 'ZhenyanGB';
+    src: url(https://zhirongip.oss-cn-hangzhou.aliyuncs.com/fonts/RuiZiZhenYanTiMianFeiShangYong-2.ttf);
 }
 
 @font-face {
-  font-family: 'OSP';
-  src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
+    font-family: 'OSP';
+    src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
 }
 
 @font-face {
-  font-family: 'DIN';
-  src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
+    font-family: 'DIN';
+    src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
 }
 @font-face {
-  font-family: 'SourceHanSans-Medium';
-  src: url(https://cdn.raex.vip/font/SourceHanSans-Medium.otf);
+    font-family: 'SourceHanSans-Medium';
+    src: url(https://cdn.raex.vip/font/SourceHanSans-Medium.otf);
 }
 
-
 @font-face {
-  font-family: 'font_family'; /* Project id 2852142 */
-  src: url('https://at.alicdn.com/t/font_2852142_ucu46yrsoc.woff2?t=1633658351572')
-      format('woff2'),
-    url('https://at.alicdn.com/t/font_2852142_ucu46yrsoc.woff?t=1633658351572')
-      format('woff'),
-    url('https://at.alicdn.com/t/font_2852142_ucu46yrsoc.ttf?t=1633658351572')
-      format('truetype');
+    font-family: 'font_family'; /* Project id 2852142 */
+    src: url('//at.alicdn.com/t/font_2852142_166h0go2986.woff2?t=1651218758575') format('woff2'),
+        url('//at.alicdn.com/t/font_2852142_166h0go2986.woff?t=1651218758575') format('woff'),
+        url('//at.alicdn.com/t/font_2852142_166h0go2986.ttf?t=1651218758575') format('truetype');
 }
 
 .font_family {
-  font-family: 'font_family' !important;
-  font-size: 16px;
-  font-style: normal;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
+    font-family: 'font_family' !important;
+    font-size: 16px;
+    font-style: normal;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-help::before {
+    content: '\e752';
+}
+
+.icon-sanjiao::before {
+    content: '\e63f';
+    display: block;
 }
 
 .icon-a-icon-dianzan5:before {
-  content: '\e634';
+    content: '\e634';
 }
 
 .icon-icon_inter:before {
-  content: '\e631';
+    content: '\e631';
 }
 
 .icon-icon_jiage:before {
-  content: '\e632';
+    content: '\e632';
 }
 
 .icon-a-icon-dianzan2:before {
-  content: '\e633';
+    content: '\e633';
 }

BIN=BIN
src/views/._.DS_Store


+ 74 - 10
src/views/Mine.vue

@@ -116,27 +116,29 @@
         <driver />
         <div class="orderList">
             <div class="order-info" @click="$router.push('/orders?type=DEFAULT')">
-                <div class="order-info-box">
-                    <img src="@assets/info_icon_yishuping.png" alt="" />
-                    <span>艺术品订单</span>
-                </div>
+                <img src="@assets/info_icon_yishuping.png" alt="" />
+                <span>艺术品订单</span>
             </div>
             <div class="order-info" @click="$router.push('/activityOrders')">
                 <img src="@assets/info_icon_zhuzaodingdan.png" alt="" />
                 <span>铸造订单</span>
             </div>
+            <div class="order-info" @click="$router.push('/auctionOrders')">
+                <img src="@assets/info_icon_paimaidingdan.png" alt="" />
+                <span>拍卖订单</span>
+            </div>
         </div>
         <driver />
         <div class="orderList prim">
             <div
-                class="order-info"
+                class="menu-info"
                 :style="{ width: $store.state.review ? '100%' : '50%' }"
                 @click="$router.push('/rank')"
             >
                 <img src="@assets/info_icon_top50.png" alt="" />
                 <span>TOP50&nbsp;探索官</span>
             </div>
-            <div class="order-info" @click="share" v-if="!$store.state.review">
+            <div class="menu-info" @click="share" v-if="!$store.state.review">
                 <van-badge :dot="shareProduct.openQuota" :offset="[-15, 5]">
                     <img src="@assets/info_icon_yaoqing.png" alt="" />
                 </van-badge>
@@ -434,6 +436,67 @@ export default {
     .flex();
     // padding: 0 12px;
     .order-info {
+        padding: 16px 0;
+        position: relative;
+        width: 33%;
+        box-sizing: border-box;
+        .flex-col();
+        align-items: center;
+        justify-content: center;
+
+        .order-info-box {
+            .flex();
+            width: 132px;
+        }
+        img {
+            width: 28px;
+            height: 28px;
+            // margin-right: 8px;
+        }
+        span {
+            font-size: 14px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 24px;
+            margin-top: 4px;
+        }
+
+        &:active {
+            // background-color: @bg2;
+        }
+    }
+    .order-info + .order-info {
+        // margin-left: 20px;
+        &::before {
+            content: '';
+            width: 1px;
+            background-color: #373b3e;
+            position: absolute;
+            left: -0.5px;
+            top: 0;
+            bottom: 0;
+        }
+    }
+
+    // /deep/.van-badge__wrapper {
+    //     width: 50%;
+    //     .order-info {
+    //         width: 100%;
+    //     }
+    // }
+
+    &.prim {
+        span {
+            font-weight: normal;
+            color: #43ce00;
+            font-family: 'ZhenyanGB';
+        }
+    }
+}
+.orderList {
+    .flex();
+    // padding: 0 12px;
+    .menu-info {
         padding: 16px 0;
         position: relative;
         width: 50%;
@@ -441,13 +504,13 @@ export default {
         .flex();
         justify-content: center;
 
-        .order-info-box {
+        .menu-info-box {
             .flex();
             width: 132px;
         }
         img {
-            width: 32px;
-            height: 32px;
+            width: 28px;
+            height: 28px;
             margin-right: 8px;
         }
         span {
@@ -461,7 +524,7 @@ export default {
             // background-color: @bg2;
         }
     }
-    .order-info + .order-info {
+    .menu-info + .menu-info {
         // margin-left: 20px;
         &::before {
             content: '';
@@ -631,6 +694,7 @@ export default {
     .van-image {
         // border: 5px solid @bg;
         flex-shrink: 0;
+        border-radius: 100px;
     }
 
     /deep/.van-image {

+ 22 - 9
src/views/Store.vue

@@ -175,6 +175,11 @@ export default {
                             value: '',
                             type: ''
                         },
+                        {
+                            label: '拍卖中',
+                            value: 'paimai',
+                            type: ''
+                        },
                         {
                             label: '寄售',
                             value: 'ON_SALE',
@@ -226,8 +231,13 @@ export default {
             } else if (this.active === 'creator') {
                 return [
                     {
-                        label: '全部',
-                        value: 'createdAt,desc',
+                        label: '市场交易',
+                        value: 'TRANSFERRED',
+                        type: ''
+                    },
+                    {
+                        label: '拍卖',
+                        value: 'AUCTIONED',
                         type: ''
                     }
                     // {
@@ -274,17 +284,17 @@ export default {
             }
         },
         sort() {
-            if (this.active === 'creator') {
-                return this.type;
-            } else {
-                return 'createdAt,desc';
-            }
+            return 'createdAt,desc';
         },
         status() {
             if (this.active === 'explore') {
-                return 'NORMAL,TRADING,GIFTING,MINTING';
+                if (this.type === 'paimai') {
+                    return 'AUCTIONING';
+                } else {
+                    return 'NORMAL,TRADING,GIFTING,MINTING,AUCTIONING';
+                }
             } else if (this.active === 'creator') {
-                return 'TRANSFERRED';
+                return this.type || 'TRANSFERRED';
             } else {
                 return '';
             }
@@ -519,6 +529,9 @@ export default {
 }
 .van-tabs {
     background-color: #222426;
+    /deep/.van-tab {
+        margin-right: 30px;
+    }
 }
 .select {
     position: absolute;

BIN=BIN
src/views/asset/._.DS_Store


+ 612 - 0
src/views/asset/AuctionPublish.vue

@@ -0,0 +1,612 @@
+<template>
+    <div class="top">
+        <div class="top-content">
+            <div class="title">拍卖说明</div>
+            <div class="name" v-for="(item, index) in list" :key="index">
+                <span>{{ item.title }}</span>
+                <span class="prim">{{ item.sub }}</span>
+                <span>{{ item.text1 }}</span>
+            </div>
+            <div class="border border1"></div>
+            <div class="box-content">
+                <div class="title">请选择拍卖模式</div>
+                <div class="box-select">
+                    <div class="select-item prim" @click="warning">
+                        <span>一口价模式</span>
+                        <img src="../../assets/icon_gouxuan_pre.png" alt="" />
+                    </div>
+                    <div class="select-item" @click="showStarting = !showStarting" :class="{ prim: showStarting }">
+                        <span>竞拍模式</span>
+                        <img v-if="showStarting" src="../../assets/icon_gouxuan_pre.png" alt="" />
+                        <img v-else src="../../assets/icon_gouxuan_huise.png" alt="" />
+                    </div>
+                </div>
+            </div>
+            <div>
+                <div class="box">
+                    <div class="content">
+                        <div class="title">一口价模式(元)<span>最高定价20000.00</span></div>
+                        <!-- <van-field type="number" input-align="center" placeholder="请输入价格" v-model="price" /> -->
+                        <van-stepper
+                            v-model="price"
+                            :default-value="''"
+                            :show-plus="false"
+                            :show-minus="false"
+                            :decimal-length="2"
+                            allow-empty
+                            min="0"
+                            max="20000"
+                            placeholder="请输入价格"
+                            @change="agreement = false"
+                        />
+                        <div class="title">预计收入(元)</div>
+                        <div class="info-item">
+                            <span>寄售定价</span>
+                            <span class="val">{{ price1 }}</span>
+                        </div>
+                        <div class="info-item">
+                            <span>版税({{ info.royalties || 0 }}%)</span>
+                            <span class="val">{{ price2 }}</span>
+                        </div>
+                        <div class="info-item">
+                            <span>技术服务费(4%) </span>
+                            <span class="val">{{ price3 }}</span>
+                        </div>
+                        <div class="info-item">
+                            <span>支付通道费(1%)</span>
+                            <span class="val">{{ price4 }}</span>
+                        </div>
+                        <div class="info-item">
+                            <span>最终收入</span>
+                            <span class="val prim">{{ price5 }}</span>
+                        </div>
+                    </div>
+                </div>
+                <div class="box" v-if="showStarting">
+                    <div class="content">
+                        <div class="title">竞拍模式(元)<span>最高定价20000.00</span></div>
+                        <!-- <van-field type="number" input-align="center" placeholder="请输入价格" v-model="price" /> -->
+                        <van-stepper
+                            v-model="startingPrice"
+                            :default-value="''"
+                            :show-plus="false"
+                            :show-minus="false"
+                            :decimal-length="2"
+                            allow-empty
+                            min="0"
+                            max="20000"
+                            placeholder="请输入起拍价"
+                            @change="agreement = false"
+                        />
+                        <div class="title">竞拍说明</div>
+                        <div class="info-item">
+                            <span>拍卖类型</span>
+                            <span class="val">增价拍</span>
+                        </div>
+                        <div class="info-item">
+                            <span>加价幅度</span>
+                            <!-- <span class="val">¥100</span> -->
+                            <van-field class="val" type="number" input-align="right" v-model="increment" />
+                        </div>
+                        <div class="info-item">
+                            <span>保证金</span>
+                            <!-- <span class="val">¥100</span> -->
+                            <van-field class="val" type="number" input-align="right" v-model="deposit" />
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="border"></div>
+            <div class="input">
+                <div class="text1">请输入交易密码</div>
+                <div v-if="sets">
+                    <van-password-input :gutter="10" :value="password" :focused="showKeyboard" @focus="keyboardEnter" />
+                    <van-number-keyboard
+                        v-model="password"
+                        :show="showKeyboard"
+                        @blur="keyBlur"
+                        :gutter="10"
+                        maxlength="6"
+                        theme="custom"
+                        close-button-text="完成"
+                        random-key-order
+                    />
+                    <div class="text2-content">
+                        <div class="text2" @click="goRouter">忘记密码?</div>
+                    </div>
+                </div>
+                <div v-else class="text3" @click="$router.push('/tradingPassword')">您当前没有交易密码,点击去设置</div>
+            </div>
+        </div>
+        <div class="bottom van-safe-area-bottom" ref="bottom">
+            <van-notice-bar
+                :color="$colors.prim"
+                :background="$colors.prim"
+                text="出售成功的数字藏品将会携带数字藏品的所有信息转让于购买方,包括但不限于:权益的使用、数字藏品的区块信息等"
+            />
+            <div class="bottom-content">
+                <div class="btn1" @click="$router.go(-1)">取消</div>
+                <div class="btn2" @click="submit">确认拍卖</div>
+            </div>
+        </div>
+        <div class="border"></div>
+        <agreement ref="agree" :info="info" @agree="agree"></agreement>
+    </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import Agreement from './Agreement.vue';
+export default {
+    components: { Agreement },
+    name: 'Top',
+    inject: ['changeScroll'],
+    data() {
+        return {
+            price: '',
+            startingPrice: '',
+            showStarting: false,
+            showKeyboard: false,
+            password: '',
+            sets: false,
+            list: [
+                {
+                    title: '1. 拍卖时间默认为5天',
+                    sub: '(期间不可下架,修改)'
+                },
+                {
+                    title: '2 拍卖价格为单个作品价格'
+                },
+                {
+                    title: '3. 用户将会看到数字权益的使用情况'
+                },
+                {
+                    title: '4. 交易成功后数字藏品的点赞数量,拍卖纪录将会被清除'
+                },
+                {
+                    title: '5. 平台会收取作品出售价格的',
+                    sub: ' 5% ',
+                    text1: '作为服务费'
+                },
+                {
+                    title: '6. 因电子支付通道限制,单笔限额20000元'
+                }
+            ],
+            info: {},
+            agreement: false,
+            deposit: 0,
+            increment: 0
+        };
+    },
+    computed: {
+        ...mapState(['userInfo']),
+        price1() {
+            let price = Math.floor(this.price * 100) / 100;
+            return price.toFixed(2);
+        },
+        price2() {
+            let price = Math.floor(this.price * (this.info.royalties || 0)) / 100;
+            return price.toFixed(2);
+        },
+        price3() {
+            let price = Math.floor(this.price * 4) / 100;
+            return price.toFixed(2);
+        },
+        price4() {
+            let price = Math.floor(this.price * 1) / 100;
+            return price.toFixed(2);
+        },
+        price5() {
+            let price = Math.floor(this.price * (95 - (this.info.royalties || 0))) / 100;
+            return price.toFixed(2);
+        }
+    },
+    mounted() {
+        this.$http.get('sysConfig/get/deposit').then(res => {
+            this.deposit = res.value;
+        });
+        this.$http.get('sysConfig/get/increment').then(res => {
+            this.increment = res.value;
+        });
+        this.passFn();
+        this.$http.get('/asset/get/' + this.$route.query.id).then(res => {
+            this.info = res;
+        });
+    },
+    methods: {
+        keyboardEnter() {
+            this.changeScroll(1000);
+            this.showKeyboard = true;
+        },
+        passFn() {
+            this.$http
+                .get('/user/tradeCodeStatus', {
+                    userId: this.userInfo.id
+                })
+                .then(res => {
+                    console.log(res);
+                    this.sets = res.set;
+                });
+        },
+        agree() {
+            this.agreement = true;
+            this.submit();
+        },
+        submit() {
+            if (this.showStarting && !Number(this.startingPrice)) {
+                this.$toast('请输入起拍价');
+                return;
+            }
+            if (Number(this.price)) {
+                this.$dialog
+                    .confirm({
+                        title: '寄售',
+                        message: `商品将以<span style='color:#ff4f50;font-weight:bold;font-size:18px;margin:0 5px'>${this.price}</span>的价格上架`,
+                        allowHtml: true
+                    })
+                    .then(() => {
+                        this.$toast.loading({
+                            message: '加载中...',
+                            forbidClick: true
+                        });
+                        return this.$http.post(
+                            '/auctionActivity/create',
+                            {
+                                assetId: this.$route.query.id,
+                                startingPrice: this.startingPrice,
+                                deposit: this.deposit,
+                                fixedPrice: this.price,
+                                startTime: this.dayjs().format('YYYY-MM-DD HH:mm:ss'),
+                                increment: this.increment,
+                                endTime: this.dayjs().add(5, 'days').format('YYYY-MM-DD HH:mm:ss'),
+                                tradeCode: this.password
+                            },
+                            { body: 'json' }
+                        );
+                    })
+                    .catch(e => {
+                        if (e.error) {
+                            this.$toast(e.error || '出现错误,请稍后再试');
+                        }
+                        return Promise.reject('cancel');
+                    })
+                    .then(res => {
+                        this.$toast.success('寄售成功');
+                        setTimeout(() => {
+                            this.$router.go(-1);
+                        }, 1000);
+                    })
+                    .catch(e => {
+                        if (e && e.error) {
+                            this.$toast(e.error);
+                        }
+                    });
+            } else {
+                this.$toast('请输入一口价');
+            }
+        },
+        goRouter() {
+            if (!this.showKeyboard) {
+                this.$router.push('/tradingPassword');
+            }
+        },
+        keyBlur() {
+            setTimeout(() => {
+                this.showKeyboard = false;
+            }, 100);
+        },
+        warning() {
+            this.$dialog.alert({
+                title: '提示',
+                message: '一口价模式为必选项,不可取消'
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+/deep/ .van-notice-bar {
+    background: rgba(255, 108, 0, 0.1) !important;
+}
+/deep/ .van-password-input {
+    margin: 0 0;
+    .van-password-input__security {
+        border: 1px solid @text3;
+        height: 42px;
+        border-radius: 2px;
+        li {
+            background-color: transparent;
+            &:not(:last-child) {
+                border-right: 1px solid @text3;
+            }
+            i {
+                // background-color: #fff;
+            }
+        }
+    }
+}
+/deep/.van-number-keyboard__body {
+    background-color: fade(#4a4a4a, 50%);
+    .van-key {
+        background-color: @bg;
+        &:active {
+            background-color: @bg3;
+        }
+    }
+}
+
+.input {
+    padding: 12px 0 20px;
+    .text1 {
+        font-size: @font2;
+        color: @text0;
+        line-height: 24px;
+        margin-bottom: 6px;
+    }
+}
+.top-content {
+    background-color: @bg;
+    padding-top: 10px;
+}
+.top {
+    background-color: @bg3;
+    /deep/ .van-password-input {
+        margin: 10px 0;
+        padding: 0 25px;
+        .van-password-input__security {
+            border-width: 0;
+            height: 42px;
+            border-radius: 2px;
+            li {
+                background-color: transparent;
+                &:not(:last-child) {
+                    border-right: 1px solid @text3;
+                }
+                border: 1px solid @text3;
+                i {
+                    // background-color: #fff;
+                }
+            }
+        }
+    }
+    /deep/ .van-cell {
+        padding-top: 20px;
+    }
+    /deep/.van-cell__title {
+        font-size: @font2;
+        font-weight: bold;
+        color: @text0;
+        line-height: 24px;
+    }
+    // background-color: @bg3;;
+    padding-bottom: 280px;
+    .title {
+        font-size: 14px;
+        color: @text0;
+        // line-height: 30px;
+        margin-top: 5px;
+        padding: 5px 16px 5px;
+        font-weight: bold;
+    }
+    .name {
+        padding-left: 16px;
+        span {
+            font-size: 12px;
+            font-weight: 400;
+            color: @text3;
+            line-height: 22px;
+
+            &.prim {
+                color: @prim;
+            }
+        }
+    }
+    .bottom {
+        position: fixed;
+        bottom: 0px;
+        left: 0;
+        right: 0;
+        background-color: @bg;
+        z-index: 20;
+        border-top: 1px solid @tabBorder;
+
+        .bottom-content {
+            padding: 6px 16px;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            .btn1 {
+                width: calc(50% - 10px);
+                height: 44px;
+                border-radius: 22px;
+                line-height: 44px;
+                color: @text3;
+                text-align: center;
+                border: 1px solid @text3;
+            }
+            .btn2 {
+                width: calc(50% - 10px);
+                height: 44px;
+                line-height: 44px;
+                text-align: center;
+
+                color: @btnText;
+                background: linear-gradient(135deg, @prim 0%, @warn 100%);
+                border-radius: 22px;
+            }
+            .van-button {
+                flex-grow: 1;
+                color: #333230 !important;
+                max-width: 210px;
+            }
+            .text {
+                font-size: @font2;
+                color: @text3;
+                line-height: 20px;
+                word-break: keep-all;
+            }
+        }
+    }
+    .border {
+        // width: 375px;
+        height: 5px;
+        background: @bg3;
+        &.border1 {
+            margin-top: 20px;
+        }
+    }
+    .box {
+        background-color: @bg;
+        padding: 16px 16px 0;
+        border-radius: 4px;
+        &:last-child {
+            padding-bottom: 16px;
+        }
+    }
+    .content {
+        // width: 375px;
+        background: @bg3;
+        padding-bottom: 12px;
+
+        .title {
+            padding-top: 16px;
+            .flex();
+            justify-content: space-between;
+            span {
+                font-size: 12px;
+                color: #ff4f50;
+                font-weight: normal;
+            }
+        }
+
+        .van-cell {
+            padding: 0 16px 0px;
+            margin: 10px 0 0;
+
+            /deep/.van-cell__value {
+                background-color: @bg;
+                padding: 8px;
+            }
+        }
+
+        .info-item {
+            padding: 0 16px;
+            .flex();
+            justify-content: space-between;
+            font-size: 12px;
+            color: #939599;
+            line-height: 24px;
+
+            .val {
+                border: 1px solid #f5f7fa;
+                box-sizing: border-box;
+                text-align: center;
+                min-width: 72px;
+                display: inline-block;
+                max-width: 50%;
+
+                &.prim {
+                    color: @prim;
+                }
+
+                &.van-field {
+                    background-color: transparent;
+                    padding: 0 0;
+                    margin: 0 0;
+                    height: 30px;
+
+                    /deep/.van-cell__value {
+                        background-color: transparent;
+                        padding: 0 16px;
+                    }
+                }
+            }
+        }
+    }
+    .input {
+        // margin-top: 20px;
+        width: 100%;
+        .text1 {
+            font-size: @font2;
+            color: @text0;
+            line-height: 24px;
+            margin-bottom: 6px;
+            padding: 0 16px;
+        }
+        .text2 {
+            font-size: @font2;
+            text-align: right;
+            font-weight: 400;
+            color: @text3;
+            line-height: 24px;
+            margin-right: 15px;
+        }
+        .text3 {
+            font-size: @font2;
+            color: #ff4f50;
+            line-height: 24px;
+            margin-top: 25px;
+            display: flex;
+            justify-content: center;
+        }
+    }
+}
+.text2-content {
+    .flex();
+    justify-content: flex-end;
+}
+/deep/.van-stepper {
+    padding: 10px 16px;
+    width: 100%;
+    box-sizing: border-box;
+    .van-stepper__input {
+        width: 100%;
+        height: 40px;
+        margin: 0 0;
+        background-color: @bg;
+    }
+}
+
+.van-notice-bar {
+    font-size: 12px;
+    height: 36px;
+    line-height: 36px;
+    background: fade(@prim, 10%) !important;
+}
+
+.box-select {
+    .flex();
+    padding: 10px 16px 0;
+    justify-content: space-between;
+    .select-item {
+        width: calc(50% - 10px);
+        .flex();
+        img {
+            width: 24px;
+            height: 24px;
+            margin-left: 4px;
+        }
+        height: 38px;
+        background: #f5f7fa;
+        border-radius: 2px;
+        border: 1px solid #c8c9cc;
+        justify-content: center;
+        span {
+            font-size: 14px;
+            color: #939599;
+            line-height: 24px;
+        }
+
+        &.prim {
+            span {
+                color: @prim;
+                font-weight: bold;
+            }
+            border-color: @prim;
+            background: rgba(58, 178, 0, 0.04);
+        }
+    }
+}
+</style>

+ 257 - 160
src/views/asset/Detail.vue

@@ -240,10 +240,10 @@
         </div> -->
         <div class="btn van-safe-area-bottom" ref="btn" v-if="info.status === 'NORMAL'">
             <div class="btns1">
-                <div class="add" @click="Add">
+                <!-- <div class="add" @click="Add">
                     <img class="img" src="@assets/icon-dianzan.png" alt="" />
                     <div class="text2">赠送</div>
-                </div>
+                </div> -->
                 <van-button
                     v-if="!$store.state.reviewPay"
                     class="btn1"
@@ -258,85 +258,89 @@
                     <div>寄售倒计时</div>
                     <div>{{ startTime }}</div>
                 </van-button>
-
-                <van-button type="primary" v-else-if="!$store.state.reviewPay" block round @click="Consignment">
-                    <!-- <div>
-                        {{ startTime }}
-                    </div> -->
-                    {{ info.consignment ? '取消寄售' : '寄售上架' }}
+                <van-button color="#FF7F1F" v-else-if="!$store.state.reviewPay" block round @click="showAction = true">
+                    流转操作
+                    <!-- {{ info.consignment ? '取消寄售' : '寄售上架' }} -->
                 </van-button>
+                <!-- <van-button type="primary" v-else-if="!$store.state.reviewPay" block round @click="Consignment">
+                    {{ info.consignment ? '取消寄售' : '寄售上架' }}
+                </van-button> -->
             </div>
         </div>
         <div
             class="btn van-safe-area-bottom"
             ref="btn"
-            v-else-if="info.status === 'TRADING' || info.status === 'GIFTING'"
+            v-else-if="info.status === 'TRADING' || info.status === 'GIFTING' || info.status === 'AUCTIONING'"
         >
             <div class="status-text">{{ getLabelName(info.status, assetStatusOptions) }}</div>
         </div>
-        <van-popup v-model:show="show">
-            <div class="title2">
-                <div class="top">
-                    <img class="img" v-if="list2.icon[1]" :src="list2.icon[1]" alt="" />
-                    <img class="img" v-else :src="list2.icon[0]" alt="" />
-                    <div class="title3">{{ list2.name }}</div>
+        <div class="popup">
+            <van-popup v-model:show="show">
+                <div class="title2">
+                    <div class="top">
+                        <img class="img" v-if="list2.icon[1]" :src="list2.icon[1]" alt="" />
+                        <img class="img" v-else :src="list2.icon[0]" alt="" />
+                        <div class="title3">{{ list2.name }}</div>
+                    </div>
+                    <img @click="allFn" class="icon" :src="require('@assets/icon-dianzan.png')" alt="" />
                 </div>
-                <img @click="allFn" class="icon" :src="require('@assets/icon-dianzan.png')" alt="" />
-            </div>
-            <div class="border"></div>
-            <div class="name">{{ list2.description }}</div>
-            <div class="name1" v-if="list2.type === 'text'">
-                <!-- <div>{{ list2.detail }}</div> -->
-                <span>{{ list2.detail || '暂无' }}</span>
-            </div>
-            <div class="name1" v-if="list2.type === 'exchange'">
-                <span>{{ list2.detail }}</span>
-            </div>
-            <div class="name1" v-if="list2.type == 'qrcode'">
-                <img class="qrcodeImg" :src="list2.detail" alt="" />
-                <div class="qrcode1">扫描二维码进行票务核销</div>
-                <span>{{ list2.remark || '暂无' }}</span>
-            </div>
-            <div v-if="list2.type === 'code'">
-                <div class="copy">
-                    <div class="id">
-                        <!-- {{ list2.detail }} -->
-                        yshsbn
+                <div class="border"></div>
+                <div class="name">{{ list2.description }}</div>
+                <div class="name1" v-if="list2.type === 'text'">
+                    <!-- <div>{{ list2.detail }}</div> -->
+                    <span>{{ list2.detail || '暂无' }}</span>
+                </div>
+                <div class="name1" v-if="list2.type === 'exchange'">
+                    <span>{{ list2.detail }}</span>
+                </div>
+                <div class="name1" v-if="list2.type == 'qrcode'">
+                    <img class="qrcodeImg" :src="list2.detail" alt="" />
+                    <div class="qrcode1">扫描二维码进行票务核销</div>
+                    <span>{{ list2.remark || '暂无' }}</span>
+                </div>
+                <div v-if="list2.type === 'code'">
+                    <div class="copy">
+                        <div class="id">
+                            <!-- {{ list2.detail }} -->
+                            yshsbn
+                        </div>
+                        <img class="copyImg" @click="copy" src="@assets/svgs/copy_icon.svg" alt="" />
                     </div>
-                    <img class="copyImg" @click="copy" src="@assets/svgs/copy_icon.svg" alt="" />
+                    <span class="span">说明:</span> <span>{{ list2.remark || '暂无' }}</span>
+                    <div class="border"></div>
+                    <div class="code">每次交易都会产生校验码</div>
+                </div>
+                <div v-if="list2.openTime">
+                    <div v-if="list2.type == 'qrcode'" class="timename">
+                        <span class="time">截止时间:</span>{{ list2.openTime }}
+                    </div>
+                    <div v-else class="timename"><span class="time">打开时间:</span>{{ list2.openTime }}</div>
+                </div>
+            </van-popup>
+            <!-- 悄悄话 -->
+            <van-popup v-model:show="show3">
+                <div class="title2">
+                    <div class="top">
+                        <img class="img" :src="init2.icon[1]" alt="" />
+                        <div class="title3">{{ init2.name }}</div>
+                    </div>
+                    <img
+                        @click="allFn2"
+                        class="icon"
+                        src="https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/image/2021-11-13-13-52-01rJiHiwBy.png"
+                        alt=""
+                    />
                 </div>
-                <span class="span">说明:</span> <span>{{ list2.remark || '暂无' }}</span>
                 <div class="border"></div>
-                <div class="code">每次交易都会产生校验码</div>
-            </div>
-            <div v-if="list2.openTime">
-                <div v-if="list2.type == 'qrcode'" class="timename">
-                    <span class="time">截止时间:</span>{{ list2.openTime }}
+                <div class="name">{{ init2.description }}</div>
+                <div class="name1">
+                    <span>{{ init2.detail || '暂无' }}</span>
                 </div>
-                <div v-else class="timename"><span class="time">打开时间:</span>{{ list2.openTime }}</div>
-            </div>
-        </van-popup>
-        <!-- 悄悄话 -->
-        <van-popup v-model:show="show3">
-            <div class="title2">
-                <div class="top">
-                    <img class="img" :src="init2.icon[1]" alt="" />
-                    <div class="title3">{{ init2.name }}</div>
+                <div v-if="init2.openTime" class="timename">
+                    <span class="time">开启时间:</span>{{ init2.openTime }}
                 </div>
-                <img
-                    @click="allFn2"
-                    class="icon"
-                    src="https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/image/2021-11-13-13-52-01rJiHiwBy.png"
-                    alt=""
-                />
-            </div>
-            <div class="border"></div>
-            <div class="name">{{ init2.description }}</div>
-            <div class="name1">
-                <span>{{ init2.detail || '暂无' }}</span>
-            </div>
-            <div v-if="init2.openTime" class="timename"><span class="time">开启时间:</span>{{ init2.openTime }}</div>
-        </van-popup>
+            </van-popup>
+        </div>
         <!-- 悄悄话 -->
         <div class="whisper">
             <van-popup v-model:show="show2">
@@ -368,6 +372,17 @@
             :id="assetId"
             :imgSrc="getImg(changeImgs(info.pic))"
         ></order-open>
+        <div class="more-btns">
+            <van-action-sheet v-model:show="showAction">
+                <div class="more-btns-content">
+                    <van-button @click="Consignment" type="primary" block round>{{
+                        info.consignment ? '取消寄售' : '寄售上架'
+                    }}</van-button>
+                    <van-button @click="publish" color="#FF7F1F" block round>拍卖上架</van-button>
+                    <van-button @click="Add" color="#FFBF27" block round>赠送</van-button>
+                </div>
+            </van-action-sheet>
+        </div>
     </van-pull-refresh>
 </template>
 
@@ -411,7 +426,8 @@ export default {
                 { label: '铸造', value: 'exchange' }
             ],
             assetId: 0,
-            royalties: 0
+            royalties: 0,
+            showAction: false
         };
     },
     computed: {
@@ -554,6 +570,24 @@ export default {
                     }
                 });
         },
+        publish() {
+            this.checkAuth()
+                .then(() => {
+                    return this.checkBank();
+                })
+                .then(() => {
+                    if (this.dayjs().diff(this.dayjs(this.info.createdAt), 'day') < this.holdDays) {
+                        this.$toast('持有满' + this.holdDays + '天才能上架');
+                    } else {
+                        Dialog.confirm({
+                            title: '拍卖上架',
+                            message: '确定拍卖上架吗?'
+                        }).then(() => {
+                            this.$router.push('/auctionPublish?id=' + this.info.id);
+                        });
+                    }
+                });
+        },
         Add() {
             if (this.userInfo.authStatus === 'PENDING' || this.userInfo.authStatus === 'FAIL') {
                 Dialog.confirm({
@@ -1090,115 +1124,161 @@ export default {
         }
     }
 }
-
-/deep/ .van-popup {
-    width: 228px;
-    background: #ffffff;
-    padding: 0 16px;
-    border-radius: 8px;
-    .title2 {
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        padding-top: 12px;
-        .top {
+.popup {
+    /deep/ .van-popup {
+        width: 228px;
+        background: #ffffff;
+        padding: 0 16px;
+        border-radius: 8px;
+        .title2 {
             display: flex;
             align-items: center;
-            .img {
+            justify-content: space-between;
+            padding-top: 12px;
+            .top {
+                display: flex;
+                align-items: center;
+                .img {
+                    width: 18px;
+                    height: 18px;
+                    color: #ff4f50;
+                    margin-right: 3px;
+                }
+                .title3 {
+                    font-size: @font2;
+                    font-weight: 400;
+                    color: #ff4f50;
+                    line-height: 24px;
+                }
+            }
+            .icon {
                 width: 18px;
                 height: 18px;
-                color: #ff4f50;
-                margin-right: 3px;
-            }
-            .title3 {
-                font-size: @font2;
-                font-weight: 400;
-                color: #ff4f50;
-                line-height: 24px;
             }
         }
-        .icon {
-            width: 18px;
-            height: 18px;
+        .border {
+            height: 1px;
+            background: #f2f3f5;
+            border-radius: 1px;
+            margin: 12px 0 6px;
         }
-    }
-    .border {
-        height: 1px;
-        background: #f2f3f5;
-        border-radius: 1px;
-        margin: 12px 0 6px;
-    }
-    .name1 {
-        width: 208px;
-        padding: 10px;
-        background: @bg3;
-        border-radius: 4px;
-        color: @text3;
-        margin-bottom: 11px;
-        .qrcodeImg {
-            width: 93px;
-            height: 93px;
-            border-radius: 11px;
-            margin-left: 60px;
+        .name1 {
+            width: 208px;
+            padding: 10px;
+            background: #f5f7fa;
+            border-radius: 4px;
+            color: @text3;
+            margin-bottom: 11px;
+            .qrcodeImg {
+                width: 93px;
+                height: 93px;
+                border-radius: 11px;
+                margin-left: 60px;
+            }
+            .qrcode1 {
+                font-size: @font1;
+                font-weight: 400;
+                color: @text3;
+                line-height: 18px;
+                margin: 12px 0px 12px 44px;
+            }
         }
-        .qrcode1 {
+        .timename {
+            color: #ff4f50;
             font-size: @font1;
-            font-weight: 400;
+            padding-bottom: 12px;
+        }
+        .time {
             color: @text3;
-            line-height: 18px;
-            margin: 12px 0px 12px 44px;
+            font-size: @font1;
         }
-    }
-    .timename {
-        color: #ff4f50;
-        font-size: @font1;
-        padding-bottom: 12px;
-    }
-    .time {
-        color: @text3;
-        font-size: @font1;
-    }
-    .copy {
-        width: 220px;
-        height: 42px;
-        background: @bg3;
-        border-radius: 24px;
-        margin-bottom: 16px;
-        justify-content: center;
-        display: flex;
-        align-items: center;
-        .id {
-            font-size: @font2;
+        .copy {
+            width: 220px;
+            height: 42px;
+            background: #f5f7fa;
+            border-radius: 24px;
+            margin-bottom: 16px;
+            justify-content: center;
+            display: flex;
+            align-items: center;
+            .id {
+                font-size: @font2;
+                color: #303133;
+            }
+            .copyImg {
+                width: 18px;
+                height: 18px;
+                margin-left: 6px;
+                cursor: pointer;
+            }
+        }
+        span {
             color: #303133;
         }
-        .copyImg {
-            width: 18px;
-            height: 18px;
-            margin-left: 6px;
-            cursor: pointer;
+        .border {
+            height: 1px;
+            background: #f2f3f5;
+            border-radius: 1px;
+            margin: 12px 0 6px;
+        }
+        .name1 {
+            width: 208px;
+            padding: 10px;
+            background: @bg3;
+            border-radius: 4px;
+            color: @text3;
+            margin-bottom: 11px;
+            .qrcodeImg {
+                width: 93px;
+                height: 93px;
+                border-radius: 11px;
+                margin-left: 60px;
+            }
+            .span {
+                color: @text3;
+            }
+            .code {
+                font-size: @font1;
+                font-weight: 400;
+                color: @text3;
+                line-height: 18px;
+                padding-bottom: 12px;
+                margin: 12px 0px 12px 44px;
+            }
+        }
+        .timename {
+            color: #ff4f50;
+            font-size: @font1;
+            padding-bottom: 12px;
+        }
+        .time {
+            color: @text3;
+            font-size: @font1;
+        }
+        .copy {
+            width: 220px;
+            height: 42px;
+            background: @bg3;
+            border-radius: 24px;
+            margin-bottom: 16px;
+            justify-content: center;
+            display: flex;
+            align-items: center;
+            .id {
+                font-size: @font2;
+                color: #303133;
+            }
+            .name {
+                font-size: @font1;
+                font-weight: 400;
+                color: @text3;
+                line-height: 18px;
+                margin-bottom: 6px;
+            }
         }
-    }
-    span {
-        color: #303133;
-    }
-    .span {
-        color: @text3;
-    }
-    .code {
-        font-size: @font1;
-        font-weight: 400;
-        color: @text3;
-        line-height: 18px;
-        padding-bottom: 12px;
-    }
-    .name {
-        font-size: @font1;
-        font-weight: 400;
-        color: @text3;
-        line-height: 18px;
-        margin-bottom: 6px;
     }
 }
+
 .textName {
     font-size: @font2;
     font-weight: 400;
@@ -1427,6 +1507,8 @@ export default {
         justify-content: center;
         .btn1 {
             margin-right: 16px;
+            width: 35%;
+            flex-shrink: 0;
         }
         .img {
             width: 24px;
@@ -1758,4 +1840,19 @@ export default {
         }
     }
 }
+/deep/.more-btns {
+    .van-action-sheet {
+        background-color: #181818;
+        color: #fff;
+    }
+
+    .more-btns-content {
+        padding: 20px 48px;
+        .bottom(20px);
+
+        .van-button + .van-button {
+            margin-top: 20px;
+        }
+    }
+}
 </style>

+ 849 - 0
src/views/auction/Detail.vue

@@ -0,0 +1,849 @@
+<template>
+    <van-pull-refresh
+        success-text="加载成功"
+        success-duration="1000"
+        class="detail"
+        :class="{ dark: isNFT, isEnd: isEnd }"
+        v-model="isLoading"
+        @refresh="onRefresh"
+    >
+        <div class="top">
+            <auction-banner :info="info" :assetInfo="assetInfo" @getProduct="getDetail"></auction-banner>
+            <div class="price-bar" v-if="isEnd">
+                <div class="price-left">
+                    <div class="text1">{{ priceText }}</div>
+                    <div class="text2">
+                        <img src="../../assets/icon_jiage_bai.png" alt="" />
+                        <span>{{ showPrice }}</span>
+                    </div>
+                    <i class="font_family icon-sanjiao"></i>
+                </div>
+                <div class="price-right">
+                    <span>{{ timeText }}</span>
+                    <span class="time-box">{{ time }}</span>
+                </div>
+            </div>
+            <div class="price-bar" v-else>
+                <div class="price-left">
+                    <div class="text1">{{ priceText }}</div>
+                    <div class="text2">
+                        <img src="../../assets/icon_jiage_bai.png" alt="" />
+                        <span>{{ showPrice }}</span>
+                    </div>
+                    <i class="font_family icon-sanjiao"></i>
+                </div>
+                <div class="price-right">
+                    <span>{{ timeText }}</span>
+                    <span class="time">{{ getNum(hours) }}</span>
+                    <span>小时</span>
+                    <span class="time">{{ getNum(current.minutes || 0) }}</span>
+                    <span>分</span>
+                    <span class="time">{{ getNum(current.seconds || 0) }}</span>
+                    <span>秒</span>
+                </div>
+            </div>
+            <div class="title">{{ info.name }}</div>
+            <div class="title-sub">
+                <span class="text1">出价{{ info.bids }}次</span>
+            </div>
+        </div>
+
+        <div class="card" v-if="recordNum > 0">
+            <div class="card-title" @click="showRecord">
+                <img src="../../assets/icon-paimaijilu-bai.png" v-if="isNFT" alt="" />
+                <img src="../../assets/icon-paimaijilu.png" alt="" v-else />
+                <span class="flex1">拍卖纪录</span>
+                <div class="card-title-r">
+                    <span>共{{ recordNum }}条</span>
+                    <img src="../../assets/icon_inter1.png" alt="" />
+                </div>
+            </div>
+            <div class="card-content">
+                <div class="record-item" v-for="(item, index) in records" :key="index">
+                    <span>{{ item.user }}</span>
+                    <span>{{ index === 0 ? '领先' : '出局' }}</span>
+                    <span>¥{{ item.bidderPrice || 0 }}</span>
+                    <span>{{ item.createdAt }}</span>
+                </div>
+            </div>
+        </div>
+        <div class="card">
+            <div class="card-title">
+                <img src="../../assets/icon-paipingxinxi-bai.png" v-if="isNFT" alt="" />
+                <img src="../../assets/auction1.png" alt="" v-else />
+                <span>拍品信息</span>
+            </div>
+            <div class="card-content">
+                <div class="card-info">
+                    <span class="text1">增价拍</span>
+                    <span class="text2">{{ info.startingPrice ? '竞拍价' : '一口价' }}</span>
+                    <div class="card-right" v-if="info.startingPrice">
+                        <span class="text1">起拍价</span>
+                        <span class="text2">¥{{ info.startingPrice }}</span>
+                    </div>
+                </div>
+                <div class="card-info" v-if="info.startingPrice">
+                    <span class="text1">加价幅度</span>
+                    <span class="text2">¥{{ info.increment }}</span>
+                    <div class="card-right">
+                        <span class="text1">保证金</span>
+                        <span class="text2">¥{{ info.deposit }}</span>
+                    </div>
+                </div>
+                <div class="card-info">
+                    <span class="text1">开拍时间</span>
+                    <span class="text2">{{ info.startTime }}</span>
+                </div>
+                <div class="card-info">
+                    <span class="text1">结束时间</span>
+                    <span class="text2">{{ info.endTime }}</span>
+                </div>
+            </div>
+        </div>
+        <auction-asset v-if="isNFT" :info="assetInfo"></auction-asset>
+        <div class="card" v-else>
+            <div class="card-title">
+                <img src="../../assets/icon-paipingxinxi-bai.png" v-if="isNFT" alt="" />
+                <img src="../../assets/auction2.png" v-else alt="" />
+                <span>拍品描述</span>
+            </div>
+            <div v-if="info.detail" class="card-content card-detail" v-html="info.detail"></div>
+        </div>
+
+        <div class="btn-bottom van-safe-area-bottom" :class="{ showPopup: showPopup }">
+            <div class="fixed-list">
+                <div class="help" @click="showHelp">
+                    <i class="font_family icon-help"></i>
+                    <div>帮助</div>
+                </div>
+
+                <div class="btn-list" v-if="isbidder">
+                    <van-button type="primary" block round @click="goBuy">
+                        <div>竞拍成功,去支付</div>
+                        <div class="sub">
+                            (请在
+                            <van-count-down :time="buyTime" @finish="getDetail" format="HH小时mm分ss秒"></van-count-down
+                            >内支付)
+                        </div>
+                    </van-button>
+                </div>
+                <div class="btn-list not" v-else-if="info.status === 'PURCHASED' || info.status === 'FINISH'">
+                    <van-button disabled block round>竞拍结束</van-button>
+                </div>
+                <div class="btn-list not" v-else-if="info.status === 'NOTSTARTED'">
+                    <van-button disabled block round>未开始</van-button>
+                </div>
+                <div class="btn-list not" v-else-if="info.status === 'PASS'">
+                    <van-button disabled block round>
+                        <div>已流拍</div>
+                        <div class="sub" v-if="info.purchaserId === userInfo.id">
+                            (保证金 ¥{{ info.deposit }} 不退回)
+                        </div>
+                    </van-button>
+                </div>
+
+                <template v-else-if="info.status === 'ONGOING' || info.status === 'FIXED_PRICE_PURCHASED'">
+                    <div class="btn-list" v-if="!info.startingPrice">
+                        <van-button
+                            type="primary"
+                            :disabled="info.status === 'FIXED_PRICE_PURCHASED'"
+                            block
+                            round
+                            @click="goBuy"
+                            >立即支付</van-button
+                        >
+                    </div>
+
+                    <div class="btn-list" v-else>
+                        <van-button type="primary" @click="goBuy" block plain>
+                            <div>直接购买</div>
+                            <div class="sub">¥{{ info.fixedPrice }}</div>
+                        </van-button>
+                        <van-button type="primary" block v-if="isLeader">
+                            <div>竞价中</div>
+                            <div class="sub">(出价金额为 ¥{{ info.purchasePrice }})</div>
+                        </van-button>
+
+                        <van-button type="primary" block v-else-if="isOut" @click="goCreated">
+                            <div>已出局</div>
+                            <div class="sub">(重新出价)</div>
+                        </van-button>
+                        <van-button type="primary" block v-else-if="recordInfo.payDeposit" @click="goCreated"
+                            >去出价</van-button
+                        >
+                        <van-button type="primary" v-else block @click="goDeposit">
+                            <div>立即参拍</div>
+                            <div class="sub">(保证金 ¥{{ info.deposit }})</div>
+                            <!-- <div class="sub">
+                                (请在
+                                <van-count-down
+                                    :time="buyTime"
+                                    @finish="getDetail"
+                                    format="HH小时mm分ss秒"
+                                ></van-count-down
+                                >内支付)
+                            </div> -->
+                        </van-button>
+                    </div>
+                </template>
+
+                <!-- <div class="btn-list">
+                    <van-button type="primary" block round>立即支付</van-button>
+                </div> -->
+            </div>
+        </div>
+
+        <auction-deposit
+            @showRule="$refs.rule.show = true"
+            ref="deposit"
+            :info="info"
+            @changePopup="changePopup"
+        ></auction-deposit>
+
+        <auction-help ref="help" @changePopup="changePopup"></auction-help>
+        <auction-rule ref="rule" @changePopup="changePopup"></auction-rule>
+        <auction-records ref="record" :auctionId="auctionId" :recordNum="recordNum"></auction-records>
+    </van-pull-refresh>
+</template>
+
+<script>
+import { Swiper, SwiperSlide } from 'swiper/vue';
+
+import 'swiper/swiper.min.css';
+import 'swiper/swiper-bundle.min.css';
+
+// import SwiperCore, { Pagination, Autoplay } from 'swiper';
+import AuctionDeposit from '../../components/auction/deposit.vue';
+import AuctionHelp from '../../components/auction/help.vue';
+import AuctionRule from '../../components/auction/rule.vue';
+import AuctionBanner from '../../components/auction/banner.vue';
+import AuctionAsset from '../../components/auction/asset.vue';
+import AuctionRecords from '../../components/auction/records.vue';
+import { useCountDown, useToggle } from '@vant/use';
+import auction from '../../mixins/auction';
+import { mapState } from 'vuex';
+export default {
+    name: 'auctionDetail',
+    inject: ['setKeeps', 'changeTab'],
+    mixins: [auction],
+    setup() {
+        const [timeDown, toggleTime] = useToggle(false);
+        const countDown = useCountDown({
+            onFinish: () => {
+                toggleTime();
+            }
+        });
+
+        return {
+            current: countDown.current,
+            countDown: countDown,
+            timeDown: timeDown
+        };
+    },
+    components: {
+        AuctionDeposit,
+        AuctionHelp,
+        AuctionRule,
+        AuctionBanner,
+        AuctionAsset,
+        AuctionRecords
+    },
+    data() {
+        return {
+            auctionId: 0,
+            info: {},
+            assetInfo: {},
+            showPopup: false,
+            time: '',
+            recordInfo: {},
+            records: [],
+            recordNum: 0,
+            buyTime: 0
+        };
+    },
+    watch: {
+        timeDown() {
+            this.getDetail();
+        }
+    },
+    computed: {
+        ...mapState(['userInfo']),
+        hours() {
+            let hours = 0;
+            if (this.current.days) {
+                hours += this.current.days * 24;
+            }
+            hours += this.current.hours || 0;
+            return hours;
+        },
+        isOut() {
+            if (
+                this.recordInfo.payDeposit &&
+                this.recordInfo.bidderPrice &&
+                this.recordInfo.bidderPrice !== this.info.deposit &&
+                !this.isLeader
+            ) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    },
+    mounted() {
+        if (this.$route.query.id) {
+            this.auctionId = this.$route.query.id;
+        }
+        this.getDetail();
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.path === '/mineAddress') {
+            this.setKeeps(['auctionDetail']);
+        } else {
+            this.setKeeps(['auctionDetail'], false);
+        }
+        next();
+    },
+    methods: {
+        showHelp() {
+            this.$refs.help.show = !this.$refs.help.show;
+            this.changePopup(true);
+        },
+        changePopup(flag = false) {
+            this.showPopup = flag;
+        },
+        startCount(time = 24 * 3600 * 1000) {
+            if (this.info.status === 'NOTSTARTED') {
+                time = this.dayjs(this.info.startTime).diff(this.dayjs());
+            } else if (this.info.status === 'ONGOING') {
+                time = this.dayjs(this.info.endTime).diff(this.dayjs());
+            }
+            if (!this.isEnd) {
+                if (time > 0) {
+                    this.countDown.reset(time);
+                    this.countDown.start();
+                }
+            } else {
+                this.time = this.info.endTime;
+            }
+        },
+        getRecord() {
+            this.$http.get('/auctionRecord/hasPayDeposit?auctionId=' + this.auctionId).then(res => {
+                this.recordInfo = res;
+            });
+
+            this.$http
+                .post(
+                    '/auctionRecord/all',
+                    {
+                        query: {
+                            auctionId: this.auctionId,
+                            type: 'BIDDER',
+                            del: false
+                        },
+                        size: 2,
+                        page: 0,
+                        sort: 'id,desc'
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.records = res.content;
+                    this.recordNum = res.totalElements;
+                });
+        },
+        getDetail() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            return this.$http
+                .get('/auctionActivity/get/' + this.auctionId)
+                .then(res => {
+                    // res.model3d = {
+                    //     name: '99.FBX',
+                    //     thumb: null,
+                    //     type: null,
+                    //     url: 'https://cdn.raex.vip/fbx/2022-01_20-11/LzpIMaHFSiCmINEx/99.FBX'
+                    // };
+
+                    this.info = res;
+                    this.startCount();
+                    this.getRecord();
+                    //改变头部颜色
+                    this.$nextTick(() => {
+                        if (this.isNFT) {
+                            this.changeTab('#0f0f0f');
+                        }
+                        if (this.isbidder) {
+                            this.$http.get('/sysConfig/get/auction_cancel_time').then(res => {
+                                let date1 = this.dayjs(this.info.endTime).add(Number(res.value), 'minute');
+                                let date2 = this.dayjs();
+                                let time = date1.diff(date2);
+                                if (time > 0) {
+                                    this.buyTime = time;
+                                }
+                            });
+                        }
+                    });
+
+                    //获取nft详情
+                    if (res.auctionType === 'NFT' && res.assetId) {
+                        return this.$http.get('/asset/get/' + res.assetId);
+                    } else {
+                        return Promise.reject();
+                    }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.$toast.clear();
+                    this.assetInfo = res;
+                })
+                .catch(e => {
+                    this.$toast.clear();
+                    if (e && e.error) {
+                        this.$dialog
+                            .alert({
+                                title: '提示',
+                                message: e.error
+                            })
+                            .then(res => {
+                                this.$router.back();
+                            });
+                    }
+                });
+        },
+        goBuy() {
+            this.checkLogin().then(() => {
+                this.$router.push({
+                    name: 'auctionSubmit',
+                    query: {
+                        auctionId: this.info.id,
+                        paymentType: this.isbidder ? 'PURCHASE_PRICE' : 'FIXED_PRICE'
+                    }
+                });
+            });
+        },
+        goDeposit() {
+            this.checkLogin().then(() => {
+                this.$refs.deposit.init();
+            });
+        },
+        goCreated() {
+            this.$router.push('/auctionOffer?auctionId=' + this.auctionId);
+        },
+        showRecord() {
+            this.$refs.record.show = true;
+        },
+        onRefresh() {
+            this.getDetail().then(() => {
+                this.isLoading = false;
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.mySwiper {
+    position: relative;
+    z-index: 1;
+    .van-image {
+        display: block;
+    }
+    .swiper-pagination {
+        background: rgba(0, 0, 0, 0.3);
+        border-radius: 9px;
+        height: 20px;
+        color: #ffffff66;
+        right: 16px;
+        width: auto;
+        left: auto;
+        bottom: 25px;
+        padding: 0 10px;
+
+        .swiper-pagination-current {
+            color: #fff;
+        }
+    }
+}
+.price-bar {
+    background: linear-gradient(270deg, #ffc61f 0%, #f95532 100%);
+    border-radius: 16px 16px 0px 0px;
+    height: 60px;
+    display: flex;
+    overflow: hidden;
+    transform: translateY(-15px);
+    position: relative;
+    z-index: 2;
+    .price-left {
+        .icon-sanjiao {
+            font-size: 62px;
+            color: #feb420;
+            position: absolute;
+            right: -23px;
+            top: -4px;
+            display: block;
+        }
+        .flex();
+        padding-left: 16px;
+        position: relative;
+        width: calc(50% - 20px);
+
+        .text1 {
+            font-size: 12px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 17px;
+            margin-top: 5px;
+        }
+
+        .text2 {
+            .flex();
+            align-items: flex-end;
+            img {
+                width: 10px;
+                height: 11px;
+                margin-bottom: 3px;
+                margin-left: 3px;
+            }
+            span {
+                font-size: 32px;
+                font-family: OSP-DIN, OSP;
+                color: #ffffff;
+                line-height: 24px;
+                margin-left: 2px;
+            }
+        }
+    }
+
+    .price-right {
+        flex-grow: 1;
+        background: linear-gradient(270deg, #ffc61f 0%, #feb420 100%);
+        .flex();
+        justify-content: center;
+        span {
+            font-size: 12px;
+            font-weight: bold;
+            color: #ffffff;
+            line-height: 17px;
+
+            &.time {
+                min-width: 22px;
+                height: 22px;
+                display: inline-block;
+                color: #cc9163;
+                line-height: 22px;
+                text-align: center;
+                background-color: #fff;
+                border-radius: 4px;
+                margin: 0 4px;
+                padding: 0 2px;
+                box-sizing: border-box;
+            }
+
+            &.time-box {
+                display: inline-block;
+                line-height: 22px;
+                text-align: center;
+                background-color: #fff;
+                border-radius: 4px;
+                margin: 0 4px;
+                padding: 0 6px;
+                font-weight: normal;
+            }
+        }
+    }
+}
+
+.title {
+    font-size: 18px;
+    font-weight: bold;
+    color: #000000;
+    line-height: 24px;
+    padding: 1px 16px 10px;
+}
+.title-sub {
+    height: 37px;
+    .flex();
+    justify-content: space-between;
+    padding: 0 16px;
+    font-size: 12px;
+    color: #c8c9cc;
+    line-height: 17px;
+}
+.detail {
+    background-color: #f5f7fa;
+    // padding-bottom: 50px;
+    .bottom(50px);
+}
+.top {
+    background-color: #fff;
+}
+
+.card {
+    background-color: #fff;
+    margin-top: 10px;
+    .card-title {
+        .flex();
+        padding: 12px 16px 10px;
+        img {
+            width: 18px;
+            height: 18px;
+        }
+        span {
+            font-size: 14px;
+            font-weight: bold;
+            color: #000000;
+            line-height: 24px;
+            margin-left: 10px;
+        }
+        .flex1 {
+            flex-grow: 1;
+        }
+        .card-title-r {
+            .flex();
+            span {
+                font-size: 12px;
+                color: #939599;
+                line-height: 17px;
+            }
+            img {
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
+
+    .card-content {
+        padding: 0 16px 16px;
+
+        .card-info {
+            .flex();
+            .text1 {
+                font-size: 12px;
+                color: #939599;
+                line-height: 17px;
+                display: inline-block;
+                min-width: 48px;
+            }
+            .text2 {
+                font-size: 12px;
+                color: #000000;
+                line-height: 17px;
+                margin-left: 10px;
+                flex-grow: 1;
+            }
+
+            .card-right {
+                .flex();
+                width: 100px;
+                .text1 {
+                    min-width: 36px;
+                }
+            }
+        }
+
+        .card-info + .card-info {
+            margin-top: 6px;
+        }
+
+        /deep/&.card-detail {
+            img {
+                width: 100%;
+                height: auto;
+                display: block;
+            }
+        }
+    }
+}
+.btn-bottom {
+    height: 56px;
+}
+
+.fixed-list {
+    padding: 9px 16px;
+    .bottom(9px);
+    position: fixed;
+    z-index: 20;
+    background-color: #fff;
+    border-top: 1px solid #f2f4f5;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    .flex();
+
+    .help {
+        .flex-col();
+        align-items: center;
+        color: #1a1a1a;
+        img {
+            width: 24px;
+            height: 24px;
+        }
+
+        .icon-help {
+            font-size: 24px;
+            display: block;
+        }
+        div {
+            font-size: 12px;
+            line-height: 12px;
+            transform: scale(0.8);
+            margin-top: 2px;
+        }
+        margin-left: 8px;
+    }
+    .btn-list {
+        flex-grow: 1;
+        margin-left: 31px;
+        .flex();
+        .van-button {
+            flex-grow: 1;
+            font-weight: bold;
+            /deep/.van-button__text {
+                .flex-col();
+                align-content: center;
+            }
+            .sub {
+                font-size: 12px;
+                font-weight: normal;
+                transform: scale(0.83);
+                text-align: center;
+                .van-count-down {
+                    color: #fff;
+                }
+                .flex();
+                justify-content: center;
+            }
+            outline: none;
+            border-radius: 0;
+        }
+        border-radius: 100px;
+        overflow: hidden;
+        border: 1px solid #3ab200;
+
+        &.not {
+            border-color: #939599;
+            .van-button--disabled {
+                border-color: #939599;
+                background-color: #939599;
+                color: #fff;
+                opacity: 1;
+            }
+        }
+    }
+}
+
+.record-item {
+    .flex();
+    font-size: 12px;
+    color: #939599;
+    line-height: 17px;
+    margin-top: 10px;
+
+    span {
+        &:first-child {
+            width: 20%;
+            overflow: hidden; //溢出隐藏
+            white-space: nowrap; //禁止换行
+            text-overflow: ellipsis;
+            display: inline-block;
+        }
+
+        &:nth-child(3) {
+            flex-grow: 1;
+        }
+    }
+
+    span + span {
+        margin-left: 18px;
+    }
+
+    &:first-child {
+        color: @prim;
+    }
+}
+
+.dark {
+    background-color: #0f0f0f;
+    .fixed-list {
+        background: #181818;
+        border-color: #313233;
+    }
+    .help {
+        color: #fff;
+    }
+
+    .top {
+        background-color: #1c1c1c;
+        .title {
+            color: #fff;
+        }
+    }
+
+    .card {
+        background-color: #131313;
+        .card-title {
+            background-color: #1c1c1c;
+            padding: 15px 16px 15px;
+            span {
+                color: #fff;
+            }
+        }
+        .card-info {
+            .text2 {
+                color: #fff;
+            }
+        }
+        .card-content {
+            padding: 10px 16px;
+        }
+    }
+
+    .btn-list {
+        &.not {
+            border-color: #303133;
+            .van-button--disabled {
+                border-color: #303133;
+                background-color: #303133;
+                color: #939599;
+            }
+        }
+    }
+}
+
+.showPopup {
+    .fixed-list {
+        background-color: #fff;
+        border-color: #f2f4f5;
+        .help {
+            color: #000;
+        }
+        .btn-list {
+            &.not {
+                border-color: #939599;
+                .van-button--disabled {
+                    border-color: #939599;
+                    background-color: #939599;
+                    color: #fff;
+                }
+            }
+        }
+    }
+}
+
+.isEnd {
+    .price-bar {
+        background: #939599;
+        .price-left .icon-sanjiao {
+            color: #f6f7fa;
+        }
+        .price-right {
+            background: #f6f7fa;
+            span {
+                color: #939599;
+            }
+        }
+    }
+}
+</style>

+ 276 - 0
src/views/auction/Home.vue

@@ -0,0 +1,276 @@
+<template>
+    <van-pull-refresh
+        class="auction"
+        success-text="加载成功"
+        success-duration="1000"
+        :style="{ backgroundColor: isSearch ? $colors.bg3 : $colors.bg }"
+        v-model="isLoading"
+        @refresh="onRefresh"
+    >
+        <van-sticky :offset-top="46">
+            <div class="search-bar">
+                <span class="icon">拍卖中心</span>
+                <div class="search-input" @click="$router.push('/auctionSearch')">
+                    <img src="../../assets/icon-sosuo1.png" alt="" />
+                    <span>搜索你要的精彩</span>
+                </div>
+            </div>
+        </van-sticky>
+
+        <swiper v-if="banners.length > 0" pagination :space-between="16" class="mySwiper" :autoplay="{ delay: 3500 }">
+            <swiper-slide v-for="item in banners" :key="item.id">
+                <van-image
+                    width="calc(100vw - 32px)"
+                    height="calc(100vw - 32px)"
+                    :src="getImg(item.pic)"
+                    fit="cover"
+                    @click="goNext(item)"
+                    radius="16"
+                />
+            </swiper-slide>
+        </swiper>
+        <van-grid :border="false">
+            <van-grid-item
+                :icon="require('../../assets/yikou.png')"
+                :to="{ path: '/auctionList', query: { status: 'ONGOING', pageName: '随时拍' } }"
+                text="随时拍"
+            />
+            <van-grid-item
+                :icon="require('../../assets/suishi.png')"
+                :to="{ path: '/auctionList', query: { hasFixedPrice: true, pageName: '一口价' } }"
+                text="一口价"
+            />
+            <van-grid-item
+                :icon="require('../../assets/shuzi.png')"
+                :to="{ path: '/auctionList', query: { auctionType: 'NFT', pageName: '数字艺术' } }"
+                text="数字艺术"
+            />
+            <van-grid-item @click="wait" :icon="require('../../assets/zhengji.png')" text="拍卖征集" />
+        </van-grid>
+        <van-tabs v-model:active="auctionType" @change="getData(true)">
+            <van-tab title="藏传文玩" name="ENTITY"></van-tab>
+            <van-tab title="数字艺术" name="NFT"></van-tab>
+        </van-tabs>
+        <van-list v-model:loading="loading" :finished="finished" finished-text="" @load="getData">
+            <template v-for="(item, index) in list" :key="index">
+                <auction-info v-model:info="list[index]"></auction-info>
+            </template>
+            <!-- <template v-for="i in 10" :key="i">
+                <auction-info></auction-info>
+            </template> -->
+
+            <van-empty
+                :image="require('@assets/empty_img_asset_dark.png')"
+                v-if="empty"
+                description="没有任何藏品哦~"
+            />
+        </van-list>
+    </van-pull-refresh>
+</template>
+
+<script>
+import { Swiper, SwiperSlide } from 'swiper/vue';
+
+import 'swiper/swiper.min.css';
+import 'swiper/swiper-bundle.min.css';
+
+import SwiperCore, { Pagination, Autoplay } from 'swiper';
+
+// install Swiper modules
+SwiperCore.use([Pagination, Autoplay]);
+import list from '../../mixins/list';
+import auctionInfo from '../../components/auction/info.vue';
+import banner from '../../mixins/banner';
+export default {
+    name: 'auctionHome',
+    mixins: [list, banner],
+    inject: ['bar', 'setKeeps', 'scrollWrapper', 'changeScroll'],
+    components: {
+        Swiper,
+        SwiperSlide,
+        auctionInfo
+    },
+    data() {
+        return {
+            auctionType: 'ENTITY',
+            url: '/auctionActivity/all',
+            list: [],
+            banners: [],
+            scrollTop: 0
+        };
+    },
+    mounted() {
+        this.getBanner();
+    },
+    methods: {
+        getBanner() {
+            return this.$http
+                .post(
+                    '/banner/all',
+                    {
+                        query: {
+                            type: 'AUCTION',
+                            del: false
+                        },
+                        sort: 'sort,asc;createdAt,desc'
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.banners = res.content;
+                    this.$toast.clear();
+                });
+        },
+        beforeData() {
+            return {
+                query: {
+                    auctionType: this.auctionType,
+                    status: 'NOTSTARTED,ONGOING'
+                },
+                sort: 'id,desc'
+            };
+        },
+        onRefresh() {
+            Promise.all([this.getBanner(), this.getData(true)]).then(() => {
+                this.isLoading = false;
+            });
+        }
+    },
+    activated() {
+        this.$nextTick(() => {
+            this.changeScroll(this.scrollTop);
+        });
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.name === 'auctionDetail') {
+            this.scrollTop = this.scrollWrapper.value.scrollTop;
+            this.setKeeps(['auctionHome']);
+        } else {
+            this.scrollTop = 0;
+            this.setKeeps(['auctionHome'], false);
+        }
+        next();
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.auction {
+    position: relative;
+}
+.search-bar {
+    padding: 9px 16px;
+    .flex();
+    .icon {
+        font-size: 16px;
+        font-weight: bold;
+        color: #000000;
+        line-height: 24px;
+    }
+
+    .search-input {
+        height: 32px;
+        background: #f5f7fa;
+        border-radius: 8px;
+        flex-grow: 1;
+        margin-left: 10px;
+        .flex();
+        padding: 0 16px;
+        img {
+            width: 16px;
+            height: 16px;
+            margin-right: 10px;
+        }
+        span {
+            font-size: 14px;
+            color: #c8c9cc;
+            line-height: 24px;
+        }
+    }
+}
+
+/deep/.mySwiper {
+    margin: 11px 16px;
+    .swiper-pagination {
+        overflow: hidden;
+
+        .swiper-pagination-bullet {
+            width: 16px;
+            height: 4px;
+            // border-radius: 2px;
+            margin: 0 0;
+            background-color: #fff;
+            opacity: 0.5;
+
+            &.swiper-pagination-bullet-active {
+                background-color: @prim;
+                opacity: 1;
+            }
+            border-radius: 0;
+
+            &:first-child {
+                border-radius: 2px 0 0 2px;
+            }
+            &:last-child {
+                border-radius: 0 2px 2px 0;
+            }
+        }
+    }
+}
+
+/deep/.van-grid {
+    .van-grid-item__content {
+        padding: 10px 16px;
+    }
+    .van-icon__image {
+        width: 32px;
+        height: 32px;
+    }
+    .van-grid-item__text {
+        margin-top: 4px;
+        font-size: 12px;
+        color: #000;
+    }
+}
+
+/deep/.van-tabs {
+    padding: 0 16px;
+    position: relative;
+    &::after {
+        content: '';
+        position: absolute;
+        left: 0;
+        height: 2px;
+        right: 0;
+        bottom: 0;
+        background: #f5f5f5;
+    }
+    .van-tab {
+        margin-right: 30px;
+        .van-tab__text {
+            font-size: 16px;
+        }
+
+        &.van-tab--active {
+            .van-tab__text {
+                color: #000;
+                font-weight: bold;
+            }
+        }
+    }
+    .van-tabs__nav--line {
+        padding-bottom: 0;
+    }
+    .van-tabs__line {
+        width: 16px;
+        height: 2px;
+        bottom: 0px;
+    }
+}
+
+.van-list {
+    padding: 8px;
+    background: linear-gradient(to bottom, #ffffff 0%, #f5f5f5 40px, #f5f5f5 100%);
+    min-height: calc(100vh - 156px);
+}
+</style>

+ 412 - 0
src/views/auction/List.vue

@@ -0,0 +1,412 @@
+<template>
+    <van-pull-refresh
+        success-text="加载成功"
+        success-duration="1000"
+        class="follow"
+        v-model="isLoading"
+        @refresh="onRefresh"
+    >
+        <van-sticky ref="top" class="list-top" :offset-top="bar.value && bar.value.show ? 46 : 0">
+            <div class="top" v-if="!minterId">
+                <div class="name">{{ pageName }}</div>
+                <img src="@assets/icon-sosuo.png" alt="" @click="goSearch" class="search" />
+            </div>
+            <van-tabs
+                v-model:active="sort"
+                :ellipsis="false"
+                line-width="16"
+                line-height="2"
+                @click-tab="changeTab"
+                :class="{ trans: source == 'TRANSFER' }"
+            >
+                <van-tab
+                    :title="item.label"
+                    :name="item.value"
+                    :title-class="item.type === 'select' && sortDes ? sortDes : ''"
+                    :key="index"
+                    v-for="(item, index) in selectOptions"
+                >
+                    <template v-if="item.type === 'select'" #title>
+                        <div class="tab">
+                            <span>{{ item.label }}</span>
+                            <van-icon size="8" name="arrow-up" />
+                            <van-icon size="8" name="arrow-down" />
+                        </div>
+                    </template>
+                </van-tab>
+            </van-tabs>
+            <!-- <van-checkbox v-if="source == 'TRANSFER' && !title" @change="getData(true)" class="sala" v-model="salable"
+                >仅看在售</van-checkbox
+            > -->
+
+            <van-button
+                @click="changeSort"
+                v-if="source == 'TRANSFER' && !title"
+                class="sala"
+                color="#F5F7FA"
+                type="primary"
+                size="small"
+                icon="arrow-down"
+                icon-position="right"
+                round
+                >{{ salable ? '在售中' : salable === false ? '仅展示' : '综合排序' }}</van-button
+            >
+        </van-sticky>
+
+        <van-action-sheet
+            v-model:show="showAction"
+            @select="selectAction"
+            :actions="actions"
+            cancel-text="取消"
+            close-on-click-action
+        />
+
+        <van-list v-model:loading="loading" :finished="finished" finished-text="" @load="getData">
+            <template v-for="(item, index) in showList" :key="index">
+                <auction-info v-model:info="list[index]"></auction-info>
+            </template>
+
+            <van-empty
+                :image="require('@assets/empty_img_asset_dark.png')"
+                v-if="empty"
+                description="没有任何藏品哦~"
+            />
+        </van-list>
+    </van-pull-refresh>
+</template>
+
+<script>
+import auctionInfo from '../../components/auction/info.vue';
+import product from '../../mixins/product';
+import list from '../../mixins/list';
+import banner from '../../mixins/banner';
+export default {
+    name: 'productList',
+    components: { auctionInfo },
+    inject: ['bar', 'setKeeps', 'scrollWrapper', 'changeScroll'],
+    mixins: [product, list, banner],
+    data() {
+        return {
+            list: [],
+            empty: false,
+            beforeSort: '',
+            sort: 'id,desc',
+            sortDes: '',
+            auctionType: '',
+            source: '',
+            minterId: '',
+            selectOptions: [
+                {
+                    label: '全部',
+                    value: 'id,desc'
+                },
+                {
+                    label: '最新',
+                    value: 'id,desc;'
+                },
+                {
+                    label: '最热',
+                    value: 'likes,desc'
+                }
+                // {
+                //     label: '价格',
+                //     value: 'price',
+                //     type: 'select'
+                // }
+            ],
+            url: '/auctionActivity/all',
+            title: '',
+            salable: '',
+            scrollTop: 0,
+            showAction: false,
+            banners: [],
+            swiperRef: null,
+            pageName: '',
+            status: '',
+            hasFixedPrice: ''
+        };
+    },
+    computed: {
+        showList() {
+            let list = [];
+            let allList = [...this.list];
+            allList.forEach(item => {
+                let info = list.find(_item => {
+                    return _item.id === item.id;
+                });
+                if (!info) {
+                    list.push(item);
+                }
+            });
+            return list;
+        },
+        actions() {
+            let list = [{ name: '综合排序' }, { name: '在售中' }, { name: '仅展示' }];
+            if (this.salable === '') {
+                list[0].color = this.$colors.prim;
+            }
+            if (this.salable === true) {
+                list[1].color = this.$colors.prim;
+            }
+            if (this.salable === false) {
+                list[2].color = this.$colors.prim;
+            }
+            return list;
+        }
+    },
+    mounted() {
+        this.$store.dispatch('getUsedBuy');
+        if (this.$route.query.auctionType) {
+            this.auctionType = this.$route.query.auctionType;
+        }
+        if (this.$route.query.status) {
+            this.status = this.$route.query.status;
+        }
+
+        if (this.$route.query.hasFixedPrice === 'true' || this.$route.query.hasFixedPrice === true) {
+            this.hasFixedPrice = true;
+        }
+
+        if (this.$route.query.pageName) {
+            this.pageName = this.$route.query.pageName;
+        }
+    },
+    methods: {
+        changeSort() {
+            this.showAction = true;
+        },
+        selectAction(action) {
+            if (action.name == '综合排序') {
+                this.salable = '';
+            }
+            if (action.name == '在售中') {
+                this.salable = true;
+            }
+            if (action.name == '仅展示') {
+                this.salable = false;
+            }
+            this.getData(true);
+        },
+        changeTab(info) {
+            console.log(info);
+            this.$nextTick(() => {
+                if (info.name === 'price') {
+                    this.sortDes = this.sortDes == 'desc' ? 'asc' : 'desc';
+                }
+                this.getData(true);
+            });
+        },
+        beforeData() {
+            let sort = this.sort;
+            if (sort == 'price') {
+                sort = 'price,' + this.sortDes;
+            }
+            return {
+                query: {
+                    auctionType: this.auctionType,
+                    del: false,
+                    status: this.status,
+                    hasFixedPrice: this.hasFixedPrice
+                },
+                sort: this.sort === 'id,desc' ? this.sortOptions[this.title] || sort : sort
+            };
+        },
+        goSearch() {
+            let url = '/auctionSearch';
+            if (this.auctionType) {
+                url += '?auctionType=' + this.type;
+            }
+            if (this.status) {
+                url += '?status=' + this.status;
+            }
+            this.$router.push(url);
+        },
+        setSwiperRef(ref) {
+            this.swiperRef = ref;
+        },
+        onRefresh() {
+            this.getData(true).then(() => {
+                this.isLoading = false;
+            });
+        }
+    },
+    activated() {
+        this.$nextTick(() => {
+            this.changeScroll(this.scrollTop);
+            setTimeout(() => {
+                this.sort = this.beforeSort;
+            }, 1000);
+        });
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.name === 'productDetail') {
+            this.beforeSort = this.sort;
+            this.scrollTop = this.scrollWrapper.value.scrollTop;
+            this.setKeeps(['productList']);
+        } else {
+            this.beforeSort = '';
+            this.scrollTop = 0;
+            this.setKeeps(['productList'], false);
+        }
+        next();
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.follow {
+    background-color: @bg3;
+    padding-bottom: 100px;
+}
+.van-list {
+    padding: 8px;
+    box-sizing: border-box;
+    min-height: calc(100vh - 200px);
+}
+.top {
+    background-color: @bg;
+    padding: 0 16px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    position: relative;
+    .name {
+        font-size: @font3;
+        font-weight: bold;
+        color: @text0;
+        line-height: 30px;
+    }
+
+    .search {
+        width: 24px;
+        height: 24px;
+        position: absolute;
+        right: 16px;
+        top: 13px;
+    }
+}
+
+/deep/.van-tabs__nav--line.van-tabs__nav--complete {
+    border-color: @tabBorder;
+}
+// /deep/.van-tab {
+// flex-grow: 0;
+// padding: 0 0 0 0;
+// margin-right: 50px;
+
+.tab {
+    position: relative;
+    padding-right: 14px;
+    .van-icon {
+        position: absolute;
+        right: 0;
+
+        &.van-icon-arrow-down {
+            top: 8px;
+        }
+
+        &.van-icon-arrow-up {
+            bottom: 8px;
+        }
+    }
+}
+
+/deep/.trans {
+    .van-tab {
+        margin-right: 30px;
+    }
+}
+
+.van-tabs {
+    background-color: @bg;
+}
+
+.list-top {
+    position: relative;
+}
+/deep/.sala {
+    position: absolute;
+    right: 16px;
+    top: 57px;
+    color: @text3!important;
+    min-width: 92px;
+    font-size: 14px;
+    // .van-checkbox__icon {
+    //     color: #fff;
+    //     transform: scale(0.6);
+
+    //     .van-icon {
+    //         border-color: @text3;
+    //     }
+
+    //     &.van-checkbox__icon--checked {
+    //         .van-icon {
+    //             border-width: 0;
+    //             .linear();
+    //             &::before {
+    //                 color: #fff;
+    //             }
+    //         }
+    //     }
+    // }
+    // .van-checkbox__label {
+    //     color: @text3;
+    //     margin-left: 0px;
+    //     font-size: @font1;
+    // }
+}
+.swiperContent {
+    background: #fff;
+    border-bottom: 1px solid @tabBorder;
+}
+::v-deep(.mySwiper) {
+    width: calc(100vw - 32px);
+    height: 134px;
+    padding: 20px 0;
+
+    .swiper-pagination {
+        bottom: 6px;
+    }
+
+    .swiper-pagination-bullet {
+        width: 6px;
+        height: 2px;
+        border-radius: 1px;
+        background: #d7d7d7;
+        margin: 0 3px;
+    }
+
+    .swiper-pagination-bullet-active {
+        background: @prim;
+    }
+}
+
+.swiper-slide {
+    text-align: center;
+    font-size: 18px;
+    width: 132px;
+    height: 132px;
+
+    /* Center slide text vertically */
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-pack: center;
+    -ms-flex-pack: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    -webkit-align-items: center;
+    align-items: center;
+}
+
+.swiper-slide img {
+    display: block;
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+    border-radius: 12px;
+}
+</style>

+ 299 - 0
src/views/auction/Offer.vue

@@ -0,0 +1,299 @@
+<template>
+    <div class="page">
+        <van-sticky :offset-top="46">
+            <div class="status">竞价中</div>
+        </van-sticky>
+
+        <div class="container">
+            <auction-info ref="info" :info="info"></auction-info>
+
+            <div class="panel">
+                <div class="panel-title">你的出价金额(元)</div>
+                <van-stepper
+                    :step="info.increment"
+                    :min="min"
+                    :max="max"
+                    v-model="value"
+                    theme="round"
+                    button-size="22"
+                    :decimal-length="2"
+                    allow-empty
+                    :default-value="defValue"
+                />
+                <div class="panel-tips">加价幅度¥{{ info.increment }}</div>
+                <van-button type="primary" block round @click="submit">立即出价</van-button>
+            </div>
+
+            <div class="list-box">
+                <div class="name">
+                    <img src="../../assets/icon-paimaijilu.png" alt="" />
+                    <span>拍卖纪录</span>
+                </div>
+
+                <div class="list">
+                    <div class="item" v-for="(item, index) in records" :key="index">
+                        <span>{{ item.user }}</span>
+                        <span>{{ item.createdAt }}</span>
+                        <span>{{ index === 0 ? '领先' : '出局' }}</span>
+                        <span>¥{{ item.bidderPrice || 0 }}</span>
+                    </div>
+                </div>
+
+                <div class="empty" v-if="records.length === 0">暂无数据</div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import auction from '../../mixins/auction';
+import auctionInfo from '../../components/auction/info.vue';
+export default {
+    data() {
+        return {
+            auctionId: 0,
+            info: {},
+            recordInfo: {},
+            records: []
+        };
+    },
+    computed: {
+        min() {
+            return (this.info.purchasePrice || this.info.startingPrice || 0) + (this.info.increment || 0);
+        },
+        defValue() {
+            return this.min;
+        }
+    },
+    components: {
+        auctionInfo
+    },
+    mounted() {
+        if (this.$route.query.auctionId) {
+            this.auctionId = this.$route.query.auctionId;
+        }
+        this.getDetail();
+    },
+    methods: {
+        getDetail() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.$http
+                .get('/auctionActivity/get/' + this.auctionId)
+                .then(res => {
+                    this.info = res;
+                    // this.startCount();
+                    this.$nextTick(() => {
+                        this.$refs.info.setTime();
+                    });
+                    this.getRecord();
+
+                    this.$toast.clear();
+                })
+                .catch(e => {
+                    this.$toast.clear();
+                    if (e && e.error) {
+                        this.$dialog
+                            .alert({
+                                title: '提示',
+                                message: e.error
+                            })
+                            .then(res => {
+                                this.$router.back();
+                            });
+                    }
+                });
+        },
+        getRecord() {
+            this.$http
+                .post(
+                    '/auctionRecord/all',
+                    {
+                        query: {
+                            auctionId: this.auctionId,
+                            type: 'BIDDER',
+                            del: false
+                        },
+                        size: 3,
+                        page: 0,
+                        sort: 'id,desc'
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.records = res.content;
+                });
+            this.$http.get('/auctionRecord/hasPayDeposit?auctionId=' + this.auctionId).then(res => {
+                this.recordInfo = res;
+            });
+        },
+        submit() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.$http
+                .post('/auctionRecord/create', {
+                    auctionId: this.auctionId,
+                    amount: this.value
+                })
+                .then(res => {
+                    this.$toast.success('出价成功');
+                    setTimeout(() => {
+                        history.back();
+                    }, 1000);
+                })
+                .catch(e => {
+                    this.$toast.clear();
+                    if (e && e.error) {
+                        this.$toast(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.page {
+    background-color: #f5f7fa;
+}
+
+.status {
+    font-size: 12px;
+    color: #ffffff;
+    line-height: 28px;
+    height: 28px;
+    background: #ff7f1f;
+    text-align: center;
+}
+
+.container {
+    padding: 16px;
+    .auction-info {
+        margin: 0;
+        width: 100%;
+        display: flex;
+    }
+}
+.panel {
+    background: #ffffff;
+    border-radius: 8px;
+    margin-top: 16px;
+    padding: 16px 18px;
+    .flex-col();
+    .panel-title {
+        font-size: 14px;
+        font-weight: bold;
+        color: #000000;
+        line-height: 24px;
+        text-align: center;
+        padding-bottom: 16px;
+    }
+
+    /deep/ .van-stepper {
+        .flex();
+        .van-stepper__minus,
+        .van-stepper__plus {
+            width: 44px !important;
+            height: 44px !important;
+            color: #3ab200 !important;
+            border: 1px solid #3ab200 !important;
+            background-color: #f2f4f5 !important;
+            font-weight: bold;
+        }
+
+        .van-stepper__input {
+            height: 60px !important;
+            background: #f5f7fa;
+            border-radius: 8px;
+            flex-grow: 1;
+            margin: 0 20px;
+            font-size: 40px;
+            font-family: OSP-DIN, OSP;
+            font-weight: normal;
+            color: #3ab200;
+        }
+
+        .van-stepper__plus--disabled,
+        .van-stepper__minus--disabled {
+            color: #939599 !important;
+            border-color: #939599 !important;
+            background-color: #f2f4f5 !important;
+            opacity: 1;
+        }
+    }
+
+    .van-button {
+        font-size: 16px;
+        font-weight: bold;
+    }
+
+    .panel-tips {
+        text-align: center;
+        font-size: 12px;
+        color: #3ab200;
+        line-height: 17px;
+        padding: 10px 0 12px;
+    }
+}
+
+.list-box {
+    padding: 20px 0;
+    .name {
+        .flex();
+        img {
+            width: 18px;
+            height: 18px;
+        }
+        span {
+            font-size: 14px;
+            font-weight: bold;
+            color: #000000;
+            line-height: 24px;
+            margin-left: 10px;
+        }
+    }
+
+    .list {
+        .item {
+            font-size: 12px;
+            color: #939599;
+            line-height: 17px;
+            .flex();
+
+            &:first-child {
+                color: #000;
+            }
+            margin-top: 10px;
+
+            span {
+                &:first-child {
+                    width: 20%;
+                    overflow: hidden; //溢出隐藏
+                    white-space: nowrap; //禁止换行
+                    text-overflow: ellipsis;
+                    display: inline-block;
+                }
+
+                &:nth-child(3) {
+                    flex-grow: 1;
+                }
+            }
+
+            span + span {
+                margin-left: 18px;
+            }
+        }
+    }
+}
+
+.empty {
+    text-align: center;
+    font-size: 12px;
+    color: #939599;
+    padding: 16px;
+}
+</style>

+ 426 - 0
src/views/auction/Search.vue

@@ -0,0 +1,426 @@
+<template>
+    <van-pull-refresh
+        class="search"
+        success-text="加载成功"
+        success-duration="1000"
+        :style="{ backgroundColor: isSearch ? $colors.bg3 : $colors.bg }"
+        v-model="isLoading"
+        @refresh="onRefresh"
+    >
+        <van-sticky ref="top" class="list-top" :offset-top="bar.value && bar.value.show ? 46 : 0">
+            <van-search
+                ref="top"
+                shape="round"
+                v-model="search"
+                placeholder="请输入"
+                show-action
+                autofocus
+                :left-icon="require('@assets/svgs/icon-sosuo.svg')"
+                @search="getSearch"
+            >
+                <template #action>
+                    <div v-if="!isSearch" @click="getSearch(search)">搜索</div>
+                    <div v-else @click="onCancel">取消</div>
+                </template>
+            </van-search>
+            <van-tabs
+                v-if="isSearch"
+                v-model:active="sort"
+                :ellipsis="false"
+                line-width="16"
+                line-height="2"
+                @click-tab="changeTab"
+                :class="{ trans: source == 'TRANSFER' }"
+            >
+                <van-tab
+                    :title="item.label"
+                    :name="item.value"
+                    :title-class="item.type === 'select' && sortDes ? sortDes : ''"
+                    :key="index"
+                    :lazy-render="false"
+                    v-for="(item, index) in selectOptions"
+                >
+                    <template v-if="item.type === 'select'" #title>
+                        <div class="tab">
+                            <span>{{ item.label }}</span>
+                            <van-icon size="8" name="arrow-up" />
+                            <van-icon size="8" name="arrow-down" />
+                        </div>
+                    </template>
+                </van-tab>
+            </van-tabs>
+            <!-- <van-checkbox
+                v-if="isSearch && source == 'TRANSFER' && !title"
+                @change="getData(true)"
+                class="sala"
+                v-model="salable"
+                >仅看在售</van-checkbox
+            > -->
+
+            <van-button
+                @click="changeSort"
+                v-if="isSearch && source == 'TRANSFER' && !title"
+                class="sala"
+                color="#F5F7FA"
+                type="primary"
+                size="small"
+                icon="arrow-down"
+                icon-position="right"
+                round
+                >{{ salable ? '在售中' : salable === false ? '仅展示' : '综合排序' }}</van-button
+            >
+        </van-sticky>
+
+        <van-action-sheet
+            v-model:show="showAction"
+            @select="selectAction"
+            :actions="actions"
+            cancel-text="取消"
+            close-on-click-action
+        />
+        <van-list
+            class="list"
+            v-model:loading="loading"
+            :immediate-check="false"
+            :finished="finished"
+            finished-text=""
+            @load="getData"
+            v-if="isSearch"
+        >
+            <template v-for="(item, index) in list" :key="index">
+                <auction-info v-model:info="list[index]"></auction-info>
+            </template>
+            <van-empty v-if="empty" description="什么都没有搜到哦~" :image="require('@assets/kong_png_wusousuo.png')" />
+        </van-list>
+        <div class="search-content" v-else>
+            <div class="hot-content" v-if="historys.length > 0">
+                <div class="title">最近搜索</div>
+                <div class="hot-list">
+                    <span v-for="(item, index) in historys" :key="index" @click="getSearch(item)">{{ item }}</span>
+                </div>
+            </div>
+            <div class="hot-content" v-if="hots.length > 0">
+                <div class="title">热门搜索</div>
+                <div class="hot-list">
+                    <span v-for="(item, index) in hots" :key="index" @click="getSearch(item)">{{ item }}</span>
+                </div>
+            </div>
+        </div>
+    </van-pull-refresh>
+</template>
+
+<script>
+import auctionInfo from '../../components/auction/info.vue';
+import product from '../../mixins/product';
+import list from '../../mixins/list';
+import search from '../../mixins/search';
+export default {
+    name: 'auctionSearch',
+    components: { auctionInfo },
+    inject: ['bar', 'setKeeps', 'scrollWrapper', 'changeScroll'],
+    mixins: [product, list, search],
+    data() {
+        return {
+            list: [],
+            beforeSort: '',
+            empty: false,
+            search: '',
+            stiky: null,
+            auctionType: '',
+            source: '',
+            status: '',
+            minterId: '',
+            url: '/auctionActivity/all',
+            scrollTop: 0,
+            sort: 'id,desc',
+            sortDes: '',
+            title: '',
+            selectOptions: [
+                {
+                    label: '全部',
+                    value: 'id,desc'
+                },
+                {
+                    label: '最新',
+                    value: 'createdAt,desc'
+                },
+                {
+                    label: '最热',
+                    value: 'likes,desc'
+                }
+                // {
+                //     label: '价格',
+                //     value: 'price',
+                //     type: 'select'
+                // }
+            ],
+            salable: '',
+            showAction: false
+        };
+    },
+    watch: {
+        isSearch() {
+            this.changeScroll(0);
+        }
+    },
+    computed: {
+        actions() {
+            let list = [{ name: '综合排序' }, { name: '在售中' }, { name: '仅展示' }];
+            if (this.salable === '') {
+                list[0].color = this.$colors.prim;
+            }
+            if (this.salable === true) {
+                list[1].color = this.$colors.prim;
+            }
+            if (this.salable === false) {
+                list[2].color = this.$colors.prim;
+            }
+            return list;
+        }
+    },
+    mounted() {
+        this.$store.dispatch('getUsedBuy');
+        if (this.$route.query.auctionType) {
+            this.auctionType = this.$route.query.auctionType;
+        }
+        if (this.$route.query.status) {
+            this.status = this.$route.query.status;
+        }
+        if (this.$route.query.search) {
+            this.search = this.$route.query.search;
+            this.getSearch(this.search);
+        }
+    },
+    methods: {
+        changeSort() {
+            this.showAction = true;
+        },
+        selectAction(action) {
+            if (action.name == '综合排序') {
+                this.salable = '';
+            }
+            if (action.name == '在售中') {
+                this.salable = true;
+            }
+            if (action.name == '仅展示') {
+                this.salable = false;
+            }
+            this.getData(true);
+        },
+        changeTab(info) {
+            this.$nextTick(() => {
+                if (info.name === 'price') {
+                    this.sortDes = this.sortDes == 'desc' ? 'asc' : 'desc';
+                }
+                this.getData(true);
+            });
+        },
+        beforeData() {
+            let sort = this.sort;
+            if (sort == 'price') {
+                sort = 'price,' + this.sortDes;
+            }
+            return {
+                query: {
+                    auctionType: this.auctionType,
+                    status: this.status,
+                    del: false
+                },
+                search: this.search,
+                sort: this.sort === 'id,desc' ? this.sortOptions[this.title] || sort : sort
+            };
+        },
+        onRefresh() {
+            if (this.isSearch) {
+                this.getData(true).then(() => {
+                    this.isLoading = false;
+                });
+            } else {
+                this.$http.get('sysConfig/get/hot_search').then(res => {
+                    this.hots = res.value.split(',').filter(item => {
+                        return item !== ' ' && !!item;
+                    });
+
+                    this.isLoading = false;
+                });
+                this.getHistory();
+            }
+        }
+    },
+    activated() {
+        this.$nextTick(() => {
+            this.changeScroll(this.scrollTop);
+
+            // setTimeout(() => {
+            //     this.sort = this.beforeSort;
+            // }, 1000);
+        });
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.name === 'auctionDetail') {
+            this.beforeSort = this.sort;
+            this.scrollTop = this.scrollWrapper.value.scrollTop;
+            this.setKeeps(['auctionSearch']);
+        } else {
+            this.beforeSort = '';
+            this.scrollTop = 0;
+            this.setKeeps(['auctionSearch'], false);
+        }
+        next();
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.search {
+    background-color: @bg3;
+    padding-bottom: 100px;
+}
+.top {
+    background-color: @bg3;
+    padding: 0 16px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    .name {
+        font-size: 20px;
+        // font-weight: bold;
+        color: @prim;
+        line-height: 30px;
+    }
+}
+
+/deep/.trans {
+    .van-tab {
+        margin-right: 30px;
+    }
+}
+
+.list-top {
+    position: relative;
+}
+/deep/.van-tabs {
+    .van-tabs__nav {
+        padding-left: 16px;
+    }
+}
+.list {
+    padding: 8px 8px 100px;
+}
+// /deep/.van-tab {
+// flex-grow: 0;
+// padding: 0 0 0 0;
+// margin-right: 50px;
+
+.tab {
+    position: relative;
+    padding-right: 14px;
+    .van-icon {
+        position: absolute;
+        right: 0;
+
+        &.van-icon-arrow-down {
+            top: 8px;
+        }
+
+        &.van-icon-arrow-up {
+            bottom: 8px;
+        }
+    }
+}
+/deep/.van-tab--active {
+    .tab {
+        .van-icon-arrow-up {
+            color: #646566;
+        }
+    }
+    &.asc {
+        .tab {
+            .van-icon-arrow-up {
+                color: @prim;
+            }
+            .van-icon-arrow-down {
+                color: #646566;
+            }
+        }
+    }
+}
+.van-tabs {
+    background-color: @bg;
+}
+/deep/.van-tabs__nav--line.van-tabs__nav--complete {
+    border-color: @tabBorder;
+}
+/deep/.van-search {
+    .van-field__left-icon {
+        display: flex;
+        align-items: center;
+    }
+    .van-icon {
+        display: flex;
+        align-items: center;
+    }
+    .van-field__control {
+        color: @text0;
+    }
+
+    .van-search__action {
+        color: @text4;
+    }
+}
+
+.hot-content {
+    padding: 10px 0 6px 16px;
+
+    .title {
+        font-size: @font2;
+        color: @text3;
+        line-height: 24px;
+    }
+
+    .hot-list {
+        span {
+            display: inline-block;
+            font-size: @font1;
+            color: @text4;
+            line-height: 22px;
+            padding: 0 12px;
+            margin: 6px 16px 0 0;
+            background: @hotBg;
+            border-radius: 12px;
+        }
+    }
+}
+
+/deep/.sala {
+    position: absolute;
+    right: 16px;
+    top: 60px;
+    color: @text3!important;
+    min-width: 92px;
+    font-size: 14px;
+    // .van-checkbox__icon {
+    //     color: #fff;
+    //     transform: scale(0.6);
+
+    //     .van-icon {
+    //         border-color: @text3;
+    //     }
+
+    //     &.van-checkbox__icon--checked {
+    //         .van-icon {
+    //             border-width: 0;
+    //             .linear();
+    //             &::before {
+    //                 color: #fff;
+    //             }
+    //         }
+    //     }
+    // }
+    // .van-checkbox__label {
+    //     color: @text3;
+    //     margin-left: 0px;
+    //     font-size: @font1;
+    // }
+}
+</style>

+ 677 - 0
src/views/auction/Submit.vue

@@ -0,0 +1,677 @@
+<template>
+    <div class="submit">
+        <van-notice-bar
+            :text="getLabelName(paymentType, paymentTypeOptions, 'text')"
+            background="#FF7F1F"
+            color="#fff"
+        />
+        <div class="address" v-if="!isNFT">
+            <div class="van-address-item van-contact-card" @click="onAdd">
+                <div class="van-cell van-cell--borderless">
+                    <div class="van-cell__value van-cell__value--alone van-address-item__value">
+                        <div role="radio" class="van-radio" tabindex="0" aria-checked="false">
+                            <span class="van-radio__label" v-if="addressInfo.id">
+                                <div class="van-address-item__name">{{ showAddress.name }} {{ showAddress.tel }}</div>
+                                <div class="van-address-item__address">{{ showAddress.address }}</div>
+                            </span>
+                            <span class="van-radio__label tips" v-else> 选择收货地址 </span>
+                        </div>
+                    </div>
+                    <i class="van-badge__wrapper van-icon van-icon-arrow van-address-item__edit"></i>
+                </div>
+            </div>
+        </div>
+        <div class="assets">
+            <div class="assets-product" :class="{ isEnd: isEnd }">
+                <van-image width="80" height="80" radius="6" :src="getImg(changeImgs(info.pic))" fit="cover" />
+                <div class="assets-info">
+                    <div class="text1">{{ info.name }}</div>
+                    <div class="flex1"></div>
+
+                    <div class="text2">
+                        <div class="time" v-if="!isEnd">
+                            <img src="../../assets/info_icon_time.png" alt="" />
+                            <span>{{ timeText }}:<van-count-down :time="time" format="HH 小时 mm 分 ss 秒" /></span>
+                        </div>
+                        <div class="time" v-else>{{ timeText }}</div>
+                    </div>
+                    <!-- <div class="text2" v-if="info.category">类型:{{ info.category }}</div>
+                    <div class="text2" v-if="info.number">编号:{{ info.number }}</div> -->
+                </div>
+            </div>
+        </div>
+
+        <div class="text-list">
+            <div class="text-info">
+                <span class="text1">{{ getLabelName(paymentType, paymentTypeOptions) }}</span>
+                <span class="text2">¥{{ preMoney }}</span>
+            </div>
+
+            <!-- <div class="text-info">
+                <span class="text1">GAS费用</span>
+                <span class="text2">¥{{ gas }}</span>
+            </div> -->
+            <div class="text-info">
+                <span class="text1">实际支付</span>
+                <span class="text2 prim">¥{{ money }}</span>
+            </div>
+
+            <template v-if="paymentType !== 'FIXED_PRICE'">
+                <div class="text-cell">
+                    <div class="text-top">
+                        <span class="text1">保证金</span>
+                        <span class="text2 warn">¥{{ info.deposit }}</span>
+                    </div>
+                    <div class="sub">
+                        竞拍成功支付后,送拍机构主动关闭交易,系统会在72小时内释放保证金;若竞拍成功未支付,保证金将不会释放
+                    </div>
+                </div>
+                <div class="text-info">
+                    <span class="text1">保证金状态</span>
+                    <span class="text2">正常</span>
+                </div>
+            </template>
+        </div>
+
+        <div class="pay" v-if="!$store.state.review">
+            <!-- <div class="pay-item" @click="payType = item.type" v-for="(item, index) in payInfos" :key="index">
+                <img class="icon" :src="item.icon" alt="" />
+                <span>{{ item.name }}</span>
+                <img class="choose-icon" :src="payType === item.type ? icons[1] : icons[0]" alt="" />
+            </div> -->
+            <pay-method-pick v-model="payType"></pay-method-pick>
+        </div>
+
+        <div class="bottom van-safe-area-bottom" ref="bottom">
+            <div class="bottom-content">
+                <span class="text">实际支付</span>
+                <span class="price"> <img src="@assets/jiage_huang.png" alt="" />{{ money }} </span>
+                <div class="btn">
+                    <van-button
+                        round
+                        :color="`linear-gradient(135deg, ${$colors.prim} 0%, ${$colors.warn} 100%)`"
+                        @click="submit"
+                        :disabled="!!orderId"
+                    >
+                        立即支付
+                    </van-button>
+                </div>
+                <a id="pay" :href="hrefUrl"></a>
+                <!-- <wx-open-launch-weapp id="launch-btn" :username="launchName" :path="launchPath"> </wx-open-launch-weapp> -->
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import asset from '../../mixins/asset';
+import imgInfo from '../../mixins/imgInfo';
+import resolveUrl from 'resolve-url';
+let inWeixin = /micromessenger/i.test(navigator.userAgent);
+let inApp = /#cordova#/i.test(navigator.userAgent);
+let inIos = /iPhone|iPad|iPod/i.test(navigator.userAgent);
+import auctionOrder from '../../mixins/auctionOrder';
+import auction from '../../mixins/auction';
+import PayMethodPick from '../../components/PayMethodPick.vue';
+export default {
+    components: { PayMethodPick },
+    name: 'activitySubmit',
+    inject: ['setKeeps'],
+    mixins: [asset, imgInfo, auctionOrder, auction],
+    data() {
+        return {
+            addressInfo: {},
+            list: [],
+            payType: null,
+            payChannel: null,
+            payInfos: [
+                {
+                    icon: require('@assets/svgs/zhifubao.svg'),
+                    name: '支付宝',
+                    type: 'ALIPAY'
+                },
+                {
+                    icon: require('@assets/svgs/wechat.svg'),
+                    name: '微信',
+                    type: 'WEIXIN'
+                }
+                // {
+                //   icon: require("@assets/svgs/png-decp.svg"),
+                //   name: "DCEP",
+                // },
+            ],
+            icons: [require('@assets/svgs/icon_gouxuan_huise.svg'), require('@assets/icon_gouxuan_pre.png')],
+            inWeixin,
+            inApp,
+            inIos,
+            gas: 1,
+            enable_wx_lite: false,
+            enable_wx_pub: false,
+            assets: '',
+            auctionId: 0,
+            orderId: 0,
+            hrefUrl: '',
+            timer: null,
+            info: {},
+            time: '',
+            paymentType: 'FIXED_PRICE',
+            recordInfo: {}
+        };
+    },
+    computed: {
+        preMoney() {
+            if (this.paymentType === 'PURCHASE_PRICE') {
+                return this.info.purchasePrice || 0;
+            } else {
+                return this.info.fixedPrice || 0;
+            }
+        },
+        money() {
+            let money = 0;
+            if (this.preMoney) {
+                money = this.accAdd(this.preMoney, money);
+            }
+            // if (this.gas) {
+            //     money = this.accAdd(money, this.gas);
+            // }
+
+            return money;
+        },
+        isNFT() {
+            return this.info.auctionType === 'NFT';
+        },
+        showAddress() {
+            if (this.addressInfo.id) {
+                return {
+                    id: this.addressInfo.id,
+                    name: this.addressInfo.name,
+                    tel: this.addressInfo.phone,
+                    address: `${this.addressInfo.provinceName} ${this.addressInfo.cityName} ${this.addressInfo.districtName} ${this.addressInfo.address}`,
+                    isDefault: this.addressInfo.def
+                };
+            } else {
+                return {};
+            }
+        }
+    },
+    mounted() {
+        console.log(this.$route.query.paymentType);
+        if (this.$route.query.paymentType) {
+            this.paymentType = this.$route.query.paymentType;
+        }
+        this.emitter.on('updateChoose', info => {
+            // console.log(id);
+            this.addressInfo = info;
+        });
+        if (this.$route.query.auctionId) {
+            this.auctionId = this.$route.query.auctionId;
+            this.$http.get('/auctionRecord/hasPayDeposit?auctionId=' + this.auctionId).then(res => {
+                this.recordInfo = res;
+            });
+            this.$http.get('/auctionActivity/get/' + this.auctionId).then(res => {
+                this.info = res;
+                this.time = this.getTime(res.endTime);
+                // this.gas = res.gasPrice;
+                this.$http
+                    .post(
+                        '/userAddress/all',
+                        {
+                            query: {
+                                userId: this.$store.state.userInfo.id,
+                                del: false,
+                                def: true
+                            },
+                            size: 99
+                        },
+                        { body: 'json' }
+                    )
+                    .then(res => {
+                        if (!res.empty) {
+                            this.addressInfo = res.content[0];
+                        }
+                    });
+            });
+        }
+    },
+    methods: {
+        onAdd() {
+            this.$router.push('/mineAddress?page=submit&chooseId=' + this.addressInfo.id);
+        },
+        getOrder(next = false) {
+            this.$http.get('/mintOrder/get/' + this.orderId).then(res => {
+                this.info = res;
+                if (this.timer) {
+                    clearTimeout(this.timer);
+                }
+                if (res.status && res.status !== 'NOT_PAID') {
+                    this.$toast.clear();
+                    this.$dialog
+                        .alert({
+                            title: '提示',
+                            message:
+                                res.status === 'CANCELLED' ? '订单支付失败,点击重新下单' : '订单已支付,点击查看订单详情'
+                        })
+                        .then(() => {
+                            if (res.status === 'CANCELLED') {
+                                this.$router.back();
+                            } else {
+                                this.$router.replace('/activityOrderDetail?id=' + res.id);
+                            }
+                            // on close
+                        });
+                } else if (next) {
+                    this.timer = setTimeout(() => {
+                        this.getOrder(next);
+                    }, 1000);
+                }
+            });
+        },
+        createOrder() {
+            this.$toast.loading('请不要离开当前页面');
+
+            let form = {
+                userId: this.$store.state.userInfo.id,
+                auctionId: this.auctionId,
+                type: this.paymentType
+            };
+
+            if (!this.isNFT) {
+                form.addressId = this.addressInfo.id;
+            }
+
+            if (this.paymentType === 'PURCHASE_PRICE') {
+                form.auctionRecordId = this.recordInfo.id;
+                return this.$http
+                    .post('/auctionOrder/create', form)
+                    .then(res => {
+                        return Promise.resolve(res);
+                    })
+                    .catch(e => {
+                        return Promise.reject(e);
+                    });
+            } else {
+                return this.$http
+                    .post('/auctionOrder/createFixPrice', form)
+                    .then(res => {
+                        return Promise.resolve(res);
+                    })
+                    .catch(e => {
+                        return Promise.reject(e);
+                    });
+            }
+        },
+        submit() {
+            if (!this.addressInfo.id && !this.isNFT) {
+                this.$toast('请选择收货地址');
+                return;
+            }
+            if (!this.payType) {
+                this.$toast('请选择支付方式');
+                return;
+            }
+            this.createOrder()
+                .then(res => {
+                    this.$toast.clear();
+                    this.orderId = res.id;
+                    if (Number(this.money) != 0) {
+                        this.$nextTick(() => {
+                            if (this.payType === 'SYXPAY') {
+                                this.$toast.clear();
+                                this.$router.replace(
+                                    '/bankPay?id=' + this.orderId + '&type=auction&paymentType=' + this.paymentType
+                                );
+                            } else if (this.$store.state.review) {
+                                window.store.order('358');
+                                this.getOrder(true);
+                            } else if (this.payType === 'ALIPAY') {
+                                if (this.inWeixin) {
+                                    document.location.replace(
+                                        resolveUrl(this.$baseUrl, '/payOrder/v2/auction/alipay_wx?id=' + res.id)
+                                    );
+                                } else {
+                                    this.$http
+                                        .get(`/payOrder/v2/auction/alipay?id=${res.id}`)
+                                        .then(res => {
+                                            this.$toast.clear();
+                                            this.hrefUrl = res;
+                                            this.$nextTick(() => {
+                                                document.getElementById('pay').click();
+                                            });
+
+                                            this.$toast.loading({
+                                                message: '加载中...',
+                                                forbidClick: true
+                                            });
+                                            this.getOrder(true);
+                                        })
+                                        .catch(e => {
+                                            if (e.error) {
+                                                this.$toast(e.error);
+                                            }
+                                        });
+                                }
+                            } else if (this.payType === 'WEIXIN') {
+                                this.$toast.loading('加载中');
+                                this.$http
+                                    .post('/payOrder/auction/weixin', {
+                                        id: res.id,
+                                        channel: this.payChannel,
+                                        openId: localStorage.getItem('openId') || 'oWJG55wLnwdVzXoKka1-DzQKOd_Y'
+                                    })
+                                    .then(res => {
+                                        if ('wx_pub' === this.payChannel) {
+                                            console.log('wxPayParams', res);
+                                            wx.chooseWXPay({
+                                                ...res,
+                                                success(res) {
+                                                    this.$toast.success('支付成功');
+                                                    setTimeout(() => {
+                                                        this.$router.replace('/orders');
+                                                    }, 1000);
+                                                },
+                                                fail(e) {
+                                                    console.log(e);
+                                                    this.$toast('支付失败,请稍后再试');
+                                                }
+                                            });
+                                        } else {
+                                            this.$toast.clear();
+                                            this.hrefUrl = res.scheme_code;
+                                            this.$nextTick(() => {
+                                                document.getElementById('pay').click();
+                                            });
+
+                                            this.$toast.loading({
+                                                message: '加载中...',
+                                                forbidClick: true
+                                            });
+                                            this.getOrder(true);
+                                        }
+                                    })
+                                    .catch(e => {
+                                        this.$toast(e.error || '支付失败请稍后再试');
+                                    });
+                            } else if (this.payType === 'UNION') {
+                                document.location.href = resolveUrl(
+                                    this.$baseUrl,
+                                    '/payOrder/v2/auction/sandQuick?id=' + this.orderId
+                                )
+                                    .replace('www.raex.vip', 'jump.raex.vip')
+                                    .replace('test.raex.vip', 'jumptest.raex.vip')
+                                    .replace(/http:\/\/192\.168.*?\//, 'https://jumptest.raex.vip/');
+                            }
+                        });
+                    } else {
+                        this.$router.replace('/activityOrderDetail?id=' + this.orderId);
+                    }
+                })
+                .catch(e => {
+                    if (e) {
+                        this.$toast(e.error);
+                    }
+                });
+        }
+    },
+    beforeRouteLeave(to, from, next) {
+        if (to.path === '/mineAddress') {
+            this.setKeeps(['activitySubmit']);
+        } else {
+            this.setKeeps(['activitySubmit'], false);
+        }
+        next();
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.hr {
+    width: 100%;
+    height: 6px;
+    display: block;
+}
+
+.address {
+    .van-address-item {
+        position: relative;
+        padding: 20px 16px 26px;
+        .van-radio__label {
+            margin-left: 0;
+        }
+        .van-address-item__edit {
+            right: 0;
+            color: @text3;
+            &::before {
+                color: @text3;
+            }
+        }
+
+        &::before {
+            height: 6px;
+            background-size: 120px;
+        }
+    }
+    .tips {
+        color: @text3;
+    }
+}
+
+.submit {
+    background-color: @bg3;
+    padding-bottom: 100px;
+}
+.assets {
+    background-color: @bg;
+    padding: 16px;
+}
+.assets-title {
+    .text1 {
+        font-size: 14px;
+        color: #000000;
+        line-height: 24px;
+    }
+    .text2 {
+        font-size: 12px;
+        color: #ff4f50;
+    }
+}
+
+.assets-product {
+    display: flex;
+    margin: 6px 0;
+
+    .assets-info {
+        display: flex;
+        flex-direction: column;
+        flex-grow: 1;
+        margin-left: 12px;
+        .text1 {
+            font-size: 14px;
+            color: #000000;
+            line-height: 24px;
+            font-weight: bold;
+        }
+
+        .text2 {
+            font-size: 12px;
+            color: #939599;
+            line-height: 17px;
+        }
+    }
+
+    &:last-child {
+        margin-bottom: 0;
+    }
+
+    &.isEnd {
+        .text2 {
+            .time {
+                font-size: 12px;
+                color: #939599;
+                background-color: #f2f4f5;
+            }
+        }
+    }
+}
+
+.pay-item {
+    display: flex;
+    align-items: center;
+    height: 48px;
+    border-top: 1px solid @tabBorder;
+    .icon {
+        height: 24px;
+        display: block;
+    }
+    span {
+        font-size: 14px;
+        font-weight: bold;
+        color: @text0;
+        line-height: 24px;
+        flex-grow: 1;
+        padding: 0 10px;
+    }
+    .choose-icon {
+        width: 24px;
+        height: 24px;
+    }
+}
+.pay {
+    padding: 0 16px;
+    background-color: @bg;
+}
+
+.bottom {
+    position: fixed;
+    bottom: 0px;
+    left: 0;
+    right: 0;
+    background-color: @bg;
+    z-index: 20;
+    border-top: 1px solid @tabBorder;
+
+    .bottom-content {
+        padding: 6px 16px;
+        display: flex;
+        align-items: flex-end;
+
+        .btn {
+            flex-grow: 1;
+            display: flex;
+            justify-content: flex-end;
+        }
+        .van-button {
+            flex-grow: 1;
+            color: @btnText !important;
+            max-width: 132px;
+        }
+        .text {
+            font-size: 14px;
+            color: @text3;
+            line-height: 20px;
+            margin-bottom: 2px;
+            word-break: keep-all;
+        }
+
+        .price {
+            font-size: 34px;
+            font-family: OSP;
+            font-weight: normal;
+            color: @prim;
+            line-height: 30px;
+            display: flex;
+            align-items: center;
+
+            // flex-grow: 1;
+            margin: 0 6px;
+            .font_family {
+                font-size: 10px;
+            }
+
+            img {
+                width: 10px;
+                height: 11px;
+                display: block;
+                margin-top: 8px;
+            }
+        }
+    }
+}
+.text-list {
+    padding: 0 16px;
+    background-color: #fff;
+}
+.text-info {
+    .flex();
+    height: 48px;
+    font-size: 14px;
+    color: #000000;
+    line-height: 24px;
+    justify-content: space-between;
+
+    .text2 {
+        font-weight: bold;
+    }
+    .prim {
+        color: @prim;
+    }
+
+    border-top: 1px solid #f5f7fa;
+}
+
+.text-cell {
+    padding: 12px 0 10px;
+    border-top: 1px solid #f5f7fa;
+    .text-top {
+        .flex();
+        font-size: 14px;
+        color: #000000;
+        line-height: 24px;
+        justify-content: space-between;
+        .text2 {
+            font-weight: bold;
+        }
+        .warn {
+            color: #ff7f1f;
+        }
+    }
+    .sub {
+        font-size: 12px;
+        color: #ff7f1f;
+        line-height: 17px;
+        margin-top: 4px;
+    }
+}
+
+.van-notice-bar {
+    height: 28px;
+    /deep/.van-notice-bar__wrap {
+        justify-content: center;
+    }
+}
+
+.time {
+    .flex();
+    height: 22px;
+    background: #fff7f2;
+    border-radius: 4px;
+    display: inline-flex;
+    padding: 0 4px;
+    margin-bottom: 10px;
+    img {
+        width: 18px;
+        height: 18px;
+    }
+    span {
+        margin-left: 2px;
+        .flex();
+        font-size: 12px;
+        color: #ff7f1f;
+        line-height: 22px;
+        .van-count-down {
+            font-size: 12px;
+            color: #ff7f1f;
+            line-height: 22px;
+        }
+    }
+}
+</style>

+ 441 - 0
src/views/order/AuctionDetail.vue

@@ -0,0 +1,441 @@
+<template>
+    <van-pull-refresh
+        success-text="加载成功"
+        success-duration="1000"
+        class="order"
+        v-model="isLoading"
+        :head-height="80"
+        @refresh="onRefresh"
+    >
+        <div class="order-content">
+            <div class="order-top">
+                <div class="text1">{{ getLabelName(info.status, orderStatusOptions) }}</div>
+                <div class="text2">
+                    {{
+                        info.status === 'FINISH'
+                            ? info.airDrop
+                                ? '交易成功啦!交易后的藏品将在您的藏品室中展示'
+                                : '交易已完成!'
+                            : getLabelName(info.status, statusOptions, 'text')
+                    }}
+                </div>
+            </div>
+            <driver />
+            <template v-if="!info.airDrop && info.contactName">
+                <div class="address" v-if="info.courierId">
+                    <img src="../../assets/dingdan_icon_wuliu.png" alt="" />
+                    <div class="text1">快递编号</div>
+                    <div class="text2" @click="copyWuliu">
+                        <span>{{ info.courierId }}</span>
+                        <img src="../../assets/icon-miaoshu.png" alt="" />
+                    </div>
+                </div>
+                <div class="address">
+                    <img src="../../assets/dingdan_icon_dizhi.png" alt="" />
+                    <div class="text1">{{ info.contactName }} {{ info.contactPhone }}</div>
+                    <div class="text1">{{ info.address }}</div>
+                </div>
+                <driver />
+            </template>
+            <div class="product">
+                <div class="product-title">
+                    <div class="text1">{{ info.mintActivity }}</div>
+                    <div class="text2" v-if="info.consume">商品的铸造将会销毁对应藏品</div>
+                </div>
+                <div class="product-info">
+                    <van-image :radius="6" width="60" height="60" :src="getImg(changeImgs(info.pic))" fit="cover" />
+                    <div class="product-content">
+                        <div class="text1 van-multi-ellipsis--l2">{{ info.name }}</div>
+                        <div class="flex1"></div>
+                        <div class="text2" v-if="info.category">类型:{{ info.category }}</div>
+                        <div class="text2" v-if="info.number">编号:{{ info.number }}</div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="info-item">
+                <div class="text1">{{ getLabelName(info.paymentType, paymentTypeOptions) }}交价</div>
+                <div class="text1 prim">¥{{ info.price }}</div>
+            </div>
+
+            <div class="info-item">
+                <div class="text1">实际支付</div>
+                <div class="text1 prim">¥{{ info.totalPrice }}</div>
+            </div>
+
+            <div class="info-item" v-if="!$store.state.review && info.payTime">
+                <div class="text1">支付方式</div>
+                <div class="text1">{{ getLabelName(info.payMethod, payMethodOptions) }}支付</div>
+            </div>
+
+            <div class="text-cell" v-if="info.paymentType !== 'FIXED_PRICE'">
+                <div class="text-top">
+                    <span class="text1">保证金</span>
+                    <span class="text2 warn">¥{{ auctionInfo.deposit }}</span>
+                </div>
+                <div class="sub">
+                    竞拍成功支付后,送拍机构主动关闭交易,系统会在72小时内释放保证金;若竞拍成功未支付,保证金将不会释放
+                </div>
+            </div>
+
+            <div class="tips-item">
+                <div class="text1">订单编号</div>
+                <div class="text2">
+                    <van-button @click="copy" color="#939599" plain size="mini">复制</van-button>
+                    <span>{{ info.id }}</span>
+                </div>
+            </div>
+            <div class="tips-item">
+                <div class="text1">创建时间</div>
+                <div class="text2">
+                    {{ info.createdAt }}
+                </div>
+            </div>
+            <div class="tips-item" v-if="info.payTime">
+                <div class="text1">付款时间</div>
+                <div class="text2">
+                    {{ info.payTime }}
+                </div>
+            </div>
+        </div>
+
+        <!-- <div class="bottom van-safe-area-bottom" ref="bottom" v-if="info.status === 'RECEIVE' || isLiantong">
+            <div class="bottom-content" v-if="isLiantong">
+                <van-button class="sure" type="primary" block @click="goLiantong" round>填写资料</van-button>
+            </div>
+            <div class="bottom-content" v-else>
+                <van-button class="sure" type="primary" block @click.prevent="sure" round> 确认收货 </van-button>
+            </div>
+        </div> -->
+    </van-pull-refresh>
+</template>
+
+<script>
+import auctionOrder from '../../mixins/auctionOrder';
+import auction from '../../mixins/auction';
+export default {
+    name: 'detail',
+    data() {
+        return {
+            info: {},
+            collection: {},
+            timer: null,
+            auctionInfo: {}
+        };
+    },
+    mixins: [auctionOrder, auction],
+    mounted() {
+        this.getInfo();
+    },
+    computed: {
+        isLiantong() {
+            if (this.info.status === 'DELIVERY' || this.info.status === 'RECEIVE') {
+                if ((this.info.mintActivity || '').indexOf('联通') !== -1) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    },
+    methods: {
+        goLiantong() {
+            window.location.href = 'https://m.75510010.com/view/NSZS5GBJL';
+        },
+        getInfo() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+
+            return this.$http
+                .get('/auctionOrder/get/' + this.$route.query.id)
+                .then(res => {
+                    this.info = res;
+                    this.$toast.clear();
+                    return this.$http.get('/auctionActivity/get/' + res.auctionId);
+                })
+                .then(res => {
+                    this.auctionInfo = res;
+                });
+        },
+        copy() {
+            this.$copyText(this.info.id).then(
+                e => {
+                    this.$toast.success('复制成功');
+                    console.log(e);
+                },
+                e => {
+                    this.$toast('复制失败');
+                    console.log(e);
+                }
+            );
+        },
+        copyWuliu() {
+            this.$copyText(this.info.courierId).then(
+                e => {
+                    this.$toast.success('复制成功');
+                    console.log(e);
+                },
+                e => {
+                    this.$toast('复制失败');
+                    console.log(e);
+                }
+            );
+        },
+        openBlindBox() {
+            this.$toast.loading({
+                message: '加载中'
+            });
+            if (this.timer) {
+                clearInterval(this.timer);
+            }
+            let getWinItem = () => {
+                if (this.info.winCollectionId) {
+                    this.$http.get('/collection/get/' + this.info.winCollectionId).then(res => {
+                        this.$toast.clear();
+                        this.collection = res;
+                        this.$refs.box.show = true;
+                        clearTimeout(this.timer);
+                        this.timer = null;
+                    });
+                } else {
+                    this.$http.get('/order/get/' + this.$route.query.id).then(res => {
+                        this.info = res;
+                    });
+                }
+            };
+            this.timer = setInterval(getWinItem, 1000);
+            this.timeout = setTimeout(() => {
+                if (this.timer) {
+                    this.$toast.clear();
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                this.timeout = null;
+            }, 10000);
+        },
+        sure() {
+            this.$dialog
+                .confirm({
+                    title: '确定已经收到货了吗?'
+                })
+                .then(() => {
+                    return this.$http.get('/mintOrder/finish/' + this.info.id);
+                })
+                .then(() => {
+                    this.$toast.success('确认成功');
+
+                    this.getInfo();
+                });
+        },
+        onRefresh() {
+            this.getInfo().then(() => {
+                this.isLoading = false;
+            });
+        }
+    },
+    beforeRouteLeave() {
+        if (this.timer) {
+            clearInterval(this.timer);
+            this.timer = null;
+        }
+        if (this.timeout) {
+            clearTimeout(this.timeout);
+            this.timer = null;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.order {
+    padding-bottom: 100px;
+    color: @text0;
+    background-color: @bg3;
+}
+.order-content {
+    background-color: @bg;
+}
+.order-top {
+    padding: 26px 16px 20px;
+    .text1 {
+        font-size: 24px;
+        font-weight: bold;
+        color: @prim;
+        line-height: 34px;
+    }
+    .text2 {
+        font-size: 14px;
+        color: @text0;
+        line-height: 24px;
+    }
+}
+.product {
+    padding: 0 16px 20px;
+    border-bottom: 1px solid @bg3;
+    .product-name {
+        padding: 15px 0 12px;
+    }
+    .product-title {
+        padding: 16px 0 12px;
+        .text1 {
+            font-size: 14px;
+            color: #000000;
+            line-height: 24px;
+        }
+
+        .text2 {
+            font-size: 12px;
+            color: #ff4f50;
+        }
+    }
+    .product-info {
+        display: flex;
+
+        .van-image {
+            flex-shrink: 0;
+        }
+        .product-content {
+            flex-grow: 1;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+            margin-left: 12px;
+            .text1 {
+                font-size: @font1;
+                font-weight: bold;
+                color: @text0;
+                line-height: 24px;
+            }
+
+            .text2 {
+                font-size: @font1;
+                color: @text3;
+                line-height: 17px;
+            }
+            .price {
+                font-size: @font1;
+                font-weight: bold;
+                color: @text0;
+                line-height: 17px;
+            }
+        }
+    }
+}
+.info-item {
+    display: flex;
+    justify-content: space-between;
+    padding: 0 16px;
+    height: 48px;
+    align-items: center;
+    border-bottom: 1px solid @bg3;
+    font-size: @font2;
+    .text1 {
+        flex-shrink: 0;
+        &:first-child {
+            margin-right: 10px;
+        }
+
+        &.prim {
+            color: @prim;
+        }
+    }
+}
+.tips-item {
+    display: flex;
+    justify-content: space-between;
+    height: 40px;
+    align-items: center;
+    padding: 0 16px;
+    .text1 {
+        font-size: 13px;
+        color: @text3;
+        line-height: 24px;
+        flex-shrink: 0;
+    }
+    .text2 {
+        font-size: 13px;
+        span {
+            vertical-align: middle;
+        }
+
+        .van-button {
+            vertical-align: middle;
+            margin-right: 5px;
+            height: 20px;
+            font-size: 13px;
+        }
+    }
+}
+
+.address {
+    position: relative;
+    padding: 20px 24px 16px 48px;
+    & > img {
+        position: absolute;
+        left: 18px;
+        top: 22px;
+        width: 20px;
+        display: block;
+    }
+
+    .text1 {
+        font-size: 14px;
+        color: #000000;
+        line-height: 24px;
+    }
+
+    .text2 {
+        font-size: 13px;
+        color: #939599;
+        line-height: 24px;
+        .flex();
+        img {
+            width: 16px;
+            height: 16px;
+            margin-left: 6px;
+        }
+    }
+}
+
+.address + .address {
+    border-top: 1px solid @tabBorder;
+}
+
+.text-cell {
+    padding: 12px 16px 10px;
+    border-bottom: 1px solid #f5f7fa;
+    .text-top {
+        .flex();
+        font-size: 14px;
+        color: #000000;
+        line-height: 24px;
+        justify-content: space-between;
+        .text2 {
+            font-weight: bold;
+        }
+        .warn {
+            color: #ff7f1f;
+        }
+    }
+    .sub {
+        font-size: 12px;
+        color: #ff7f1f;
+        line-height: 17px;
+        margin-top: 4px;
+    }
+}
+
+.bottom {
+    position: fixed;
+    bottom: 0px;
+    left: 0;
+    right: 0;
+    background-color: @bg;
+    z-index: 20;
+    border-top: 1px solid @tabBorder;
+
+    .bottom-content {
+        padding: 6px 16px;
+    }
+}
+</style>

+ 324 - 0
src/views/order/AuctionOrders.vue

@@ -0,0 +1,324 @@
+<template>
+    <van-pull-refresh
+        success-text="加载成功"
+        success-duration="1000"
+        class="discover"
+        v-model="isLoading"
+        :head-height="80"
+        @refresh="onRefresh"
+    >
+        <van-sticky ref="top" :offset-top="46">
+            <div class="top">
+                <div class="top-btn">
+                    <div class="btn" :class="{ active: type === 'ENTITY' }" @click="changeActive('ENTITY')">
+                        藏传文玩拍卖
+                    </div>
+                    <div class="btn" :class="{ active: type === 'NFT' }" @click="changeActive('NFT')">数字艺术拍卖</div>
+                </div>
+            </div>
+
+            <van-tabs
+                v-model:active="paymentType"
+                :ellipsis="false"
+                line-width="16"
+                line-height="2"
+                @click="changeStatus"
+            >
+                <van-tab v-for="(item, index) in tabs" :key="index" :title="item.name" :name="item.status"></van-tab>
+            </van-tabs>
+
+            <!-- <div class="btns">
+                <div class="btn-item" v-for="(item, index) in statusBtns" :key="index">{{ item.name }}</div>
+            </div> -->
+        </van-sticky>
+
+        <van-list class="list" v-model:loading="loading" :finished="finished" finished-text="" @load="getData">
+            <order-info-auction
+                @delFn="delFn"
+                v-for="(item, index) in list"
+                :key="item.id"
+                v-model:info="list[index]"
+                :isOrder="paymentType === 'FIXED_PRICE'"
+            ></order-info-auction>
+            <van-empty v-if="empty" description="你还没有订单哦~" :image="require('@assets/kong_png_wudingdan.png')" />
+        </van-list>
+    </van-pull-refresh>
+</template>
+
+<script>
+import OrderInfoAuction from '../../components/order/OrderInfoAuction.vue';
+import list from '../../mixins/list';
+export default {
+    name: 'discover',
+    inject: ['bar', 'setKeeps', 'scrollWrapper', 'changeScroll'],
+    mixins: [list],
+    components: {
+        OrderInfoAuction
+    },
+    data() {
+        return {
+            active: 'explore',
+            stiky: null,
+            status: 'DELIVERY,PENDING,RECEIVE,AIR_DROP,FINISH',
+            type: 'ENTITY',
+            list: [],
+            paymentType: 'FIXED_PRICE',
+            tabs: [
+                {
+                    status: 'FIXED_PRICE',
+                    name: '一口价订单'
+                },
+                {
+                    status: 'BIDDER',
+                    name: '竞拍订单'
+                }
+            ],
+            statusBtns: [
+                {
+                    status: 'AIR_DROP,',
+                    name: '全部'
+                },
+                {
+                    status: 'AIR_DROP,',
+                    name: '待发货'
+                },
+                {
+                    status: 'AIR_DROP,',
+                    name: '待收货'
+                },
+                {
+                    status: 'AIR_DROP,',
+                    name: '已完成'
+                }
+            ],
+            scrollTop: 0
+        };
+    },
+    mounted() {
+        if (this.$route.query.status) {
+            this.status = this.$route.query.status;
+        }
+    },
+    computed: {
+        url() {
+            if (this.paymentType === 'FIXED_PRICE') {
+                return '/auctionOrder/all';
+            } else {
+                return '/auctionRecord/userRecord';
+            }
+        }
+    },
+    methods: {
+        beforeData() {
+            if (this.paymentType === 'FIXED_PRICE') {
+                return {
+                    query: {
+                        userId: this.$store.state.userInfo.id,
+                        paymentType: this.paymentType,
+                        source: this.type === 'ENTITY' ? 'OFFICIAL' : 'TRANSFER'
+                        // hide: false,
+                        // del: false
+                    },
+                    sort: 'id,desc'
+                };
+            } else {
+                return {
+                    type: this.type
+                };
+            }
+        },
+        getData(isFirst = false, scrollTop = 0) {
+            if (isFirst) {
+                this.page = 0;
+                this.list = [];
+                this.$root.$el.scrollTop = scrollTop;
+            }
+
+            this.loading = true;
+            this.finished = false;
+            this.empty = false;
+            let data = { page: this.page, size: this.size, sort: 'createdAt,desc' };
+            if (this.beforeData) {
+                data = {
+                    ...data,
+                    ...this.beforeData()
+                };
+            }
+            let url = this.url;
+
+            if (this.paymentType !== 'FIXED_PRICE') {
+                data = {};
+                url += '?type=' + this.type;
+            }
+
+            return this.$http.post(url, data, { body: 'json' }).then(res => {
+                if (this.paymentType !== 'FIXED_PRICE') {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.finished = true;
+                    this.loading = false;
+                } else {
+                    if (res.first) {
+                        this.list = [];
+                    }
+                    this.list = [...this.list, ...res.content];
+                    this.empty = res.empty;
+                    this.loading = false;
+                    this.finished = res.last;
+                    if (!this.finished) {
+                        this.page = this.page + 1;
+                    }
+                    this.totalElements = Number(res.totalElements);
+                }
+            });
+        },
+        delFn() {
+            console.log('删除成功');
+            this.getData(true);
+            this.beforeData();
+        },
+        changeStatus(name) {
+            this.$router.replace({
+                path: '/auctionOrders',
+                query: {
+                    status: name,
+                    type: this.type
+                }
+            });
+            this.getData(true);
+        },
+        changeActive(type) {
+            this.$router.replace({
+                path: '/auctionOrders',
+                query: {
+                    status: this.status,
+                    type: type
+                }
+            });
+            this.type = type;
+            this.getData(true);
+        },
+        onRefresh() {
+            this.getData(true).then(() => {
+                this.isLoading = false;
+            });
+        }
+    },
+    activated() {
+        this.$nextTick(() => {
+            this.changeScroll(this.scrollTop);
+        });
+    },
+    beforeRouteLeave(to, from, next) {
+        if (!to.meta.menuPage) {
+            this.scrollTop = this.scrollWrapper.value.scrollTop;
+            this.setKeeps(['index', 'discover']);
+        } else {
+            this.scrollTop = 0;
+            this.setKeeps(['index', 'discover'], false);
+        }
+        next();
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.top {
+    display: flex;
+    padding: 10px 16px;
+    background-color: @bg;
+    align-items: center;
+    .top-btn {
+        flex-grow: 1;
+        .flex();
+        .btn {
+            font-size: @font3;
+            line-height: 26px;
+            display: inline-block;
+            vertical-align: text-bottom;
+            color: #939599;
+
+            &.active {
+                color: #000;
+                font-size: @font3;
+                font-weight: bold;
+                line-height: 30px;
+            }
+        }
+
+        .btn + .btn {
+            margin-left: 30px;
+        }
+    }
+}
+
+.discover {
+    background-color: @bg3;
+    min-height: 100vh;
+}
+
+.list {
+    padding-bottom: 100px;
+}
+/deep/.van-tab {
+    margin-right: 30px;
+}
+/deep/.van-tabs__nav--line.van-tabs__nav--complete {
+    border-color: @tabBorder;
+}
+.grid-img {
+    display: block;
+}
+.van-grid {
+    margin-top: 12px;
+}
+/deep/ .van-grid-item__content {
+    padding: 14px 20px 16px;
+}
+/deep/ .van-grid-item__text {
+    color: #fff;
+    font-size: 13px;
+    line-height: 18px;
+    margin-top: 4px;
+}
+
+.title {
+    padding: 16px 20px 8px;
+    color: @prim;
+    font-size: 18px;
+    font-weight: bold;
+}
+
+.box-list {
+    // display: flex;
+    // flex-wrap: wrap;
+    padding: 0 8px;
+}
+
+.discover {
+    padding-bottom: 50px;
+}
+.van-tabs {
+    background-color: @bg;
+}
+
+.btns {
+    background-color: #fff;
+    padding: 10px 16px 16px;
+    .flex();
+
+    .btn-item {
+        height: 22px;
+        background: #f5f7fa;
+        border-radius: 12px;
+        font-size: 12px;
+        color: #939599;
+        line-height: 22px;
+        width: calc(25% - 9px);
+        text-align: center;
+    }
+    .btn-item + .btn-item {
+        margin-left: 16px;
+    }
+}
+</style>

+ 56 - 18
src/views/pay/BankPay.vue

@@ -37,7 +37,8 @@ export default {
             orderId: 0,
             price: 0,
             payOrder: {},
-            type: 'order'
+            type: 'order',
+            paymentType: ''
         };
     },
     computed: {
@@ -50,25 +51,42 @@ export default {
         }
     },
     mounted() {
-        this.orderId = this.$route.query.id;
-        if (this.$route.query.type) {
-            this.type = this.$route.query.type;
-        }
-        if (this.type === 'gift') {
-            this.$http.get('/giftOrder/get/' + this.orderId).then(res => {
-                this.price = res.gasPrice;
-            });
-        } else if (this.type === 'mint') {
-            this.$http.get('/mintOrder/get/' + this.orderId).then(res => {
-                this.price = res.gasPrice;
-            });
-        } else if (this.type === 'recharge') {
+
+        if (this.$route.query.id) {
+            this.orderId = this.$route.query.id;
+              }
+            if (this.$route.query.type) {
+                this.type = this.$route.query.type;
+            }
+            if (this.$route.query.paymentType) {
+                this.paymentType = this.$route.query.paymentType;
+            }
+            if (this.type === 'gift') {
+                this.$http.get('/giftOrder/get/' + this.orderId).then(res => {
+                    this.price = res.gasPrice;
+                });
+            } else if (this.type === 'mint') {
+                this.$http.get('/mintOrder/get/' + this.orderId).then(res => {
+                    this.price = res.gasPrice;
+                });
+            } else if (this.type === 'recharge') {
             this.price = this.$route.query.amount;
-        } else {
-            this.$http.get('/order/get/' + this.orderId).then(res => {
-                this.price = res.totalPrice;
+        }else if (this.type === 'auction') {
+                this.$http.get('/auctionOrder/get/' + this.orderId).then(res => {
+                    this.price = res.totalPrice;
+                });
+            } else {
+                this.$http.get('/order/get/' + this.orderId).then(res => {
+                    this.price = res.totalPrice;
+                });
+            }
+
+            this.$http.get('/user/myBankCard').then(res => {
+                if (res.length !== 0) {
+                    this.bankInfo = res[0];
+                }
             });
-        }
+
         this.$store.dispatch('getBankCard');
     },
     methods: {
@@ -130,6 +148,20 @@ export default {
                     .catch(e => {
                         this.$toast(e.error);
                     });
+            } else if (this.type === 'auction') {
+                this.$http
+                    .post('/payOrder/v2/auction/agreement?id=' + this.orderId, {
+                        bindCardId: this.bankInfo.bindCardId
+                    })
+                    .then(res => {
+                        this.payOrder = res;
+                        if (res.needCaptcha) {
+                            this.onSubmit(e);
+                        }
+                    })
+                    .catch(e => {
+                        this.$toast(e.error);
+                    });
             } else {
                 this.$http
                     .post('/payOrder/v2/agreement', {
@@ -175,6 +207,12 @@ export default {
                             this.$router.replace({ name: 'activityOrderDetail', query: { id: this.orderId } });
                         } else if (this.type === 'recharge') {
                             this.$router.replace({ name: 'mineWallet' });
+                        } else if (this.type === 'auction') {
+                            if (this.paymentType === 'DEPOSIT') {
+                                this.$router.go(-1);
+                            } else {
+                                this.$router.replace('/auctionOrderDetail?id=' + this.orderId);
+                            }
                         } else {
                             this.$router.replace({ name: 'orderDetail', query: { id: this.orderId } });
                         }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 327 - 327
yarn.lock


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio