Просмотр исходного кода

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

yuanyuan 3 лет назад
Родитель
Сommit
ec0eac5adf
100 измененных файлов с 2316 добавлено и 18227 удалено
  1. 1 1
      .env.development
  2. 1 18100
      package-lock.json
  3. 70 67
      package.json
  4. BIN
      public/favicon.ico
  5. BIN
      public/favicon.png
  6. BIN
      public/font/iconfont.ttf
  7. BIN
      public/font/iconfont.woff
  8. BIN
      public/font/iconfont.woff2
  9. 4 1
      public/index.html
  10. 119 3
      src/App.vue
  11. BIN
      src/assets/arrow-up.png
  12. BIN
      src/assets/banquanshichang-diwen@3x.png
  13. BIN
      src/assets/box1.png
  14. BIN
      src/assets/box2.png
  15. BIN
      src/assets/icon-funnegqingdan@3x.png
  16. BIN
      src/assets/icon-gongkaizhanshi.png
  17. BIN
      src/assets/icon-goumaixuzhi@3x.png
  18. BIN
      src/assets/icon-guanlianxinwen@3x.png
  19. BIN
      src/assets/icon-jiantou@3x.png
  20. BIN
      src/assets/icon-quanbuleimu@3x.png
  21. BIN
      src/assets/icon-quanbuleimuone@3x.png
  22. BIN
      src/assets/icon-weizhanshi.png
  23. BIN
      src/assets/icon-zengsong.png
  24. BIN
      src/assets/icon-zhengshu.png
  25. BIN
      src/assets/icon-zhuzaoxinghe.png
  26. BIN
      src/assets/icon.png
  27. BIN
      src/assets/icon1.png
  28. BIN
      src/assets/icon2.png
  29. BIN
      src/assets/icon3.jpg
  30. BIN
      src/assets/icon_gouxuan_pre@3x.png
  31. BIN
      src/assets/icon_gouxuan_xiao@3x.png
  32. BIN
      src/assets/info_icon_lingqishangcheng.png
  33. BIN
      src/assets/info_icon_no1-2.png
  34. BIN
      src/assets/info_icon_no1-ip.png
  35. BIN
      src/assets/info_icon_no2-2.png
  36. BIN
      src/assets/info_icon_no2-ip.png
  37. BIN
      src/assets/info_icon_no3-2.png
  38. BIN
      src/assets/info_icon_no3-ip.png
  39. 0 0
      src/assets/lottie/star.json
  40. 0 0
      src/assets/lottie/star1.json
  41. 0 0
      src/assets/lottie/star2.json
  42. 0 0
      src/assets/lottie/zuzhao.json
  43. BIN
      src/assets/png-bg-shangping2.png
  44. BIN
      src/assets/png-bg.png
  45. BIN
      src/assets/png-diwen-hei.png
  46. BIN
      src/assets/png-fuhe.png
  47. BIN
      src/assets/png-kapian.png
  48. BIN
      src/assets/png-renzheng.png
  49. BIN
      src/assets/png-shenhe-shibai.png
  50. BIN
      src/assets/png-shenhe.png
  51. BIN
      src/assets/png-shibai.png
  52. BIN
      src/assets/png-xiaohuicangping@3x.png
  53. BIN
      src/assets/png-xingtu-bg.png
  54. BIN
      src/assets/png-xiushi.png
  55. BIN
      src/assets/png-xiushi1.png
  56. BIN
      src/assets/png-zhengshu-diwen.png
  57. BIN
      src/assets/png-zhiding.png
  58. BIN
      src/assets/rank-left.png
  59. BIN
      src/assets/splash1.jpg
  60. BIN
      src/assets/splash2.jpg
  61. BIN
      src/assets/splash3.jpg
  62. BIN
      src/assets/splash4.jpg
  63. BIN
      src/assets/splash5.jpg
  64. BIN
      src/assets/splash6.jpg
  65. BIN
      src/assets/tabbar_icon_05.png
  66. BIN
      src/assets/tabbar_icon_05_pre.png
  67. BIN
      src/assets/top50.jpg
  68. BIN
      src/assets/top50.png
  69. BIN
      src/assets/topbg1.png
  70. BIN
      src/assets/zhi_fu_zhong.png
  71. 64 0
      src/components/PayBalance.vue
  72. 1 0
      src/components/PayMethodPick.vue
  73. 177 0
      src/components/PictureCropper.vue
  74. 2 2
      src/components/asset/assetInfo.vue
  75. 2 2
      src/components/asset/assetInfoSe.vue
  76. 133 0
      src/components/creator/RankInfo.vue
  77. 1 0
      src/components/order/OrderInfoAct.vue
  78. 1 1
      src/components/order/OrderOpen.vue
  79. 2 2
      src/components/phoneCode.vue
  80. 117 0
      src/components/product/HotCollect.vue
  81. 293 0
      src/components/product/NewsRecord.vue
  82. 3 3
      src/components/product/ProductBanner.vue
  83. 1 1
      src/components/product/SaleInfo.vue
  84. 77 15
      src/components/product/productInfo.vue
  85. 19 13
      src/components/product/productLarge.vue
  86. 2 2
      src/components/product/productSmall.vue
  87. 52 0
      src/components/star/Info.vue
  88. 353 0
      src/components/star/assetInfo.vue
  89. 275 0
      src/components/star/pay.vue
  90. 388 0
      src/components/star/post.vue
  91. 8 0
      src/main.js
  92. 1 1
      src/mixins/auction.js
  93. 2 1
      src/mixins/banner.js
  94. 7 3
      src/mixins/common.js
  95. 4 1
      src/mixins/phone.js
  96. 3 4
      src/mixins/product.js
  97. 16 4
      src/mixins/search.js
  98. 11 0
      src/mixins/star.js
  99. 28 0
      src/plugins/keeps.js
  100. 78 0
      src/plugins/list.js

+ 1 - 1
.env.development

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

Разница между файлами не показана из-за своего большого размера
+ 1 - 18100
package-lock.json


+ 70 - 67
package.json

@@ -1,69 +1,72 @@
 {
-    "name": "nine-space",
-    "version": "0.1.0",
-    "private": true,
-    "scripts": {
-        "serve": "vue-cli-service serve",
-        "serveRaex": "vue-cli-service serve --mode development_raex",
-        "build": "vue-cli-service build",
-        "lint": "vue-cli-service lint"
-    },
-    "dependencies": {
-        "@better-scroll/core": "^2.4.2",
-        "@chenfengyuan/vue-qrcode": "^2.0.0-rc.1",
-        "@vant/area-data": "^1.1.3",
-        "@vueuse/core": "^8.7.5",
-        "ali-oss": "^6.16.0",
-        "axios": "^0.21.4",
-        "better-scroll": "^2.4.2",
-        "clipboard": "^2.0.8",
-        "compressorjs": "^1.1.1",
-        "core-js": "^3.6.5",
-        "crypto-js": "^4.1.1",
-        "date-fns": "^2.27.0",
-        "dayjs": "^1.10.7",
-        "echarts": "^4.9.0",
-        "element-ui": "^2.15.6",
-        "eruda": "^2.4.1",
-        "html2canvas": "^1.3.2",
-        "lodash": "^4.17.21",
-        "mathjs": "^9.5.1",
-        "mitt": "^3.0.0",
-        "qrcode": "^1.4.4",
-        "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",
-        "vant": "^3.2.3",
-        "vconsole": "^3.9.4",
-        "vue": "^3.2.20",
-        "vue-clipboard2": "^0.3.3",
-        "vue-croppie": "^2.0.2",
-        "vue-lottie": "^0.2.1",
-        "vue-router": "^4.0.0-0",
-        "vuex": "^4.0.0-0"
-    },
-    "devDependencies": {
-        "@volar-plugins/prettier": "^1.1.4",
-        "@vue/cli-plugin-babel": "~4.5.0",
-        "@vue/cli-plugin-eslint": "~4.5.0",
-        "@vue/cli-plugin-router": "~4.5.0",
-        "@vue/cli-plugin-vuex": "~4.5.0",
-        "@vue/cli-service": "~4.5.0",
-        "@vue/compiler-sfc": "^3.0.0",
-        "@vue/composition-api": "^1.6.1",
-        "@vue/eslint-config-prettier": "^6.0.0",
-        "babel-eslint": "^10.1.0",
-        "eslint": "^6.7.2",
-        "eslint-plugin-prettier": "^3.3.1",
-        "eslint-plugin-vue": "^7.0.0",
-        "less": "^3.0.4",
-        "less-loader": "^5.0.0",
-        "prettier": "^2.2.1",
-        "style-resources-loader": "^1.4.1",
-        "vue-cli-plugin-style-resources-loader": "^0.1.5"
-    }
+  "name": "nine-space",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "serveRaex": "vue-cli-service serve --mode development_raex",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@better-scroll/core": "^2.4.2",
+    "@chenfengyuan/vue-qrcode": "^2.0.0-rc.1",
+    "@vant/area-data": "^1.1.3",
+    "@vueuse/core": "^8.7.5",
+    "ali-oss": "^6.16.0",
+    "axios": "^0.21.4",
+    "better-scroll": "^2.4.2",
+    "clipboard": "^2.0.8",
+    "compressorjs": "^1.1.1",
+    "core-js": "^3.6.5",
+    "crypto-js": "^4.1.1",
+    "date-fns": "^2.27.0",
+    "dayjs": "^1.10.7",
+    "echarts": "^4.9.0",
+    "element-ui": "^2.15.6",
+    "eruda": "^2.4.1",
+    "html2canvas": "^1.3.2",
+    "lodash": "^4.17.21",
+    "mathjs": "^9.5.1",
+    "mitt": "^3.0.0",
+    "qrcode": "^1.4.4",
+    "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",
+    "vant": "^3.2.3",
+    "vconsole": "^3.9.4",
+    "vue": "^3.2.20",
+    "vue-clipboard2": "^0.3.3",
+    "vue-croppie": "^2.0.2",
+    "vue-lottie": "^0.2.1",
+    "vue-picture-cropper": "^0.5.1",
+    "vue-router": "^4.0.0-0",
+    "vue3-lottie": "^2.3.0",
+    "vuex": "^4.0.0-0"
+  },
+  "devDependencies": {
+    "@volar-plugins/prettier": "^1.1.4",
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/compiler-sfc": "^3.0.0",
+    "@vue/composition-api": "^1.6.1",
+    "@vue/eslint-config-prettier": "^6.0.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-prettier": "^3.3.1",
+    "eslint-plugin-vue": "^7.0.0",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "prettier": "^2.2.1",
+    "style-resources-loader": "^1.4.1",
+    "vue-cli-plugin-style-resources-loader": "^0.1.5",
+    "vue-picture-cropper": "^0.5.1"
+  }
 }

BIN
public/favicon.ico


BIN
public/favicon.png


BIN
public/font/iconfont.ttf


BIN
public/font/iconfont.woff


BIN
public/font/iconfont.woff2


+ 4 - 1
public/index.html

@@ -3,7 +3,7 @@
     <head>
         <meta charset="utf-8" />
         <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-        <link rel="icon" href="<%= BASE_URL %>favicon.png" />
+        <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
         <meta
             name="viewport"
             content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, viewport-fit=cover"
@@ -16,6 +16,9 @@
         <meta name="full-screen" content="yes" />
         <meta name="x5-fullscreen" content="true" />
         <meta name="theme-color" content="#000000" />
+        <meta http-equiv="Pragma" content="no-cache">
+        <meta http-equiv="Cache-Control" content="no-cache">
+        <meta http-equiv="Expires" content="0">
         <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
         <% if (htmlWebpackPlugin.options.app) { %>
         <script src="cordova.js"></script>

+ 119 - 3
src/App.vue

@@ -1,5 +1,11 @@
 <template>
-    <div class="scroll-wrapper" id="scroll-wrapper" ref="scroll" @scroll="scrollEvent">
+    <div
+        class="scroll-wrapper"
+        :class="{ darkTheme: darkTheme }"
+        id="scroll-wrapper"
+        ref="scroll"
+        @scroll="scrollEvent"
+    >
         <app-bar ref="bar"></app-bar>
         <router-view v-slot="{ Component }">
             <keep-alive :include="keeps">
@@ -7,6 +13,36 @@
             </keep-alive>
         </router-view>
         <phone-ver></phone-ver>
+        <Transition>
+            <swiper
+                v-if="showSplash"
+                pagination
+                :space-between="16"
+                @reachEnd="reachEnd"
+                class="appSwiper"
+                :autoplay="{ delay: 1500, disableOnInteraction: false }"
+            >
+                <swiper-slide>
+                    <img src="@assets/splash1.jpg" alt="" />
+                </swiper-slide>
+                <swiper-slide>
+                    <img src="@assets/splash2.jpg" alt="" />
+                </swiper-slide>
+                <swiper-slide>
+                    <img src="@assets/splash3.jpg" alt="" />
+                </swiper-slide>
+                <swiper-slide>
+                    <img src="@assets/splash4.jpg" alt="" />
+                </swiper-slide>
+                <swiper-slide>
+                    <img src="@assets/splash5.jpg" alt="" />
+                </swiper-slide>
+                <swiper-slide>
+                    <img src="@assets/splash6.jpg" alt="" />
+                </swiper-slide>
+                <div class="tiaozhuan" @click="goApp">跳转</div>
+            </swiper>
+        </Transition>
     </div>
 </template>
 
@@ -14,8 +50,18 @@
 import AppBar from './components/AppBar.vue';
 import { computed } from 'vue';
 import PhoneVer from './components/PhoneVer.vue';
+import { mapState } from 'vuex';
+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]);
 export default {
-    components: { AppBar, PhoneVer },
+    components: { AppBar, PhoneVer, Swiper, SwiperSlide },
     name: 'App',
     provide() {
         return {
@@ -31,6 +77,7 @@ export default {
     },
     inject: ['barHeight'],
     computed: {
+        ...mapState(['darkTheme']),
         barValue() {
             return this.$refs.bar;
         },
@@ -45,7 +92,8 @@ export default {
         return {
             checkEvent: null,
             keeps: [],
-            bodyScroll: 0
+            bodyScroll: 0,
+            showSplash: false
         };
     },
     watch: {
@@ -55,7 +103,23 @@ export default {
             });
         }
     },
+    mounted() {
+        // if (window.cordova && StatusBar) {
+        //     StatusBar.overlaysWebView(false);
+        // }
+    },
     methods: {
+        goApp() {
+            if (window.cordova && StatusBar) {
+                StatusBar.overlaysWebView(true);
+            }
+            this.showSplash = false;
+        },
+        reachEnd() {
+            setTimeout(() => {
+                this.goApp();
+            }, 1500);
+        },
         setKeeps(keep = [], isAdd = true, isClear = false) {
             let keeps = [...this.keeps];
             if (isAdd) {
@@ -100,4 +164,56 @@ export default {
 .scroll-wrapper {
     background-color: @bg;
 }
+
+.appSwiper {
+    position: fixed;
+    width: 100vw;
+    height: 100vh;
+    // height: var(--app-height);
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 9999;
+    object-fit: cover;
+    opacity: 1;
+    transition: opacity 0.8s ease-in-out;
+    background-color: #000;
+    --swiper-theme-color: #fff;
+    .swiper-slide {
+        img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+        }
+    }
+
+    /deep/.swiper-pagination {
+        .fixedBottom(40px);
+    }
+
+    .tiaozhuan {
+        height: 26px;
+        background: rgba(0, 0, 0, 0.5);
+        border-radius: 14px;
+        font-size: 14px;
+        font-weight: 400;
+        color: #ffffff;
+        line-height: 26px;
+        padding: 0 16px;
+        position: fixed;
+        z-index: 30;
+        top: 36px;
+        right: 30px;
+    }
+}
+.v-enter-active,
+.v-leave-active {
+    transition: opacity 0.5s ease;
+}
+
+.v-enter-from,
+.v-leave-to {
+    opacity: 0;
+}
 </style>

BIN
src/assets/arrow-up.png


BIN
src/assets/banquanshichang-diwen@3x.png


BIN
src/assets/box1.png


BIN
src/assets/box2.png


BIN
src/assets/icon-funnegqingdan@3x.png


BIN
src/assets/icon-gongkaizhanshi.png


BIN
src/assets/icon-goumaixuzhi@3x.png


BIN
src/assets/icon-guanlianxinwen@3x.png


BIN
src/assets/icon-jiantou@3x.png


BIN
src/assets/icon-quanbuleimu@3x.png


BIN
src/assets/icon-quanbuleimuone@3x.png


BIN
src/assets/icon-weizhanshi.png


BIN
src/assets/icon-zengsong.png


BIN
src/assets/icon-zhengshu.png


BIN
src/assets/icon-zhuzaoxinghe.png


BIN
src/assets/icon.png


BIN
src/assets/icon1.png


BIN
src/assets/icon2.png


BIN
src/assets/icon3.jpg


BIN
src/assets/icon_gouxuan_pre@3x.png


BIN
src/assets/icon_gouxuan_xiao@3x.png


BIN
src/assets/info_icon_lingqishangcheng.png


BIN
src/assets/info_icon_no1-2.png


BIN
src/assets/info_icon_no1-ip.png


BIN
src/assets/info_icon_no2-2.png


BIN
src/assets/info_icon_no2-ip.png


BIN
src/assets/info_icon_no3-2.png


BIN
src/assets/info_icon_no3-ip.png


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/assets/lottie/star.json


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/assets/lottie/star1.json


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/assets/lottie/star2.json


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/assets/lottie/zuzhao.json


BIN
src/assets/png-bg-shangping2.png


BIN
src/assets/png-bg.png


BIN
src/assets/png-diwen-hei.png


BIN
src/assets/png-fuhe.png


BIN
src/assets/png-kapian.png


BIN
src/assets/png-renzheng.png


BIN
src/assets/png-shenhe-shibai.png


BIN
src/assets/png-shenhe.png


BIN
src/assets/png-shibai.png


BIN
src/assets/png-xiaohuicangping@3x.png


BIN
src/assets/png-xingtu-bg.png


BIN
src/assets/png-xiushi.png


BIN
src/assets/png-xiushi1.png


BIN
src/assets/png-zhengshu-diwen.png


BIN
src/assets/png-zhiding.png


BIN
src/assets/rank-left.png


BIN
src/assets/splash1.jpg


BIN
src/assets/splash2.jpg


BIN
src/assets/splash3.jpg


BIN
src/assets/splash4.jpg


BIN
src/assets/splash5.jpg


BIN
src/assets/splash6.jpg


BIN
src/assets/tabbar_icon_05.png


BIN
src/assets/tabbar_icon_05_pre.png


BIN
src/assets/top50.jpg


BIN
src/assets/top50.png


BIN
src/assets/topbg1.png


BIN
src/assets/zhi_fu_zhong.png


+ 64 - 0
src/components/PayBalance.vue

@@ -0,0 +1,64 @@
+<template>
+    <van-number-keyboard class="balance-keyboard" v-model="code" :show="showKeyboard" @blur="showKeyboard = false" />
+    <van-dialog
+        v-model:show="showPwdDialog"
+        title="请输入支付密码"
+        confirmButtonText="立即支付"
+        show-cancel-button
+        confirmButtonColor="#3ab200"
+        @cancel="(showPwdDialog = false), $toast.clear()"
+        @confirm="pay"
+    >
+        <div style="padding: 20px 0">
+            <van-password-input :value="code" :focused="showKeyboard" @focus="showKeyboard = true" gutter="4px" />
+        </div>
+    </van-dialog>
+</template>
+
+<script>
+import { ref, watch } from 'vue-demi';
+export default {
+    props: {
+        tradeCode: {
+            type: String,
+            default: ''
+        }
+    },
+    setup(props, context) {
+        const code = ref('');
+        const showPwdDialog = ref(false);
+        const showKeyboard = ref(false);
+
+        watch(code, val => {
+            context.emit('update:tradeCode', val);
+        });
+
+        const show = () => {
+            code.value = '';
+            showPwdDialog.value = true;
+        };
+
+        const pay = () => {
+            context.emit('pay');
+        };
+
+        return {
+            code,
+            showPwdDialog,
+            showKeyboard,
+            show,
+            pay
+        };
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.balance-keyboard {
+    z-index: 3000;
+}
+
+/deep/.van-password-input__security li {
+    border: 1px solid @text3;
+}
+</style>

+ 1 - 0
src/components/PayMethodPick.vue

@@ -6,6 +6,7 @@
                 @click="pick(item)"
                 v-if="item.show && (item.key === 'BALANCE' ? showBalance : true)"
                 :key="index"
+                :class="{ not: !item.enabled }"
             >
                 <div class="img-icon">
                     <img class="icon" :src="item.icon" alt="" />

+ 177 - 0
src/components/PictureCropper.vue

@@ -0,0 +1,177 @@
+<template>
+    <van-overlay :show="show">
+        <VuePictureCropper
+            :boxStyle="{
+                width: '100%',
+                height: '100%',
+                backgroundColor: '#f8f8f8',
+                margin: 'auto'
+            }"
+            :img="pic"
+            :options="{
+                viewMode: 1,
+                dragMode: 'crop',
+                aspectRatio: 1 / 1
+            }"
+        />
+
+        <div class="btns">
+            <van-button type="primary" plain @click="cancel(true)">取消</van-button>
+            <van-button type="primary" @click="getResult"> 确认</van-button>
+        </div>
+    </van-overlay>
+    <van-image-preview class="cropPreview" v-model:show="showPreview" :onClose="cancel" :images="imgs">
+        <template v-slot:cover>
+            <div class="btn-list" @click.stop="">
+                <van-button type="primary" plain @click="cancel(true)">取消</van-button>
+                <van-button v-if="!isGif" type="primary" plain @click="edit">编辑</van-button>
+                <van-button type="primary" @click="sure"> 确认</van-button>
+            </div>
+        </template>
+    </van-image-preview>
+</template>
+
+<script>
+import VuePictureCropper, { cropper } from 'vue-picture-cropper';
+import http from '../plugins/http';
+export default {
+    data() {
+        return {
+            show: false,
+            pic: '',
+            result: {},
+            imgs: [],
+            showPreview: false,
+            file: null,
+            next: false
+        };
+    },
+    computed: {
+        isGif() {
+            return this.file && this.file.file.type === 'image/gif';
+        }
+    },
+    methods: {
+        init(img = '', file) {
+            this.pic = img;
+            this.imgs = [img];
+            this.file = file;
+            this.showPreview = true;
+            this.next = false;
+        },
+        edit() {
+            this.next = true;
+            this.showPreview = false;
+            this.show = true;
+        },
+        sure() {
+            this.next = true;
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            this.updateFile(this.file).then(img => {
+                this.$toast.clear();
+                this.showPreview = false;
+                this.$emit('updateImg', img);
+            });
+        },
+        cancel(finish = false) {
+            if (this.next && finish !== true) {
+                return;
+            }
+            this.showPreview = false;
+            this.show = false;
+            this.$emit('updateImg', '');
+        },
+        async getResult() {
+            this.$toast.loading({
+                message: '加载中...',
+                forbidClick: true
+            });
+            // 获取生成的base64图片地址
+            const base64 = cropper.getDataURL();
+            // 获取生成的blob文件信息
+            const blob = await cropper.getBlob();
+            // 获取生成的file文件信息
+            const file = await cropper.getFile({
+                fileName: '测试文件名,可不传'
+            });
+            console.log({ base64, blob, file });
+            // 把base64赋给结果展示区
+            this.result.dataURL = base64;
+            this.result.blobURL = URL.createObjectURL(blob);
+            console.log(this.result);
+            this.updateFile2(base64)
+                .then(img => {
+                    this.$toast.clear();
+                    this.show = false;
+                    this.$emit('updateImg', img);
+                })
+                .catch(e => {
+                    this.$toast('图片太大,上传失败');
+                    this.cancel(true);
+                });
+            // 隐藏裁切弹窗
+            // this.isShowDialog = false;
+        },
+        updateFile2(base64) {
+            const formData = new FormData();
+            formData.append('base64', base64);
+            return http.axios.post('/upload/base64', formData).then(res => {
+                return Promise.resolve(res.data);
+            });
+        }
+    },
+    components: {
+        VuePictureCropper
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.van-overlay {
+    z-index: 99;
+}
+.btns {
+    position: absolute;
+    padding: 9px 48px;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    .bottom(9px);
+    background-color: #222426;
+    .flex();
+    padding: 9px 16px;
+    z-index: 30;
+    justify-content: space-between;
+    .van-button {
+        width: 120px;
+    }
+}
+/deep/.cropper-view-box {
+    outline-color: @prim;
+}
+
+/deep/.cropper-point {
+    background-color: @prim;
+}
+.btn-list {
+    .flex();
+    padding: 9px 16px;
+    justify-content: space-between;
+    .bottom(9px);
+    background-color: #222426;
+}
+</style>
+
+<style lang="less">
+.cropPreview {
+    .van-image-preview__cover {
+        z-index: 20;
+        bottom: 0;
+        top: auto;
+        right: 0;
+    }
+}
+</style>

+ 2 - 2
src/components/asset/assetInfo.vue

@@ -15,7 +15,7 @@
                 width="21.3vw"
                 height="21.3vw"
                 :src="getImg(changeImgs(info.pic))"
-                fit="cover"
+                fit="contain"
             />
             <van-image
                 class="more-img"
@@ -23,7 +23,7 @@
                 width="21.3vw"
                 height="21.3vw"
                 :src="getImg(changeImgs(info.pic))"
-                fit="cover"
+                fit="contain"
                 v-if="isMore"
             />
         </template>

+ 2 - 2
src/components/asset/assetInfoSe.vue

@@ -219,9 +219,9 @@ export default {
 
 .number {
     position: absolute;
-    top: calc(21.3vw - 17px);
+    top: calc(80px - 16px);
     left: 0;
-    width: 21.3vw;
+    width: 80px;
     font-size: 10px;
     color: @text3;
     line-height: 17px;

+ 133 - 0
src/components/creator/RankInfo.vue

@@ -0,0 +1,133 @@
+<template>
+    <div class="rank" :class="[`rank${index}`]">
+        <div class="rank-icon">
+            <img v-if="index < 3" :src="icons[index]" alt="" />
+            <span v-else>{{ getNum(index + 1) }}</span>
+        </div>
+        <div class="content">
+            <van-image round width="42" height="42" :src="info.avatar" />
+            <div class="name van-ellipsis">{{ info.nickname }}</div>
+        </div>
+        <van-button :class="{ follow: info.follow }" @click="follow" type="primary" round size="mini" plain>
+            {{ info.follow ? '已关注' : '关注' }}
+        </van-button>
+    </div>
+</template>
+
+<script>
+export default {
+    props: {
+        index: {
+            type: Number,
+            default: 0
+        },
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    data() {
+        return {
+            icons: [
+                require('@assets/info_icon_no1-2.png'),
+                require('@assets/info_icon_no2-2.png'),
+                require('@assets/info_icon_no3-2.png')
+            ]
+        };
+    },
+    methods: {
+        follow() {
+            this.checkLogin().then(() => {
+                if (!this.info.follow) {
+                    this.$http.get(`/user/${this.info.id}/follow`).then(res => {
+                        this.$emit('update:info', {
+                            ...this.info,
+                            follow: true
+                        });
+                        this.$toast.success('关注成功');
+                    });
+                } else {
+                    this.$http.get(`/user/${this.info.id}/unfollow`).then(() => {
+                        this.$emit('update:info', {
+                            ...this.info,
+                            follow: false
+                        });
+                        this.$toast.success('取消关注');
+                    });
+                }
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.rank {
+    .flex();
+    padding: 12px 12px;
+    overflow: hidden;
+    position: relative;
+
+    .rank-icon {
+        width: 38px;
+        height: 38px;
+        flex-shrink: 0;
+        .flex();
+        justify-content: center;
+        img {
+            width: 38px;
+            height: 38px;
+        }
+        span {
+            font-size: 16px;
+            font-family: AlibabaPuHuiTi-Regular, AlibabaPuHuiTi;
+            color: var(--text0);
+            line-height: 20px;
+        }
+    }
+
+    .content {
+        .flex();
+        overflow: hidden;
+        flex-grow: 1;
+        margin-left: 14px;
+        .van-image {
+            flex-shrink: 0;
+        }
+
+        .name {
+            font-size: 14px;
+            line-height: 24px;
+            margin-left: 10px;
+            color: var(--text0);
+            font-weight: bold;
+        }
+    }
+
+    .van-button {
+        border: 1px solid var(--prim);
+        --van-button-primary-background-color: var(--prim);
+        --van-button-mini-font-size: 12px;
+        min-width: 60px;
+
+        &.follow {
+            border-color: var(--btnBorderInfo);
+            --van-button-primary-background-color: var(--btnInfo);
+        }
+    }
+
+    &:not(:last-child) {
+        &::after {
+            content: '';
+            position: absolute;
+            left: 16px;
+            right: 16px;
+            bottom: 0;
+            height: 1px;
+            background-color: var(--border);
+        }
+    }
+}
+</style>

+ 1 - 0
src/components/order/OrderInfoAct.vue

@@ -161,6 +161,7 @@ export default {
 
     .status {
         color: @prim;
+        flex-shrink: 0;
     }
 }
 

+ 1 - 1
src/components/order/OrderOpen.vue

@@ -7,7 +7,7 @@
                 <img class="img1" src="@assets/box1.png" alt="" />
                 <img class="img2" ref="img2" src="@assets/box2.png" alt="" />
                 <img class="img3" ref="img3" src="@assets/png-kapian.png" alt="" />
-                <img class="guang" src="@assets/png-guang.png" alt="" />
+                <!-- <img class="guang" src="@assets/png-guang.png" alt="" /> -->
             </div>
 
             <div class="product" ref="product">

+ 2 - 2
src/components/phoneCode.vue

@@ -5,10 +5,10 @@
             <div class="title">输入验证码</div>
             <div class="phone">已发送到您{{ phoneText }}手机</div>
             <div class="send" @click="onSubmit">未收到验证码?</div>
-            <van-password-input :value="code" :length="6" />
+            <van-password-input :value="code" :length="4" />
             <!-- 数字键盘 -->
             <van-number-keyboard
-                maxlength="6"
+                maxlength="4"
                 theme="custom"
                 v-model="code"
                 :show="show"

+ 117 - 0
src/components/product/HotCollect.vue

@@ -0,0 +1,117 @@
+<template>
+    <div class="collect-info" @click="goSearch">
+        <van-image width="46" height="46" radius="8" :src="getImg(changeImgs(info.pic, 600))" />
+        <div class="content">
+            <div class="text1 van-ellipsis">{{ info.name }}</div>
+            <div class="text2">
+                <span>收藏品</span>
+            </div>
+        </div>
+        <van-button size="mini" plain type="primary" round> 查看</van-button>
+
+        <img :src="icons[index]" v-if="index < 3" alt="" class="rank-img" />
+        <div class="rank-num" v-else>{{ index + 1 }}</div>
+    </div>
+</template>
+
+<script>
+import product from '../../mixins/product';
+export default {
+    mixins: [product],
+    props: {
+        index: {
+            type: Number,
+            default: 0
+        },
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    data() {
+        return {
+            icons: [
+                require('@assets/info_icon_no1-ip.png'),
+                require('@assets/info_icon_no2-ip.png'),
+                require('@assets/info_icon_no3-ip.png')
+            ]
+        };
+    },
+    methods: {
+        goSearch() {
+            this.$router.push({
+                path: '/productSearchCorpse',
+                query: {
+                    search: this.info.prefixName
+                }
+            });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.collect-info {
+    .flex();
+    padding: 12px 16px;
+    position: relative;
+    .van-image {
+        flex-shrink: 0;
+    }
+}
+
+.content {
+    flex-grow: 1;
+    overflow: hidden;
+    padding: 0 20px 0 12px;
+
+    .text1 {
+        font-size: 14px;
+        font-weight: bold;
+        color: var(--text0);
+        line-height: 24px;
+    }
+    .text2 {
+        margin-top: 4px;
+        span {
+            font-size: 12px;
+            color: #8a8a8e;
+            line-height: 18px;
+            background: var(--btnplaintBg);
+            border-radius: 2px;
+            padding: 0 10px;
+            overflow: hidden;
+        }
+    }
+}
+
+.van-button {
+    min-width: 68px;
+    background: var(--btnplaintBg);
+}
+
+.rank-img {
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    top: 12px;
+    left: 16px;
+}
+
+.rank-num {
+    position: absolute;
+    top: 12px;
+    left: 16px;
+    text-align: center;
+    font-size: 14px;
+    font-weight: bold;
+    color: #ffffff;
+    line-height: 20px;
+    width: 20px;
+    height: 20px;
+    background: linear-gradient(42deg, #8d94b2 0%, #abb2d4 100%);
+    border-radius: 8px 0px 8px 0px;
+}
+</style>

+ 293 - 0
src/components/product/NewsRecord.vue

@@ -0,0 +1,293 @@
+<template>
+    <router-link
+        :to="{
+            path: '/newsDetail',
+            query: {
+                id: info.id
+            }
+        }"
+        class="news-record"
+        :class="{ isLight: type === 'light' }"
+    >
+        <van-badge :dot="isNew" :offset="[-2, 2]">
+            <van-image :src="getImg(info.pic)" :radius="8" width="46" height="46" fit="cover" />
+        </van-badge>
+        <div class="content">
+            <div class="name van-ellipsis">{{ info.title }}</div>
+            <!-- <div class="sales-list">
+                <div class="sales">
+                    <span>绿洲头条新闻</span>
+                </div>
+            </div> -->
+            <div class="bottom">
+                <div class="miner">
+                    <span style="margin-left: 0">{{ time }}</span>
+                </div>
+            </div>
+        </div>
+        <van-button type="primary" size="mini" round plain>查看</van-button>
+    </router-link>
+</template>
+
+<script>
+import product from '../../mixins/product';
+export default {
+    mixins: [product],
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        type: {
+            type: String,
+            default: 'dark'
+        }
+    },
+    computed: {
+        time() {
+            if (this.info.createdAt) {
+                return this.dayjs(this.info.createdAt).format('YYYY-MM-DD HH:mm');
+            }
+
+            return '';
+        },
+        isNew() {
+            if (this.info.createdAt) {
+                let time = this.dayjs(this.info.createdAt).add(1, 'day');
+                return this.dayjs().isBefore(time);
+            } else {
+                return false;
+            }
+        }
+    },
+    mounted() {
+        if (this.info.startTime) {
+            var x = this.dayjs(this.info.startTime, 'YYYY-MM-DD HH:mm:ss');
+            var y = this.dayjs();
+            let d = this.dayjs.duration(x.diff(y));
+            let day = parseInt(d.asDays());
+            if (day <= 0) {
+                this.getTime(this.info.startTime);
+            }
+        }
+    },
+    methods: {
+        likeProduct() {
+            if (!this.info.liked) {
+                this.$http.get(`/collection/${this.info.id}/like`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: true,
+                        likes: this.info.likes + 1
+                    });
+                    this.$toast.success('收藏成功');
+                });
+            } else {
+                this.$http.get(`/collection/${this.info.id}/unlike`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: false,
+                        likes: this.info.likes - 1
+                    });
+                    this.$toast.success('取消收藏');
+                });
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.van-badge {
+    z-index: 20;
+
+    &.van-badge--dot {
+        border: 1px solid #ffffff;
+        --van-badge-dot-size: 10px;
+    }
+}
+.news-record {
+    position: relative;
+    background-color: var(--bg2);
+    display: inline-block;
+    border-radius: 12px;
+    overflow: hidden;
+    padding: 12px 16px;
+    overflow: hidden;
+    .flex();
+
+    .bg {
+        position: absolute;
+        width: 92px;
+        height: 116px;
+        right: 0;
+        bottom: 0;
+        z-index: 0;
+    }
+
+    .van-image {
+        flex-shrink: 0;
+    }
+
+    .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;
+        }
+    }
+
+    .van-image {
+        display: block;
+        position: relative;
+        z-index: 2;
+    }
+    .content {
+        margin-left: 12px;
+        align-self: stretch;
+        .flex-col();
+        justify-content: space-between;
+        flex-grow: 1;
+        overflow: hidden;
+        margin-right: 12px;
+        .name {
+            font-size: 14px;
+            font-weight: bold;
+            color: var(--text0);
+            line-height: 24px;
+        }
+
+        .sales-list {
+            margin-top: 8px;
+            .flex();
+        }
+
+        .sales {
+            overflow: hidden;
+            font-size: @font1;
+            border-radius: 4px;
+
+            span {
+                padding: 0 10px;
+                line-height: 20px;
+                height: 20px;
+                display: inline-block;
+                &.sales-fir {
+                    background: @prim;
+                    color: @bg;
+                }
+                background-color: @bg3;
+                color: @prim;
+            }
+        }
+        .sales + .sales {
+            margin-left: 14px;
+        }
+
+        .bottom {
+            display: flex;
+            // margin-top: 14px;
+            align-items: center;
+
+            .miner {
+                display: flex;
+                align-items: center;
+
+                span {
+                    color: @text3;
+                    font-size: @font1;
+                    margin-left: 6px;
+                }
+            }
+
+            .price {
+                font-size: @font4;
+                color: @text0;
+                line-height: 20px;
+                font-family: OSP;
+                img {
+                    width: 8px;
+                    display: inline-block;
+                }
+            }
+        }
+    }
+
+    .text {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    .top-bg {
+        width: 100%;
+        display: block;
+        position: absolute;
+        z-index: 2;
+        top: 0;
+        left: 0;
+    }
+
+    // &.isLight {
+    //     .content {
+    //         .name {
+    //             color: #000000;
+    //         }
+    //         .bottom {
+    //             .miner {
+    //                 color: #939599;
+    //             }
+    //         }
+    //     }
+    // }
+
+    &:not(:last-child) {
+        &::after {
+            content: '';
+            height: 1px;
+            background-color: var(--border);
+            position: absolute;
+            left: 74px;
+            right: 16px;
+            bottom: 0;
+        }
+    }
+}
+
+.status {
+    font-size: @font2;
+    color: @text0;
+}
+.sold {
+    background-color: @bg2;
+    font-size: @font1;
+    color: @text3;
+    padding: 0 17px;
+    border-radius: 13px;
+    line-height: 24px;
+    position: absolute;
+    top: 16px;
+    left: 16px;
+    z-index: 3;
+}
+.van-button {
+    background: var(--btnplaintBg);
+    border: 1px solid var(--btnplaintBorder);
+    min-width: 68px;
+    font-size: 16px;
+    font-weight: bold;
+}
+</style>

+ 3 - 3
src/components/product/ProductBanner.vue

@@ -16,7 +16,7 @@
                         width="calc(100vw - 134px)"
                         height="calc(100vw - 134px)"
                         :src="require('../../assets/manghe.png')"
-                        fit="cover"
+                        fit="contain"
                     />
                     <video
                         class="swiper-video"
@@ -37,7 +37,7 @@
                         :src="getImg(item.url, '', 1200)"
                         width="calc(100vw - 134px)"
                         height="calc(100vw - 134px)"
-                        fit="cover"
+                        :fit="info.type === 'PICTURE' ? 'cover' : 'contain'"
                     />
                 </swiper-slide>
             </swiper>
@@ -226,7 +226,7 @@ export default {
                 border: 2px solid #2f2f2f;
                 border-radius: @radius;
                 overflow: hidden;
-                background-color: @bg;
+                background-color: transparent;
             }
         }
     }

+ 1 - 1
src/components/product/SaleInfo.vue

@@ -19,7 +19,7 @@
                     <div class="user">
                         <van-image width="24" height="24" radius="24" :src="item.ownerAvatar" fit="cover" />
                         <span>{{ item.owner }}</span>
-                        <span class="status out" v-if="item.soldOut">支付中</span>
+                        <span class="status out" v-if="item.inPaying">支付中</span>
                         <span class="status prim" v-else>寄售</span>
                     </div>
                     <div class="price">¥{{ item.price }}</div>

+ 77 - 15
src/components/product/productInfo.vue

@@ -1,25 +1,42 @@
 <template>
     <div class="product" @click="goDetail" :class="{ dark: dark }">
-        <van-image width="100%" height="calc(50vw - 24px)" :src="getImg(changeImgs(info.pic, 600))" fit="cover" />
+        <div class="product-top">
+            <van-image
+                width="100%"
+                height="calc(50vw - 24px)"
+                :src="getImg(changeImgs(info.pic, 600))"
+                :fit="info.type === 'PICTURE' ? 'cover' : 'contain'"
+            />
+            <div class="number" v-if="info.number">编号:{{ info.number }}</div>
+        </div>
 
-        <div class="number" v-if="info.number">编号:{{ info.number }}</div>
         <div class="content">
             <div class="name van-ellipsis">
                 {{ info.name }}
             </div>
-            <div class="price-content" v-if="info.salable">
-                <div class="price">
-                    <img src="@assets/jiage_huang.png" alt="" />
-                    <span>{{ info.price }}</span>
+            <template v-if="info.type === 'PICTURE'">
+                <div class="types">
+                    <div class="type">个人作品</div>
                 </div>
-                <div class="flex1"></div>
-                <div class="text1" v-if="info.total !== 1">
-                    <span>{{ Math.min(info.sale, info.total) }}/</span>
-                    <span>{{ info.total }}</span>
+
+                <div class="types-status">仅展示</div>
+            </template>
+
+            <template v-else>
+                <div class="price-content" v-if="info.salable">
+                    <div class="price">
+                        <img src="@assets/jiage_huang.png" alt="" />
+                        <span>{{ info.price }}</span>
+                    </div>
+                    <div class="flex1"></div>
+                    <div class="text1" v-if="info.total !== 1">
+                        <span>{{ Math.min(info.sale, info.total) }}/</span>
+                        <span>{{ info.total }}</span>
+                    </div>
                 </div>
-            </div>
-            <div class="status" v-else>仅展示</div>
-            <div class="text">
+                <div class="status" v-else>仅展示</div>
+            </template>
+            <div class="text" v-if="info.type !== 'PICTURE'">
                 <div class="minter">
                     <van-image width="18" height="18" radius="18" :src="info.minterAvatar" fit="cover" />
                     <span class="van-ellipsis">{{ info.minter }}</span>
@@ -34,6 +51,10 @@
                 <span>{{ startTime || time }}</span>
             </div>
             <div class="sold" v-if="isSolded">已售罄</div>
+            <div class="sold zhifu" v-else-if="info.inPaying">
+                <img src="@assets/zhi_fu_zhong.png" alt="" />
+                <span>支付中</span>
+            </div>
             <div class="sold" v-else-if="isSold" style="color: #ff4f50">即将售罄</div>
         </div>
     </div>
@@ -126,6 +147,7 @@ export default {
     width: calc(50vw - 24px);
     margin: 8px;
     background-color: @bg2;
+    // background: #373B3E;
     display: inline-block;
     border-radius: 8px;
     overflow: hidden;
@@ -141,6 +163,7 @@ export default {
         .name {
             font-size: @font2;
             color: @text0;
+            // color: #FFFFFF;
             line-height: 24px;
         }
 
@@ -229,6 +252,22 @@ export default {
     top: 6px;
     left: 6px;
     z-index: 5;
+
+    &.zhifu {
+        background: #ffefd2;
+        padding: 0 8px;
+        .flex();
+        img {
+            width: 18px;
+            height: 18px;
+        }
+        span {
+            font-size: 12px;
+            color: #bf8c31;
+            line-height: 20px;
+            margin-left: 1px;
+        }
+    }
 }
 
 .xianliang {
@@ -249,10 +288,14 @@ export default {
         margin-right: 3px;
     }
 }
-
+.product-top {
+    position: relative;
+    overflow: hidden;
+    // box-shadow: inset 0 0 5px 10px #000;
+}
 .number {
     position: absolute;
-    top: calc(50vw - 46px);
+    bottom: 0px;
     left: 0;
     right: 0;
     font-size: 12px;
@@ -260,5 +303,24 @@ export default {
     line-height: 22px;
     background-color: fade(#000, 80%);
     padding: 0 10px;
+    height: 22px;
+}
+.types {
+    .flex();
+    padding-top: 6px;
+    .type {
+        font-size: 11px;
+        color: #3b260c;
+        line-height: 18px;
+        padding: 0 6px;
+        background: #ffe196;
+        border-radius: 2px;
+    }
+}
+.types-status {
+    font-size: 12px;
+    color: #939599;
+    line-height: 18px;
+    margin-top: 8px;
 }
 </style>

+ 19 - 13
src/components/product/productLarge.vue

@@ -38,7 +38,8 @@
                     </div>
                     <div class="flex1"></div>
                     <div class="price" v-if="info.salable">
-                        <img src="@assets/icon_jiage.png" alt="" />
+                        <!-- <img src="@assets/icon_jiage.png" alt="" /> -->
+                        <van-icon name="icon-icon_jiage" class-prefix="font_family" />
                         <span> {{ info.price }}</span>
                     </div>
                     <div v-else class="status">仅展示</div>
@@ -68,12 +69,14 @@
             </div>
         </div>
 
-        <img class="bg" src="@assets/png-diwen.png" alt="" />
+        <img class="bg" v-if="darkTheme" src="@assets/png-diwen-hei.png" alt="" />
+        <img class="bg" v-else src="@assets/png-diwen.png" alt="" />
         <!-- <img class="top-bg" v-if="time" src="@assets/collecbg.png" alt="" /> -->
     </router-link>
 </template>
 
 <script>
+import { mapState } from 'vuex';
 import product from '../../mixins/product';
 export default {
     mixins: [product],
@@ -90,6 +93,7 @@ export default {
         }
     },
     computed: {
+        ...mapState(['darkTheme']),
         time() {
             if (this.info.startTime) {
                 if (this.dayjs().isSameOrBefore(this.info.startTime, 'YYYY-MM-DD HH:mm:ss')) {
@@ -142,7 +146,7 @@ export default {
     width: calc(100vw - 32px);
     margin: 8px 16px;
     position: relative;
-    background-color: @bg2;
+    background-color: var(--bg2);
     display: inline-block;
     border-radius: 30px;
     overflow: hidden;
@@ -183,9 +187,9 @@ export default {
     .content {
         padding: 10px 16px 18px;
         .name {
-            font-size: @font2;
+            font-size: 16px;
             font-weight: bold;
-            color: @text0;
+            color: var(--text0);
             line-height: 24px;
         }
 
@@ -201,14 +205,14 @@ export default {
 
             span {
                 padding: 0 10px;
-                line-height: 20px;
-                height: 20px;
+                line-height: 18px;
+                height: 18px;
                 display: inline-block;
                 &.sales-fir {
                     background: @prim;
                     color: @bg;
                 }
-                background-color: @bg3;
+                background-color: var(--saleBg);
                 color: @prim;
             }
         }
@@ -234,12 +238,14 @@ export default {
 
             .price {
                 font-size: @font4;
-                color: @text0;
+                color: var(--text0);
                 line-height: 20px;
                 font-family: OSP;
-                img {
-                    width: 8px;
-                    display: inline-block;
+                .flex();
+                .font_family {
+                    font-size: 8px;
+                    line-height: 16px;
+                    margin-top: 3px;
                 }
             }
         }
@@ -263,7 +269,7 @@ export default {
 
 .status {
     font-size: @font2;
-    color: @text0;
+    color: var(--text0);
 }
 .sold {
     background-color: @bg2;

+ 2 - 2
src/components/product/productSmall.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="product" @click="goNext(info)">
-        <van-image width="100%" height="140px" :radius="30" :src="getImg(info.pic)" fit="cover" />
+        <van-image width="100%" height="calc(100vw - 32px)" :src="getImg(info.pic)" fit="cover" />
 
         <!-- <div class="content">
             <div class="name van-ellipsis">
@@ -35,7 +35,7 @@ export default {
     width: 100%;
     background-color: @bg2;
     display: inline-block;
-    border-radius: 30px;
+    // border-radius: 30px;
     overflow: hidden;
 
     .van-image {

+ 52 - 0
src/components/star/Info.vue

@@ -0,0 +1,52 @@
+<template>
+    <div class="star-info">
+        <van-image width="100%" height="calc(50vw - 24px)" :src="getImg(changeImgs([info.pic], 600))" fit="cover" />
+
+        <div class="content">
+            <div class="name">{{ info.picName }}</div>
+            <div class="status">{{ getLabelName(info.status, statusOptions) }}</div>
+        </div>
+    </div>
+</template>
+
+<script>
+import product from '../../mixins/product';
+import star from '../../mixins/star';
+export default {
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    mixins: [product, star]
+};
+</script>
+
+<style lang="less" scoped>
+.star-info {
+    width: calc(50vw - 24px);
+    background: #373b3e;
+    border-radius: 8px;
+    overflow: hidden;
+    margin: 8px;
+    display: inline-block;
+}
+
+.content {
+    padding: 6px 10px;
+    .name {
+        font-size: 14px;
+        color: #ffffff;
+        line-height: 24px;
+    }
+    .status {
+        font-size: 12px;
+        color: #939599;
+        line-height: 18px;
+        margin-top: 8px;
+    }
+}
+</style>

+ 353 - 0
src/components/star/assetInfo.vue

@@ -0,0 +1,353 @@
+<template>
+    <div class="product" @click="goAsset">
+        <van-image
+            v-if="opened === false"
+            width="21.3vw"
+            height="21.3vw"
+            radius="8"
+            :src="require('../../assets/manghe.png')"
+            fit="cover"
+        />
+        <template v-else>
+            <van-image
+                class="icon-img"
+                radius="8"
+                width="21.3vw"
+                height="21.3vw"
+                :src="getImg(changeImgs(pic))"
+                fit="cover"
+            />
+        </template>
+
+        <div class="number" v-if="info.number && opened">编号:{{ info.number }}</div>
+        <img src="../../assets/png-touxing.png" class="touying" alt="" />
+        <template v-if="opened && !isMore">
+            <!-- <div class="status status1" v-if="info.consignment">寄售中</div> -->
+            <img v-if="isLock" class="status-img" src="../../assets/png-shangsuo.png" alt="" />
+            <img v-else-if="info.consignment" class="status-img" src="../../assets/png-jishouzhong.png" alt="" />
+            <img
+                v-else-if="info.status === 'NORMAL' && info.publicShow"
+                class="status-img"
+                src="../../assets/png-jinzhanshi.png"
+                alt=""
+            />
+            <img
+                v-else-if="info.status === 'AUCTIONING'"
+                class="status-img"
+                src="../../assets/png-paimaizhong.png"
+                alt=""
+            />
+            <img v-else-if="info.status === 'PENDING'" class="status-img" src="../../assets/png-shenhe.png" alt="" />
+            <img
+                v-else-if="info.status === 'FAIL'"
+                class="status-img"
+                src="../../assets/png-shenhe-shibai.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 ? '仅展示' : '未展示' }}
+            </div>
+            <div class="status" v-else>
+                {{ getLabelName(info.status, assetStatusOptions) }}
+            </div> -->
+        </template>
+        <img v-else-if="!isMore" class="status-img" src="../../assets/png-kaiqi.png" alt="" />
+        <div class="num-icon" v-else>
+            <span>×{{ num }}</span>
+        </div>
+        <!-- <div class="status status2" v-else>待开启</div> -->
+        <div class="content">
+            <div class="name van-ellipsis">
+                {{ !opened ? '盲盒待开启' : info.name }}
+            </div>
+            <!-- <template v-if="opened">
+                <div class="price-content" v-if="info.consignment">
+                    <div class="price">
+                        <img src="@assets/jiage_huang.png" alt="" />
+                        <span>{{ info.sellPrice }}</span>
+                    </div>
+                </div>
+                <div class="status" v-else-if="info.status === 'NORMAL'">
+                    {{ info.publicShow ? '仅展示' : '未展示' }}
+                </div>
+                <div class="status" v-else>
+                    {{ getLabelName(info.status, assetStatusOptions) }}
+                </div>
+            </template>
+            <div v-else class="status" style="min-height: 24px;"></div> -->
+            <div class="text">
+                <div class="minter">
+                    <!-- <van-image width="18" height="18" radius="18" :src="info.minterAvatar" fit="cover" /> -->
+                    <span class="van-ellipsis">{{ info.minter }}</span>
+                </div>
+                <!-- <van-image width="18" height="18" :radius="100" :src="info.minterAvatar" fit="cover" />
+                <span>{{ info.minter }}</span> -->
+                <!-- <div class="text1" v-if="info.type === 'BLIND_BOX'">
+          <span>{{ info.sale }}/ </span>
+          <span>{{ info.stock }}</span>
+        </div>
+        <div class="flex1"></div>
+        <like-button :isLike="info.liked" @click="likeProduct">
+          {{ info.likes }}
+        </like-button> -->
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import asset from '../../mixins/asset';
+import product from '../../mixins/product';
+
+export default {
+    mixins: [asset, product],
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        num: {
+            type: Number,
+            default: 1
+        }
+    },
+    computed: {
+        isMore() {
+            return this.num > 1;
+        },
+        pic() {
+            if (this.info.pic) {
+                return [this.info.pic];
+            } else {
+                return [];
+            }
+        }
+    },
+    methods: {
+        likeProduct() {
+            if (!this.info.liked) {
+                this.$http.get(`/collection/${this.info.id}/like`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: true,
+                        likes: this.info.likes + 1
+                    });
+                    this.$toast.success('收藏成功');
+                });
+            } else {
+                this.$http.get(`/collection/${this.info.id}/unlike`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: false,
+                        likes: this.info.likes - 1
+                    });
+                    this.$toast.success('取消收藏');
+                });
+            }
+        },
+        goAsset() {
+            if (this.info.createAssetId) {
+                this.$router.push({
+                    path: '/assetDetail',
+                    query: {
+                        id: this.info.createAssetId
+                    }
+                });
+            } else if (this.info.orderStatus === 'NOT_PAID') {
+                this.$router.push({
+                    path: '/starCreate',
+                    query: {
+                        id: this.info.id
+                    }
+                });
+            } else {
+                this.$router.push({
+                    path: '/starCreateResult',
+                    query: {
+                        id: this.info.id
+                    }
+                });
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.product {
+    width: 25.6vw;
+    padding-top: 5.3vw;
+    // margin: 8px;
+    // background-color: #1c1e25;
+    display: inline-block;
+    border-radius: 8px;
+    overflow: hidden;
+    position: relative;
+    min-height: 35.8vw;
+
+    &:nth-child(3n + 1) {
+        padding-right: 7.5vw;
+    }
+    &:nth-child(3n + 2) {
+        padding-right: 7.5vw;
+    }
+
+    .icon-img {
+        overflow: hidden;
+        display: block;
+        z-index: 1;
+        box-shadow: 2px -2px 4px 0px rgba(0, 0, 0, 0.3);
+    }
+    .more-img {
+        position: absolute;
+        top: calc(5.3vw - 5px);
+        left: 5px;
+        z-index: 0;
+    }
+    .content {
+        // padding: 6px 10px 8px;
+        padding: 5.3vw 0 0;
+
+        .name {
+            font-size: @font1;
+            color: #ffffff;
+            line-height: 4.5vw;
+            width: calc(21.3vw + 16px);
+        }
+
+        .price {
+            font-size: @font4;
+            font-family: OSP;
+            color: @prim;
+            line-height: 18px;
+            padding: 12px 0;
+
+            img {
+                display: inline-block;
+                width: 8px;
+            }
+        }
+        .status {
+            line-height: 24px;
+            padding: 10px 0 8px;
+            color: @text3;
+            font-size: @font2;
+        }
+    }
+
+    .text {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .text1 {
+            font-weight: 400;
+            color: @text3;
+            line-height: 117px;
+            span {
+                &:last-child {
+                    color: #fff;
+                    font-size: @font1;
+                }
+            }
+        }
+    }
+}
+.price-content {
+    display: flex;
+    align-items: center;
+    .text1 {
+        font-size: @font1;
+        color: @text3;
+        line-height: 12px;
+    }
+}
+
+.minter {
+    display: flex;
+    font-size: @font1;
+    color: @text3;
+    line-height: 4.5vw;
+    align-items: center;
+    overflow: hidden;
+    span {
+        // margin-left: 4px;
+    }
+    .van-image {
+        flex-shrink: 0;
+    }
+}
+
+.number {
+    position: absolute;
+    top: calc(26.6vw - 17px);
+    left: 0;
+    width: 21.3vw;
+    font-size: 10px;
+    color: @text3;
+    line-height: 17px;
+    background-color: fade(#000, 80%);
+    padding: 0 5px;
+    box-sizing: border-box;
+    border-radius: 0 0 8px 8px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    z-index: 2;
+}
+.touying {
+    position: absolute;
+    width: 25.6vw;
+    height: 6.4vw;
+    left: 0;
+    top: 21.3vw;
+    z-index: 0;
+}
+.status-img {
+    height: 14px;
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 5.3vw;
+    z-index: 3;
+}
+.status {
+    background-color: #fff;
+    font-size: 12px;
+    font-weight: bold;
+    color: @text3;
+    position: absolute;
+    top: 4px;
+    left: 3px;
+    line-height: 14px;
+    border-radius: 9px;
+    z-index: 3;
+    padding: 0 10px;
+    transform: scaleX(0.8);
+    &.status1 {
+        color: #3ab200;
+    }
+    &.status2 {
+        color: #ff4f50;
+    }
+}
+.num-icon {
+    font-size: 12px;
+    font-weight: bold;
+    color: #ffffff;
+    line-height: 14px;
+    padding: 0 6px;
+    background: #b65dff;
+    backdrop-filter: blur(39px);
+    position: absolute;
+    top: 5.3vw;
+    left: 0;
+    border-radius: 8px 0 8px 0;
+    z-index: 2;
+    span {
+        transform: scale(0.8);
+    }
+}
+</style>

+ 275 - 0
src/components/star/pay.vue

@@ -0,0 +1,275 @@
+<template>
+    <div>
+        <van-action-sheet v-model:show="show" :closeable="false" class="recharge-dialog">
+            <div class="title">
+                <div class="text">支付信息</div>
+                <div class="close" @click="show = false">
+                    <img src="@assets/icon_dialog_close.png" />
+                </div>
+            </div>
+            <div class="content">
+                <div class="amount">
+                    <div class="text">铸造费(元)</div>
+                    <div class="num">{{ price }}</div>
+                </div>
+                <div class="line"></div>
+                <div class="title-methods">支付方式</div>
+                <div style="padding: 0 16px">
+                    <pay-method-pick v-model="payMethod"></pay-method-pick>
+                </div>
+            </div>
+            <div class="btn-wrapper">
+                <van-button type="primary" :color="$colors.prim" round block class="btn-recharge" @click="pay">
+                    立即支付
+                </van-button>
+            </div>
+        </van-action-sheet>
+        <pay-balance v-model:tradeCode="tradeCode" ref="payBalance" @pay="pay"></pay-balance>
+    </div>
+</template>
+
+<script>
+import PayMethodPick from '../PayMethodPick.vue';
+import PayBalance from '../PayBalance.vue';
+import resolveUrl from 'resolve-url';
+export default {
+    data() {
+        return {
+            show: false,
+            payMethod: '',
+            tradeCode: '',
+            price: 0,
+            orderId: 0
+        };
+    },
+    components: {
+        PayMethodPick,
+        PayBalance
+    },
+    methods: {
+        init(price, orderId) {
+            this.price = price;
+            this.orderId = orderId;
+            this.show = true;
+        },
+        hide() {
+            this.show = false;
+        },
+        pay() {
+            switch (this.payMethod) {
+                case 'ALIPAY':
+                    this.$toast.loading('支付中');
+                    this.$http
+                        .post('/payOrder/v2/pic/ali', { id: this.orderId })
+                        .then(res => {
+                            this.openScheme(res);
+                            setTimeout(() => {
+                                this.$toast.clear();
+                            }, 1000);
+                        })
+                        .catch(e => {
+                            this.$toast(e.error || '支付失败');
+                        });
+                    break;
+                case 'BALANCE':
+                    if (!this.tradeCode) {
+                        this.$refs.payBalance.show();
+                        return;
+                    }
+                    this.$toast.loading('支付中');
+                    this.$http
+                        .post('/payOrder/v2/pic/balance', { id: this.orderId, tradeCode: this.tradeCode })
+                        .then(res => {
+                            this.$toast.success('支付成功');
+                            this.show = false;
+                            this.$emit('payNext');
+                        })
+                        .catch(e => {
+                            this.tradeCode = '';
+                            this.$toast(e.error || '支付失败');
+                            this.show = false;
+                        });
+                    break;
+                case 'UNION':
+                    window.open(
+                        resolveUrl(this.$baseUrl, `/payOrder/v2/pic/sandQuick?id=${this.orderId}`)
+                            .replace('www.raex.vip', 'jump.raex.vip')
+                            .replace('test.raex.vip', 'jumptest.raex.vip'),
+                        '_blank'
+                    );
+                    break;
+                case 'QUICK_BIND':
+                    this.$toast.loading('支付中');
+                    this.$http
+                        .get('/payOrder/v2/pic/sandQuickBind', {
+                            id: this.orderId
+                        })
+                        .then(res => {
+                            this.$toast.clear();
+                            this.openScheme(res);
+                        })
+                        .catch(e => {
+                            this.$toast.clear();
+                            this.$toast(e.error || '支付失败');
+                        });
+                    break;
+                case 'ALI':
+                    this.$toast.loading('支付中');
+                    this.$http
+                        .post('/payOrder/v2/pic/ali', { id: this.orderId })
+                        .then(res => {
+                            this.openScheme(res);
+                            setTimeout(() => {
+                                this.$toast.clear();
+                            }, 1000);
+                        })
+                        .catch(e => {
+                            this.$toast(e.error || '支付失败');
+                        });
+                    break;
+                case 'SYXPAY':
+                    this.$router.push({
+                        name: 'bankPay',
+                        query: {
+                            id: this.orderId,
+                            type: 'star'
+                        }
+                    });
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.recharge-dialog {
+    overflow: auto;
+    .content {
+        flex-basis: calc(80vh - 150px);
+        flex-grow: 1;
+        overflow: auto;
+        //height: calc(100vh - 300px);
+    }
+    .title {
+        height: 50px;
+        position: relative;
+        &::after {
+            .setBottomLine();
+        }
+        .flex();
+        .text {
+            margin-left: 16px;
+            font-size: 14px;
+            color: black;
+            font-weight: bold;
+            flex-grow: 1;
+        }
+        .close {
+            padding: 10px 16px;
+            img {
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
+    .amount {
+        background: #f5f7fa;
+        border-radius: 4px;
+        margin: 16px;
+        .flex-col();
+        align-items: center;
+        padding: 18px 0;
+        .text {
+            font-size: 14px;
+            color: #939599;
+            line-height: 24px;
+        }
+        .num {
+            margin-top: 7px;
+            font-size: 36px;
+            font-family: OSP;
+            color: #000000;
+            line-height: 36px;
+        }
+    }
+    .line {
+        background: @bg3;
+        height: 1px;
+        margin: 0 16px;
+    }
+    .title-methods {
+        font-size: 14px;
+        line-height: 24px;
+        font-weight: bold;
+        margin-left: 16px;
+        margin-top: 20px;
+        margin-right: 16px;
+        .bank-name {
+            font-size: 14px;
+            color: @text3;
+            font-weight: normal;
+            float: right;
+        }
+    }
+    .btn-wrapper {
+        height: 56px;
+        min-height: 56px;
+        .flex();
+        padding-bottom: env(safe-area-inset-bottom);
+        position: relative;
+        &::after {
+            .setTopLine();
+        }
+        .btn-recharge {
+            // flex-grow: 1;
+            // height: 38px;
+            // border-radius: 19px;
+            // background: #373a60;
+            // font-size: 16px;
+            // color: white;
+            // font-weight: bold;
+            // .flex();
+            // justify-content: center;
+            margin: 0 48px;
+            ::v-deep(.van-button__content) {
+                font-weight: bold;
+            }
+        }
+    }
+    .iap-row {
+        .flex();
+        padding: 0 15px;
+        margin-top: 15px;
+        .iap-item {
+            flex-basis: 0;
+            flex-grow: 1;
+            height: 50px;
+            border-radius: 8px;
+            background-color: @bg3;
+            color: @text1;
+            .flex-col();
+            align-items: center;
+            justify-content: center;
+            margin-left: 15px;
+            .name {
+                font-size: 14px;
+            }
+            .price {
+                margin-top: 2px;
+                font-size: 13px;
+                color: @text3;
+            }
+            &:first-child {
+                margin-left: 0;
+            }
+            &.active {
+                background: @prim;
+                color: white;
+                .price {
+                    color: rgba(255, 255, 255, 0.5);
+                }
+            }
+        }
+    }
+}
+</style>

+ 388 - 0
src/components/star/post.vue

@@ -0,0 +1,388 @@
+<template>
+    <van-overlay :show="show" :lock-scroll="false" @click="show = false" z-index="99">
+        <div class="box">
+            <img v-if="img" @click.stop="" :src="img" alt="" class="post-img" />
+            <div v-else class="post" ref="post" @click.stop="">
+                <div class="post-content">
+                    <div class="title">
+                        <div class="text1">{{ info.name }}</div>
+                        <div class="text2">铸造时间(GMT+8): {{ info.createdAt }}</div>
+                    </div>
+                    <div class="post-box">
+                        <div class="show-box">
+                            <img class="show-bg" ref="showBg" src="@assets/png-bg-shangping2.png" alt="" />
+                            <div class="banner">
+                                <van-image width="53vw" height="53vw" :src="detailImg" fit="cover" />
+                            </div>
+
+                            <img src="@assets/png-xiushi.png" class="icon1" alt="" />
+                            <img src="@assets/png-xiushi1.png" class="icon2" alt="" />
+                        </div>
+                        <div class="info-box">
+                            <img src="@assets/png-renzheng.png" alt="" class="renzhen" />
+                            <div class="info">
+                                <div class="text1">持有者昵称</div>
+                                <div class="text2">
+                                    <span>{{ info.owner }}</span>
+                                </div>
+                            </div>
+                            <div class="info">
+                                <div class="text1">铸造者昵称</div>
+                                <div class="text2">
+                                    <span>{{ info.minter }}</span>
+                                </div>
+                            </div>
+                            <div class="info" v-if="info.hcTokenId">
+                                <div class="text1">CRC华储链令牌ID</div>
+                                <div class="text2" ref="hcTokenId">
+                                    <span>{{ getShort(info.hcTokenId, 30) }}</span>
+                                </div>
+                            </div>
+                            <div class="info" v-if="info.hcTxHash">
+                                <div class="text1">HASH地址</div>
+                                <div class="text2" ref="hcTxHash">
+                                    <span>{{ getShort(info.hcTxHash, 30) }}</span>
+                                </div>
+                            </div>
+                            <div class="info" v-if="info.hcBlockNumber">
+                                <div class="text1">区块高度</div>
+                                <div class="text2">
+                                    <span>{{ info.hcBlockNumber }}</span>
+                                </div>
+                            </div>
+                            <div class="info" v-if="info.ipfsUrl">
+                                <div class="text1">IPFS分布式存储地址</div>
+                                <div class="text2" ref="ipfsUrl">
+                                    <span>{{ getShort(info.ipfsUrl, 30) }}</span>
+                                </div>
+                            </div>
+
+                            <div class="info">
+                                <div class="text1">确权平台</div>
+                                <div class="text2">RAEX绿洲宇宙</div>
+                            </div>
+
+                            <div class="info">
+                                <div class="text1">确权查询</div>
+                                <div class="text2">www.raex.co</div>
+                            </div>
+                        </div>
+                        <img src="@assets/png-zhengshu-diwen.png" alt="" class="box-bg" />
+                    </div>
+                </div>
+            </div>
+            <img src="@assets/icon_dialog_close.png" class="close" alt="" />
+            <img
+                src="@assets/copy_icon.png"
+                v-for="(item, index) in copys"
+                :key="index"
+                :style="this[item]"
+                alt=""
+                class="copy"
+                @click.stop="copy(item)"
+            />
+
+            <div class="btn" @click.stop="save" v-if="inApp">
+                <van-button block round type="primary">保存图片</van-button>
+            </div>
+            <div class="tips" v-else>长按图片保存</div>
+        </div>
+    </van-overlay>
+</template>
+
+<script>
+import product from '../../mixins/product';
+import html2canvas from 'html2canvas';
+let inApp = /#cordova#/i.test(navigator.userAgent);
+import { ImagePreview } from 'vant';
+export default {
+    mixins: [product],
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    data() {
+        return {
+            show: false,
+            img: '',
+            detailImg: '',
+            txHash: {},
+            tokenId: {},
+            ipfsUrl: {},
+            hcTxHash: {},
+            hcTokenId: {},
+            inApp,
+            copys: ['txHash', 'tokenId', 'ipfsUrl', 'hcTxHash', 'hcTokenId']
+        };
+    },
+    mounted() {
+        // setTimeout(() => {
+        //     this.init();
+        // }, 1000);
+    },
+    methods: {
+        init() {
+            this.show = true;
+            if (!this.img) {
+                this.$toast.loading({
+                    message: '加载中...',
+                    forbidClick: true
+                });
+                this.$nextTick(() => {
+                    this.getImgBase64(this.getImg(this.changeImgs(this.info.pic, 600)), 'detailImg');
+                    setTimeout(() => {
+                        [...this.copys].forEach(item => {
+                            this.getCopy(item);
+                        });
+                    }, 500);
+                    setTimeout(() => {
+                        this.loadImg();
+                    }, 1000);
+                });
+            }
+        },
+        getCopy(refName = 'txHash') {
+            if (this.$refs[refName]) {
+                let top = this.$refs[refName].parentNode.offsetTop + 167 + this.$refs.showBg.offsetHeight;
+                let left = this.$refs[refName].childNodes[0].offsetWidth + 53;
+                this[refName] = {
+                    top: top + 'px',
+                    left: left + 'px'
+                };
+            } else {
+                this[refName] = {
+                    display: 'none'
+                };
+            }
+        },
+        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;
+        },
+        copy(key) {
+            this.$copyText(this.info[key]).then(
+                e => {
+                    this.$toast.success('复制成功');
+                    console.log(e);
+                },
+                e => {
+                    this.$toast('复制失败');
+                    console.log(e);
+                }
+            );
+        },
+        preview(index = 0, list = []) {
+            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>
+.box {
+    .flex-col();
+    align-items: center;
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    box-sizing: border-box;
+    padding: 50px 0;
+}
+
+.post-img {
+    width: calc(100vw - 32px);
+    display: block;
+}
+
+.post {
+    width: calc(100vw - 32px);
+    border-radius: 12px;
+    border: 1px solid rgba(243, 224, 184, 0.5);
+    padding: 12px;
+    box-sizing: border-box;
+    background-color: #0f0f0f;
+    .post-content {
+        background: linear-gradient(180deg, #ffd694 0%, #f3e0b8 17%, #9f875e 100%);
+        border-radius: 12px;
+        padding: 1px;
+        .title {
+            padding: 16px;
+            .text1 {
+                font-size: 20px;
+                font-weight: bold;
+                color: #0d090b;
+                line-height: 24px;
+            }
+            .text2 {
+                font-size: 12px;
+                color: rgba(13, 9, 11, 0.5);
+                line-height: 17px;
+            }
+        }
+    }
+}
+
+.post-box {
+    background: linear-gradient(180deg, #0f0f0f 0%, #0a0a0a 100%);
+    border-radius: 12px;
+    padding-bottom: 20px;
+    position: relative;
+
+    .info {
+        padding: 6px 16px;
+        .text1 {
+            font-size: 12px;
+            font-weight: bold;
+            color: #939599;
+            line-height: 17px;
+        }
+        .text2 {
+            font-size: 14px;
+            color: #ffffff;
+            line-height: 24px;
+            margin-top: 4px;
+        }
+    }
+
+    .box-bg {
+        width: 100%;
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        z-index: 0;
+    }
+}
+.info-box {
+    position: relative;
+    z-index: 1;
+    .renzhen {
+        width: 108px;
+        height: 108px;
+        position: absolute;
+        top: 12px;
+        right: 24px;
+    }
+}
+.show-box {
+    position: relative;
+    .show-bg {
+        width: 100%;
+        display: block;
+    }
+    .banner {
+        position: absolute;
+        box-shadow: 0px 0px 5px 0px #ffffff;
+        border-radius: 16px;
+        padding: 8px;
+        border: 1px solid rgba(255, 255, 255, 0.2);
+        left: 50%;
+        transform: translateX(-50%);
+        top: 9.3vw;
+        .van-image {
+            border: 2px solid #2f2f2f;
+            border-radius: 16px;
+        }
+    }
+}
+
+.btn {
+    width: calc(100vw - 102px);
+    margin: 20px 0 0;
+    --van-button-primary-background-color: #303133;
+}
+.copy {
+    position: absolute;
+    width: 18px;
+    height: 18px;
+    z-index: 20;
+}
+.tips {
+    font-size: 13px;
+    color: @text3;
+    line-height: 22px;
+    margin-top: 30px;
+}
+
+.icon1 {
+    width: 9px;
+    height: 18px;
+    position: absolute;
+    bottom: 30px;
+    left: 0;
+}
+.icon2 {
+    width: 9px;
+    height: 18px;
+    position: absolute;
+    bottom: 30px;
+    right: 0;
+}
+
+.close {
+    position: absolute;
+    right: 5px;
+    top: 40px;
+    width: 30px;
+    height: 30px;
+    z-index: 99;
+}
+</style>

+ 8 - 0
src/main.js

@@ -7,6 +7,7 @@ import { ConfigProvider } from 'vant';
 import 'vant/lib/index.css';
 import './styles/app.less';
 import './styles/font.less';
+import './styles/theme.less';
 import http from './plugins/http';
 import colors from './plugins/colors';
 // import ElementUI from 'element-ui';
@@ -133,12 +134,17 @@ if (query.invitor) {
 if (query.from) {
     store.commit('setFrom', query.from);
 }
+store.commit('setFrom', 'scanCode');
 if (query.inviteCode) {
     store.commit('setInviteCode', query.inviteCode);
 }
 if (query.review === 'true' || query.review === true) {
     store.commit('setReview', true);
 }
+if (query.starPage === 'true' || query.starPage === true || sessionStorage.getItem('starPage')) {
+    store.commit('setStarPage', true);
+    sessionStorage.setItem('starPage', true);
+}
 if (query.reviewPay === 'true' || query.reviewPay === true || sessionStorage.getItem('reviewPay')) {
     store.commit('setReviewPay', true);
     sessionStorage.setItem('reviewPay', true);
@@ -150,6 +156,8 @@ if (query.hopeMarket === 'true' || query.hopeMarket === true || sessionStorage.g
 
 store.commit('setPlatform', /iPad|iPhone|iPod/i.test(navigator.userAgent) ? 'ios' : 'android');
 
+store.dispatch('getTheme');
+
 const loadSplash = (onload, onerror) =>
     new Promise((resolve, reject) => {
         let isHide = false;

+ 1 - 1
src/mixins/auction.js

@@ -22,7 +22,7 @@ export default {
         };
     },
     computed: {
-        //是否数字
+        //是否数字艺术
         isNFT() {
             return this.info.auctionType === 'NFT';
         },

+ 2 - 1
src/mixins/banner.js

@@ -18,7 +18,8 @@ export default {
                 this.$router.push(`/activityDetail?id=${info.linkContent}${props}`);
             } else if (info.link && info.linkType === 'collections') {
                 info.linkContent = encodeURIComponent(info.linkContent);
-                this.$router.push(`/productSearch?search=${info.linkContent}${props}`);
+                // this.$router.push(`/productSearch?search=${info.linkContent}${props}`);
+                this.$router.push(`/productSearchCorpse?search=${info.linkContent}${props}`);
             } else if (info.link && info.linkType === 'showroom') {
                 info.linkContent = encodeURIComponent(info.linkContent);
                 this.$router.push(`/hall?id=${info.linkContent}${props}`);

+ 7 - 3
src/mixins/common.js

@@ -53,9 +53,13 @@ export default {
             formData.append('width', size);
             formData.append('height', size);
             formData.append('size', size);
-            return http.axios.post('/upload/user', formData).then(res => {
-                return Promise.resolve(res.data);
-            });
+            return http.axios
+                .post('/upload/user', formData, {
+                    headers: { 'Content-Type': 'multipart/form-data' }
+                })
+                .then(res => {
+                    return Promise.resolve(res.data);
+                });
         },
         getImg(imgs = '', type = '', size = 800) {
             if (!imgs) {

+ 4 - 1
src/mixins/phone.js

@@ -32,6 +32,7 @@ export default {
             return this.$http.get('/captcha/get').then(res => {
                 this.captchaKey = res.key;
                 this.codeImg = res.image;
+                this.$toast.clear();
                 this.emitter.emit('phoneShow');
             });
         },
@@ -43,7 +44,7 @@ export default {
             }
             this.isSend = true;
             this.setTime(60);
-            this.$http
+            return this.$http
                 .get('/sms/sendSecureVerify', {
                     phone: phone,
                     captcha: this.captcha,
@@ -54,6 +55,7 @@ export default {
                     this.$toast.success('发送成功');
                     this.captcha = '';
                     this.captchaKey = '';
+                    return Promise.resolve();
                 })
                 .catch(e => {
                     if (e) {
@@ -62,6 +64,7 @@ export default {
                         this.captchaKey = '';
                     }
                     this.setTime(0);
+                    return Promise.reject();
                 });
         },
         setTime(num) {

+ 3 - 4
src/mixins/product.js

@@ -79,7 +79,6 @@ export default {
     },
     methods: {
         changeImgs(list = []) {
-            // console.log(list);
             return list.map(item => {
                 if (item.type === 'video/mp4') {
                     return item.thumb;
@@ -148,9 +147,9 @@ export default {
                 return num;
             }
         },
-        getShort(str = '') {
-            if (str) {
-                str = '...' + str.substr(-8, 8);
+        getShort(str = '', num = 8) {
+            if (str && str.length > num) {
+                str = '...' + str.substr(0 - num, num);
             }
             return str;
         },

+ 16 - 4
src/mixins/search.js

@@ -16,9 +16,8 @@ export default {
     },
     methods: {
         getHistory() {
-            let historys = window.localStorage.getItem('ninthHistory')
-                ? window.localStorage.getItem('ninthHistory').split(',')
-                : [];
+            let historys = window.localStorage.getItem('ninthHistory') ?
+                window.localStorage.getItem('ninthHistory').split(',') : [];
             this.historys = historys;
         },
         addHistory(val) {
@@ -41,7 +40,20 @@ export default {
             this.search = search;
             this.addHistory(search);
             this.getData(true);
+            // this.getData(true);
+            // if (search === '僵尸动物园') {
+            //     this.$router.push(`/productSearchCorpse?search=${search}`);
+            // } else {
+            //     this.isSearch = true;
+            //     this.search = search;
+            //     this.addHistory(search);
+            //     this.getData(true);
+            // }
         },
+        // getSearches(search){
+        //     this.$router.push(`/productSearchCorpse?search=${search}`);
+        //     this.addHistory(search);
+        // },
         onCancel() {
             if (this.isSearch) {
                 this.isSearch = false;
@@ -51,4 +63,4 @@ export default {
             }
         }
     }
-};
+};

+ 11 - 0
src/mixins/star.js

@@ -0,0 +1,11 @@
+export default {
+    data() {
+        return {
+            statusOptions: [
+                { label: '审核中', value: 'PENDING' },
+                { label: '通过', value: 'SUCCESS' },
+                { label: '失败', value: 'FAIL' }
+            ]
+        };
+    }
+};

+ 28 - 0
src/plugins/keeps.js

@@ -0,0 +1,28 @@
+import { onActivated, ref, nextTick, inject } from 'vue';
+import { onBeforeRouteLeave } from 'vue-router';
+
+const useKeep = (names = [], checkSave) => {
+    const setKeeps = inject('setKeeps');
+    const bodyScroll = inject('bodyScroll');
+    const changeScroll = inject('changeScroll');
+    const scrollTop = ref(0);
+
+    onActivated(() => {
+        nextTick(() => {
+            changeScroll(scrollTop.value || 0);
+        });
+    });
+
+    onBeforeRouteLeave((to, from, next) => {
+        if (checkSave && checkSave(to, from)) {
+            scrollTop.value = bodyScroll.value;
+            setKeeps(['index', 'starMap']);
+        } else {
+            scrollTop.value = 0;
+            setKeeps(['index', 'starMap'], false);
+        }
+        next();
+    });
+};
+
+export default useKeep;

+ 78 - 0
src/plugins/list.js

@@ -0,0 +1,78 @@
+import { ref } from 'vue';
+import { getCurrentInstance } from 'vue';
+
+function useList(url, beforeData = {}, httpType) {
+    const {
+        appContext: {
+            config: { globalProperties: global }
+        }
+    } = getCurrentInstance();
+
+    const empty = ref(false);
+    const loading = ref(false);
+    const finished = ref(false);
+    const page = ref(0);
+    const totalElements = ref(0);
+    const size = ref(20);
+    const list = ref([]);
+    const getData = (isRefresh = false) => {
+        if (isRefresh) {
+            page.value = 0;
+            list.value = [];
+        }
+        loading.value = true;
+        finished.value = false;
+        empty.value = false;
+
+        let data = { page: page.value, size: size.value, sort: 'createdAt,desc' };
+        if (beforeData) {
+            data = {
+                ...data,
+                ...beforeData
+            };
+        }
+
+        if (httpType === 'get') {
+            return global.$http.get(url, data, { body: 'json' }).then(res => {
+                if (res.first) {
+                    list.value = [];
+                }
+                list.value = [...list.value, ...res.content];
+                empty.value = res.empty;
+                loading.value = false;
+                finished.value = res.last;
+                if (!finished.value) {
+                    page.value = page.value + 1;
+                }
+                totalElements.value = Number(res.totalElements);
+            });
+        } else {
+            return global.$http.post(url, data, { body: 'json' }).then(res => {
+                if (res.first) {
+                    list.value = [];
+                }
+                list.value = [...list.value, ...res.content];
+                empty.value = res.empty;
+                loading.value = false;
+                finished.value = res.last;
+                if (!finished.value) {
+                    page.value = page.value + 1;
+                }
+                totalElements.value = Number(res.totalElements);
+            });
+        }
+    };
+
+    return {
+        empty,
+        loading,
+        finished,
+        page,
+        totalElements,
+        size,
+        list,
+        getData
+    };
+}
+
+export default useList;

Некоторые файлы не были показаны из-за большого количества измененных файлов