瀏覽代碼

茶权存储

xiaomei 7 月之前
父節點
當前提交
777f2665f6

+ 6 - 0
package-lock.json

@@ -27,6 +27,7 @@
         "vant": "^2.12.26",
         "vue": "^2.6.11",
         "vue-animate-number": "^0.4.2",
+        "vue-count-to": "^1.0.13",
         "vue-i18n": "^8.26.5",
         "vue-monoplasty-slide-verify": "^1.3.1",
         "vue-router": "^3.2.0",
@@ -17056,6 +17057,11 @@
       "integrity": "sha512-LluhjWTZmpGl3tiXg51EciF+T70IN/9t6UvfmgluJBqxbrb6OV9i7L5lTd+OKtcTeghDkhcBmYhtTxxU4w/8sQ==",
       "dev": true
     },
+    "node_modules/vue-count-to": {
+      "version": "1.0.13",
+      "resolved": "https://registry.npmmirror.com/vue-count-to/-/vue-count-to-1.0.13.tgz",
+      "integrity": "sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ=="
+    },
     "node_modules/vue-eslint-parser": {
       "version": "7.11.0",
       "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
     "vant": "^2.12.26",
     "vue": "^2.6.11",
     "vue-animate-number": "^0.4.2",
+    "vue-count-to": "^1.0.13",
     "vue-i18n": "^8.26.5",
     "vue-monoplasty-slide-verify": "^1.3.1",
     "vue-router": "^3.2.0",

+ 77 - 0
src/api/home.js

@@ -864,4 +864,81 @@ export default {
       data
     })
   },
+  // 存储列表
+  pledgeList(data) {
+    return request.request({
+      url: '/Pledge/list',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 存储详情
+  pledgeDetail(data) {
+    return request.request({
+      url: '/Pledge/detail',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 获取指定产品订单
+  holdProductList(data) {
+    return request.request({
+      url: '/pledge/holdProductList',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 提交存储
+  createPledge(data) {
+    return request.request({
+      url: '/pledge/create',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 我的茶矿
+  teamine(data) {
+    return request.request({
+      url: '/pledge/teamine',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 解除
+  removePledge(data) {
+    return request.request({
+      url: '/pledge/remove',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 收取
+  collectPledge(data) {
+    return request.request({
+      url: '/pledge/collect',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
 }

二進制
src/assets/images/index/cc.png


二進制
src/assets/images/index/hc.png


+ 18 - 1
src/language/en.json

@@ -316,5 +316,22 @@
   "lang315": "Insufficient materials",
   "lang316": "The synthesis activity has ended",
   "lang317": "Collect 1 of the following materials",
-  "lang318": "Congratulations, synthesis is successful"
+  "lang318": "Congratulations, synthesis is successful",
+  "lang319": "Combined storage",
+  "lang320": "Single product storage",
+  "lang321": "Storage details",
+  "lang322": "Release storage",
+  "lang323": "Details",
+  "lang324": "Estimated daily output",
+  "lang325": "Start storage",
+  "lang326": "Storage successful",
+  "lang327": "Are you sure to store?",
+  "lang328": "Receive TEAC rewards",
+  "lang329": "Receive",
+  "lang330": "Please select RWA",
+  "lang331": "Please select",
+  "lang332": "Daily income",
+  "lang333": "Selected",
+  "lang334": "Select RWA",
+  "lang335": "Are you sure to release storage?"
 }

+ 17 - 17
src/language/zh.json

@@ -317,23 +317,23 @@
   "lang316": "合成活动已结束",
   "lang317": "以下任意材料集齐1份",
   "lang318": "恭喜,合成成功",
-  "lang319": "",
-  "lang320": "",
-  "lang321": "",
-  "lang322": "",
-  "lang323": "",
-  "lang324": "",
-  "lang325": "",
-  "lang326": "",
-  "lang327": "",
-  "lang328": "",
-  "lang329": "",
-  "lang330": "",
-  "lang331": "",
-  "lang332": "",
-  "lang333": "",
-  "lang334": "",
-  "lang335": "",
+  "lang319": "组合存储",
+  "lang320": "单品存储",
+  "lang321": "存储详情",
+  "lang322": "解除存储",
+  "lang323": "详情",
+  "lang324": "预估每日产出",
+  "lang325": "开始存储",
+  "lang326": "存储成功",
+  "lang327": "是否确定存储?",
+  "lang328": "收取TEAC奖励",
+  "lang329": "收取",
+  "lang330": "请选择RWA",
+  "lang331": "请选择",
+  "lang332": "每日收益",
+  "lang333": "已选",
+  "lang334": "选择RWA",
+  "lang335": "是否确定解除存储?",
   "lang336": "",
   "lang337": "",
   "lang338": "",

+ 36 - 0
src/router/index.js

@@ -40,6 +40,10 @@ import teaTalk from '../views/mine/teaTalk.vue'; //茶说
 import synthesis from '../views/mine/synthesis.vue'; //合成中心
 import synthesisDetail from '../views/mine/synthesisDetail.vue'; //合成详情
 import rule from '../views/rule/index.vue'; //合成规则
+import storage from '../views/storage/list.vue'; //茶权存储
+import MulStorageDetail from '../views/storage/mulDetail.vue'; //组合茶权存储详情
+import SingleStorageDetail from '../views/storage/singleDetail.vue'; //单个茶权存储详情
+import storing from '../views/storage/storing.vue'; //我的茶矿
 Vue.use(VueRouter);
 const routes = [
 
@@ -278,6 +282,38 @@ const routes = [
           requiresAuth: true
         }
       },
+      {
+        path: 'storage',
+        name: 'storage',
+        component: storage,
+        meta: {
+          requiresAuth: true
+        }
+      },
+      {
+        path: 'MulStorageDetail',
+        name: 'MulStorageDetail',
+        component: MulStorageDetail,
+        meta: {
+          requiresAuth: true
+        }
+      },
+      {
+        path: 'SingleStorageDetail',
+        name: 'SingleStorageDetail',
+        component: SingleStorageDetail,
+        meta: {
+          requiresAuth: true
+        }
+      },
+      {
+        path: 'storing',
+        name: 'storing',
+        component: storing,
+        meta: {
+          requiresAuth: true
+        }
+      },
     ],
   },
 ];

+ 5 - 5
src/views/index/index.vue

@@ -184,16 +184,16 @@ export default {
       product_list: [],
       mortgage_list: [],
       navlist: [
-        {
-          text: this.$t('lang258'),
-          icon: require('@/assets/images/index/rb.png'),
-          url: '',
-        },
         {
           text: this.$t('lang259'),
           icon: require('@/assets/images/index/hc.png'),
           url: 'synthesis',
         },
+        {
+          text: this.$t('lang217'),
+          icon: require('@/assets/images/index/cc.png'),
+          url: 'storage',
+        },
         {
           text: this.$t('lang264'),
           icon: require('@/assets/images/index/cj.png'),

+ 1 - 1
src/views/mine/assets.vue

@@ -34,7 +34,7 @@
         </div>
         <div v-else>
           <div class="list">
-            <div v-for="(item, index) in coinList" :key="index" class="li" @click="navigatorToPage('share')">
+            <div v-for="(item, index) in coinList" :key="index" class="li" @click="navigatorToPage('share', { coin_type: item.coin_key })">
               <div class="li_left">
                 <!-- <div class="imgbox">
                   <img :src="require('@/assets/images/wallet/' + item.coin_key + '.png')" class="li_img" />

+ 8 - 4
src/views/mine/index.vue

@@ -283,10 +283,14 @@ export default {
     submit() {},
     onClick(status) {
       // console.log(status);
-      this.chooseStatus = status;
-      this.page = 1;
-      this.nft_list = [];
-      this.getNftList();
+      if (status == 3) {
+        this.$router.push({ name: 'storing' });
+      } else {
+        this.chooseStatus = status;
+        this.page = 1;
+        this.nft_list = [];
+        this.getNftList();
+      }
     },
     getNftList() {
       homeApi.getMyNftList({ page: this.page, type_id: this.chooseStatus }).then(res => {

+ 2 - 2
src/views/mine/sendChaBao.vue

@@ -89,7 +89,7 @@ export default {
       this.$router.back();
     },
     navigation(name) {
-      this.$router.push({ name });
+      this.$router.push({ name, query: { coin_type: 'token' } });
     },
     chabaoInfo() {
       homeApi.chabaoInfo().then(res => {
@@ -325,7 +325,7 @@ export default {
       .box_item:first-child {
         align-items: flex-start;
       }
-      
+
       &_item {
         display: flex;
         align-items: center;

+ 8 - 4
src/views/mine/share.vue

@@ -54,9 +54,11 @@
                 <div class="box_item">
                   <div class="f-c">
                     <span class="num">{{ dateFormatFn(item.create_time) }}</span>
-                    <span class="amount"
-                      >{{ item.change_amount >= 0 ? '+' + Number(item.change_amount) : Number(item.change_amount) }}<span class="ssm">{{ $t('lang174') }}</span></span
-                    >
+                    <span class="amount">
+                      {{ item.change_amount >= 0 ? '+' + Number(item.change_amount) : Number(item.change_amount) }}
+                      <span class="ssm" v-if="coin_type == 'token'">{{ $t('lang174') }}</span>
+                      <span class="ssm" v-else-if="coin_type == 'teac'">TeaC</span>
+                    </span>
                   </div>
                   <div class="f-c">
                     <span class="key">{{ statusList[item.action] }}</span>
@@ -104,9 +106,11 @@ export default {
       nft_list: [],
       statusList: [],
       totalReward: 0,
+      coin_type: '',
     };
   },
   mounted() {
+    this.coin_type = this.$route.query.coin_type;
     // this.actionGet();
     this.getUserBalanceLog();
     this.coinList();
@@ -163,7 +167,7 @@ export default {
       let params = {
         page: this.page,
         query: {
-          coin_type: 'token',
+          coin_type: this.coin_type,
           action: -1,
         },
       };

+ 1 - 1
src/views/mine/synthesis.vue

@@ -13,7 +13,7 @@
             <div class="buy" @click="navigatorToPage('synthesisDetail', item.id)" v-if="current > item.start_time && current < item.end_time">
               <van-button class="buy_btn" type="primary">{{ $t('lang296') }}</van-button>
             </div>
-            <div class="buy" v-else-if="current < item.start_time">
+            <div class="buy" v-else-if="current < item.start_time" @click="navigatorToPage('synthesisDetail', item.id)" >
               <van-button class="buy_btn will" type="primary">
                 <span>
                   {{ $t('lang297') }}

+ 21 - 1
src/views/mine/synthesisDetail.vue

@@ -151,6 +151,10 @@
         </div>
         <div class="btn_box">
           <div class="btn" v-if="showStatus == 1">{{ $t('lang315') }}</div>
+          <div class="btn" v-else-if="showStatus == 3">
+            <span>{{ $t('lang297') }}</span>
+            <van-count-down class="countdown" :time="(product.start_time - current) * 1000" format="HHhmmmsss" />
+          </div>
           <div class="btn" v-else-if="showStatus == 2">{{ $t('lang316') }}</div>
           <div class="flex sb" v-else>
             <div class="step_box">
@@ -247,7 +251,8 @@ export default {
       materialOneId: -1,
       materialTwoId: -1,
       materialThreeId: -1,
-      showStatus: 0, // 1材料不足  2时间结束 其余正常
+      showStatus: 0, // 1材料不足  2时间结束 3即将开放 其余正常
+      current: parseInt(new Date().getTime() / 1000), //
     };
   },
   mounted() {
@@ -291,6 +296,9 @@ export default {
           } else {
             this.showStatus = 1;
           }
+          if (new Date().getTime() / 1000 < this.product.start_time) {
+            this.showStatus = 3;
+          }
           if (new Date().getTime() / 1000 > this.product.end_time) {
             this.showStatus = 2;
           }
@@ -575,6 +583,12 @@ export default {
       padding: 16px 20px;
       background-color: #000;
       .btn {
+        display: flex;
+        align-items: center;
+        flex-direction: column;
+        justify-content: center;
+        height: 100%;
+        box-sizing: border-box;
         font-size: 15px;
         text-align: center;
         font-weight: 600;
@@ -582,6 +596,12 @@ export default {
         padding: 12px 10px;
         border-radius: 22px;
         background-color: #666666;
+        .countdown {
+          font-size: 12px;
+          color: #e2e2e2;
+          font-weight: normal;
+          margin-top: -2px;
+        }
       }
       .submit {
         width: 58%;

+ 392 - 0
src/views/storage/list.vue

@@ -0,0 +1,392 @@
+<template>
+  <div>
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang217') }}</span>
+    </div>
+    <div class="btn_box">
+      <van-button :class="[typeIndex == 2 ? 'cc_btn cc_active' : 'cc_btn']" @click="changeType(2)">{{ $t('lang319') }}</van-button>
+      <van-button :class="[typeIndex == 1 ? 'cc_btn cc_active' : 'cc_btn']" @click="changeType(1)">{{ $t('lang320') }}</van-button>
+    </div>
+    <div class="home_page" @scroll="handleScroll">
+      <div class="pd goods_box" v-if="list.length > 0">
+        <div class="goods_list jsb" v-for="(item, index) in list" :key="index">
+          <div class="box" @click="toPage(item.id)">
+            <div class="box_top">
+              <span class="ellipsis name">{{ item.title }}</span>
+              <div class="box_arraw">
+                <span>{{ $t('lang323') }}</span>
+                <van-icon name="arrow" />
+              </div>
+            </div>
+            <div class="box_bottom">
+              <div class="flex">
+                <div v-if="Object.values(item.product_list).length > 1">
+                  <img
+                    v-for="(item1, index1) in [Object.values(item.product_list)[0], Object.values(item.product_list)[1]]"
+                    :key="index1"
+                    :src="item1.thum"
+                    alt=""
+                    :class="[typeIndex == 1 ? 'goods_img typeimg' : 'goods_img']"
+                  />
+                </div>
+                <div v-else>
+                  <img v-for="(item1, index1) in Object.values(item.product_list)" :key="index1" :src="item1.thum" alt="" :class="[typeIndex == 1 ? 'goods_img typeimg' : 'goods_img']" />
+                </div>
+                <div class="ellipsis_box">
+                  <van-icon name="ellipsis" v-if="Object.values(item.product_list).length > 2" />
+                </div>
+              </div>
+              <div class="right">
+                <div class="flex_col">
+                  <span class="value_1">{{ item.day_num }}</span>
+                  <span class="key">{{ $t('lang324') }}</span>
+                </div>
+                <div class="flex_col">
+                  <span class="value_2">{{ Number(item.income_reta) * 100 }}</span>
+                  <span class="key">APY</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="bare" v-else>
+        <span>{{ $t('lang60') }}</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { homeApi } from '@/api/index';
+import { dateFormat } from '@/utils/formatTool.js';
+export default {
+  data() {
+    return {
+      typeIndex: 2, //1单 2组
+      time: 30 * 60 * 60 * 1000,
+      showLoading: true,
+      list: [],
+      page: 1,
+      current: parseInt(new Date().getTime() / 1000), //1743648326
+    };
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    //返回上一页
+    back() {
+      this.$router.back();
+    },
+    init() {
+      this.pledgeList();
+    },
+    dateFormatFn(date) {
+      return dateFormat(new Date(date * 1000), 'MM/dd hh:mm');
+    },
+    handleScroll(event) {
+      const container = event.target;
+      const scrollTop = container.scrollTop; // 滚动距离
+      const scrollHeight = container.scrollHeight; // 内容总高度
+      const clientHeight = container.clientHeight; // 可视区域高度
+      // 判断是否滑动到底部
+      if (scrollTop + clientHeight >= scrollHeight - 10) {
+        console.log('Bottom');
+        if (this.page != -1) {
+          this.page++; // 页数加 1
+          this.pledgeList(); // 触发加载更多
+        }
+      }
+    },
+
+    pledgeList() {
+      homeApi.pledgeList({ type_id: this.typeIndex, page: this.page }).then(res => {
+        if (res.code == 200) {
+          if (this.list.length >= res.data.total) {
+            this.page = -1; // 重置为 -1,表示没有更多数据
+          } else {
+            this.list = [...this.list, ...res.data.data];
+            if (this.list.length >= res.data.total) {
+              this.page = -1; // 重置为 -1,表示没有更多数据
+            }
+          }
+        } else {
+        }
+      });
+    },
+    changeType(index) {
+      this.typeIndex = index;
+      this.list = [];
+      this.page = 1;
+      this.pledgeList();
+    },
+    navigatorToPage(name, id) {
+      this.$router.push({ name, query: { id: id } });
+    },
+    toPage(id) {
+      if (this.typeIndex == 2) {
+        this.$router.push({ name: 'MulStorageDetail', query: { id } });
+      } else if (this.typeIndex == 1) {
+        this.$router.push({ name: 'SingleStorageDetail', query: { id } });
+      }
+    },
+    toSiniglePage(id) {},
+  },
+  computed: {
+    ...mapState(['account']),
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(#000, 0.8);
+  letter-spacing: 1.5px;
+  font-weight: 550;
+  background: #fff;
+  padding: 14px 0;
+  z-index: 99;
+  .arrow_img {
+    position: absolute;
+    left: 20px;
+    width: 10px;
+    height: 16px;
+    // transform: translate(0, -50%);
+  }
+}
+.btn_box {
+  width: 100%;
+  box-sizing: border-box;
+  position: fixed;
+  top: 49px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 10px 16px 0;
+  background-color: #fff;
+  .cc_btn {
+    width: 48%;
+    height: 38px;
+    color: #29b286;
+    line-height: 38px;
+    font-size: 13px;
+    // letter-spacing: 2px;
+    text-align: center;
+    white-space: nowrap;
+    padding: 0 20px;
+    border: none;
+    border-radius: 4px;
+    border: 1px solid #29b286;
+    background-color: #fff;
+  }
+  .cc_active {
+    color: #fff;
+    background-color: #29b286;
+  }
+}
+.home_page {
+  padding: 100px 0 30px;
+  height: 100vh;
+  overflow: auto;
+
+  .pd {
+    padding: 14px;
+    // background-color: #fff;
+  }
+
+  .jsb {
+    justify-content: space-between;
+  }
+
+  .goods_box {
+    // margin: 14px;
+    border-radius: 14px;
+    .good_icon {
+      width: 16px;
+      height: 16px;
+      margin-right: 5px;
+    }
+  }
+
+  .goods_list {
+    color: #000;
+    // padding: 14px;
+    border-radius: 10px;
+    margin-bottom: 16px;
+    background-color: #fff;
+    &_img {
+      width: 125px;
+      height: 125px;
+      border-radius: 0 10px 10px 0 !important;
+    }
+    /deep/.van-image {
+      border-radius: 0 10px 10px 0 !important;
+    }
+
+    .box {
+      font-size: 13px;
+      padding: 14px;
+      box-sizing: border-box;
+      // padding: 6px 0;
+      &_top {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .name {
+          font-size: 16px;
+          font-weight: 600;
+          letter-spacing: 1px;
+        }
+      }
+      &_arraw {
+        display: flex;
+        align-items: center;
+        font-size: 11px;
+        color: #7f7f7f;
+      }
+      &_bottom {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding-top: 20px;
+        .goods_img {
+          width: 52px;
+          height: 52px;
+          border-radius: 50%;
+          margin-right: 6px;
+        }
+        .typeimg {
+          width: 63px;
+          height: 63px;
+        }
+        .ellipsis_box {
+          width: 17px;
+        }
+        .flex {
+          color: #7f7f7f;
+          font-size: 17px;
+          font-weight: 700;
+        }
+        .flex::after {
+          content: ' ';
+          width: 1px;
+          height: 28px;
+          margin-left: 10px;
+          background-color: #e4e4e4;
+        }
+        .right {
+          display: flex;
+          // align-items: center;
+          flex: 1;
+          padding: 0 0 0 14px;
+          .flex_col {
+            width: 50%;
+            // white-space: nowrap;
+            text-align: center;
+            .value_1 {
+              color: #29b286;
+              font-size: 21px;
+              font-weight: 600;
+            }
+            .value_1::after {
+              content: 'TeaC';
+              font-size: 15px;
+              font-weight: normal;
+            }
+            .value_2::after {
+              content: '%';
+              font-size: 15px;
+              font-weight: normal;
+            }
+            .value_2 {
+              color: #ed5111;
+              font-size: 21px;
+              font-weight: 600;
+            }
+            .key {
+              color: #4b4b4b;
+              font-size: 12px;
+              padding-top: 10px;
+            }
+          }
+        }
+      }
+    }
+    .buy {
+      display: flex;
+      align-items: flex-end;
+      &_btn {
+        height: 30px;
+        min-width: 102px;
+        line-height: 26px;
+        font-size: 12px;
+        letter-spacing: 1px;
+        text-align: center;
+        white-space: nowrap;
+        padding: 0 20px;
+        border: none;
+        border-radius: 30px;
+        background-color: #29b286;
+      }
+      .will {
+        background-color: #585858;
+        .van-button__text {
+          display: flex;
+          align-items: center;
+          flex-direction: column;
+          line-height: 108%;
+        }
+        .countdown {
+          font-size: 9px;
+          letter-spacing: 0;
+        }
+        /deep/.van-count-down {
+          line-height: 116% !important;
+          color: #fff !important;
+        }
+      }
+      .finish {
+        color: #585858;
+        background-color: #dedede;
+      }
+    }
+  }
+}
+.bare {
+  text-align: center;
+  font-size: 14px;
+  padding: 60px 14px;
+  color: #888;
+}
+.flex {
+  display: flex;
+  align-items: center;
+}
+.flex_col {
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+}
+.flex_end {
+  align-items: flex-end;
+}
+::v-deep .van-cascader__option {
+  color: #000;
+}
+.ellipsis {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+</style>

+ 385 - 0
src/views/storage/mulDetail.vue

@@ -0,0 +1,385 @@
+<template>
+  <div>
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang321') }}</span>
+    </div>
+    <div class="home_page">
+      <div class="goods_info flex_col">
+        <img :src="product.thum" alt="" />
+        <span class="goods_info_title">{{ product.title }}</span>
+        <div class="flex">
+          <div class="">
+            <span class="key">APY:</span>
+            <span class="value_2">{{ Number(product.income_reta) * 100 }}</span>
+          </div>
+          <div class="">
+            <span class="key">{{ $t('lang332') }}:</span>
+            <span class="value_1">{{ product.day_num }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="goods_list">
+        <div class="goods_list_box">
+          <!-- <van-checkbox-group v-model="result" ref="checkboxGroup"> -->
+          <div class="goods_list_box_item flex jsb" v-for="(item, index) in product.product_list" :key="index">
+            <div class="flex">
+              <img :src="item.thum" alt="" />
+              <span class="name">{{ item.name }}</span>
+            </div>
+            <div class="flex" @click="chooseProduct(item.id, index)">
+              <span class="orderSn" v-if="order_no[item.id]">{{ order_no[item.id] }}</span>
+              <span class="tip" v-else>{{ $t('lang331') }}</span>
+              <!-- <van-checkbox :name="item.id" icon-size="16px" checked-color="#21926F"> </van-checkbox> -->
+              <div :class="[order_no[item.id] ? 'checkbox checkbox-active' : 'checkbox']">
+                <van-icon name="success" size="13px" color="#fff" v-if="order_no[item.id]" />
+              </div>
+            </div>
+          </div>
+          <!-- </van-checkbox-group> -->
+        </div>
+        <div class="desc" v-html="product.detail"></div>
+      </div>
+      <div class="btn_box">
+        <van-button class="btn" @click="submit">{{ $t('lang325') }}</van-button>
+      </div>
+      <van-popup v-model="showOrders" round closeable>
+        <div class="orderpopup">
+          <div class="orderpopup_title">{{ $t('lang334') }}</div>
+          <van-radio-group v-model="radio" class="orderpopup_list" v-if="orderlist.length > 0">
+            <div v-for="(item, index) in orderlist" :key="index" class="orderpopup_item flex jsb">
+              <span :class="[radio == item ? 'radio-active' : '']">
+                {{ item.order_no }}
+              </span>
+              <van-radio :name="item.order_no" icon-size="18px" checked-color="#21926f"></van-radio>
+            </div>
+          </van-radio-group>
+          <div class="nodata" v-else>
+            <span>{{ $t('lang60') }} </span>
+          </div>
+          <van-button type="default" class="btn" @click="chooseOrder">{{ $t('lang111') }}</van-button>
+        </div>
+      </van-popup>
+    </div>
+    <van-overlay :show="show">
+      <div class="wrapper" @click.stop>
+        <van-loading type="spinner" class="loading" color="#29b286" />
+      </div>
+    </van-overlay>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { homeApi } from '@/api/index';
+import { Dialog } from 'vant';
+export default {
+  data() {
+    return {
+      showOrders: false,
+      orderlist: [],
+      page: 1,
+      radio: {},
+      product: {},
+      order_no: {}, // 存放已选择订单
+      show: false,
+    };
+  },
+  mounted() {
+    this.getInfo();
+  },
+  methods: {
+    //返回上一页
+    back() {
+      this.$router.back();
+    },
+    getInfo() {
+      homeApi.pledgeDetail({ id: this.$route.query.id }).then(res => {
+        if (res.code == 200) {
+          this.product = res.data;
+        } else {
+          this.$toast(res.msg);
+        }
+      });
+    },
+    holdProductList(product_id) {
+      homeApi.holdProductList({ product_id }).then(res => {
+        if (res.code == 200) {
+          this.orderlist = res.data;
+        } else {
+          this.$toast(res.msg);
+        }
+      });
+    },
+    chooseProduct(id, index) {
+      console.log(id, index);
+
+      // if (this.result.indexOf(id) >= 0) {
+      //   this.order_no[id] = '';
+      //   this.result.splice(this.result.indexOf(id), 1);
+      // } else {
+      this.showOrders = true;
+      this.holdProductList(id);
+      this.productId = id;
+      this.radio = this.order_no[this.productId];
+      console.log(this.radio);
+
+      // }
+    },
+    chooseOrder() {
+      if (!this.radio) {
+        return this.$toast(this.$t('lang330'));
+      }
+      this.order_no[this.productId] = this.radio;
+      this.showOrders = false;
+      this.productId = '';
+      console.log('order_no', this.order_no);
+      console.log('radio', this.radio);
+      this.radio = {};
+    },
+
+    submit() {
+      console.log(Object.assign({}, this.order_no));
+      if (JSON.stringify(this.order_no) == '{}') {
+        return this.$toast(this.$t('lang330'));
+      }
+      let _this = this;
+      Dialog.confirm({
+        title: _this.$t('lang136'),
+        message: _this.$t('lang327'),
+        confirmButtonText: _this.$t('lang111'),
+        cancelButtonText: _this.$t('lang135'),
+      })
+        .then(() => {
+          _this.show = true
+          let params = { pledge_id: _this.$route.query.id, order_no: Object.assign({}, _this.order_no) };
+          homeApi.createPledge(params).then(res => {
+            if (res.code == 200) {
+              _this.show = false
+              _this.$toast(_this.$t('lang326'));
+              _this.$router.push({ name: 'storing' });
+            } else {
+              _this.show = false
+              _this.$toast(res.msg);
+            }
+          });
+        })
+        .catch(() => {
+          // on cancel
+        });
+    },
+  },
+  computed: {
+    ...mapState(['account']),
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(#000, 0.8);
+  letter-spacing: 1.5px;
+  font-weight: 550;
+  background: #fff;
+  padding: 14px 0;
+  z-index: 99;
+  .arrow_img {
+    position: absolute;
+    left: 20px;
+    width: 10px;
+    height: 16px;
+    // transform: translate(0, -50%);
+  }
+}
+.home_page {
+  padding: 60px 16px 20px;
+  height: 100vh;
+
+  .jsb {
+    justify-content: space-between;
+  }
+
+  .goods_info {
+    padding: 16px;
+    border-radius: 10px;
+    background-color: #fff;
+    img {
+      width: 100%;
+      border-radius: 10px;
+    }
+    &_title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #000;
+      letter-spacing: 1px;
+      padding: 13px 0 10px;
+    }
+    .value_1 {
+      color: #29b286;
+      font-size: 18px;
+      font-weight: 600;
+    }
+    .value_1::after {
+      content: 'TeaC';
+      font-size: 13px;
+      font-weight: normal;
+    }
+    .value_2::after {
+      content: '%';
+      font-size: 13px;
+      font-weight: normal;
+    }
+    .value_2 {
+      color: #ed5111;
+      font-size: 18px;
+      font-weight: 600;
+      padding-right: 50px;
+    }
+    .key {
+      color: #4b4b4b;
+      font-size: 12px;
+      padding-top: 10px;
+    }
+  }
+
+  .goods_list {
+    color: #000;
+    padding: 16px;
+    border-radius: 10px;
+    margin-top: 16px;
+    background-color: #fff;
+
+    &_box {
+      padding-bottom: 8px;
+      &_item {
+        padding-bottom: 8px;
+        img {
+          width: 45px;
+          height: 45px;
+          border-radius: 50%;
+        }
+        .name {
+          font-size: 14px;
+          width: 90px;
+          margin-left: 6px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .tip {
+          color: #b9b9b9;
+          font-size: 12px;
+          padding-right: 6px;
+        }
+        .orderSn {
+          color: #000;
+          font-size: 12px;
+          padding-right: 6px;
+        }
+
+        .checkbox {
+          width: 16px;
+          height: 16px;
+          border-radius: 50%;
+          border: 0.0625rem solid #c8c9cc;
+        }
+        .checkbox-active {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          background-color: #21926f;
+        }
+      }
+    }
+    .desc {
+      font-size: 14px;
+      line-height: 160%;
+      letter-spacing: 1px;
+      padding-top: 16px;
+    }
+  }
+  .btn_box {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 20px;
+    background-color: #fff;
+    .btn {
+      width: 100%;
+      color: #fff;
+      letter-spacing: 2px;
+      border-radius: 20px;
+      background-color: #29b286;
+    }
+  }
+  .nodata {
+    font-size: 13px;
+    padding: 60px;
+    color: #4b4b4b;
+    text-align: center;
+  }
+  .orderpopup {
+    width: 300px;
+    height: fit-content;
+    color: #000;
+    padding: 16px 30px 0;
+    &_title {
+      text-align: center;
+    }
+    &_list {
+      min-height: 100px;
+      max-height: 160px;
+      margin: 28px 0 10px;
+      overflow: auto;
+    }
+    &_item {
+      color: #9b9b9b;
+      font-size: 15px;
+      padding-bottom: 10px;
+      .radio-active {
+        color: #000;
+      }
+    }
+    .btn {
+      width: 100%;
+      color: #21926f;
+      letter-spacing: 2px;
+      border: 0;
+      border-top: 1px solid rgba(#cccccc, 0.8);
+      border-radius: 0;
+      background-color: #fff;
+    }
+  }
+}
+.flex {
+  display: flex;
+  align-items: center;
+}
+.flex_col {
+  display: flex;
+  flex-direction: column;
+}
+.flex_end {
+  align-items: flex-end;
+}
+::v-deep .van-popup__close-icon {
+  color: #575757;
+}
+.wrapper {
+  // display: flex;
+  // justify-content: center;
+  .loading {
+    position: absolute;
+    left: 46%;
+    top: 46%;
+  }
+}
+</style>

+ 388 - 0
src/views/storage/singleDetail.vue

@@ -0,0 +1,388 @@
+<template>
+  <div>
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang321') }}</span>
+    </div>
+    <div class="home_page">
+      <div class="goods_info flex_col">
+        <img :src="product.thum" alt="" />
+        <span class="goods_info_title">{{ product.title }}</span>
+        <div class="flex">
+          <div class="">
+            <span class="key">APY:</span>
+            <span class="value_2">{{ Number(product.income_reta) * 100 }}</span>
+          </div>
+          <div class="">
+            <span class="key">{{ $t('lang332') }}:</span>
+            <span class="value_1">{{ product.day_num }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="goods_list">
+        <div class="goods_list_box">
+          <!-- <van-checkbox-group v-model="result" ref="checkboxGroup"> -->
+          <div class="goods_list_box_item flex jsb" v-for="(item, index) in product.product_list" :key="index">
+            <div class="flex">
+              <img :src="item.thum" alt="" />
+              <span class="name">{{ item.name }}</span>
+            </div>
+            <div class="flex" @click="chooseProduct(item.id, index)">
+              <span class="orderSn" v-if="checkbox.length > 0">{{ $t('lang333') + checkbox.length + $t('lang95') }}</span>
+              <span class="tip" v-else>{{ $t('lang331') }}</span>
+              <!-- <van-checkbox :name="item.id" icon-size="16px" checked-color="#21926F"> </van-checkbox> -->
+              <div :class="[checkbox.length > 0 ? 'checkbox checkbox-active' : 'checkbox']">
+                <van-icon name="success" size="13px" color="#fff" v-if="checkbox.length > 0" />
+              </div>
+            </div>
+          </div>
+          <!-- </van-checkbox-group> -->
+        </div>
+        <div class="desc" v-html="product.detail"></div>
+      </div>
+      <div class="btn_box">
+        <van-button class="btn" @click="submit">{{ $t('lang325') }}</van-button>
+      </div>
+      <van-popup v-model="showOrders" round closeable>
+        <div class="orderpopup">
+          <div class="orderpopup_title">{{ $t('lang334') }}</div>
+          <van-checkbox-group v-model="checkbox" class="orderpopup_list" v-if="orderlist.length > 0">
+            <div v-for="(item, index) in orderlist" :key="index" class="orderpopup_item flex jsb">
+              <span :class="[checkbox.indexOf(item.order_no) >= 0 ? 'radio-active' : '']">
+                {{ item.order_no }}
+              </span>
+              <van-checkbox :name="item.order_no" icon-size="18px" checked-color="#21926f"></van-checkbox>
+            </div>
+          </van-checkbox-group>
+          <div class="nodata" v-else>
+            <span>{{ $t('lang60') }} </span>
+          </div>
+          <van-button type="default" class="btn" @click="chooseOrder">{{ $t('lang111') }}</van-button>
+        </div>
+      </van-popup>
+    </div>
+    <van-overlay :show="show">
+      <div class="wrapper" @click.stop>
+        <van-loading type="spinner" class="loading" color="#29b286" />
+      </div>
+    </van-overlay>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { homeApi } from '@/api/index';
+import { Dialog } from 'vant';
+export default {
+  data() {
+    return {
+      showOrders: false,
+      orderlist: [],
+      page: 1,
+      checkbox: [],
+      product: {},
+      product: {},
+      order_no: {},
+      show: false,
+    };
+  },
+  watch: {
+    radio(val) {
+      console.log(val);
+    },
+    checkbox(val) {
+      console.log(val);
+    },
+  },
+  mounted() {
+    this.getInfo();
+  },
+  methods: {
+    //返回上一页
+    back() {
+      this.$router.back();
+    },
+    getInfo() {
+      homeApi.pledgeDetail({ id: this.$route.query.id }).then(res => {
+        if (res.code == 200) {
+          this.product = res.data;
+        } else {
+          this.$toast(res.msg);
+        }
+      });
+    },
+    holdProductList(product_id) {
+      homeApi.holdProductList({ product_id }).then(res => {
+        if (res.code == 200) {
+          this.orderlist = res.data;
+        } else {
+          this.$toast(res.msg);
+        }
+      });
+    },
+    chooseProduct(id, index) {
+      // if (this.result.indexOf(id) >= 0) {
+      //   this.order_no[id] = '';
+      //   this.result.splice(this.result.indexOf(id), 1);
+      // } else {
+      this.showOrders = true;
+      this.holdProductList(id);
+      this.productId = id;
+      // }
+    },
+    chooseOrder() {
+      if (this.checkbox.length <= 0) {
+        return this.$toast(this.$t('lang330'));
+      }
+      this.order_no = this.checkbox;
+      this.showOrders = false;
+      this.productId = '';
+      // this.checkbox = [];
+      console.log('order_no', this.order_no);
+      console.log('checkbox', this.checkbox);
+    },
+
+    submit() {
+      if (JSON.stringify(this.order_no) == '{}') {
+        return this.$toast(this.$t('lang330'));
+      }
+      let _this = this;
+      Dialog.confirm({
+        title: _this.$t('lang136'),
+        message: _this.$t('lang327'),
+        confirmButtonText: _this.$t('lang111'),
+        cancelButtonText: _this.$t('lang135'),
+      })
+        .then(() => {
+          _this.show = true
+          let params = { pledge_id: _this.$route.query.id, order_no: Object.assign({}, _this.order_no) };
+          homeApi.createPledge(params).then(res => {
+            if (res.code == 200) {
+              _this.show = false
+              _this.$toast(_this.$t('lang326'));
+              _this.$router.push({ name: 'storing' });
+            } else {
+              _this.show = false
+              _this.$toast(res.msg);
+            }
+          });
+        })
+        .catch(() => {
+          // on cancel
+        });
+    },
+  },
+  computed: {
+    ...mapState(['account']),
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(#000, 0.8);
+  letter-spacing: 1.5px;
+  font-weight: 550;
+  background: #fff;
+  padding: 14px 0;
+  z-index: 99;
+  .arrow_img {
+    position: absolute;
+    left: 20px;
+    width: 10px;
+    height: 16px;
+    // transform: translate(0, -50%);
+  }
+}
+.home_page {
+  padding: 60px 16px 20px;
+  height: 100vh;
+
+  .jsb {
+    justify-content: space-between;
+  }
+
+  .goods_info {
+    padding: 16px;
+    border-radius: 10px;
+    background-color: #fff;
+    img {
+      width: 100%;
+      border-radius: 10px;
+    }
+    &_title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #000;
+      letter-spacing: 1px;
+      padding: 13px 0 10px;
+    }
+    .value_1 {
+      color: #29b286;
+      font-size: 18px;
+      font-weight: 600;
+    }
+    .value_1::after {
+      content: 'TeaC';
+      font-size: 13px;
+      font-weight: normal;
+    }
+    .value_2::after {
+      content: '%';
+      font-size: 13px;
+      font-weight: normal;
+    }
+    .value_2 {
+      color: #ed5111;
+      font-size: 18px;
+      font-weight: 600;
+      padding-right: 50px;
+    }
+    .key {
+      color: #4b4b4b;
+      font-size: 12px;
+      padding-top: 10px;
+    }
+  }
+
+  .goods_list {
+    color: #000;
+    padding: 16px;
+    border-radius: 10px;
+    margin-top: 16px;
+    background-color: #fff;
+
+    &_box {
+      padding-bottom: 8px;
+      &_item {
+        padding-bottom: 8px;
+        img {
+          width: 45px;
+          height: 45px;
+          border-radius: 50%;
+        }
+        .name {
+          font-size: 14px;
+          width: 90px;
+          margin-left: 6px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .tip {
+          color: #b9b9b9;
+          font-size: 12px;
+          padding-right: 6px;
+        }
+        .orderSn {
+          color: #000;
+          font-size: 12px;
+          padding-right: 6px;
+        }
+
+        .checkbox {
+          width: 16px;
+          height: 16px;
+          border-radius: 50%;
+          border: 0.0625rem solid #c8c9cc;
+        }
+        .checkbox-active {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          background-color: #21926f;
+        }
+      }
+    }
+    .desc {
+      font-size: 14px;
+      line-height: 160%;
+      letter-spacing: 1px;
+      padding-top: 16px;
+    }
+  }
+  .btn_box {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 20px;
+    background-color: #fff;
+    .btn {
+      width: 100%;
+      color: #fff;
+      letter-spacing: 2px;
+      border-radius: 20px;
+      background-color: #29b286;
+    }
+  }
+  .nodata {
+    font-size: 13px;
+    padding: 60px;
+    color: #4b4b4b;
+    text-align: center;
+  }
+  .orderpopup {
+    width: 300px;
+    height: fit-content;
+    color: #000;
+    padding: 16px 30px 0;
+    &_title {
+      text-align: center;
+    }
+    &_list {
+      min-height: 100px;
+      max-height: 160px;
+      margin: 28px 0 10px;
+      overflow: auto;
+    }
+    &_item {
+      color: #9b9b9b;
+      font-size: 15px;
+      padding-bottom: 10px;
+      .radio-active {
+        color: #000;
+      }
+    }
+    .btn {
+      width: 100%;
+      color: #21926f;
+      letter-spacing: 2px;
+      border: 0;
+      border-top: 1px solid rgba(#cccccc, 0.8);
+      border-radius: 0;
+      background-color: #fff;
+    }
+  }
+}
+.flex {
+  display: flex;
+  align-items: center;
+}
+.flex_col {
+  display: flex;
+  flex-direction: column;
+}
+.flex_end {
+  align-items: flex-end;
+}
+::v-deep .van-popup__close-icon {
+  color: #575757;
+}
+.wrapper {
+  // display: flex;
+  // justify-content: center;
+  .loading {
+    position: absolute;
+    left: 46%;
+    top: 46%;
+  }
+}
+</style>

+ 498 - 0
src/views/storage/storing.vue

@@ -0,0 +1,498 @@
+·<template>
+  <div class="assets">
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang38') }}</span>
+    </div>
+    <div class="total_box">
+      <div>{{ $t('lang328') }}</div>
+      <div class="total f-sb">
+        <!-- <div>{{ total }}</div> -->
+        <countTo :startVal="total" :endVal="endVal" :duration="2000" :decimals="6"></countTo>
+        <van-button class="get_btn" type="primary" @click="collectPledge">{{ $t('lang329') }}</van-button>
+      </div>
+    </div>
+
+    <div class="">
+      <div class="pd1 goods_box" v-if="nft_list.length > 0">
+        <div class="goods_list" v-for="(item, index) in nft_list" :key="index">
+          <div class="f-sb">
+            <span class="title">{{ item.title }}</span>
+            <span class="status">{{ $t('lang222') }}</span>
+          </div>
+
+          <div class="f-r box">
+            <div class="f-col item" v-for="(item1, index1) in JSON.parse(item.details)" :key="index1">
+              <van-image class="goods_list_img" radius="10" :src="item1.thum" />
+              <div class="right">
+                <div style="font-size: 13px">{{ item1.order_no.substring(0, 4) + '****' + item1.order_no.substring(item1.order_no.length - 5, item1.order_no.length) }}</div>
+              </div>
+            </div>
+          </div>
+
+          <div class="btn_box">
+            <!-- 按钮 -->
+            <div class="buy" @click="removePledge(item.id)">
+              <van-button class="buy_btn btn1" type="primary">{{ $t('lang322') }}</van-button>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="bare" v-if="nft_list.length <= 0">
+        <span>{{ $t('lang82') }}</span>
+      </div>
+    </div>
+    <van-overlay :show="show">
+      <div class="wrapper" @click.stop>
+        <van-loading type="spinner" class="loading" color="#29b286" />
+      </div>
+    </van-overlay>
+  </div>
+</template>
+
+<script>
+import { homeApi } from '@/api/index';
+import { Dialog, Notify, Toast } from 'vant';
+import countTo from 'vue-count-to';
+export default {
+  components: { countTo },
+  data() {
+    return {
+      loading: false,
+      total: 0,
+      endVal: 0,
+      growth: 0,
+      nft_list: [],
+      timer: null,
+      show: false,
+    };
+  },
+  mounted() {
+    this.teamine();
+  },
+  beforeDestroy() {
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+  methods: {
+    //返回上一页
+    back() {
+      this.$router.back();
+    },
+    teamine() {
+      homeApi.teamine({}).then(res => {
+        if (res.code == 200) {
+          this.total = res.data.total;
+          this.endVal = res.data.total;
+          this.growth = res.data.growth;
+          this.nft_list = res.data.list;
+          this.timer = setInterval(() => {
+            this.total = this.endVal;
+            this.endVal += this.growth * 7;
+          }, 7000);
+        } else {
+        }
+      });
+    },
+    removePledge(pledge_id) {
+      let _this = this;
+      Dialog.confirm({
+        title: _this.$t('lang136'),
+        message: _this.$t('lang335'),
+        confirmButtonText: _this.$t('lang111'),
+        cancelButtonText: _this.$t('lang135'),
+      })
+        .then(() => {
+          _this.show = true;
+          homeApi.removePledge({ pledge_id }).then(res => {
+            if (res.code == 200) {
+              _this.show = false;
+              _this.nft_list = [];
+              _this.teamine();
+              Notify({ type: 'success', message: _this.$t('lang152') });
+            } else {
+              _this.show = false;
+              _this.$toast(res.msg);
+            }
+          });
+        })
+        .catch(() => {
+          // on cancel
+        });
+    },
+    collectPledge() {
+      this.show = true;
+      homeApi.collectPledge({}).then(res => {
+        if (res.code == 200) {
+          this.show = false;
+          this.teamine();
+          Notify({ type: 'success', message: this.$t('lang152') });
+        } else {
+          this.show = false;
+          this.$toast(res.msg);
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(#000, 0.8);
+  letter-spacing: 1.2px;
+  font-weight: 550;
+  background: #fff;
+  padding: 14px 0;
+  height: 50px;
+  z-index: 999;
+  .arrow_img {
+    position: absolute;
+    left: 20px;
+    width: 10px;
+    height: 16px;
+    // transform: translate(0, -50%);
+  }
+}
+.f-sb {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.f-sa {
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+}
+.f-sb-n {
+  display: flex;
+  align-items: flex-end;
+  justify-content: space-between;
+}
+.f-col {
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+}
+.f-r {
+  display: flex;
+  align-items: center;
+}
+.f {
+  display: flex;
+}
+.f-s {
+  display: flex;
+  align-items: flex-start;
+}
+.btn_box {
+  padding-top: 14px;
+}
+.assets {
+  height: 100vh;
+  padding: 50px 0 0;
+  overflow: scroll;
+  // background-color: #fafbfc;
+  .top {
+    color: #000;
+    padding-bottom: 16px;
+    margin: 0 6px;
+  }
+  .navbar {
+    position: fixed;
+    top: 50px;
+    z-index: 999;
+    width: 100%;
+    color: #000;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background-color: #fff;
+    span {
+      color: #aaaaaa;
+      width: 50%;
+      font-size: 14px;
+      text-align: center;
+      line-height: 50px;
+    }
+  }
+  .pd {
+    min-height: 100vh;
+    padding: 4px;
+    margin-top: 54px;
+    background-color: #fff;
+  }
+  .total_box {
+    color: #707070;
+    padding: 18px;
+    margin: 16px 16px 0;
+    box-sizing: border-box;
+    border-radius: 10px;
+    background-color: #ffffff;
+
+    .total {
+      color: #000;
+      font-size: 24px;
+      text-align: center;
+      font-weight: 600;
+      padding-top: 26px;
+      .get_btn {
+        color: #ffffff;
+        height: 30px;
+        line-height: 30px;
+        font-size: 14px;
+        font-weight: normal;
+        border: none;
+        padding: 0 20px;
+        white-space: nowrap;
+        border-radius: 30px;
+        background-color: #29b286;
+      }
+    }
+    .text {
+      color: rgba(#fff, 0.8);
+    }
+    .buy_box {
+      position: absolute;
+      bottom: 14px;
+      display: flex;
+      width: 100%;
+      padding: 0 14px;
+      align-items: center;
+      justify-content: space-between;
+    }
+    .buy {
+      &_btn {
+        color: #29b286;
+        height: 30px;
+        line-height: 30px;
+        font-size: 14px;
+        background-color: #ffffff;
+        border: none;
+        padding: 0 16px;
+        white-space: nowrap;
+        border-radius: 30px;
+      }
+    }
+  }
+
+  .bare {
+    text-align: center;
+    font-size: 14px;
+    padding: 110px 14px 60px;
+    color: #aaa;
+  }
+  .list {
+    border-radius: 20px;
+    padding: 0 8px;
+    margin-top: 16px;
+    background-color: #fff;
+    margin: 16px 6px;
+    .li {
+      // display: flex;
+      // align-items: center;
+      // justify-content: space-between;
+      font-size: 14px;
+      color: rgba(51, 51, 51, 1);
+      padding: 14px 0;
+
+      .li_left {
+        // display: flex;
+        // align-items: center;
+        .imgbox {
+          width: 40px;
+          height: 40px;
+          border-radius: 15px;
+          background-color: #f1f1f1;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          margin-right: 6px;
+        }
+        .li_img {
+          display: block;
+          width: 32px;
+          height: 32px;
+          border-radius: 50%;
+        }
+        .title {
+          color: #29b286;
+          font-size: 14px;
+          font-weight: bold;
+        }
+      }
+      .box {
+        padding-top: 10px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        &_item {
+          width: 33%;
+          display: flex;
+          flex-direction: column;
+          .key {
+            color: #aaa;
+            font-size: 12px;
+          }
+          .num {
+            font-size: 14px;
+            color: #000;
+            padding-top: 2px;
+          }
+        }
+        .box_item:last-child {
+          text-align: right;
+        }
+      }
+    }
+  }
+
+  .goods_box {
+    // margin: 14px;
+    height: 100vh;
+    overflow: auto;
+    border-radius: 14px;
+    .good_icon {
+      width: 16px;
+      height: 16px;
+      margin-right: 5px;
+    }
+  }
+  .pd1 {
+    padding: 16px 14px 14px;
+    height: auto;
+  }
+  .goods_list {
+    position: relative;
+    color: #000;
+    padding: 18px;
+    border-radius: 10px;
+    margin-bottom: 16px;
+    background-color: #fff;
+
+    .tags {
+      position: absolute;
+      left: 0;
+      top: 0;
+      font-size: 10px;
+      color: #fff;
+      padding: 4px 14px;
+      z-index: 99;
+      background-color: #29b2b0;
+      border-radius: 6px 0 6px 0;
+    }
+    .tags1 {
+      position: absolute;
+      left: 0;
+      top: 0;
+      font-size: 10px;
+      color: #fff;
+      padding: 4px 14px;
+      z-index: 99;
+      background-color: #f4ab1e;
+      border-radius: 6px 0 6px 0;
+    }
+    .tags3 {
+      position: absolute;
+      left: 3px;
+      top: 3px;
+      z-index: 99;
+      font-size: 15px;
+    }
+    .tags2 {
+      background-color: #1e8df4;
+    }
+    &_img {
+      width: 60px;
+      height: 60px;
+      margin: 16px 0;
+    }
+    .title {
+      width: 80%;
+      font-weight: 700;
+      font-size: 18px;
+      overflow: hidden; /* 确保超出容器的文本被裁剪 */
+      white-space: nowrap; /* 确保文本在一行内显示 */
+      text-overflow: ellipsis; /* 使用省略号表示文本超出 */
+    }
+    .status {
+      font-size: 12px;
+      color: #a0a0a0;
+    }
+    .box {
+      width: 100%;
+      overflow: auto;
+      .item {
+        margin-right: 6px;
+      }
+    }
+
+    .buy {
+      display: flex;
+      align-items: flex-end;
+      justify-content: flex-end;
+      &_btn {
+        height: 32px;
+        min-width: 96px;
+        text-align: center;
+        line-height: 32px;
+        font-size: 13px;
+        border: none;
+        white-space: nowrap;
+        border-radius: 30px;
+        box-sizing: border-box;
+        border: 1px solid #29b286;
+        background-color: #29b286;
+      }
+      .btn1 {
+        color: #29b286;
+        background-color: #fff;
+      }
+    }
+    .buy1 {
+      justify-content: flex-end;
+    }
+  }
+}
+::v-deep .van-cell {
+  padding: 10px 0 !important;
+}
+::v-deep .van-button--danger {
+  background-color: #29b286;
+  border-color: #29b286;
+}
+::v-deep .van-address-edit {
+  padding: 10px 0;
+}
+::v-deep .van-ellipsis {
+  font-size: 10px !important;
+}
+::v-deep .van-overlay {
+  background-color: rgba(#000, 0.3);
+}
+::v-deep van-hairline-unset--top-bottom,
+::v-deep .van-picker__frame {
+  border: 1px solid #fff !important;
+}
+::v-deep .van-address-edit__buttons {
+  padding-bottom: 10px !important;
+  padding-top: 10px !important;
+}
+.wrapper {
+  // display: flex;
+  // justify-content: center;
+  .loading {
+    position: absolute;
+    left: 46%;
+    top: 46%;
+  }
+}
+</style>