xiaomei преди 7 месеца
родител
ревизия
2eb8ed9f9f
променени са 11 файла, в които са добавени 1281 реда и са изтрити 3 реда
  1. 13 0
      package-lock.json
  2. 1 0
      package.json
  3. 33 0
      src/api/home.js
  4. 24 1
      src/language/en.json
  5. 77 1
      src/language/zh.json
  6. 2 0
      src/main.js
  7. 27 0
      src/router/index.js
  8. 1 1
      src/views/index/index.vue
  9. 263 0
      src/views/mine/synthesis.vue
  10. 712 0
      src/views/mine/synthesisDetail.vue
  11. 128 0
      src/views/rule/index.vue

+ 13 - 0
package-lock.json

@@ -28,6 +28,7 @@
         "vue": "^2.6.11",
         "vue-animate-number": "^0.4.2",
         "vue-i18n": "^8.26.5",
+        "vue-monoplasty-slide-verify": "^1.3.1",
         "vue-router": "^3.2.0",
         "vuex": "^3.4.0",
         "vuex-persistedstate": "^4.1.0",
@@ -17247,6 +17248,18 @@
         "node": ">=4.0.0"
       }
     },
+    "node_modules/vue-monoplasty-slide-verify": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/vue-monoplasty-slide-verify/-/vue-monoplasty-slide-verify-1.3.1.tgz",
+      "integrity": "sha512-oMP9RdBo/2M2D8CcEE1IJCXKWOGPUyFNKFgMwj8+BMEA5Je4wF3jUbCnQe/hNNmV1cUBdeTNp0w/TdlP1A96SQ==",
+      "dependencies": {
+        "vue": "^2.5.11"
+      },
+      "engines": {
+        "node": ">= 6.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
     "node_modules/vue-router": {
       "version": "3.6.5",
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",

+ 1 - 0
package.json

@@ -28,6 +28,7 @@
     "vue": "^2.6.11",
     "vue-animate-number": "^0.4.2",
     "vue-i18n": "^8.26.5",
+    "vue-monoplasty-slide-verify": "^1.3.1",
     "vue-router": "^3.2.0",
     "vuex": "^3.4.0",
     "vuex-persistedstate": "^4.1.0",

+ 33 - 0
src/api/home.js

@@ -831,4 +831,37 @@ export default {
       data
     })
   },
+  // 合成中心
+  getSynthesisList(data) {
+    return request.request({
+      url: '/synthesis/list',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 合成中心详情
+  getSynthesisDetail(data) {
+    return request.request({
+      url: '/synthesis/detail',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
+  // 合成中心提交
+  synthesisCreate(data) {
+    return request.request({
+      url: '/synthesis/create',
+      method: "post",
+      headers: {
+        'Accept-Language': localStorage.getItem('language') || 'zh-cn',
+      },
+      data
+    })
+  },
 }

+ 24 - 1
src/language/en.json

@@ -293,5 +293,28 @@
   "lang292": "Link copied, open in browser to download image",
   "lang293": "Download",
   "lang294": "Transfer address:",
-  "lang295": "Receiving address:"
+  "lang295": "Receiving address:",
+  "lang296": "Participate in synthesis",
+  "lang297": "Starting soon",
+  "lang298": "Synthesis rules",
+  "lang299": "Synthesis confirmation",
+  "lang300": "Target tea rights",
+  "lang301": "Issuance",
+  "lang302": "Circulation",
+  "lang303": "Synthesis materials",
+  "lang304": "Priority use",
+  "lang305": "Current maximum number of synthesis copies:",
+  "lang306": "Now Synthesize",
+  "lang307": "Estimated target number of synthesis",
+  "lang308": "If the target tea rights are insufficient, the actual synthesis quantity will be less than the estimated quantity",
+  "lang309": "Synthesis conditions",
+  "lang310": "Number of copies consumed",
+  "lang311": "Necessary conditions",
+  "lang312": "Please complete security verification",
+  "lang313": "Slide right to verify",
+  "lang314": "Necessary",
+  "lang315": "Insufficient materials",
+  "lang316": "The synthesis activity has ended",
+  "lang317": "Collect 1 of the following materials",
+  "lang318": "Congratulations, synthesis is successful"
 }

+ 77 - 1
src/language/zh.json

@@ -293,5 +293,81 @@
   "lang292": "链接已复制,在浏览器打开下载图片",
   "lang293": "下载图片",
   "lang294": "转账地址:",
-  "lang295": "收款地址:"
+  "lang295": "收款地址:",
+  "lang296": "参与合成",
+  "lang297": "即将开始",
+  "lang298": "合成规则",
+  "lang299": "合成确认",
+  "lang300": "目标茶权",
+  "lang301": "发行",
+  "lang302": "流通",
+  "lang303": "合成材料",
+  "lang304": "优先用",
+  "lang305": "当前最大合成份数:",
+  "lang306": "立即合成",
+  "lang307": "预计可合成目标数量",
+  "lang308": "若目标茶权份数不足,则实际合成数量会少于预计数量",
+  "lang309": "合成条件",
+  "lang310": "消耗份数",
+  "lang311": "必要条件",
+  "lang312": "请完成安全验证",
+  "lang313": "向右滑动完成验证",
+  "lang314": "必要",
+  "lang315": "材料不足",
+  "lang316": "合成活动已结束",
+  "lang317": "以下任意材料集齐1份",
+  "lang318": "恭喜,合成成功",
+  "lang319": "",
+  "lang320": "",
+  "lang321": "",
+  "lang322": "",
+  "lang323": "",
+  "lang324": "",
+  "lang325": "",
+  "lang326": "",
+  "lang327": "",
+  "lang328": "",
+  "lang329": "",
+  "lang330": "",
+  "lang331": "",
+  "lang332": "",
+  "lang333": "",
+  "lang334": "",
+  "lang335": "",
+  "lang336": "",
+  "lang337": "",
+  "lang338": "",
+  "lang339": "",
+  "lang340": "",
+  "lang341": "",
+  "lang342": "",
+  "lang343": "",
+  "lang344": "",
+  "lang345": "",
+  "lang346": "",
+  "lang347": "",
+  "lang348": "",
+  "lang349": "",
+  "lang350": "",
+  "lang351": "",
+  "lang352": "",
+  "lang353": "",
+  "lang354": "",
+  "lang355": "",
+  "lang356": "",
+  "lang357": "",
+  "lang358": "",
+  "lang359": "",
+  "lang360": "",
+  "lang361": "",
+  "lang362": "",
+  "lang363": "",
+  "lang364": "",
+  "lang365": "",
+  "lang366": "",
+  "lang367": "",
+  "lang368": "",
+  "lang369": "",
+  "lang370": "",
+  "lang371": ""
 }

+ 2 - 0
src/main.js

@@ -14,6 +14,8 @@ import './utils/rem.js';
 // Vue.prototype.$eventBus = new Vue();
 import VueAnimateNumber from 'vue-animate-number'
 import VueAwesomeSwiper from "vue-awesome-swiper";
+import SlideVerify from 'vue-monoplasty-slide-verify'; 
+Vue.use(SlideVerify)
 import "swiper/css/swiper.css";
 Vue.use(VueAwesomeSwiper);
 Vue.use(VueAnimateNumber)

+ 27 - 0
src/router/index.js

@@ -37,6 +37,9 @@ import teaRights from '../views/mine/teaRights.vue'; //我的茶权
 import operationLog from '../views/mine/operationLog.vue'; //操作记录
 import welfare from '../views/index/welfare.vue'; //新人福利
 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'; //合成规则
 Vue.use(VueRouter);
 const routes = [
 
@@ -251,6 +254,30 @@ const routes = [
           requiresAuth: true
         }
       },
+      {
+        path: 'synthesis',
+        name: 'synthesis',
+        component: synthesis,
+        meta: {
+          requiresAuth: true
+        }
+      },
+      {
+        path: 'synthesisDetail',
+        name: 'synthesisDetail',
+        component: synthesisDetail,
+        meta: {
+          requiresAuth: true
+        }
+      },
+      {
+        path: 'rule',
+        name: 'rule',
+        component: rule,
+        meta: {
+          requiresAuth: true
+        }
+      },
     ],
   },
 ];

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

@@ -192,7 +192,7 @@ export default {
         {
           text: this.$t('lang259'),
           icon: require('@/assets/images/index/hc.png'),
-          url: '',
+          url: 'synthesis',
         },
         {
           text: this.$t('lang264'),

+ 263 - 0
src/views/mine/synthesis.vue

@@ -0,0 +1,263 @@
+<template>
+  <div>
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang259') }}</span>
+    </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="right" style="flex: 1">
+            <span class="ellipsis name">{{ item.title }}</span>
+            <span class="time_text t2">{{ dateFormatFn(item.start_time) }}-{{ dateFormatFn(item.end_time) }}</span>
+            <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">
+              <van-button class="buy_btn will" type="primary">
+                <span>
+                  {{ $t('lang297') }}
+                </span>
+                <!-- <span class="countdown">24h13m25s</span> -->
+                <van-count-down class="countdown" :time="(item.start_time - current) * 1000" format="HHhmmmsss" />
+              </van-button>
+            </div>
+            <div class="buy" @click="navigatorToPage('synthesisDetail', item.id)" v-else-if="current > item.end_time">
+              <van-button class="buy_btn finish" type="primary">{{ $t('lang74') }}</van-button>
+            </div>
+          </div>
+          <van-image class="goods_list_img" radius="10" :src="item.img_url" />
+        </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 {
+      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.getSynthesisList();
+    },
+    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.getSynthesisList(); // 触发加载更多
+        }
+      }
+    },
+
+    getSynthesisList() {
+      homeApi.getSynthesisList({ sort: this.sort, type_id: this.type_id, key_val: this.key, 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 {
+        }
+      });
+    },
+
+    navigatorToPage(name, id) {
+      this.$router.push({ name, query: { id: 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%);
+  }
+}
+.home_page {
+  padding: 50px 0 100px;
+  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 {
+    display: flex;
+    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;
+    }
+
+    .right {
+      width: calc(100% - 100px);
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      font-size: 13px;
+      padding: 14px;
+      box-sizing: border-box;
+      // padding: 6px 0;
+
+      .name {
+        font-size: 15px;
+        font-weight: 600;
+        letter-spacing: 1px;
+      }
+
+      .time_text {
+        color: #7f7f7f;
+        font-weight: normal;
+        font-size: 10px;
+        letter-spacing: 1px;
+        text-decoration: line-through;
+      }
+
+      .t2 {
+        text-decoration: none;
+        white-space: nowrap;
+        padding: 2px 0;
+      }
+    }
+    .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_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>

+ 712 - 0
src/views/mine/synthesisDetail.vue

@@ -0,0 +1,712 @@
+<template>
+  <div class="product-detail-page">
+    <!-- 顶部返回按钮 -->
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span @click="navigatorTo('rule', product.announcement_id)">{{ $t('lang298') }}</span>
+    </div>
+    <div class="box">
+      <div class="bg" :style="{ backgroundImage: `url(${product.img_url})` }"></div>
+      <div class="content">
+        <div class="mb">
+          <span>{{ $t('lang300') }}</span>
+        </div>
+        <img :src="product.img_url" alt="" class="pic" />
+
+        <span class="name">{{ product.title }}</span>
+        <div class="num">
+          <div class="num_box">
+            <div class="left">{{ $t('lang301') }}</div>
+            <div class="right">{{ product.stock }}{{ $t('lang7') }}</div>
+          </div>
+          <div class="num_box">
+            <div class="left">{{ $t('lang302') }}</div>
+            <div class="right">{{ product.num }}{{ $t('lang7') }}</div>
+          </div>
+        </div>
+        <div class="bottom">
+          <div class="title">{{ $t('lang303') }}</div>
+          <div class="list">
+            <div class="item" v-if="product.material_one.length > 0">
+              <div>
+                <div class="item_top grey" v-if="product.material_one.length == 1">{{ $t('lang314') }}1</div>
+                <div v-else class="flex item_top_box">
+                  <div class="item_top grey">{{ $t('lang314') }}1</div>
+                  <div class="desc">
+                    <span>{{ $t('lang317') }} {{ materialOneId > 0 ? 1 : 0 }}</span>
+                    <span class="grey">/1</span>
+                  </div>
+                </div>
+                <van-radio-group v-model="materialOneId">
+                  <div class="flex">
+                    <div class="item_box" v-for="(item, index) in product.material_one" :key="index">
+                      <img class="item_img" :src="item.thum" alt="" />
+                      <span class="item_name">{{ item.name }}</span>
+                      <van-progress
+                        class="progress"
+                        :percentage="((item.hold_num / item.num) * 100 > 100 ? 100 : (item.hold_num / item.num) * 100) || 0"
+                        :show-pivot="false"
+                        color="#00FEAA"
+                        track-color="#656565"
+                        stroke-width="2px"
+                        v-if="product.material_one.length == 1"
+                      />
+                      <div class="pers" v-if="product.material_one.length == 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                      <div class="radio" v-if="product.material_one.length > 1">
+                        <van-radio checked-color="#1B52F8" icon-size="14px" :name="item.id"> {{ $t('lang304') }}</van-radio>
+                      </div>
+                      <div class="pers pers1" v-if="product.material_one.length > 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                    </div>
+                  </div>
+                </van-radio-group>
+              </div>
+            </div>
+            <div class="item" v-if="product.material_two.length > 0">
+              <div>
+                <div class="item_top grey" v-if="product.material_two.length == 1">{{ $t('lang314') }}2</div>
+                <div v-else class="flex item_top_box">
+                  <div class="item_top grey">{{ $t('lang314') }}2</div>
+                  <div class="desc">
+                    <span>{{ $t('lang317') }} {{ materialTwoId > 0 ? 1 : 0 }}</span>
+                    <span class="grey">/1</span>
+                  </div>
+                </div>
+                <van-radio-group v-model="materialTwoId">
+                  <div class="flex">
+                    <div class="item_box" v-for="(item, index) in product.material_two" :key="index">
+                      <img class="item_img" :src="item.thum" alt="" />
+                      <span class="item_name">{{ item.name }}</span>
+                      <van-progress
+                        class="progress"
+                        :percentage="((item.hold_num / item.num) * 100 > 100 ? 100 : (item.hold_num / item.num) * 100) || 0"
+                        :show-pivot="false"
+                        color="#00FEAA"
+                        track-color="#656565"
+                        stroke-width="2px"
+                        v-if="product.material_two.length == 1"
+                      />
+                      <div class="pers" v-if="product.material_two.length == 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                      <div class="radio" v-if="product.material_two.length > 1">
+                        <van-radio checked-color="#1B52F8" icon-size="14px" :name="item.id"> {{ $t('lang304') }}</van-radio>
+                      </div>
+                      <div class="pers pers1" v-if="product.material_two.length > 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                    </div>
+                  </div>
+                </van-radio-group>
+              </div>
+            </div>
+            <div class="item" v-if="product.material_three.length > 0">
+              <div>
+                <div class="item_top grey" v-if="product.material_three.length == 1">{{ $t('lang314') }}3</div>
+                <div v-else class="flex item_top_box">
+                  <div class="item_top grey">{{ $t('lang314') }}3</div>
+                  <div class="desc">
+                    <span>{{ $t('lang317') }} {{ materialThreeId > 0 ? 1 : 0 }}</span>
+                    <span class="grey">/1</span>
+                  </div>
+                </div>
+                <van-radio-group v-model="materialThreeId">
+                  <div class="flex">
+                    <div class="item_box" v-for="(item, index) in product.material_three" :key="index">
+                      <img class="item_img" :src="item.thum" alt="" />
+                      <span class="item_name">{{ item.name }}</span>
+                      <van-progress
+                        class="progress"
+                        :percentage="((item.hold_num / item.num) * 100 > 100 ? 100 : (item.hold_num / item.num) * 100) || 0"
+                        :show-pivot="false"
+                        color="#00FEAA"
+                        track-color="#656565"
+                        stroke-width="2px"
+                        v-if="product.material_three.length == 1"
+                      />
+                      <div class="pers" v-if="product.material_three.length == 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                      <div class="radio" v-if="product.material_three.length > 1">
+                        <van-radio checked-color="#1B52F8" icon-size="14px" :name="item.id"> {{ $t('lang304') }}</van-radio>
+                      </div>
+                      <div class="pers pers1" v-if="product.material_three.length > 1">
+                        <span>{{ item.hold_num }}</span>
+                        <span class="grey">/{{ item.num }}</span>
+                      </div>
+                    </div>
+                  </div>
+                </van-radio-group>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="btn_box">
+          <div class="btn" v-if="showStatus == 1">{{ $t('lang315') }}</div>
+          <div class="btn" v-else-if="showStatus == 2">{{ $t('lang316') }}</div>
+          <div class="flex sb" v-else>
+            <div class="step_box">
+              <!-- <div>{{ $t('lang305') }}1</div> -->
+              <van-stepper class="step" v-model="number" />
+            </div>
+            <div class="btn submit" @click="submitPopop = true">{{ $t('lang306') }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <van-popup v-model="submitPopop" round position="bottom">
+      <div class="popup">
+        <div class="title">{{ $t('lang299') }}</div>
+        <div class="popup_box flex">
+          <div class="yj">
+            {{ $t('lang307') }}:
+            <span class="popup_box_num">{{ number }}</span>
+          </div>
+          <div class="desc">{{ $t('lang308') }}</div>
+          <div class="table">
+            <div class="table_head flex">
+              <span>{{ $t('lang309') }}</span>
+              <span>{{ $t('lang310') }}</span>
+            </div>
+            <div class="table_body flex" v-if="product.material_one.length > 0">
+              <span>{{ $t('lang311') }}1</span>
+              <span>{{ product.material_one_num * number }}</span>
+            </div>
+            <div class="table_body flex" v-if="product.material_two.length > 0">
+              <span>{{ $t('lang311') }}2</span>
+              <span>{{ product.material_two_num * number }}</span>
+            </div>
+            <div class="table_body flex" v-if="product.material_three.length > 0">
+              <span>{{ $t('lang311') }}3</span>
+              <span>{{ product.material_three * number }}</span>
+            </div>
+          </div>
+        </div>
+        <div class="submit">
+          <van-button class="submit_btn" type="primary" @click="showVerify = true">
+            {{ $t('lang71') }}
+          </van-button>
+        </div>
+        <div class="submit pt">
+          <van-button class="submit_btn" type="primary" @click="submitPopop = false">
+            {{ $t('lang135') }}
+          </van-button>
+        </div>
+      </div>
+    </van-popup>
+    <van-popup v-model="loading" round class="loading-popup">
+      <div class="loading">
+        <van-loading type="spinner" />
+      </div>
+    </van-popup>
+    <van-popup v-model="showVerify" closeable class="verify_popup">
+      <div class="title">{{ $t('lang312') }}</div>
+      <div class="verify">
+        <slide-verify
+          :l="32"
+          :r="8"
+          :w="310"
+          :h="155"
+          :imgs="picArray"
+          :show="showVerify"
+          :slider-text="$t('lang313')"
+          ref="slideverify"
+          @success="onSuccess"
+          @fail="onFail"
+          @refresh="onRefresh"
+        ></slide-verify>
+      </div>
+    </van-popup>
+  </div>
+</template>
+  <script>
+import { homeApi } from '@/api/index';
+import { Dialog, Notify, Toast } from 'vant';
+export default {
+  data() {
+    return {
+      loading: false,
+      submitPopop: false,
+      showVerify: false,
+      number: 1,
+      picArray: [require('@/assets/image/banner.png')],
+      imageSrc: 'https://dapp-static.oss-cn-shenzhen.aliyuncs.com/rwacha/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250305112405.jpgNfkI1eMnLOt767c7c3d94bd2e',
+      product: {
+        material_one: [],
+        material_two: [],
+        material_three: [],
+      },
+      materialOneId: -1,
+      materialTwoId: -1,
+      materialThreeId: -1,
+      showStatus: 0, // 1材料不足  2时间结束 其余正常
+    };
+  },
+  mounted() {
+    this.getSynthesisDetail(this.$route.query.id);
+  },
+  methods: {
+    back() {
+      this.$router.back();
+    },
+    getSynthesisDetail(id) {
+      homeApi.getSynthesisDetail({ id: id }).then(res => {
+        if (res.code == 200) {
+          this.product = res.data;
+          this.product.material_one = Object.values(res.data.material_one);
+          this.product.material_two = Object.values(res.data.material_two);
+          this.product.material_three = Object.values(res.data.material_three);
+          let one = [{}];
+          let two = [{}];
+          let three = [{}];
+
+          if (this.product.material_one.length > 0) {
+            this.materialOneId = this.product.material_one[0].id;
+            one = this.product.material_one.filter(i => {
+              return i.hold_num >= i.num;
+            });
+          }
+          if (this.product.material_two.length > 0) {
+            this.materialTwoId = this.product.material_two[0].id;
+            two = this.product.material_two.filter(i => {
+              return i.hold_num >= i.num;
+            });
+          }
+          if (this.product.material_three.length > 0) {
+            this.materialThreeId = this.product.material_three[0].id;
+            three = this.product.material_three.filter(i => {
+              return i.hold_num >= i.num;
+            });
+          }
+          if (one.length > 0 && two.length > 0 && three.length > 0) {
+            this.showStatus = 0;
+          } else {
+            this.showStatus = 1;
+          }
+          if (new Date().getTime() / 1000 > this.product.end_time) {
+            this.showStatus = 2;
+          }
+        } else {
+        }
+      });
+    },
+    onSuccess() {
+      //往父级传递验证通过的函数
+      this.$emit('success');
+      this.showVerify = false;
+      this.onReset();
+      this.submit();
+    },
+    onReset() {
+      //重置图片验证组件
+      this.$refs.slideverify.reset();
+    },
+    onFail() {},
+    onRefresh() {},
+    submit() {
+      let _this = this;
+      // Dialog.confirm({
+      //   title: this.$t('lang136'),
+      //   message: this.$t('lang137'),
+      //   confirmButtonText: _this.$t('lang111'),
+      //   cancelButtonText: _this.$t('lang135'),
+      // })
+      //   .then(() => {
+      let params = {
+        id: this.$route.query.id,
+        num: this.number,
+        product_list: {},
+      };
+      if (this.product.material_one.length > 0) {
+        params.product_list.material_one = this.materialOneId;
+      }
+      if (this.product.material_two.length > 0) {
+        params.product_list.material_two = this.materialTwoId;
+      }
+      if (this.product.material_three.length > 0) {
+        params.product_list.material_three = this.materialThreeId;
+      }
+      this.loading = true;
+      homeApi.synthesisCreate(params).then(res => {
+        if (res.code == 200) {
+          _this.loading = false;
+          _this.submitPopop = false;
+          Toast({ message: _this.$t('lang318') });
+          _this.$router.push('mine');
+        } else if (res.code == 15001) {
+          _this.loading = false;
+          setTimeout(() => {
+            _this.$router.push('recharge');
+          }, 300);
+        } else {
+          _this.loading = false;
+        }
+      });
+      //     })
+      //     .catch(() => {
+      //       // on cancel
+      //     });
+    },
+    navigatorTo(name, id) {
+      this.$router.push({ name, query: { id: id } });
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  color: rgba(#000, 0.8);
+  letter-spacing: 1.5px;
+  padding: 14px 20px;
+  background: #fff;
+  z-index: 99;
+  .arrow_img {
+    // position: absolute;
+    width: 10px;
+    height: 16px;
+    // transform: translate(0, -50%);
+  }
+}
+.box {
+  position: relative;
+  width: 100%;
+  height: 100vh;
+  padding-top: 50px;
+  box-sizing: border-box;
+
+  .bg {
+    width: 100%;
+    height: 100vh;
+    position: absolute;
+    inset: 0;
+    background-size: 100%;
+    background-position: center;
+    filter: blur(60px);
+    // transform: scale(1.1); /* 防止边缘模糊 */
+    z-index: 1;
+    pointer-events: none; /* 不阻挡点击事件 */
+  }
+  .content {
+    position: relative;
+    z-index: 2;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+    align-items: center;
+    padding: 50px 0 80px;
+    .mb {
+      position: absolute;
+      top: 54px;
+      font-size: 8px;
+      padding: 2px 6px;
+      border-radius: 0 0 4px 4px;
+      box-shadow: 0 2px 2px rgba(#fff, 0.6);
+      background-color: #fd9a34;
+    }
+    .pic {
+      width: 200px;
+      height: 200px;
+      border-radius: 18px;
+      border: 4px solid #fff;
+    }
+    .name {
+      font-size: 17px;
+      letter-spacing: 2px;
+      font-weight: 600;
+      padding: 16px 0;
+    }
+
+    .num {
+      display: flex;
+      align-items: center;
+
+      &_box {
+        display: flex;
+        align-items: center;
+        font-size: 8px;
+        letter-spacing: 1px;
+        margin: 0 5px;
+        .left {
+          color: #000;
+          padding: 2px 4px;
+          border-radius: 3px 0 0 3px;
+          border: 0.5px solid #ffe493;
+          background-color: #ffe493;
+        }
+        .right {
+          padding: 2px 10px;
+          border-radius: 0 3px 3px 0;
+          border: 0.5px solid #fff;
+          border-left: 0;
+        }
+      }
+    }
+    .bottom {
+      width: 100%;
+      margin-top: 30px;
+      padding: 20px 20px 50px;
+      border-radius: 20px 20px 0 0;
+      background-color: #2c2c2c;
+      .title {
+        letter-spacing: 1px;
+        font-size: 15px;
+        font-weight: 600;
+      }
+
+      .list {
+        display: flex;
+        min-width: 100%;
+        overflow: auto;
+        padding-top: 16px;
+        .item {
+          display: flex;
+          width: fit-content;
+          padding: 15px 15px 8px;
+          border-radius: 16px;
+          margin-right: 10px;
+          background-color: #3a3a3a;
+          &_box {
+            margin-right: 10px;
+            display: flex;
+            align-items: center;
+            flex-direction: column;
+          }
+
+          &_top {
+            width: fit-content;
+            font-size: 10px;
+            padding: 4px 10px;
+            border-radius: 6px;
+            border: 1px solid #fff;
+            &_box {
+              font-size: 12px;
+              .desc {
+                letter-spacing: 1px;
+                padding-left: 8px;
+              }
+            }
+          }
+          .progress {
+            width: 100%;
+            overflow: hidden;
+          }
+          &_img {
+            width: 100px;
+            height: 100px;
+            margin: 15px 0 12px;
+            border-radius: 6px;
+          }
+          &_name {
+            display: block;
+            text-align: center;
+            width: 100px;
+            font-size: 14px;
+            font-weight: 600;
+            overflow: hidden; /* 确保超出容器的文本被裁剪 */
+            white-space: nowrap; /* 确保文本在一行内显示 */
+            text-overflow: ellipsis; /* 使用省略号表示文本超出 */
+            padding-bottom: 12px;
+          }
+          .pers {
+            font-size: 13px;
+            font-weight: 600;
+            text-align: center;
+            letter-spacing: 2px;
+            padding: 16px 0 3px;
+          }
+          .pers1 {
+            padding: 6px 0 3px;
+          }
+          .radio {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 100%;
+            padding: 3px 6px;
+            border-radius: 30px;
+
+            background-color: #1d1d24;
+            /deep/.van-radio__label {
+              color: #fff !important;
+              font-size: 12px;
+            }
+            /deep/.van-radio__icon {
+              color: #fff;
+              /deep/.van-icon {
+                font-weight: 700;
+                color: #fff !important;
+              }
+            }
+          }
+        }
+      }
+      .grey {
+        color: #b2b2b2;
+      }
+    }
+    .flex {
+      display: flex;
+      align-items: center;
+    }
+    .sb {
+      justify-content: space-between;
+    }
+    .btn_box {
+      position: fixed;
+      bottom: 0;
+      width: 100%;
+      height: 80px;
+      padding: 16px 20px;
+      background-color: #000;
+      .btn {
+        font-size: 15px;
+        text-align: center;
+        font-weight: 600;
+        letter-spacing: 1px;
+        padding: 12px 10px;
+        border-radius: 22px;
+        background-color: #666666;
+      }
+      .submit {
+        width: 58%;
+        background-color: #17ab79;
+      }
+      .step_box {
+        font-size: 12px;
+        .step {
+          padding-top: 4px;
+        }
+        /deep/.van-stepper__minus,
+        /deep/.van-stepper__plus {
+          color: #fff;
+          border-radius: 0;
+          background-color: #646464;
+        }
+        /deep/.van-stepper__input {
+          width: 60px;
+          color: #fff;
+          margin: 0 1px;
+          background-color: #646464;
+        }
+        /deep/.van-stepper__minus::before,
+        /deep/.van-stepper__plus::before {
+          width: 36%;
+        }
+        /deep/.van-stepper__plus::after {
+          height: 36%;
+        }
+      }
+    }
+  }
+}
+.popup {
+  height: fit-content;
+  color: #363636;
+  font-size: 14px;
+  padding: 20px 0 0;
+  width: 100%;
+  box-sizing: border-box;
+
+  .title {
+    color: #000;
+    font-size: 16px;
+    text-align: center;
+    font-weight: bold;
+    // padding: 0 0 14px;
+  }
+  &_box {
+    flex-direction: column;
+    justify-content: center;
+    text-align: center;
+    .yj {
+      color: #000;
+      font-size: 15px;
+      padding: 8px 0;
+    }
+    .desc {
+      font-size: 13px;
+    }
+    &_num {
+      font-size: 17px;
+      font-weight: 600;
+      color: #ff8e1d;
+    }
+    .table {
+      padding: 20px 30px;
+      &_head {
+        width: 100%;
+        display: flex;
+        color: #727272;
+        padding: 3px 0;
+        background-color: #e2e2e2;
+        span {
+          display: block;
+          width: 50%;
+          text-align: center;
+        }
+      }
+      &_body {
+        width: 100%;
+        display: flex;
+        color: #000;
+        padding: 3px 0;
+        span {
+          display: block;
+          width: 50%;
+          text-align: center;
+        }
+      }
+    }
+  }
+  .submit {
+    width: 100%;
+    &_btn {
+      width: 100%;
+      height: 50px;
+      color: #000;
+      font-size: 16px;
+      border-radius: 0;
+      border: 0;
+      border-top: 1px solid rgba(#c9c9c9, 0.3);
+      background-color: #fff;
+    }
+  }
+  .pt {
+    border-top: 6px solid #f5f5f5;
+  }
+}
+.verify_popup {
+  border-radius: 10px;
+  .title {
+    color: #000;
+    padding: 16px 20px;
+    border-bottom: 1px solid rgba(#d8d8d8, 0.5);
+  }
+  .verify {
+    padding: 16px 16px 16px;
+    background-color: #fff;
+  }
+}
+
+::v-deep .van-overlay {
+  background-color: rgba(#000, 0.3);
+}
+</style>
+  
+  

+ 128 - 0
src/views/rule/index.vue

@@ -0,0 +1,128 @@
+<template>
+  <div class="invite">
+    <div class="head">
+      <img @click="back" src="@/assets/images/back.png" class="arrow_img" />
+      <span>{{ $t('lang298') }}</span>
+    </div>
+    <div class="box">
+      <div class="title">
+        <span> {{ dataObj.title }} </span>
+      </div>
+      <div class="time">
+        <span>{{ dateFormatFn(dataObj.createtime) }}</span>
+      </div>
+      <div class="content">
+        <div v-if="dataObj.img_url">
+          <img :src="dataObj.img_url" class="image" alt="" />
+        </div>
+        <div class="">
+          <span v-html="dataObj.body"></span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+  
+<script>
+import { homeApi } from '@/api/index';
+import { dateFormat } from '@/utils/formatTool.js';
+export default {
+  data() {
+    return {
+      dataObj: {
+        title: undefined,
+        create_time: undefined,
+        body: undefined,
+      },
+    };
+  },
+  mounted() {
+    // this.dataObj = ;
+    this.getData(this.$route.query.id);
+  },
+  methods: {
+    //返回上一页
+    back() {
+      this.$router.back();
+    },
+    dateFormatFn(date) {
+      if (date) {
+        return dateFormat(new Date(date * 1000), 'yyyy-MM-dd');
+      }
+    },
+    getData(id) {
+      let params = {
+        id,
+      };
+      homeApi.getAnnouncementDetail(params).then(res => {
+        if (res.code == 200) {
+          this.dataObj = res.data;
+        }
+      });
+    },
+  },
+};
+</script>
+  
+<style lang="less" scoped>
+.invite {
+  min-height: 100vh;
+  padding-top: 50px;
+  .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;
+    .arrow_img {
+      position: absolute;
+      left: 20px;
+      width: 10px;
+      height: 16px;
+    }
+  }
+  .box {
+    border-radius: 16px;
+    margin: 16px;
+    color: #000;
+    font-size: 13px;
+    padding: 16px;
+    box-shadow: 4px 4px 15px 0px rgba(180, 212, 212, 0.59);
+    background-color: rgba(255, 255, 255, 1);
+    // .flex {
+    //   display: flex;
+    //   align-items: center;
+    //   justify-content: space-between;
+    // }
+
+    .title {
+      font-weight: 550;
+      // text-align: center;
+      color: rgba(#000, 0.86);
+      font-size: 16px;
+      padding-bottom: 16px;
+    }
+    .time {
+      text-align: right;
+      padding-bottom: 16px;
+    }
+    .content {
+      font-size: 13px;
+      color: #2e2e2e;
+      line-height: 200%;
+      padding-top: 16px;
+      border-top: 1px solid rgba(232, 240, 247, 1);
+      .image {
+        width: 100%;
+      }
+    }
+  }
+}
+</style>