| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | type: 'left' //left 从左往右 right 从有王座 |
| | | } |
| | | }, |
| | | |
| | | props: { |
| | | showMore: { |
| | | type: Boolean, |
| | |
| | | [List.name]: List, |
| | | [Cell.name]: Cell, |
| | | ExTabs |
| | | }, |
| | | mounted() { |
| | | }, mounted() { |
| | | this.SET_CURRENCY() |
| | | }, |
| | | methods: { |
| | |
| | | } else if (this.active == 3) { |
| | | this.showList = [...this.listData].sort(this.compare("volume", 'up')) |
| | | } |
| | | this.$forceUpdate() |
| | | this.$forceUpdate(); |
| | | } |
| | | } |
| | | } |
| | |
| | | </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" /> |
| | |
| | | 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" /> |
| | |
| | | <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> |
| | |
| | | <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> |
| | | |
| | |
| | | <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"> |
| | |
| | | </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"> |
| | |
| | | }, |
| | | 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') { |
| | |
| | | }) |
| | | }, |
| | | //数字排序 |
| | | 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; |
| | |
| | | margin-right: 20px; |
| | | } |
| | | } |
| | | .diviLine{ |
| | | |
| | | .diviLine { |
| | | background-color: #f5f5f5; |
| | | } |
| | | .textColor2, .textColor{ |
| | | |
| | | .textColor2, |
| | | .textColor { |
| | | color: #fff; |
| | | } |
| | | |
| | | .deep-div { |
| | | min-height: 370px; |
| | | } |
| | |
| | | </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> |
| | |
| | | <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> |
| | |
| | | // {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}`) |
| | |
| | | <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;"> |
| | |
| | | </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" /> |
| | |
| | | [Tab.name]: Tab |
| | | }, |
| | | props: { |
| | | |
| | | symbol: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | symbol: { |
| | | type: String, |
| | | default: '' |
| | |
| | | order_price_type: 'opponent', // 市价or限价 |
| | | }, |
| | | type: "1",//选中市价或限价类型 |
| | | // currentType: "close", //开仓类型 |
| | | currentType: 'open', // 默认选中买入 |
| | | interval: 0.001, |
| | | marks: (val) => val % 25 === 0, |
| | | isTotal: false, |
| | |
| | | ] |
| | | 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: { |
| | |
| | | .close { |
| | | background-color: #DE5D56; |
| | | // background: url(@/assets/image/public/close-bg.png) no-repeat left center; |
| | | |
| | | |
| | | background-size: 100% 100%; |
| | | color: white; |
| | | } |
| | |
| | | color: $text_color; |
| | | } |
| | | </style> |
| | | |
| | |
| | | <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> |
| | |
| | | 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' |
| | |
| | | }, |
| | | 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') } |
| | | ] |
| | | }, |
| | | { |
| | |
| | | }, |
| | | 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') }, |
| | |
| | | :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> |
| | |
| | | } |
| | | }, |
| | | order() { |
| | | console.log('order', this.direction) |
| | | this.onSubmit(this.direction); |
| | | }, |
| | | onTab(e) { |
| | |
| | | <!-- <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=""> |
| | |
| | | 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'" |
| | |
| | | </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('我知道了') }} |
| | |
| | | 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"; |
| | |
| | | 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", |
| | |
| | | [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(); |
| | |
| | | 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', |
| | |
| | | }), |
| | | }, |
| | | 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: [], |
| | |
| | | }) |
| | | }, |
| | | 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({ |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | span { |
| | | color: $text_color1;; |
| | | color: $text_color1; |
| | | ; |
| | | font-size: 22px; |
| | | line-height: 30px; |
| | | } |
| | |
| | | height: 40px !important; |
| | | margin-top: 8px; |
| | | } |
| | | .content-title{ |
| | | font-size: 28px; |
| | | |
| | | .content-title { |
| | | font-size: 28px; |
| | | } |
| | | </style> |
| | |
| | | <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> |
| | |
| | | }).then(res => { |
| | | userStore.userInfo = {} |
| | | store.state.user.userInfo = {} |
| | | router.push('/login') |
| | | }) |
| | | } |
| | | const getIdentify = () => { |
| | |
| | | </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> |
| | |
| | | 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 = () => { |