فهرست منبع

Merge branch 'master' of http://git.izouma.com/xiongzhu/9th

xuqiang 4 سال پیش
والد
کامیت
9ed23d260d

+ 1 - 1
src/main/nine-space/.env.development

@@ -1 +1 @@
-VUE_APP_BASE_URL=https://nft.9space.vip
+VUE_APP_BASE_URL=https://nfttest.9space.vip

+ 2 - 0
src/main/pc-space/package.json

@@ -8,11 +8,13 @@
         "lint": "vue-cli-service lint"
     },
     "dependencies": {
+        "@chenfengyuan/vue-qrcode": "^1.0.2",
         "axios": "^0.24.0",
         "clipboard": "^2.0.8",
         "core-js": "^3.6.5",
         "dayjs": "^1.10.7",
         "element-ui": "^2.15.6",
+        "mathjs": "^10.0.0",
         "qs": "^6.10.1",
         "swiper": "5.x",
         "vue": "^2.6.11",

+ 1 - 1
src/main/pc-space/public/index.html

@@ -7,7 +7,7 @@
         <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
         <title><%= htmlWebpackPlugin.options.title %></title>
         <link rel="stylesheet" href="./client.css" />
-        <link rel="stylesheet" href="https://at.alicdn.com/t/font_2852142_86r1qgys8y5.css" />
+        <link rel="stylesheet" href="https://at.alicdn.com/t/font_2852142_5nb94jewry2.css" />
         <link
         rel="stylesheet"
         href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"

+ 2 - 26
src/main/pc-space/src/components/AssetInfo.vue

@@ -50,10 +50,9 @@
 </template>
 
 <script>
+import asset from '../mixins/asset';
 import product from '../mixins/product';
-import LikeButton from './LikeButton.vue';
 export default {
-    components: { LikeButton },
     props: {
         info: {
             type: Object,
@@ -62,30 +61,7 @@ export default {
             }
         }
     },
-    mixins: [product],
-    methods: {
-        likeProduct() {
-            if (!this.info.liked) {
-                this.$http.get(`/collection/${this.info.id}/like`).then(() => {
-                    this.$emit('update:info', {
-                        ...this.info,
-                        liked: true,
-                        likes: this.info.likes + 1
-                    });
-                    this.$message.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.$message.success('取消收藏');
-                });
-            }
-        }
-    }
+    mixins: [asset, product]
 };
 </script>
 <style lang="less" scoped>

+ 8 - 1
src/main/pc-space/src/components/LoginInfo.vue

@@ -1,6 +1,13 @@
 <template>
     <div>
-        <el-dialog :title="Title" :visible.sync="Show" width="30%" :before-close="handleClose" @close="closeDialog">
+        <el-dialog
+            :title="Title"
+            append-to-body
+            :visible.sync="Show"
+            width="30%"
+            :before-close="handleClose"
+            @close="closeDialog"
+        >
             <div class="content">
                 <el-form v-if="!phoneLogin" :model="form" ref="form" :rules="rules" label-width="0">
                     <el-form-item

+ 1 - 1
src/main/pc-space/src/plugins/http.js

@@ -4,7 +4,7 @@ import qs from 'qs';
 let baseUrl = 'http://localhost:8080';
 switch (process.env.NODE_ENV) {
     case 'development':
-        baseUrl = 'https://nft.9space.vip';
+        baseUrl = 'https://nfttest.9space.vip/';
         // baseUrl = 'http://192.168.50.190:8080';
         // baseUrl = 'http://localhost:8080';
         // baseUrl = 'http://192.168.50.190:8080';

+ 100 - 50
src/main/pc-space/src/views/AssetDetail.vue

@@ -55,14 +55,11 @@
                         <img class="name4" src="../assets/img/icon_inter@3x (4).png" alt="" />
                     </div>
                 </div>
-                <div class="time" v-if="info.salable">
+                <div class="time">
                     <div class="time1">卖家定价</div>
-                    <div class="time2" v-if="info.isAppointment">
-                        首发抢购倒计时<span>{{ startTime }}</span>
-                    </div>
                 </div>
-                <div class="price" v-if="info.salable">
-                    <div class="price1">
+                <div class="price">
+                    <div class="price1" v-if="info.salable">
                         <div class="price2">价格</div>
                         <img class="price3" src="../assets/img/icon_jiage@3x.png" alt="" />
                         <div class="price4">{{ info.price }}</div>
@@ -70,25 +67,36 @@
                             含<span>{{ info.royalties }}%</span>版税
                         </div>
                     </div>
-                    <div class="price1 num">
+                    <div class="status" v-else-if="info.status === 'NORMAL'">
+                        商品{{ info.publicShow ? '仅展示' : '未展示' }}
+                    </div>
+                    <div class="status" v-else>
+                        {{ getLabelName(info.status, assetStatusOptions) }}
+                    </div>
+
+                    <div class="price1 num" v-if="info.salable">
                         <div class="num1">
                             <div class="price2 num2">数量</div>
                             <span class="span">{{ info.total }}</span>
                         </div>
                         <div class="price2 num2">已售 {{ info.sale }} / 剩余 {{ info.stock }}</div>
                     </div>
-                    <el-button
-                        class="buy"
-                        :class="{ used: info.appointment }"
-                        v-if="info.isAppointment"
-                        @click="appointment"
-                        type="primary"
-                        size="default"
-                    >
-                        {{ info.appointment ? '已预约' : '一键预约' }}
-                    </el-button>
 
-                    <el-button class="buy" v-else-if="isBuy" type="primary" size="default">立即购买</el-button>
+                    <div class="btn-content">
+                        <div class="btn-list">
+                            <div class="btn-item" @click="changeShow">
+                                <i class="font_family icon-icon-gongkaizhanshi"></i>
+                                <span>公开展示</span>
+                            </div>
+                            <div class="btn-item">
+                                <i class="font_family icon-icon-zengsong"></i>
+                                <span>赠送好友</span>
+                            </div>
+                        </div>
+                        <el-button class="buy" type="primary" size="default"
+                            ><i class="font_family icon-icon-zhuanrang1"></i><span>寄售上架</span></el-button
+                        >
+                    </div>
                 </div>
                 <div v-if="properties.length > 0">
                     <div class="time">
@@ -161,19 +169,20 @@
             </collection-info>
         </div>
 
-        <submit></submit>
+        <send></send>
     </div>
 </template>
 <script>
 import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
+import asset from '../mixins/asset';
 import product from '../mixins/product';
 import 'swiper/css/swiper.css';
 import CollectionInfo from '../components/CollectionInfo.vue';
-import Submit from './Submit.vue';
 import { mapState } from 'vuex';
+import Send from './Send.vue';
 export default {
-    components: { Swiper, SwiperSlide, CollectionInfo, Submit },
-    mixins: [product],
+    components: { Swiper, SwiperSlide, CollectionInfo, Send },
+    mixins: [asset, product],
     data() {
         return {
             showMore: false,
@@ -217,34 +226,12 @@ export default {
     },
     methods: {
         getDetail() {
-            this.$http
-                .get('/asset/get/' + this.$route.query.id)
-                .then(res => {
-                    this.info = res;
-                    this.loading = false;
-                    this.getTime(res.startTime);
-                    this.getRelated(res.ownerId);
-                    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;
-                    } else {
-                        this.blindBoxItems = [];
-                    }
-                });
+            this.$http.get('/asset/get/' + this.$route.query.id).then(res => {
+                this.info = res;
+                this.loading = false;
+                this.getTime(res.startTime);
+                this.getRelated(res.ownerId);
+            });
         },
         likeProduct() {
             if (!this.info.liked) {
@@ -297,6 +284,20 @@ export default {
                         this.$message.warning(e.error);
                     }
                 });
+        },
+        changeShow() {
+            this.$confirm('藏品将公开展示,无报价', '公开展示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                center: true
+            })
+                .then(() => {
+                    return this.$http.post(`/asset/publicShow?id=${this.info.id}`);
+                })
+                .then(res => {
+                    this.getDetail();
+                    this.$message.success('展示成功');
+                });
         }
     }
 };
@@ -637,6 +638,7 @@ export default {
     border-radius: 8px;
     border-width: 0;
     color: #000;
+    margin-top: 30px;
     &:hover {
         background: linear-gradient(135deg, darken(@prim, 10%), darken(@warn, 10%));
     }
@@ -645,6 +647,13 @@ export default {
         background: linear-gradient(135deg, darken(@prim, 50%), darken(@warn, 50%));
         color: #939599;
     }
+    i {
+        font-size: 24px;
+    }
+    span {
+        font-size: 20px;
+        margin-left: 16px;
+    }
 }
 
 /deep/.content {
@@ -704,6 +713,13 @@ export default {
     }
 }
 
+.status {
+    font-size: 26px;
+    color: #fdfb60;
+    line-height: 36px;
+    padding: 20px 0 16px;
+}
+
 /deep/.boxs {
     .el-image {
         width: 100%;
@@ -711,4 +727,38 @@ export default {
         border-radius: 12px;
     }
 }
+.btn-content {
+    padding: 20px 0;
+    border-top: 1px solid #494a4d;
+}
+
+.btn-list {
+    .flex();
+
+    .btn-item {
+        .line();
+        color: #fff;
+        flex-grow: 1;
+        line-height: 52px;
+        text-align: center;
+        span {
+            font-size: 20px;
+            vertical-align: middle;
+        }
+        i {
+            font-size: 24px;
+            margin-right: 16px;
+            vertical-align: middle;
+        }
+
+        &:hover {
+            &::before {
+                background-color: fade(#1c1e26, 90%);
+            }
+        }
+    }
+    .btn-item + .btn-item {
+        margin-left: 30px;
+    }
+}
 </style>

+ 7 - 6
src/main/pc-space/src/views/Home.vue

@@ -4,7 +4,7 @@
             <div class="center-content">
                 <div class="title">游戏数字资产的链上开创者们</div>
                 <div class="title2">全球领先的游戏数字藏品NFT集结地</div>
-                <div class="btn">立即探索</div>
+                <div class="btn" @click="$router.push('/collection')"><span>立即探索</span></div>
             </div>
         </div>
 
@@ -142,7 +142,6 @@ export default {
     },
     mounted() {
         this.getCreators();
-        this.autoChange();
         this.getProduct().then(res => {
             this.products = res;
         });
@@ -177,6 +176,10 @@ export default {
                 )
                 .then(res => {
                     this.creators = res.content;
+                    this.showCreator = res.content.length - 1;
+                    if (res.content.length == 4) {
+                        this.autoChange();
+                    }
                 });
         },
         autoChange() {
@@ -250,15 +253,13 @@ export default {
         .btn {
             width: 136px;
             height: 44px;
-            line-height: 44px;
+            line-height: 42px;
             text-align: center;
             margin: 50px 0 0 10px;
             position: relative;
             font-size: 24px;
             color: @prim;
-            border: 1px solid;
-            border-radius: 8px;
-            cursor: pointer;
+            .line();
         }
     }
 }

+ 323 - 0
src/main/pc-space/src/views/Send.vue

@@ -0,0 +1,323 @@
+<template>
+    <el-dialog center title="赠送" :visible.sync="show" width="680px">
+        <div class="page" v-loading="loading">
+            <div class="top-tips">通过手机号码检索用户信息,<span>赠送后该加密作品将会被转移</span></div>
+            <div class="user">
+                <el-input
+                    v-model="phone"
+                    placeholder="请输入手机号码进行检索"
+                    suffix-icon="el-icon-search"
+                    size="small"
+                    clearable
+                    type="tel"
+                    @change="getUser"
+                ></el-input>
+
+                <div class="user-content">
+                    <div class="empty">检索用户区域</div>
+                </div>
+            </div>
+            <div class="info">
+                <div class="price">
+                    <span class="text1">应付金额</span>
+                    <img src="../assets/icon_jiage.png" alt="" />
+                    <span class="text2">{{ orderInfo.price }}</span>
+                </div>
+                <div class="flex1"></div>
+                <div class="order">
+                    <span class="text1">订单编号</span>
+                    <span class="text2">{{ orderInfo.id }}</span>
+                    <el-button type="info" @click="copy" size="mini" plain>复制</el-button>
+                </div>
+            </div>
+
+            <div class="payMethods">
+                <div class="title">选择支付方式</div>
+                <div class="pay-list">
+                    <div class="pay-info">
+                        <el-radio-group v-model="payMethods">
+                            <el-radio v-for="item in payList" border :label="item.type" :key="item.type">
+                                <img :src="item.icon" alt="" />
+                                <span> {{ item.name }}</span>
+                            </el-radio>
+                        </el-radio-group>
+                    </div>
+                </div>
+            </div>
+
+            <div class="tips">
+                <div class="text1">购买须知</div>
+                <div class="text2">
+                    1.数字盲盒按照随机概率进行抽取<br />
+                    2.数字盲盒及其数字内容为虚拟商品<span style="color: #ff4f50">支付完成后,不可退换</span><br />
+                    3.数字盲盒及其数字内容仅作为消费娱乐(或其他约定场景)使用<br />
+                    4.切勿当成投资和投机品进行盲目消费
+                </div>
+            </div>
+        </div>
+
+        <span slot="footer" class="dialog-footer">
+            <el-button type="primary" class="pay" @click="submit">立即支付</el-button>
+        </span>
+    </el-dialog>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            show: false,
+            payMethods: 'ALIPAY',
+            payList: [
+                {
+                    icon: require('../assets/alipay.png'),
+                    name: '支付宝',
+                    type: 'ALIPAY'
+                },
+                {
+                    icon: require('../assets/weixin.png'),
+                    name: '微信',
+                    type: 'WEIXIN'
+                },
+                {
+                    icon: require('../assets/dcep.png'),
+                    name: 'DCEP支付',
+                    type: 'DCEP'
+                }
+            ],
+            loading: false,
+            orderInfo: {},
+            phone: ''
+        };
+    },
+    methods: {
+        submit() {
+            if (this.payMethods === 'DCEP') {
+                this.wait();
+            }
+        },
+        init(info) {
+            this.checkLogin()
+                .then(() => {
+                    this.show = true;
+                    this.loading = true;
+                    return this.$http.get('/order/get/' + 2368);
+                    // return this.$http.post('/order/create?collectionId=' + info.id + '&qty=1');
+                })
+                .then(res => {
+                    this.orderInfo = res;
+                    this.loading = false;
+                })
+                .catch(e => {
+                    if (e) {
+                        this.$message.warning(e.error);
+                    }
+                });
+        },
+        copy() {
+            this.$copyText(this.orderInfo.id).then(
+                e => {
+                    this.$message.success('复制成功');
+                },
+                e => {
+                    this.$message.warning('复制失败');
+                }
+            );
+        },
+        getUser() {
+            this.$http.post(
+                '/user/all',
+                {
+                    search: this.phone
+                },
+                {
+                    body: 'json'
+                }
+            );
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.info {
+    .flex();
+    height: 94px;
+    .price {
+        .flex();
+        align-items: flex-end;
+        .text1 {
+            font-size: 16px;
+            color: #000000;
+            line-height: 24px;
+        }
+        img {
+            width: 10px;
+            display: block;
+            margin: 0 0 4px 10px;
+        }
+        .text2 {
+            font-size: 40px;
+            font-family: OSP;
+            font-weight: normal;
+            color: #ff4f50;
+            line-height: 36px;
+        }
+    }
+
+    .order {
+        .text1 {
+            font-size: 13px;
+            color: #939599;
+            line-height: 24px;
+        }
+
+        .text2 {
+            font-size: 13px;
+            color: #0e0e0e;
+            line-height: 22px;
+            padding: 0 6px 0 30px;
+        }
+        .el-button {
+            height: 20px;
+            line-height: 20px;
+            padding: 0 10px;
+        }
+    }
+}
+/deep/.el-loading-mask {
+    background-color: #ffffffee;
+}
+
+/deep/.el-radio {
+    .flex();
+    display: inline-flex;
+    flex-direction: row-reverse;
+    justify-content: space-between;
+    width: 190px;
+    height: 42px;
+    color: #939599;
+    padding: 0;
+    box-sizing: border-box;
+    .el-radio__label {
+        .flex();
+        img {
+            width: 24px;
+            height: 24px;
+        }
+        span {
+            font-size: 16px;
+            font-weight: bold;
+            padding: 0 10px;
+        }
+        margin-left: 24px;
+    }
+    .el-radio__input {
+        margin-right: 24px;
+        width: 20px;
+        flex-shrink: 0;
+
+        .el-radio__inner {
+            width: 20px;
+            height: 20px;
+            &::after {
+                content: '\e6da';
+                font-family: 'element-icons';
+                width: 14px;
+                height: 14px;
+                font-size: 14px;
+                color: #fff;
+                font-weight: bold;
+                background-color: transparent;
+            }
+        }
+
+        &.is-checked {
+            .el-radio__inner {
+                background-image: linear-gradient(135deg, @prim 20%, @warn 100%);
+                border-width: 0;
+            }
+        }
+    }
+    &.is-checked {
+        .line(@bg:#E0FFF8,@radius:4px);
+        border-width: 0;
+        .el-radio__label {
+            color: #000;
+        }
+    }
+}
+.payMethods {
+    padding: 30px 0;
+    .title {
+        font-size: 16px;
+        color: #000000;
+        line-height: 24px;
+        padding-bottom: 20px;
+    }
+}
+/deep/.el-radio.is-bordered + .el-radio.is-bordered {
+    margin-left: 0;
+}
+
+.tips {
+    padding-top: 20px;
+    .text1 {
+        font-size: 16px;
+        color: #939599;
+        line-height: 24px;
+    }
+    .text2 {
+        font-size: 14px;
+        color: #939599;
+        line-height: 28px;
+        margin-top: 10px;
+    }
+}
+.pay {
+    background-image: linear-gradient(135deg, @prim, @warn);
+    border-width: 0;
+    width: 200px;
+    color: #000;
+    &:hover {
+        background-image: linear-gradient(135deg, darken(@prim, 20), darken(@warn, 20));
+    }
+}
+
+.top-tips {
+    text-align: center;
+    font-size: 14px;
+    color: #939599;
+    line-height: 28px;
+    span {
+        color: #ff4f50;
+    }
+}
+
+.user {
+    padding: 20px 0;
+
+    .el-input {
+        border-radius: 8px;
+    }
+
+    .user-content {
+        background: #f5f7fa;
+        border-radius: 8px;
+        height: 142px;
+        margin-top: 10px;
+        position: relative;
+
+        .empty {
+            font-size: 14px;
+            color: rgba(147, 149, 153, 0.5);
+            line-height: 24px;
+            text-align: center;
+            position: absolute;
+            left: 50%;
+            top: 50%;
+            transform: translate(-50%, -50%);
+        }
+    }
+}
+</style>

+ 64 - 10
src/main/pc-space/src/views/Submit.vue

@@ -5,18 +5,19 @@
                 <div class="price">
                     <span class="text1">应付金额</span>
                     <img src="../assets/icon_jiage.png" alt="" />
-                    <span class="text2">{{ orderInfo.price }}</span>
+                    <span class="text2">{{ money }}</span>
+                    <span class="text3">(含gas费¥{{ gas }})</span>
                 </div>
                 <div class="flex1"></div>
-                <div class="order">
+                <!-- <div class="order">
                     <span class="text1">订单编号</span>
                     <span class="text2">{{ orderInfo.id }}</span>
                     <el-button type="info" @click="copy" size="mini" plain>复制</el-button>
-                </div>
+                </div> -->
             </div>
 
             <div class="payMethods">
-                <div class="title">选择支付方式</div>
+                <!-- <div class="title">选择支付方式</div>
                 <div class="pay-list">
                     <div class="pay-info">
                         <el-radio-group v-model="payMethods">
@@ -26,7 +27,13 @@
                             </el-radio>
                         </el-radio-group>
                     </div>
+                </div> -->
+
+                <div class="qrcode">
+                    <vue-qrcode :value="payUrl" :options="{ width: 140, margin: 1 }" class="code"></vue-qrcode>
                 </div>
+                <!-- <div class="qrcode-text">二维码有效时常为5分钟,请尽快支付</div> -->
+                <div class="qrcode-text">手机微信扫描二维码下单</div>
             </div>
 
             <div class="tips">
@@ -40,13 +47,16 @@
             </div>
         </div>
 
-        <span slot="footer" class="dialog-footer">
-            <el-button type="primary" class="pay" @click="submit">立即支付</el-button>
-        </span>
+        <!-- <span slot="footer" class="dialog-footer">
+            <el-button type="primary" class="pay" @click="submit">确认</el-button>
+        </span> -->
     </el-dialog>
 </template>
 
 <script>
+import vueQrcode from '@chenfengyuan/vue-qrcode';
+import resolveUrl from 'resolve-url';
+import { add } from 'mathjs';
 export default {
     data() {
         return {
@@ -70,9 +80,22 @@ export default {
                 }
             ],
             loading: true,
-            orderInfo: {}
+            info: {},
+            gas: 0
         };
     },
+    computed: {
+        payUrl() {
+            return resolveUrl(this.$baseUrl, '9th/submit?id=' + this.info.id);
+        },
+        money() {
+            if (this.info.price) {
+                return add(this.info.price, this.gas);
+            } else {
+                return 0;
+            }
+        }
+    },
     methods: {
         submit() {
             if (this.payMethods === 'DCEP') {
@@ -84,11 +107,13 @@ export default {
                 .then(() => {
                     this.show = true;
                     this.loading = true;
-                    return this.$http.get('/order/get/' + 2368);
+                    this.info = info;
+                    return this.$http.get('/sysConfig/get/gas_fee');
+                    // return this.$http.get('/order/get/' + 1216);
                     // return this.$http.post('/order/create?collectionId=' + info.id + '&qty=1');
                 })
                 .then(res => {
-                    this.orderInfo = res;
+                    this.gas = res.value;
                     this.loading = false;
                 })
                 .catch(e => {
@@ -107,6 +132,9 @@ export default {
                 }
             );
         }
+    },
+    components: {
+        vueQrcode
     }
 };
 </script>
@@ -135,6 +163,12 @@ export default {
             color: #ff4f50;
             line-height: 36px;
         }
+        .text3 {
+            font-size: 13px;
+            color: #000000;
+            line-height: 24px;
+            margin-left: 15px;
+        }
     }
 
     .order {
@@ -255,4 +289,24 @@ export default {
         background-image: linear-gradient(135deg, darken(@prim, 20), darken(@warn, 20));
     }
 }
+.qrcode {
+    width: 160px;
+    height: 160px;
+    background: #f5f7fa;
+    border-radius: 11px;
+    margin: 30px auto 10px;
+    padding: 10px;
+    box-sizing: border-box;
+    .code {
+        border-radius: 11px;
+        overflow: hidden;
+    }
+}
+.qrcode-text {
+    font-size: 16px;
+    color: #939599;
+    line-height: 24px;
+    margin: 0 auto;
+    text-align: center;
+}
 </style>

+ 123 - 5
src/main/pc-space/yarn.lock

@@ -871,6 +871,13 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.16.0":
+  version "7.16.0"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.0.tgz#e27b977f2e2088ba24748bf99b5e1dece64e4f0b"
+  integrity sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/template@^7.0.0", "@babel/template@^7.15.4":
   version "7.15.4"
   resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.15.4.tgz?cache=0&sync_timestamp=1630618813723&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftemplate%2Fdownload%2F%40babel%2Ftemplate-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194"
@@ -903,6 +910,13 @@
     "@babel/helper-validator-identifier" "^7.14.9"
     to-fast-properties "^2.0.0"
 
+"@chenfengyuan/vue-qrcode@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@chenfengyuan/vue-qrcode/-/vue-qrcode-1.0.2.tgz#37d71902e166e1ae58176bd6cb9c40905c1b0949"
+  integrity sha512-hwy1d4YMJAyEh+V7dLPG8eAKACRvugzSB4ylwb6QNqo84KHTF50/5EJcBYdUhTRPfAqrxG0i6jDAXONWOGyQbQ==
+  dependencies:
+    qrcode "^1.4.4"
+
 "@hapi/address@2.x.x":
   version "2.1.4"
   resolved "https://registry.nlark.com/@hapi/address/download/@hapi/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@@ -1928,7 +1942,7 @@ balanced-match@^1.0.0:
   resolved "https://registry.nlark.com/balanced-match/download/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
   integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=
 
-base64-js@^1.0.2:
+base64-js@^1.0.2, base64-js@^1.3.1:
   version "1.5.1"
   resolved "https://registry.nlark.com/base64-js/download/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo=
@@ -2151,7 +2165,25 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4
     node-releases "^2.0.1"
     picocolors "^1.0.0"
 
-buffer-from@^1.0.0:
+buffer-alloc-unsafe@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+  integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+  integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+  dependencies:
+    buffer-alloc-unsafe "^1.1.0"
+    buffer-fill "^1.0.0"
+
+buffer-fill@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+  integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
+buffer-from@^1.0.0, buffer-from@^1.1.1:
   version "1.1.2"
   resolved "https://registry.nlark.com/buffer-from/download/buffer-from-1.1.2.tgz?cache=0&sync_timestamp=1627578710888&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbuffer-from%2Fdownload%2Fbuffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
   integrity sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U=
@@ -2180,6 +2212,14 @@ buffer@^4.3.0:
     ieee754 "^1.1.4"
     isarray "^1.0.0"
 
+buffer@^5.4.3:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+  integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.1.13"
+
 builtin-status-codes@^3.0.0:
   version "3.0.0"
   resolved "https://registry.nlark.com/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
@@ -2599,6 +2639,11 @@ commondir@^1.0.1:
   resolved "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
   integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
 
+complex.js@^2.0.15:
+  version "2.0.15"
+  resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.0.15.tgz#7add6848b4c1d12aa9262f7df925ebe7a51a7406"
+  integrity sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w==
+
 component-emitter@^1.2.1:
   version "1.3.0"
   resolved "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
@@ -3064,6 +3109,11 @@ decamelize@^1.2.0:
   resolved "https://registry.npmmirror.com/decamelize/download/decamelize-1.2.0.tgz?cache=0&sync_timestamp=1633055713394&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
 
+decimal.js@^10.3.1:
+  version "10.3.1"
+  resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
+  integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
+
 decode-uri-component@^0.2.0:
   version "0.2.0"
   resolved "https://registry.nlark.com/decode-uri-component/download/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -3197,6 +3247,11 @@ diffie-hellman@^5.0.0:
     miller-rabin "^4.0.0"
     randombytes "^2.0.0"
 
+dijkstrajs@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
+  integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==
+
 dir-glob@^2.0.0, dir-glob@^2.2.2:
   version "2.2.2"
   resolved "https://registry.nlark.com/dir-glob/download/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
@@ -3498,6 +3553,11 @@ escape-html@~1.0.3:
   resolved "https://registry.nlark.com/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
 
+escape-latex@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1"
+  integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==
+
 escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.nlark.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -4037,6 +4097,11 @@ forwarded@0.2.0:
   resolved "https://registry.nlark.com/forwarded/download/forwarded-0.2.0.tgz?cache=0&sync_timestamp=1622503451002&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fforwarded%2Fdownload%2Fforwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
   integrity sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE=
 
+fraction.js@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff"
+  integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==
+
 fragment-cache@^0.2.1:
   version "0.2.1"
   resolved "https://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -4588,7 +4653,7 @@ icss-utils@^4.0.0, icss-utils@^4.1.1:
   dependencies:
     postcss "^7.0.14"
 
-ieee754@^1.1.4:
+ieee754@^1.1.13, ieee754@^1.1.4:
   version "1.2.1"
   resolved "https://registry.nlark.com/ieee754/download/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I=
@@ -5083,6 +5148,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
   resolved "https://registry.nlark.com/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
   integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
 
+isarray@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
+  integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
+
 isexe@^2.0.0:
   version "2.0.0"
   resolved "https://registry.nlark.com/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -5105,6 +5175,11 @@ isstream@~0.1.2:
   resolved "https://registry.nlark.com/isstream/download/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
   integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
 
+javascript-natural-sort@^0.7.1:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
+  integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=
+
 javascript-stringify@^2.0.1:
   version "2.1.0"
   resolved "https://registry.nlark.com/javascript-stringify/download/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
@@ -5458,6 +5533,21 @@ map-visit@^1.0.0:
   dependencies:
     object-visit "^1.0.0"
 
+mathjs@^10.0.0:
+  version "10.0.0"
+  resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.0.0.tgz#872e8e5c0d23a383760cb84e16542fad5093c6a5"
+  integrity sha512-PZcQ73mVvVG2GZXvE47q+j7P3ALVxWUM51wTmlVX3F/3IJMLNziNIqStwyIDAO64ZGB8u3iFlQwxT7DIijtNlw==
+  dependencies:
+    "@babel/runtime" "^7.16.0"
+    complex.js "^2.0.15"
+    decimal.js "^10.3.1"
+    escape-latex "^1.2.0"
+    fraction.js "^4.1.1"
+    javascript-natural-sort "^0.7.1"
+    seedrandom "^3.0.5"
+    tiny-emitter "^2.1.0"
+    typed-function "^2.0.0"
+
 md5.js@^1.3.4:
   version "1.3.5"
   resolved "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -6370,6 +6460,11 @@ pkg-dir@^4.1.0:
   dependencies:
     find-up "^4.0.0"
 
+pngjs@^3.3.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
+  integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
+
 pnp-webpack-plugin@^1.6.4:
   version "1.7.0"
   resolved "https://registry.nlark.com/pnp-webpack-plugin/download/pnp-webpack-plugin-1.7.0.tgz#65741384f6d8056f36e2255a8d67ffc20866f5c9"
@@ -6858,6 +6953,19 @@ q@^1.1.2:
   resolved "https://registry.nlark.com/q/download/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
   integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
 
+qrcode@^1.4.4:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83"
+  integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==
+  dependencies:
+    buffer "^5.4.3"
+    buffer-alloc "^1.2.0"
+    buffer-from "^1.1.1"
+    dijkstrajs "^1.0.1"
+    isarray "^2.0.1"
+    pngjs "^3.3.0"
+    yargs "^13.2.4"
+
 qs@6.7.0:
   version "6.7.0"
   resolved "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz?cache=0&sync_timestamp=1616385248556&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
@@ -7288,6 +7396,11 @@ schema-utils@^3.0.0:
     ajv "^6.12.5"
     ajv-keywords "^3.5.2"
 
+seedrandom@^3.0.5:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
+  integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
+
 select-hose@^2.0.0:
   version "2.0.0"
   resolved "https://registry.nlark.com/select-hose/download/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -8015,7 +8128,7 @@ timsort@^0.3.0:
   resolved "https://registry.nlark.com/timsort/download/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
   integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
 
-tiny-emitter@^2.0.0:
+tiny-emitter@^2.0.0, tiny-emitter@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
   integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
@@ -8149,6 +8262,11 @@ type-is@~1.6.17, type-is@~1.6.18:
     media-typer "0.3.0"
     mime-types "~2.1.24"
 
+typed-function@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.0.0.tgz#15ab3825845138a8b1113bd89e60cd6a435739e8"
+  integrity sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==
+
 typedarray@^0.0.6:
   version "0.0.6"
   resolved "https://registry.nlark.com/typedarray/download/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -8811,7 +8929,7 @@ yargs-parser@^20.2.2:
   resolved "https://registry.nlark.com/yargs-parser/download/yargs-parser-20.2.9.tgz?cache=0&sync_timestamp=1624233275366&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
   integrity sha1-LrfcOwKJcY/ClfNidThFxBoMlO4=
 
-yargs@^13.3.2:
+yargs@^13.2.4, yargs@^13.3.2:
   version "13.3.2"
   resolved "https://registry.npmmirror.com/yargs/download/yargs-13.3.2.tgz?cache=0&sync_timestamp=1632604912933&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fyargs%2Fdownload%2Fyargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
   integrity sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=