1
2026-05-23 30d1ee7be942d7a2201e1ab2ca7d96badff8bf50
src/views/homePage/index.vue
@@ -1,5 +1,5 @@
<template>
    <div class="home_page mainBackground textColor">
    <div class="home_page  textColor" style="background-color: #f6f5fa;">
        <Head @search="onSearch"></Head>
        <!-- <div class="home_logo flex justify-center"><img src="@/assets/imgs/home/home_logo.png" alt=""></div> -->
@@ -9,11 +9,14 @@
            <van-swipe-item><img src="@/assets/imgs/home/Slider-3.jpg" alt=""></van-swipe-item>
            <van-swipe-item><img src="@/assets/imgs/home/Slider-4.jpg" alt=""></van-swipe-item>
        </van-swipe> -->
        <video autoplay loop muted playsinline class="home_logo">
            <source src="@/assets/video/home_1.mp4" type="video/mp4">
            您的浏览器不支持 video 标签。
        </video>
        <div class="flex flex-col items-center justify-center home-kyc-block" @click="toPage('/certificationCenter')">
            <img style="width: 100%;border-radius: 10px;" src="@/assets/imgs/new/kyc-reward.png" alt="">
            <!-- <div style="font-size: 25px;">{{ $t('kycLotteryBroadcast') }}</div>
            <div style="font-size: 12px;">{{ $t('kycLotterySubtitle') }}</div> -->
        </div>
        <!-- <video autoplay loop muted playsinline class="home_logo"> -->
            <!-- <source src="@/assets/video/home_1.mp4" type="video/mp4"> -->
        <!-- </video> -->
        <!-- <div class="text-center font-bold mt-8 logo_text">{{ $t('复制财富,從此刻開始') }}</div>
        <div class="text-center mt-2 logo_text_small">{{ $t('超6000種熱門交易類別,立即註冊领取5000USDT') }}!</div> -->
@@ -25,29 +28,38 @@
            <div class="login_but_d text-center" @click="toPage('/login')">{{ $t('登录') }}</div>
        </div>
        <div class="home_grid flex justify-start flex-wrap">
            <div class="grid_item pt-10" v-for="value in tabbers" :key="value.key" @click="toPage(value.path)">
        <!-- 轮播图:使用本地两张图片,带圆角 -->
        <div class="home_banner mp-20">
            <van-swipe
                class="home_banner_swipe"
                :autoplay="4000"
                :show-indicators="false"
                @change="onBannerChange"
            >
                <van-swipe-item
                    v-for="(item, index) in bannerImages"
                    :key="index"
                    class="home_banner_item"
                    @click="onBannerClick(item)"
                >
                    <img :src="item.img" :alt="item.alt" class="home_banner_img" />
                </van-swipe-item>
            </van-swipe>
            <div class="home_banner_indicator">
                <span
                    v-for="(_, i) in bannerImages"
                    :key="i"
                    class="home_banner_dot"
                    :class="{ active: currentBanner === i }"
                />
            </div>
        </div>
        <div class="home_grid flex justify-start flex-wrap home_grid_bg mt-10 pt-8" style="height: 110px;">
            <div class="grid_item" v-for="value in tabbers" :key="value.key" @click="onGridClick(value)">
                <div class="grid_item_img flex justify-center"><img :src="value.icon" alt=""></div>
                <div class="text-center mt-2">{{ value.name }}</div>
            </div>
        </div>
        <!-- 新闻 -->
        <!-- <van-notice-bar class="font-26 mt-10 index_notice" background="#fafbfc" :scrollable="false" wrapable
            color="#333333">
            <van-swipe vertical class="notice-swipe" :autoplay="2000" :show-indicators="false">
                <van-swipe-item v-for="item in announceList" :key="item.id" @click="toAnnounceDetail(item.uuid)">
                    <div class="flex justify-start items-center">
                        <img :src="item.imgUrl" alt="" class="notice_img mr-5">
                        <div class="notice_content">
                            <div>{{ item.startTime }}</div>
                            <div>{{ item.title }}</div>
                        </div>
                    </div>
                </van-swipe-item>
            </van-swipe>
        </van-notice-bar> -->
        <!-- <div class="flex justify-between mt-10">
            <van-swipe class="home_swipe_1" :autoplay="2000">
                <van-swipe-item v-for="value in swipe1" :key="value.key" class="flex justify-center items-center">
@@ -79,23 +91,159 @@
</div>
</div> -->
        <div id="cryptos" class="pt-10">
            <list-quatation :listData="qList" :tabShow="false" :tabActive="2" />
        <!-- 列表区:Favorites / Markets 切换 -->
        <div id="cryptos" class="pt-10 home-list-section">
            <div class="home-list-tabs">
                <span class="home-list-tab" :class="{ active: listMode === 'favorites' }" @click="listMode = 'favorites'">{{ $t('favorites') }}</span>
                <span class="home-list-tab" :class="{ active: listMode === 'markets' }" @click="listMode = 'markets'">{{ $t('markets') }}</span>
            </div>
            <list-quatation :listData="displayedList" :tabShow="false" :tabActive="2" />
            <div
                v-if="!showMoreList && currentList.length > listInitialCount"
                class="home-list-more"
                @click="showMoreList = true"
            >
                {{ $t('展示更多') }}
            </div>
            <!-- HOT COINS:横向滚动卡片 -->
            <div class="home-hot-coins">
                <div class="home-hot-title">{{ $t('HOT COINS') }}</div>
                <div class="home-hot-subtitle">{{ $t('The popular cryptocurrency') }}</div>
                <div class="home-hot-scroll">
                    <div
                        v-for="item in hotCoinsList"
                        :key="item.symbol_data"
                        class="home-hot-card"
                        @click="toQuote(item)"
                    >
                        <img :src="item.symbol ? `${HOST_URL}/symbol/${item.symbol_data}.png` : ''" alt="" class="home-hot-logo" />
                        <div class="home-hot-symbol">{{ (item.symbol_data || '').toUpperCase() }}</div>
                        <div class="home-hot-pct" :class="(item.change_ratio || 0) >= 0 ? 'up' : 'down'">
                            {{ (item.change_ratio || 0) >= 0 ? '↗' : '↘' }} {{ (item.change_ratio != null ? item.change_ratio : 0).toFixed(2) }}%
                        </div>
                    </div>
                </div>
            </div>
            <!-- Trend / Follow / News / IPO 切换 -->
            <div class="home-trend-tabs">
                <span class="home-trend-tab" :class="{ active: trendTab === 'trend' }" @click="trendTab = 'trend'">{{ $t('trend') }}</span>
                <span class="home-trend-tab" :class="{ active: trendTab === 'follow' }" @click="trendTab = 'follow'">{{ $t('follow') }}</span>
                <span class="home-trend-tab" :class="{ active: trendTab === 'news' }" @click="trendTab = 'news'">{{ $t('news') }}</span>
                <span class="home-trend-tab" :class="{ active: trendTab === 'ipo' }" @click="trendTab = 'ipo'">{{ $t('ipo') }}</span>
            </div>
            <!-- Trend:riseBg.jpg 背景 + 3 条数据 -->
            <div v-if="trendTab === 'trend'" class="home-trend-card home-trend-card--bg">
                <div class="home-trend-card-inner">
                    <div class="home-trend-heading">{{ $t('trend') }}</div>
                    <div class="home-trend-subtitle">{{ $t('trendSubtitle') }}</div>
                    <div class="home-trend-list">
                        <div
                            v-for="item in trendList"
                            :key="item.symbol_data"
                            class="home-trend-item"
                            @click="toQuote(item)"
                        >
                            <img :src="item.iconUrl || ''" alt="" class="home-trend-logo" />
                            <div class="home-trend-info">
                                <span class="home-trend-name">{{ item.symbol_data }}</span>
                            </div>
                            <div class="home-trend-right">
                                <span class="home-trend-price">{{ (item.close || 0).toFixed(3) }}</span>
                                <span class="home-trend-pct up">↗ {{ (item.change_ratio != null ? item.change_ratio : 0).toFixed(2) }}%</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!-- News:news!getUsHeadNews.action -->
            <div v-else-if="trendTab === 'news'" class="home-trend-card home-trend-card--news">
                <div class="home-trend-card-inner">
                    <div class="home-trend-heading home-trend-heading--dark">{{ $t('news') }}</div>
                    <div v-if="newsLoading" class="home-trend-card--empty-inner">
                        <van-loading type="spinner" size="24" />
                        <div class="home-empty-text mt-8">{{ $t('加载中...') }}</div>
                    </div>
                    <div v-else-if="newsListForTab.length" class="home-news-list">
                        <div
                            v-for="(item, index) in newsListForTab"
                            :key="(item.url || item.uuid) || index"
                            class="home-news-item"
                            @click="onNewsItemClick(item)"
                        >
                            <div v-if="item.urlToImage" class="home-news-thumb">
                                <img :src="item.urlToImage" alt="" />
                            </div>
                            <div class="home-news-body">
                                <div class="home-news-title textColor">{{ item.title }}</div>
                                <div class="home-news-meta">
                                    <div class="home-news-date text-grey">{{ item.author }}</div>
                                    <span class="home-news-detail text-grey">{{ $t('详情') }}</span>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div v-else class="home-trend-card--empty-inner">
                        <img :src="emptyImg" alt="" class="home-empty-img" />
                        <div class="home-empty-text">{{ $t('暂无数据') }}</div>
                    </div>
                </div>
            </div>
            <!-- Follow / IPO:empty.png 暂无数据 -->
            <div v-else class="home-trend-card home-trend-card--empty">
                <img :src="emptyImg" alt="" class="home-empty-img" />
                <div class="home-empty-text">{{ $t('暂无数据') }}</div>
            </div>
        </div>
        <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 popup_news">
                <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="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('我知道了') }}
                </van-button>
            </div>
        </van-popup>
        <!-- 新闻详情弹层(站内展示,不跳外链) -->
        <van-popup v-model:show="showNewsDetailPopup" round position="bottom" :style="{ height: '88%' }" class="news-detail-popup">
            <div class="news-detail-inner" v-if="selectedNewsDetail">
                <div class="news-detail-drag-bar" />
                <div class="news-detail-header">
                    <span class="news-detail-source">{{ selectedNewsDetail.sourceName || '' }}</span>
                </div>
                <h2 class="news-detail-title textColor">{{ selectedNewsDetail.title }}</h2>
                <div class="news-detail-img-wrap" v-if="selectedNewsDetail.urlToImage">
                    <img :src="selectedNewsDetail.urlToImage" alt="" class="news-detail-img" />
                </div>
                <div class="news-detail-content textColor">
                    {{ selectedNewsDetail.description || selectedNewsDetail.content || '' }}
                </div>
                <van-button color="#1194F7" class="news-detail-close" block round @click="showNewsDetailPopup = false">
                    {{ $t('关闭') }}
                </van-button>
            </div>
        </van-popup>
    </div>
</template>
<script setup>
import Head from './components/head.vue'
import { useI18n } from "vue-i18n";
import { ref, computed, onBeforeUnmount } from 'vue';
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { useRouter } from 'vue-router';
import ListQuatation from "@/components/Transform/list-quotation/index.vue";
import { _getHomeList } from '@/service/cryptos.api'
import { _getNewsList1, _getPopupNews } from '@/service/user.api'
import { _getNewsList1, _getPopupNews, _getUsHeadNews } from '@/service/user.api'
import { useStore } from "vuex";
import { TIME_OUT, customerServiceUrl } from "@/config";
import { TIME_OUT, HOST_URL } from "@/config";
import { useUserStore } from '@/store/user';
import { showToast } from 'vant';
import { setStorage, getStorage } from '@/utils/index.js';
let catchSymbol = getStorage('symbol')
if (!catchSymbol) {
@@ -105,30 +253,35 @@
const { t } = useI18n()
const router = useRouter()
const store = useStore();
const customer_service_url = ref(customerServiceUrl) // 客服链接,有值的话就会跳转到客服外链
const tabbers = [
    // { key: 1, name: t('跟单'), icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url) },
    // { key: 3, name: `C2C ${t('交易')}`, icon: new URL('@/assets/imgs/home/home_3.png', import.meta.url) },
    // { key: 4, name: t('邀请好友'), icon: new URL('@/assets/imgs/home/home_4.png', import.meta.url) },
    // { key: 5, name: t('合约'), icon: new URL('@/assets/imgs/home/home_5.png', import.meta.url), path: '/trade/index' },
    // { key: 6, name: t('现货'), icon: new URL('@/assets/imgs/home/home_5.png', import.meta.url), path: '/cryptos/trade/btcusdt' },
    { key: 2, name: t('储值'), icon: new URL('@/assets/imgs/home/home_2.png', import.meta.url), path: '/cryptos/recharge/rechargeList?isForeign=true' },
    // { key: 7, name: t('提现'), icon: new URL('@/assets/imgs/home/home_6.png', import.meta.url), path: '/exchange/withdraw-usdt' }
    { key: 7, name: t('提现'), icon: new URL('@/assets/imgs/home/home_6.png', import.meta.url), path: '/cryptos/Withdraw/withdrawPage' },
    // { key: 8, name: t('卡券中心'), icon: new URL('@/assets/imgs/home/home_7.png', import.meta.url) },
    // { key: 9, name: t('闪兑'), icon: new URL('@/assets/imgs/home/home_8.png', import.meta.url), path: '/cryptos/exchangePage' },
    // { key: 9, name: t('划转'), icon: new URL('@/assets/imgs/home/home_8.png', import.meta.url), path: '/my/transfer' },
    // { key: 10, name: t('更多'), icon: new URL('@/assets/imgs/home/home_9.png', import.meta.url) },
    // { key: 11, name: "STO", icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: '/ICO/ico' },
    // { key: 12, name: "C2C", icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: '/wantBuy' },
    // { key: 13, name: t('质押'), icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: '' },
    { key: 14, name: t('onLineService'), icon: new URL('@/assets/imgs/home/home_10.png', import.meta.url), path: '/customerService' },
    { key: 15, name: t('MCB白皮书'), icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: '/aboutUs?serviceTerm=28' },
    { key: 2, name: t('recharge'), icon: new URL('@/assets/imgs/new/quick-function2.png', import.meta.url), path: '/cryptos/recharge/rechargeList?isForeign=true' },
    { key: 7, name: t('提现'), icon: new URL('@/assets/imgs/new/quick-function1.png', import.meta.url), path: '/cryptos/Withdraw/withdrawPage' },
    { key: 5, name: t('合约'), icon: new URL('@/assets/imgs/new/index-function5.png', import.meta.url), path: '/trade/index' },
    { key: 14, name: t('客服'), icon: new URL('@/assets/imgs/new/index-function3.png', import.meta.url), path: '/customerService' },
]
// 获取公告数据
// 交易区列表:外汇、股票、ETF(均带图标)
const tradingList = [
    { name: t('外汇'), icon: new URL('@/assets/theme/dark/image/nav/trade.png', import.meta.url), path: '/foreign/coinChart?symbol=USDSGD' },
    { name: t('股票'), icon: new URL('@/assets/theme/dark/image/nav/trade.png', import.meta.url), path: '/quotes/openTrade?tabActive=0&symbol=AAPL&type=US-stocks' },
    { name: t('ETF'), icon: new URL('@/assets/theme/dark/image/nav/contract.png', import.meta.url), path: '/quotes/openTrade?tabActive=0&symbol=GlobalETF500&type=indices' },
]
// 轮播图:使用本地两张图片(swiper_1、swiper_2 放在 src/assets/imgs/new/ 下)
const bannerImages = [
    { img: new URL('@/assets/imgs/new/swiper_1.png', import.meta.url).href, alt: 'Banner 1' },
    { img: new URL('@/assets/imgs/new/swiper_2.png', import.meta.url).href, alt: 'Banner 2' },
]
const currentBanner = ref(0)
const onBannerChange = (index) => {
    currentBanner.value = index
}
const onBannerClick = (item) => {
    if (item.link) router.push(item.link)
}
// 获取公告数据(用作轮播图)
const announceList = ref([])
_getNewsList1({
    language: useI18n().locale.value,
@@ -136,26 +289,67 @@
    announceList.value = res
})
// 获取弹出新闻
const popupNewsList = ref([])
_getPopupNews({
    language: useI18n().locale.value,
}).then(res => {
    if (res && res.length > 0) {
        let list = res
        list.forEach(item => {
            item.showPopUp = true
        })
        popupNewsList.value = list
    }
})
// 关闭弹窗新闻
const closePopNotice = (item) => {
    item.showPopUp = false
}
// 跳转公告详情
const toAnnounceDetail = (announceId) => {
    if (announceId) {
        router.push({ path: '/cryptos/AnnounceDetail', query: { id: announceId } })
        router.push({ path: '/cryptos/announceDetail', query: { id: announceId } })
    }
}
// 新闻项点击:站内弹层展示详情(不跳外链);公告项仍走公告详情页
const onNewsItemClick = (item) => {
    if (item && item.url) {
        selectedNewsDetail.value = item
        showNewsDetailPopup.value = true
    } else if (item && item.uuid) {
        toAnnounceDetail(item.uuid)
    }
}
// 新闻日期展示:ISO 取前 10 位
const formatNewsDate = (publishedAt) => {
    if (!publishedAt) return ''
    return String(publishedAt).substring(0, 10)
}
// 首页四个按钮点击:无 path 时提示暂未开放
const onGridClick = (value) => {
    if (!value.path) {
        showToast(t('notOpenYet'));
        return;
    }
    toPage(value.path);
};
// 跳转页面
const toPage = (path) => {
    if (!path) return
    if (path == '/customerService') {
        if (customer_service_url.value) {
            window.location.href = customer_service_url.value;
        } else {
            router.push(path)
        }
    } else {
        router.push(path)
    // 如果路径包含 "http",则作为外链跳转
    if (path && (path.startsWith('http://') || path.startsWith('https://'))) {
        window.open(path, '_blank');
        return;
    }
    router.push(path)
}
// 轮播图数据
@@ -170,12 +364,76 @@
    { key: 3, img: new URL('@/assets/imgs/home/home_3.png', import.meta.url) },
])
// 列表区:Favorites / Markets 切换
const listMode = ref('markets') // 'favorites' | 'markets'
const listInitialCount = 8 // 竖列表默认展示条数,点击「展示更多」后显示全部
const showMoreList = ref(false)
const favoritesList = ref([
    { symbol: 'btcusdt', symbol_data: 'BTC', name: 'BTC/USDT', close: 43250.5, change_ratio: 2.18, amount: 12345678 },
    { symbol: 'ethusdt', symbol_data: 'ETH', name: 'ETH/USDT', close: 2280.2, change_ratio: -0.85, amount: 8765432 },
    { symbol: 'xrpusdt', symbol_data: 'XRP', name: 'XRP/USDT', close: 0.62, change_ratio: 1.25, amount: 5678901 },
])
// HOT COINS / Trend 数据(HOT 用 qList 前几条,Trend 用 mock 3 条)
const hotCoinsList = ref([])
// Trend 三条:使用本地图片 a-DOT / a-APT / a-FIL(放在 src/assets/imgs/new/ 下)
const trendList = ref([
    { symbol: 'dotusdt', symbol_data: 'DOT', iconUrl: new URL('@/assets/imgs/new/a-DOT.png', import.meta.url).href, name: 'DOT/USDT', close: 1.589, change_ratio: 25.51 },
    { symbol: 'aptusdt', symbol_data: 'APT', iconUrl: new URL('@/assets/imgs/new/a-APT.png', import.meta.url).href, name: 'APT/USDT', close: 0.958, change_ratio: 14.18 },
    { symbol: 'filusdt', symbol_data: 'FIL', iconUrl: new URL('@/assets/imgs/new/a-FIL.png', import.meta.url).href, name: 'FIL/USDT', close: 1.005, change_ratio: 12.54 },
])
const trendTab = ref('trend') // 'trend' | 'follow' | 'news' | 'ipo'
const emptyImg = new URL('@/assets/imgs/new/empty.png', import.meta.url).href
// 新闻 tab:仅使用 news!getUsHeadNews.action 接口数据
const newsApiList = ref([])
const newsLoading = ref(false)
const newsListForTab = computed(() => {
    const list = newsApiList.value || []
    if (list.length === 0) return []
    return list.map((a) => ({
        title: a.title || '',
        author: a.author || '',
        publishedAt: a.publishedAt || '',
        url: a.url || '',
        urlToImage: a.urlToImage || '',
        description: a.description || '',
        content: a.content || '',
        sourceName: (a.source && a.source.name) ? a.source.name : '',
        source: a.source,
    }))
})
// 新闻详情弹层(站内展示,不跳外链)
const showNewsDetailPopup = ref(false)
const selectedNewsDetail = ref(null)
// 首页新闻:在 onMounted 中请求,避免重复请求、便于统一管理
function fetchUsHeadNews() {
    if (newsLoading.value) return
    newsLoading.value = true
    _getUsHeadNews()
        .then((list) => { newsApiList.value = list || [] })
        .finally(() => { newsLoading.value = false })
}
// 跳转行情/交易页
const toQuote = (item) => {
    if (item && item.symbol) router.push(`/cryptos/trade/${item.symbol}`)
}
//#region 行情数据----------------------------------------
let qList = ref([])
let qListCope = ref([]) // 备份数据
let key = ref('') // 搜索关键词
let timeout = ref(null)
const coinArr = computed(() => store.getters['home/coinArr']);
// 竖列表:当前数据源与展示条数(展示更多前只显示 5 条)
const currentList = computed(() => (listMode.value === 'markets' ? qList.value : favoritesList.value))
const displayedList = computed(() => {
    const list = currentList.value
    return showMoreList.value ? list : (list || []).slice(0, listInitialCount)
})
const fetchQList = async () => { // 获取行情
    const list = await _getHomeList(coinArr.value.join(',')).catch(() => {
@@ -194,6 +452,8 @@
        qList.value = list
    }
    qListCope.value = list; // 备份数据
    // HOT COINS 取前 8 条
    hotCoinsList.value = (list || []).slice(0, 8)
    if (timeout.value) {
        clearTimeout(timeout.value)
@@ -218,6 +478,9 @@
    qList.value = newList
}
onMounted(() => {
    fetchUsHeadNews()
})
onBeforeUnmount(() => {
    if (timeout.value) {
        clearTimeout(timeout.value)
@@ -228,6 +491,14 @@
</script>
<style lang="scss">
@import '@/assets/theme/index.scss';
.mainBackground{
    background-color: #f6f5fa !important;
}
.home-kyc-block {
    cursor: pointer;
    width: 100%;
}
.home_page {
    // background: $white;
    min-height: 100vh;
@@ -237,26 +508,62 @@
    $tab-c: #888;
    $inp-c: #999;
    $crd-b: #f7f7f7;
    .popup_news{
        font-size: 1.8rem;
    }
    .index_notice {
        height: 100px;
        border-radius: 10px;
    /* 首页轮播图(BlueWhale 风格) */
    .home_banner {
        position: relative;
        width: 100%;
        margin: 12px auto;
        border-radius: 12px;
        overflow: hidden;
        background: $crd-b;
    }
        .notice-swipe {
            height: 82px;
        }
    .home_banner_swipe {
        width: 100%;
        border-radius: 12px;
    }
        .notice_img {
            height: 80px;
            width: 100px;
            // background-color: $icon-bg;
        }
    .home_banner_item {
        width: 100%;
        border-radius: 12px;
        overflow: hidden;
    }
        .notice_content {
            &>div:first-child {
                color: $text_color1;
            }
        }
    .home_banner_img {
        width: 100%;
        height: auto;
        display: block;
        vertical-align: top;
        border-radius: 12px;
    }
    .home_banner_indicator {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 12px;
        display: flex;
        justify-content: center;
        gap: 8px;
        z-index: 2;
    }
    .home_banner_dot {
        width: 6px;
        height: 6px;
        border-radius: 3px;
        background: rgba(255, 255, 255, 0.4);
        transition: all 0.3s;
    }
    .home_banner_dot.active {
        width: 16px;
        border-radius: 3px;
        background: #fff;
    }
    .home_logo {
@@ -302,6 +609,12 @@
    .home_grid {
        width: 100%;
        background-size: 100% 100%;
        background-repeat: no-repeat;
        &.home_grid_bg {
            background-image: url('@/assets/imgs/new/index-funbg.png');
        }
        .grid_item {
            width: 25%;
@@ -312,7 +625,7 @@
                width: 100%;
                img {
                    width: 6.3rem;
                    width: 5.8rem;
                }
            }
        }
@@ -388,5 +701,349 @@
        padding: 1.6rem 1.6rem 2rem 1.6rem;
        font-size: 2rem;
    }
    /* 列表区 Favorites / Markets 切换(与下方 Trend 等统一样式) */
    .home-list-section {
        .home-list-tabs {
            display: flex;
            gap: 2.4rem;
            margin-bottom: 1.2rem;
            padding: 0 0.8rem;
            .home-list-tab {
                font-size: 1.8rem;
                color: $tab-c;
                padding: 0.6rem 1.4rem;
                border-radius: 2rem;
                &.active {
                    background: #fff;
                    color: #000;
                    font-weight: 600;
                }
            }
        }
        .home-list-more {
            text-align: center;
            padding: 1.2rem;
            font-size: 2rem;
            color: #1194F7;
            margin-top: 0.8rem;
        }
    }
    /* HOT COINS 横向滚动卡片:一屏约 3 个,细体 + 色 #29155a */
    .home-hot-coins {
        margin-top: 2.4rem;
        .home-hot-title {
            font-size: 2.1rem;
            font-weight: 400;
            color: #29155a;
            margin-bottom: 0.4rem;
        }
        .home-hot-subtitle {
            font-size: 1.5rem;
            font-weight: 400;
            color: #29155a;
            margin-bottom: 1rem;
            opacity: 0.75;
        }
        .home-hot-scroll {
            display: flex;
            gap: 1.4rem;
            overflow-x: auto;
            padding: 0.8rem 0 1.2rem 0;
            -webkit-overflow-scrolling: touch;
            &::-webkit-scrollbar { height: 6px; }
            &::-webkit-scrollbar-thumb { background: #ddd; border-radius: 3px; }
        }
        .home-hot-card {
            flex-shrink: 0;
            width: calc((100vw ) / 3);
            min-width: 10rem;
            padding: 1.4rem 1rem;
            background: #fff;
            border-radius: 12px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.06);
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 0.6rem;
        }
        .home-hot-logo {
            width: 5rem;
            height: 5rem;
            border-radius: 50%;
        }
        .home-hot-symbol {
            font-size: 1.7rem;
            font-weight: 400;
            color: #29155a;
        }
        .home-hot-pct {
            font-size: 1.5rem;
            font-weight: 400;
            &.up { color: #0ecb81; }
            &.down { color: #f6465d; }
        }
    }
    /* Trend / Follow / News / IPO 切换:左右内外边距加宽 */
    .home-trend-tabs {
        display: flex;
        gap: 3rem;
        margin-top: 2.4rem;
        margin-bottom: 1rem;
        padding: 0 1.8rem;
        .home-trend-tab {
            font-size: 1.8rem;
            color: $tab-c;
            padding: 0.8rem 2.2rem;
            border-radius: 2rem;
            &.active {
                background: #fff;
                color: #000;
                font-weight: 600;
            }
        }
    }
    .home-trend-card {
        border-radius: 16px;
        overflow: hidden;
        min-height: 200px;
        margin-top: 10px;
        &.home-trend-card--bg {
            background: url('@/assets/imgs/new/riseBg.jpg') no-repeat center/cover;
            background-color: #fff;
            background-size: 100% 100%;
            .home-trend-card-inner {
                padding: 1.6rem;
                position: relative;
                z-index: 1;
            }
            .home-trend-heading {
                font-size: 2.8rem;
                color: #fff;
                margin-bottom: 0.4rem;
                margin-top: 30px;
                padding: 0 2rem;
            }
            .home-trend-subtitle {
                padding: 0 2rem;
                font-size: 1.5rem;
                color: rgba(255,255,255,0.85);
                margin-bottom: 1.2rem;
            }
            .home-trend-list {
                display: flex;
                flex-direction: column;
                gap: 1rem;
            }
            .home-trend-item {
                display: flex;
                align-items: center;
                gap: 1rem;
                padding: 0rem 0rem;
                margin: 0.5rem 2rem;
                border-bottom: 1px solid hsla(0, 0%, 100%, .1);
                &:last-child {
                    border-bottom: none;
                }
            }
            .home-trend-logo {
                width: 3.6rem;
                height: 3.6rem;
                border-radius: 50%;
            }
            .home-trend-info {
                flex: 1;
                display: flex;
                flex-direction: column;
                gap: 0.2rem;
            }
            .home-trend-name {
                font-size: 1.7rem;
                font-weight: 600;
                color: #fff;
            }
            .home-trend-right {
                display: flex;
                flex-direction: column;
                align-items: flex-end;
                gap: 0.3rem;
            }
            .home-trend-price {
                font-size: 1.5rem;
                color: #fff;
            }
            .home-trend-pct {
                font-size: 1.6rem;
                font-weight: 600;
                color: #0ecb81;
            }
        }
        &.home-trend-card--empty {
            background: #f7f7f7;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 2rem;
            .home-empty-img {
                width: 12rem;
                height: auto;
                margin-bottom: 1rem;
            }
            .home-empty-text {
                font-size: 1.8rem;
                color: $tab-c;
            }
        }
        &.home-trend-card--news {
            background: #fff;
            .home-trend-card-inner {
                padding: 1.6rem 1.8rem;
            }
            .home-trend-heading--dark {
                color: #29155a;
                font-size: 2.2rem;
                margin-top: 0;
                padding: 0;
            }
            .home-news-list {
                display: flex;
                flex-direction: column;
                gap: 0;
            }
            .home-news-item {
                display: flex;
                align-items: flex-start;
                gap: 1rem;
                padding: 1.2rem 0;
                border-bottom: 1px solid #eee;
                cursor: pointer;
                &:last-child {
                    border-bottom: none;
                }
            }
            .home-news-thumb {
                flex-shrink: 0;
                width: 7.2rem;
                height: 7.2rem;
                border-radius: 8px;
                overflow: hidden;
                background: #f0f0f0;
                img {
                    width: 100%;
                    height: 100%;
                    object-fit: cover;
                }
            }
            .home-news-body {
                flex: 1;
                min-width: 0;
            }
            .home-news-title {
                font-size: 1.5rem;
                line-height: 1.4;
                margin-bottom: 0.4rem;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
                overflow: hidden;
            }
            .home-news-meta {
                display: flex;
                align-items: center;
                justify-content: space-between;
                font-size: 1.2rem;
                gap: 0.5rem;
            }
            .home-news-date {
                flex: 1;
                min-width: 0;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                color: #999;
            }
            .home-news-detail {
                flex-shrink: 0;
                color: #999;
            }
            .home-trend-card--empty-inner {
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                min-height: 160px;
                .home-empty-img {
                    width: 10rem;
                    height: 10rem;
                }
                .home-empty-text {
                    margin-top: 0.8rem;
                    font-size: 1.4rem;
                    color: #999;
                }
            }
        }
    }
}
.news-detail-popup {
    .news-detail-inner {
        padding: 0 2rem 2.4rem;
        overflow-y: auto;
        max-height: 100%;
        background: #fff;
    }
    .news-detail-drag-bar {
        width: 3.6rem;
        height: 4px;
        margin: 1rem auto 1.2rem;
        background: #e0e0e0;
        border-radius: 2px;
    }
    .news-detail-header {
        margin-bottom: 0.6rem;
    }
    .news-detail-source {
        font-size: 1.2rem;
        color: #999;
    }
    .news-detail-title {
        font-size: 2rem;
        font-weight: 600;
        line-height: 1.35;
        margin: 0 0 1.4rem;
        color: #1a1a1a;
    }
    .news-detail-img-wrap {
        border-radius: 12px;
        overflow: hidden;
        margin-bottom: 1.4rem;
        background: #f5f5f5;
        .news-detail-img {
            width: 100%;
            display: block;
            object-fit: cover;
            max-height: 22rem;
        }
    }
    .news-detail-content {
        font-size: 1.45rem;
        line-height: 1.7;
        color: #333;
        white-space: pre-wrap;
        word-break: break-word;
        margin-bottom: 2rem;
    }
    .news-detail-close {
        margin-top: 0.4rem;
        height: 4.4rem;
        font-size: 1.6rem;
    }
}
</style>