lxf
2025-07-16 f96f952d95930e1295051c1bfe348dd324ebf878
添加缓存
11 files modified
358 ■■■■■ changed files
src/components/Transform/list-quotation/index.vue 14 ●●●●● patch | view | raw | blame | history
src/components/Transform/perpetual-open/index.vue 60 ●●●●● patch | view | raw | blame | history
src/components/Transform/popup-delivery/index.vue 21 ●●●●● patch | view | raw | blame | history
src/components/Transform/trade-order-area/index.vue 17 ●●●●● patch | view | raw | blame | history
src/components/foreign/foreign-popup-delivery/index.vue 6 ●●●● patch | view | raw | blame | history
src/config/index.js 5 ●●●●● patch | view | raw | blame | history
src/router/index.js 5 ●●●●● patch | view | raw | blame | history
src/views/cryptos/TrendDetails/index.vue 3 ●●●● patch | view | raw | blame | history
src/views/cryptos/index.vue 198 ●●●●● patch | view | raw | blame | history
src/views/my/newindex.vue 3 ●●●● patch | view | raw | blame | history
src/views/news/index.vue 26 ●●●● patch | view | raw | blame | history
src/components/Transform/list-quotation/index.vue
@@ -30,7 +30,7 @@
                <p class="flex flex-col">
                  <span class="flex items-end font-32 flex items-center">
                    <span class="textColor font-600 font-30">{{ item.name || '--'
                      }}</span>
                    }}</span>
                  </span>
                  <span class="font-24 text-grey text-left">{{ (item.amount * 1).toFixed(2) }}</span>
                </p>
@@ -39,10 +39,8 @@
                <p class="textColor font-32 font-600">{{ item.close || '--' }}</p>
              </li>
              <li class="right flex items-center justify-end">
                <p
                  class="w-153 font-31 h-71 text-white border-0 text-center btn"
                  :class="item.change_ratio > 0 ? 'bg-green' : 'bg-red'"
                >
                <p class="w-153 font-31 h-71 text-white border-0 text-center btn"
                  :class="item.change_ratio > 0 ? 'bg-green' : 'bg-red'">
                  {{ item.change_ratio === 0 ? 0 : item.change_ratio }}%
                </p>
              </li>
@@ -75,6 +73,7 @@
      type: 'left' //left 从左往右 right 从有王座
    }
  },
  props: {
    showMore: {
      type: Boolean,
@@ -98,8 +97,7 @@
    [List.name]: List,
    [Cell.name]: Cell,
    ExTabs
  },
  mounted() {
  }, mounted() {
    this.SET_CURRENCY()
  },
  methods: {
@@ -178,7 +176,7 @@
      } else if (this.active == 3) {
        this.showList = [...this.listData].sort(this.compare("volume", 'up'))
      }
      this.$forceUpdate()
      this.$forceUpdate();
    }
  }
}
src/components/Transform/perpetual-open/index.vue
@@ -34,26 +34,28 @@
                </p>
              </div>
              <div class="mt-22 mb-30" style="position:relative;">
                <div class="greyBg flex justify-between items-center w-full h-76 rounded-lg textColor" @click="selectBtn">
                <div class="greyBg flex justify-between items-center w-full h-76 rounded-lg textColor"
                  @click="selectBtn">
                  <img src="../../../assets/image/public/warn.png" alt="warn-icon" class="w-25 h-25 ml-20" />
                  <div class="text-center" style="width:80%;">{{ title }}</div>
                  <img src="../../../assets/image/public/grey-select.png" alt="select-icon" class="w-22 h-11 mr-20" />
                </div>
                <div class="option-box" v-show="isShow">
                  <div class="font-30" v-for="item in selectData" :key="item.type" @click="selectItem(item)">{{ item.title
                  }}</div>
                  <div class="font-30" v-for="item in selectData" :key="item.type" @click="selectItem(item)">{{
                    item.title
                    }}</div>
                </div>
              </div>
            </template>
            <contract-futrue v-if="selectIndex == 2" class="mb-20"
              :initFutrue="initFutrue" @paraId="onParaId" />
            <contract-futrue v-if="selectIndex == 2" class="mb-20" :initFutrue="initFutrue" @paraId="onParaId" />
            <div class="h-76 lh-76 greyBg mb-30 flex pr-20 justify-center rounded-lg textColor" v-if="selectIndex == 1">
              <input placeholder="" class="greyBg w-full pl-20  h-76 border-none text-left rounded-lg"
                :disabled="type / 1 === 1" @focus="focus = true" v-model="form.price" />
              <span class="ml-20">{{ queryType === 'cryptos' ? 'USDT' : 'USD' }}</span>
            </div>
            <div class=" flex items-center greyBg h-76 lh-76 rounded-lg" style="background-color:#f5f5f5;" v-if="initFutrue" >
            <div class=" flex items-center greyBg h-76 lh-76 rounded-lg" style="background-color:#f5f5f5;"
              v-if="initFutrue">
              <!-- <div v-if="selectIndex == 1 && initFutrue.para && initFutrue.para.length > 0"
                class="w-80 flex items-center justify-center" style="height:100%;" @click="onReduce">
                <img src="../../../assets/image/public/reduce.png" alt="add" class="w-30 h-6" />
@@ -62,8 +64,8 @@
                style="width: 156px;" v-model="form.amount" type="number" @input="onInput" /> -->
              <input v-if="selectIndex == 2 && JSON.stringify(initFutrue.para) != '[]'"
                :placeholder="($t('最少') + initFutrue && initFutrue.para ? $t('最小金额') + initFutrue.para[paraIndex].buy_min : '')"
                class="border-none greyBg text-center textColor" style="width: 226px;background-color:#f5f5f5;" v-model="form.amount" type="number"
                @input="onInput" />
                class="border-none greyBg text-center textColor" style="width: 226px;background-color:#f5f5f5;"
                v-model="form.amount" type="number" @input="onInput" />
              <div class="w-80 flex items-center justify-center" style="height:100%;background-color:#f5f5f5;">
                <template v-if="selectIndex == 1">
                  <img @click="onAdd" src="../../../assets/image/public/add.png" alt="reduce" class="w-30 h-30" />
@@ -88,14 +90,14 @@
              <template v-slot:step="{ active }">
                <div :class="['custom-step', { active }]"></div>
              </template>
            </vue-slider>
            <div style="color: #868D9A" class="mt-36 font-24 w-full flex justify-between items-center">
              <span class="flex-1 text-left">0%</span>
              <span class="flex-1 text-left">25%</span>
              <span class="flex-1 text-center">50%</span>
              <span class="flex-1 text-right">75%</span>
              <span class="flex-1 text-right">100%</span>
            </div> -->
</vue-slider>
<div style="color: #868D9A" class="mt-36 font-24 w-full flex justify-between items-center">
  <span class="flex-1 text-left">0%</span>
  <span class="flex-1 text-left">25%</span>
  <span class="flex-1 text-center">50%</span>
  <span class="flex-1 text-right">75%</span>
  <span class="flex-1 text-right">100%</span>
</div> -->
              <!-- 张数输入 -->
              <amount-slider ref="sliderRef" :maxAmount="getVolumnByLever()" @getAmount="getAmount"></amount-slider>
            </template>
@@ -116,7 +118,7 @@
                <div class="text-grey">{{ $t("建仓手续费") }}</div>
                <div class="textColor">{{ userInfo.perpetual_contracts_status === '1' ? initData.fee *
                  (form.amount / 1) : initData.fee * (form.amount / 1) * form.lever_rate }} {{ queryType === 'cryptos' ?
    'USDT' : 'USD' }}</div>
                  'USDT' : 'USD' }}</div>
              </div>
            </template>
@@ -195,7 +197,8 @@
                <p class="pt-8">{{ $t('登陆后继续') }}</p>
              </div>
              <div class="h-80 lh-80 btnBackground flex text-white rounded-md justify-center mt-50"
                @click="$router.push('/login')">{{ $t('logIn') }}</div>
                @click="$router.push('/login')">
                {{ $t('logIn') }}</div>
            </div>
          </div>
          <!-- <div class="ml-30">
@@ -286,8 +289,8 @@
        </div>
      </div>
      <van-popup v-model:show="show" class="rounded-2xl">
        <popup-delivery style="padding: 10px;" showBtns :detailData="detailData" :key="detailData.order_no" @close="onClose"
          @continueToBuy="continueTobuy" @timeEnd="handleTimeEnd" :price="price" />
        <popup-delivery style="padding: 10px;" showBtns :detailData="detailData" :key="detailData.order_no"
          @close="onClose" @continueToBuy="continueTobuy" @timeEnd="handleTimeEnd" :price="price" />
      </van-popup>
      <van-action-sheet v-model:show="isSelectShow" @select="onSelect" :actions="actions" :cancel-text="$t('取消')"
        close-on-click-action @cancel="onCancel">
@@ -638,9 +641,10 @@
    },
    continueTobuy(detailData) {
      this.show = false
      setTimeout(() => {
        this.$router.push(`/trendDetails/${detailData.symbol}?direction=${detailData.direction}`)
      }, 300);
      // this.order()
      // setTimeout(() => {
      //   this.$router.push(`/trendDetails/${detailData.symbol}?direction=${detailData.direction}`)
      // }, 300);
    },
    onQuickPrice(price) { // 点击金额变化
      if (this.type === '2') {
@@ -839,7 +843,7 @@
      })
    },
    //数字排序
    orderListAsc(filed, type = "asc"){
    orderListAsc(filed, type = "asc") {
      return (a, b) => {
        if (type == "asc") return parseFloat(a[filed]) > parseFloat(b[filed]) ? 1 : -1;
        return parseFloat(a[filed]) > parseFloat(b[filed]) ? -1 : 1;
@@ -1062,12 +1066,16 @@
    margin-right: 20px;
  }
}
.diviLine{
.diviLine {
  background-color: #f5f5f5;
}
.textColor2, .textColor{
.textColor2,
.textColor {
  color: #fff;
}
.deep-div {
  min-height: 370px;
}
src/components/Transform/popup-delivery/index.vue
@@ -17,8 +17,10 @@
        </van-circle>
      </div>
      <div class="mt-45 font-50 text-center"
        :class="{ 'text-green': detailData.profit_state === '1', 'text-red': detailData.profit_state === '0' }" v-else>{{
          $t('服务费') }}<span>{{ detailData.profit_state === '1' ? '+' : '' }}{{ detailData.profit }}</span> {{ routeType == 'cryptos' ? 'USDT' : 'USD' }}</div>
        :class="{ 'text-green': detailData.profit_state === '1', 'text-red': detailData.profit_state === '0' }" v-else>
        {{
          $t('服务费') }}<span>{{ detailData.profit_state === '1' ? '+' : '' }}{{ detailData.profit }}</span> {{ routeType ==
          'cryptos' ? 'USDT' : 'USD' }}</div>
      <ul class="flex flex-col pb-61 textColor">
        <li v-for="item in listItem" :key="item.id" class="flex justify-between px-38 mt-28">
          <p class="text-grey font-30">{{ item.text }}</p>
@@ -37,12 +39,12 @@
          <p class="font-30 " :class="colorChoose(item)" v-else>{{ handleBuyWord(item) }}</p>
        </li>
      </ul>
      <div v-if="showBtns" class="flex justify-between text-white px-38 pb-61">
      <div v-if="showBtns" class="flex justify-center text-white px-38 pb-61">
        <p :class="{ 'btnMain': detailData.state !== 'created', 'bgDark': detailData.state === 'created' }"
          class="w-255 h-90 rounded-lg flex justify-center items-center mr-20" @click="onClose">{{ $t('关闭') }}</p>
        <p @click="continueToBuy"
        <!-- <p @click="continueToBuy"
          :class="{ 'btnMain': detailData.state === 'created', 'bgDark': detailData.state !== 'created', 'disableBtn': disabled }"
          class="w-385 h-90 rounded-lg flex justify-center items-center">{{ $t('继续下单') }}</p>
          class="w-385 h-90 rounded-lg flex justify-center items-center">{{ $t('继续下单') }}</p> -->
      </div>
    </div>
  </div>
@@ -138,14 +140,15 @@
      //     {id: 4, text: '数量', key: 'amount', extro: 'USDT'},
      //     {id: 5, text: '交割时间', key: 'settlement_time'}
      // ]
      routeType:'cryptos'
      routeType: 'cryptos'
    }
  },
  methods: {
    continueToBuy() {
      if (this.detailData.state !== 'created') {
        return
      }
      console.log('detailData: ', this.detailData)
      // if (this.detailData.state !== 'created') {
      //   return
      // }
      this.$emit('continueToBuy', this.detailData)
      //this.$router.push(`/trendDetails/${symbol}`)
src/components/Transform/trade-order-area/index.vue
@@ -2,9 +2,9 @@
  <div class="flex flex-col flex-1 font-28" style="width: 280px;">
    <div class="flex items-center h-66 tabBackground text-grey">
      <p class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'open' ? 'open' : ''" @click="changeTab('open')">{{ $t('买入') }}</p>
        :class="currentType === 'open' ? 'open' : ''" @click="currentType = 'open'">{{ $t('买入') }}</p>
      <p class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'close' ? 'close' : ''" @click="changeTab('close')">{{ $t('卖出') }}</p>
        :class="currentType === 'close' ? 'close' : ''" @click="currentType = 'close'">{{ $t('卖出') }}</p>
    </div>
    <div class="mt-22 mb-22 inputBackground" style="position:relative;">
@@ -18,6 +18,7 @@
        </div>
      </div>
    </div>
    <!-- {{ form }} -->
    <div class="h-70 lh-70  inputBackground mb-25 flex justify-center px-16 textColor2">
      <input placeholder="" class="targetPrice  w-full  h-70 border-none" v-model="form.price"
        :disabled="type / 1 === 1" />
@@ -90,11 +91,6 @@
    [Tab.name]: Tab
  },
  props: {
    symbol: {
      type: String,
      default: ''
    },
    symbol: {
      type: String,
      default: ''
@@ -167,7 +163,7 @@
        order_price_type: 'opponent', // 市价or限价
      },
      type: "1",//选中市价或限价类型
      // currentType: "close", //开仓类型
      currentType: 'open', // 默认选中买入
      interval: 0.001,
      marks: (val) => val % 25 === 0,
      isTotal: false,
@@ -181,7 +177,7 @@
    ]
    this.title = this.selectData[0].title
    this.type = this.selectData[0].type
    // this.currentType = this.currentTypes
    // this.currentType = this.currentTypes
    this.form.order_price_type = 'opponent'
  },
  methods: {
@@ -482,7 +478,7 @@
.close {
  background-color: #DE5D56;
  // background: url(@/assets/image/public/close-bg.png) no-repeat left center;
  background-size: 100% 100%;
  color: white;
}
@@ -589,4 +585,3 @@
  color: $text_color;
}
</style>
src/components/foreign/foreign-popup-delivery/index.vue
@@ -36,12 +36,12 @@
        <p class="font-30 " :class="colorChoose(item)" v-else>{{ handleBuyWord(item) }}</p>
      </li>
    </ul>
    <div v-if="showBtns" class="flex justify-between text-white px-18 pb-30">
    <div v-if="showBtns" class="flex justify-center text-white px-18 pb-30">
      <p :class="{ 'btnMain': detailData.state !== 'created', 'bgDark': detailData.state === 'created' }"
        class="w-122 h-44 rounded-lg flex justify-center items-center mr-10" @click="onClose">{{ $t('close') }}</p>
      <p @click="continueToBuy"
      <!-- <p @click="continueToBuy"
        :class="{ 'btnMain': detailData.state === 'created', 'bgDark': detailData.state !== 'created', 'disableBtn': disabled }"
        class="w-162 h-44 rounded-lg flex justify-center items-center">{{ $t('继续下单') }}</p>
        class="w-162 h-44 rounded-lg flex justify-center items-center">{{ $t('继续下单') }}</p> -->
    </div>
  </div>
</template>
src/config/index.js
@@ -7,7 +7,12 @@
export const REQUEST_TIMEOUT = 30000
// 请求频率
// 全局基础超时时间
export const TIME_OUT = 2000
// 行情轮询间隔(毫秒) - 优化性能调整为5秒
export const QUOTE_POLLING_INTERVAL = 5000
// 缓存过期时间(毫秒)
export const CACHE_EXPIRE = 5 * 60 * 1000 // 5分钟
// 表单类型key
export const CONTENT_TYPE = 'Content-Type'
src/router/index.js
@@ -107,8 +107,8 @@
        },
        component: () => import('@/views/Layout.vue'),
        children: [
          { path: 'index', meta: { tarbar: false, keepAlive: true }, component: () => import('@/views/position/newindex.vue') },
          // { path: 'index', meta: { tarbar: false, keepAlive: true }, component: () => import('@/views/position/index.vue') },
          { path: 'index', meta: { tarbar: false, keepAlive: true }, component: () => import(/* webpackChunkName: "cryptos" */ /* webpackPrefetch: true */ '@/views/cryptos/index.vue') }
          // { path: 'index', meta: { tarbar: false, keepAlive: true }, component: () => import(/* webpackChunkName: "cryptos" */ /* webpackPrefetch: true */ '@/views/cryptos/index.vue') }
        ]
      },
      {
@@ -184,6 +184,7 @@
        },
        component: () => import('@/views/Layout.vue'),
        children: [
          { path: 'index', meta: { tarbar: false, keepAlive: true }, component: () => import(/* webpackChunkName: "cryptos" */ /* webpackPrefetch: true */ '@/views/cryptos/index.vue') },
          { path: 'announce', meta: { tarbar: false, keepAlive: true }, component: () => import('@/views/cryptos/Announce/index.vue') },
          { path: 'announceDetail', meta: { tarbar: false, keepAlive: true }, component: () => import('@/views/cryptos/Announce/announceDetail.vue') },
          { path: 'exchangePage', meta: { tarbar: false, keepAlive: true }, component: () => import('@/views/cryptos/Exchange/exchangePage.vue') },
src/views/cryptos/TrendDetails/index.vue
@@ -219,7 +219,7 @@
          :balance="initFutrue.amount" :price="quote.close" @close="onClose" @confirm="onOrderConfirm"
          v-if="popType === 'confirm'" />
        <popup-delivery showBtns :detailData="detailData" :key="detailData.order_no" @close="onClose"
          @continueToBuy="order()" @timeEnd="handleTimeEnd" :price="quote.close" v-else />
          @continueToBuy="order" @timeEnd="handleTimeEnd" :price="quote.close" v-else />
      </van-popup>
    </div>
  </div>
@@ -338,6 +338,7 @@
      }
    },
    order() {
      console.log('order', this.direction)
      this.onSubmit(this.direction);
    },
    onTab(e) {
src/views/cryptos/index.vue
@@ -4,7 +4,7 @@
    <!-- <ioe-swiper /> -->
    <!-- <div class="py-10"> -->
    <!-- <van-notice-bar class="font-26 textColor" left-icon="" :scrollable="false" background="transparent">
      <div slot="left-icon" class=" flex items-center more-img"><img class="w-20 h-20  more-img"
          src="../../assets/Horn.png" alt="">
@@ -17,7 +17,7 @@
          class="w-20 h-20 more-img" src="../../assets/more.png" alt="">
      </div>
    </van-notice-bar> -->
  <!-- </div> -->
    <!-- </div> -->
    <!-- <cry-nav /> -->
    <!-- <div class="quickly">
      <div class="quickBox chongbi" :class="THEME == 'dark' ? 'dark' : 'white'"
@@ -42,13 +42,13 @@
      </div>
    </div> -->
    <!-- <ex-hot :listData="hList"></ex-hot> -->
    <list-quatation :listData="qList" @onfetchQList="fetchQList"/>
    <list-quatation :listData="qList" :hList="filteredHList" @onfetchQList="fetchQList" />
    <van-popup v-model:show="item.showPopUp" style="border-radius:10px;" :close-on-click-overlay="false"
      v-for="item in popupNewsList" :key="item.id">
      <div class="w-350 p-20 box-border">
        <div class="font-700 text-center font-28 textColor">{{ item.title }}</div>
        <div class="flex justify-center mt-30" v-if="item.imgUrl"><img
            :src="`${item.imgUrl}`" class="w-200 h-200" alt="" /></div>
        <div class="flex justify-center mt-30" v-if="item.imgUrl"><img :src="`${item.imgUrl}`" class="w-200 h-200"
            alt="" /></div>
        <div class="py-10 textColor   content-title" v-html="item.content"></div>
        <van-button color="#1194F7" class="w-full h-40 rounded-full" type="info" @click="closePopNotice(item)">
          {{ $t('我知道了') }}
@@ -62,7 +62,7 @@
import IoeSwiper from "@/components/Transform/ioe-swiper/index.vue";
import ListQuatation from "@/components/Transform/list-quotation/index.vue";
import { mapGetters, mapActions } from "vuex";
import { TIME_OUT } from "@/config";
import { TIME_OUT, QUOTE_POLLING_INTERVAL, CACHE_EXPIRE } from "@/config";
import { SET_COIN_LIST } from '@/store/const.store'
import { _getHomeList } from '@/service/cryptos.api'
import ExHeader from "@/components/Transform/ex-header/index.vue";
@@ -73,7 +73,7 @@
import { _getUnreadMsg } from '@/service/im.api'
import { _getNewsList1, _getPopupNews } from '@/service/user.api'
import { BASE_URL } from "@/config";
import { _getCoinList } from '@/service/quotes.api';
import { _getCoinList } from '@/service/quotes.api';
const THEME = 'dark'
export default {
  name: "HomePage",
@@ -87,6 +87,14 @@
    [Swipe.name]: Swipe,
    [SwipeItem.name]: SwipeItem,
  },
  watch: {
    hotArr(newVal) {
      // 当热门币种列表更新时重新计算hList
      if (this.qList && newVal.length) {
        this.hList = this.qList.filter(item => newVal.includes(item.symbol)).slice(0, 3);
      }
    }
  },
  async created() {
    this.init();
    this.checkingMesk();
@@ -94,6 +102,17 @@
    await this.fetchQList()
  },
  computed: {
    // 优化:使用计算属性高效生成热门列表
    filteredHList() {
      const result = [];
      for (const item of this.qList) {
        if (this.hotArr.includes(item.symbol)) {
          result.push(item);
          if (result.length >= 3) break;
        }
      }
      return result;
    },
    ...mapGetters({
      coinList: 'home/coinList',
      currency: 'home/currency',
@@ -103,19 +122,20 @@
    }),
  },
  data() {
    const arr = [] // 初始化数据
    for (let i = 0; i < 10; i++) {
      arr.push({ id: i })
    }
    // 优先从localStorage加载缓存数据
    const cachedData = getStorage('qoutes');
    const now = Date.now();
    const isCacheValid = cachedData && cachedData.timestamp && (now - cachedData.timestamp < CACHE_EXPIRE);
    return {
      BASE_URL,
      THEME,
      account: "",
      hList: arr.slice(0, 3), // 热门
      qList: arr, // 行情列表
      qList: isCacheValid ? cachedData.data : [], // 行情列表 - 优先使用缓存
      active: 0,
      timeout: null,
      loading: true,
      loading: !isCacheValid, // 有缓存数据时不显示加载状态
      announceTitle: '',
      announceId: '',
      announceList: [],
@@ -135,61 +155,79 @@
      })
    },
    async fetchQList(v) { // 获取行情
      let coninArr = ''
      // if (v) { this.getVal = v }
      let arr = getStorage('qoutes')
      // 优化:使用缓存数据快速展示,同时后台更新
      const cachedQuotes = getStorage('quotes');
      if (cachedQuotes && cachedQuotes.data && Date.now() - cachedQuotes.timestamp < CACHE_EXPIRE) {
        this.qList = cachedQuotes.data;
        this.hList = cachedQuotes.data.filter(item => this.hotArr.includes(item.symbol)).slice(0, 3);
        this.loading = false;
        return;
      }
      // 优先用本地缓存的 coins
      let coins = (arr && arr.coins && arr.coins.length) ? arr.coins : arr
      // 优化:变量名修正与符号拼接
      let coinArr = '';
      const arr = getStorage('quotes');
      const coins = (arr && arr.coins && arr.coins.length) ? arr.coins : arr;
      if (coins && coins.length) {
        // 如果本地有 coins,优先用本地
        coins.forEach(item => {
          coninArr += item.symbol + ','
        })
        // 优化:使用map和join提升性能
        coinArr = coins.map(item => item.symbol).join(',');
      } else {
        // 如果本地没有 coins,拉取接口
        const quotesData = await _getCoinList()
        if (quotesData && quotesData.coins && quotesData.coins.length) {
          quotesData.coins.forEach(item => {
            coninArr += item.symbol + ','
          })
        const quotesData = await _getCoinList().catch(err => {
          console.error('获取币种列表失败:', err);
          this.loading = false; // 错误状态处理
          return null;
        });
        if (quotesData?.coins?.length) {
          coinArr = quotesData.coins.map(item => item.symbol).join(',');
        }
      }
      console.log('fetchQList', v, coninArr)
      // if()
      const list = await _getHomeList(coninArr).catch(() => {
        //请求失败时,1秒后重试
        this.timeout = setTimeout(() => {
          this.fetchQList()
        }, 1000)
      })
      if (!(list instanceof Array)) {
        return
      }
      // console.log('接口:_getHomeList 热门:',list)
      this.loading = false
      // this.qList = list.slice(0,10);
      this.qList = list;
      const list = await _getHomeList(coinArr).catch(err => {
        console.error('获取行情列表失败:', err);
        this.loading = false;
        return [];
      });
      //请求失败时,1秒后重试
      this.timeout = setTimeout(() => {
        this.fetchQList();
      }, 1000);
      this.hList = list.filter(item => this.hotArr.includes(item.symbol));
      if (this.hList.length == 4) {
        this.hList.pop()
      // console.log('接口:_getHomeList 热门:',list)
      this.loading = false;
      // 优化:仅在获取有效数据时更新
      if (list.length) {
        // 冻结数据减少响应式开销提升性能
        this.qList = Object.freeze(list);
        setStorage('quotes', { data: list, timestamp: Date.now() });
      }
      console.log(this.hList)
      if (this.timeout) {
        clearTimeout(this.timeout)
      }
      // 检查缓存是否有效
      const cacheData = getStorage('quotes');
      const now = Date.now();
      const isCacheValid = cacheData && cacheData.timestamp && (now - cacheData.timestamp < CACHE_EXPIRE);
      this.timeout = setTimeout(async () => {
        await this.fetchQList()
      }, TIME_OUT)
        // 如果缓存有效则直接使用缓存数据
        // if (isCacheValid) {
        //   this.qList = cacheData.data;
        //   this.hList = cacheData.data.filter(item => this.hotArr.includes(item.symbol));
        //   if (this.hList.length === 4) this.hList.pop();
        // } else {
        await this.fetchQList();
        // }
      }, QUOTE_POLLING_INTERVAL);
    },
    getNews() {
      _getNewsList1({
        language: this.$i18n.locale,
      }).then(res => {
        this.announceList = res
      })
        this.announceList = res;
      });
    },
    getPopupNews() {
      _getPopupNews({
@@ -200,62 +238,70 @@
          if (!getStorage('popNotice')) {
            let list = res
            list.forEach(item => {
              item.showPopUp = true
            })
              item.showPopUp = true;
            });
            this.popupNewsList = list
          }
        }
      })
    },
    closePopNotice(item) {
      item.showPopUp = false
      setStorage('popNotice', true)
      item.showPopUp = false;
      setStorage('popNotice', true);
    },
    toAnnounceDetail(announceId) {
      if (announceId) {
        this.$router.push({ path: '/cryptos/AnnounceDetail', query: { id: announceId } })
        this.$router.push({ path: '/cryptos/AnnounceDetail', query: { id: announceId } });
      }
    },
    onClickLeft() { },
    onClickRight() { },
    startTimeout() {
      this.clearTimeout()
      this.fetchQList()
      this.clearTimeout();
      this.fetchQList();
    },
    clearTimeout() {
      if (this.timeout) {
        clearTimeout(this.timeout)
        this.timeout = null
        clearTimeout(this.timeout);
        this.timeout = null;
      }
    }
  },
  async created() {
    this.getNews();
    this.getPopupNews()
    await this.SET_COIN_LIST('cryptos')
    this.startTimeout()
    this.getPopupNews();
    this.startTimeout(); // 优先执行缓存加载
    await this.SET_COIN_LIST('cryptos');
    // 缓存已加载,重新计算hList
    if (this.qList && this.qList.length) {
      this.hList = this.qList.filter(item => this.hotArr.includes(item.symbol)).slice(0, 3);
    }
  },
  async activated() {
    this.getNews()
    this.getPopupNews()
    await this.SET_COIN_LIST('cryptos')
    this.startTimeout()
    this.getNews();
    this.getPopupNews();
    this.startTimeout(); // 优先执行缓存加载
    await this.SET_COIN_LIST('cryptos');
    // 缓存已加载,重新计算hList
    if (this.qList && this.qList.length) {
      this.hList = this.qList.filter(item => this.hotArr.includes(item.symbol)).slice(0, 3);
    }
    if (this.userInfo.token) {
      this.fetchUnread()
      this.unreadMsg_timer = setInterval(() => { this.fetchUnread() }, 5000);
      this.fetchUnread();
      this.unreadMsg_timer = setInterval(() => { this.fetchUnread(); }, 5000);
    } else {
      this.unreadMsg_num = ''
      this.unreadMsg_num = '';
    }
  },
  deactivated() {
    this.clearTimeout()
    this.clearTimeout();
    if (this.unreadMsg_timer) {
      clearInterval(this.unreadMsg_timer);
      this.unreadMsg_timer = null;
    }
  },
  beforeUnmount() {
    this.clearTimeout()
    this.clearTimeout();
    if (this.unreadMsg_timer) {
      clearInterval(this.unreadMsg_timer);
      this.unreadMsg_timer = null;
@@ -336,7 +382,8 @@
    }
    span {
      color: $text_color1;;
      color: $text_color1;
      ;
      font-size: 22px;
      line-height: 30px;
    }
@@ -485,7 +532,8 @@
  height: 40px !important;
  margin-top: 8px;
}
.content-title{
  font-size: 28px;
.content-title {
  font-size: 28px;
}
</style>
src/views/my/newindex.vue
@@ -41,7 +41,7 @@
      <div class="mt-15 p-15 rounded-15 bg-#f5f7f9">
        <div v-for="(item, index) in helpItems" :key="index" class="flex items-center justify-between text-16"
          :class="{ 'mt-15': index > 0 }" @click="onRoute(item.path)">
          <div v-if="item.button" class="flex items-center" @click="loginOut">
          <div v-if="item.button" class="flex items-center" @click.stop="loginOut">
            <img :src="`${item.icon}`" class="w-20 h-20">
            <div class="ml-10">{{ item.title }}</div>
          </div>
@@ -201,6 +201,7 @@
  }).then(res => {
    userStore.userInfo = {}
    store.state.user.userInfo = {}
    router.push('/login')
  })
}
const getIdentify = () => {
src/views/news/index.vue
@@ -104,13 +104,11 @@
    </div>
    <div class="px-17 mt-10">
      <!-- 新闻条目1 -->
      <div class="rounded-5 overflow-hidden mb-10" v-for="(t, i) in list" :key="t.dataId">
        <div class="bg-#f5f7f9 py-12 px-15 " @click="openOriginUrl(t.originUrl)">
      <div class="rounded-5 overflow-hidden mb-10" v-for="(t) in list" :key="t.dataId">
        <div class="bg-#f5f7f9 py-12 px-15 ">
          <div class="flex" style="border-bottom: 1px solid rgb(209, 209, 209);">
            <div class="text-12 h-70 flex-1 line3">{{ t.description }}</div>
            <!-- <img class="w-90 h-55 flex-none rounded-10 ml-10"
              :src="t.img"
              draggable="false"> -->
            <div class="text-12 h-70 flex-1 line3">{{ t.title }}</div>
            <img class="w-90 h-55 flex-none rounded-10 ml-10" :src="t.imgUrl" draggable="false">
          </div>
          <div class="mt-5 text-10 text-#8c8c8c flex justify-between">
            <span>{{ t.createTime }}</span>
@@ -163,14 +161,14 @@
  goToPage('/customerService')
}
const goToPage = (path) => {
    if(path=='/mining'){
        showToast({
          message: 'Stay tuned',
          position: 'bottom',
        })
    }else{
        router.push(path)
    }
  if (path == '/mining') {
    showToast({
      message: 'Stay tuned',
      position: 'bottom',
    })
  } else {
    router.push(path)
  }
}
const getInformationList = () => {