10.10综合交易所原始源码_移动端
1
7 days ago 543735d5141ce80b5f48c1a0d777fc29b0b34c86
src/views/home/index.vue
@@ -4,7 +4,7 @@
        <div class="header">
            <div class="header-left">
                <img src="@/assets/image/login_logo.png" alt="Wealthinfra" class="logo" />
                <span class="logo-text">Wealthinfra</span>
                <span class="logo-text">Bitget</span>
            </div>
            <div class="header-right">
                <div class="lang-selector" @click="$router.push('/language')">
@@ -114,15 +114,7 @@
                    @click="goToOptions(pair.symbol, pair.type)">
                    <div class="currency-info">
                        <div class="currency-pair-row">
                            <template v-if="activeTab === 'forex' && getPairIconUrl(pair)">
                                <div class="currency-card-icon-wrap">
                                    <img :src="getPairIconUrl(pair)" alt=""
                                        class="currency-card-icon currency-card-icon--large" />
                                    <img v-if="getPairIconUrlSm(pair)" :src="getPairIconUrlSm(pair)" alt=""
                                        class="currency-card-icon currency-card-icon--sm" />
                                </div>
                            </template>
                            <img v-else-if="getPairIconUrl(pair)" :src="getPairIconUrl(pair)" alt=""
                            <img v-if="getPairIconUrl(pair)" :src="getPairIconUrl(pair)" alt=""
                                class="currency-card-icon" />
                            <div class="currency-pair">{{ pair.symboltxt.toUpperCase() }}</div>
                        </div>
@@ -138,17 +130,9 @@
        <!-- Trading Instruments -->
        <div class="trading-section">
            <div class="trading-tabs">
                <div class="tab-item" :class="{ active: activeTab === 'forex' }" @click="activeTab = 'forex'">
                    {{ $t('外汇') }}
                </div>
                <div class="tab-item" :class="{ active: activeTab === 'crypto' }" @click="activeTab = 'crypto'">
                    {{ $t('加密货币') }}
                </div>
                <div class="tab-item" :class="{ active: activeTab === 'stock' }" @click="activeTab = 'stock'">
                    {{ $t('股票') }}
                </div>
                <div class="tab-item" :class="{ active: activeTab === 'etf' }" @click="activeTab = 'etf'">
                    ETF
                <div class="tab-item" v-for="tab in marketTabs" :key="tab.value"
                    :class="{ active: activeTab === tab.value }" @click="switchTab(tab.value)">
                    {{ $t(tab.label) }}
                </div>
            </div>
            <div class="trading-pairs">
@@ -156,17 +140,9 @@
                    @click="goToOptions(pair.symbol, pair.type)">
                    <div class="pair-header">
                        <div class="pair-symbol">
                            <template v-if="activeTab === 'forex' && getPairIconUrl(pair)">
                                <div class="pair-symbol-icon-wrap">
                                    <img :src="getPairIconUrl(pair)" alt=""
                                        class="pair-symbol-icon pair-symbol-icon--large" />
                                    <img v-if="getPairIconUrlSm(pair)" :src="getPairIconUrlSm(pair)" alt=""
                                        class="pair-symbol-icon pair-symbol-icon--sm" />
                                </div>
                            </template>
                            <img v-else-if="getPairIconUrl(pair)" :src="getPairIconUrl(pair)" alt=""
                            <img v-if="getPairIconUrl(pair)" :src="getPairIconUrl(pair)" alt=""
                                class="pair-symbol-icon" />
                            {{ pair.symboltxt.toUpperCase() }}
                            {{ (pair.symboltxt || pair.symbol || '').toUpperCase() }}
                        </div>
                        <div class="pair-change" :class="pair.change >= 0 ? 'up' : 'down'">
                            {{ pair.change >= 0 ? '+' : '' }}{{ pair.change.toFixed(4) }}%
@@ -260,7 +236,7 @@
                        <li>{{ $t('home.teamIntro') }}</li>
                        <li>{{ $t('帮助中心') }}</li>
                        <li>{{ $t('home.emailSupport') }}</li>
                        <li>support@wealthinfra.com</li>
                        <li>support@1m.com</li>
                    </ul>
                </div>
                <div class="info-section">
@@ -286,7 +262,7 @@
</template>
<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { ref, computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { IMG_PATH } from '@/config'
@@ -294,14 +270,6 @@
import { _getRealtimeByType } from '@/service/quotes.api'
import MiniKlineChart from '@/components/MiniKlineChart/index.vue'
// 外汇货币代码 -> 国旗图国家/地区代码(用于 flagcdn.com)
const CURRENCY_TO_FLAG = {
    eur: 'eu', usd: 'us', gbp: 'gb', jpy: 'jp', chf: 'ch', aud: 'au', cad: 'ca', nzd: 'nz',
    cny: 'cn', cnh: 'cn', hkd: 'hk', sgd: 'sg', nok: 'no', sek: 'se', dkk: 'dk', mxn: 'mx',
    zar: 'za', try: 'tr', pln: 'pl', inr: 'in', krw: 'kr', thb: 'th', myr: 'my', idr: 'id',
    php: 'ph', brl: 'br', rub: 'ru', czk: 'cz', huf: 'hu', ron: 'ro', bgn: 'bg', hrk: 'hr'
}
const FLAG_CDN = 'https://flagcdn.com/w40'
import { _getUsHeadNews } from '@/service/user.api'
// import newsPlaceholder from '@/assets/image/news-placeholder.png'
@@ -320,7 +288,7 @@
    if (!symbol) return
    router.push({
        path: '/trade/options',
        query: { symbol, activeTab: type || 'cryptos' }
        query: { symbol, activeTab: type || activeTab.value }
    })
}
@@ -351,97 +319,46 @@
    return langMap[locale.value] || '简体'
})
const activeTab = ref('forex')
const tradingPairs = ref([])
const activeTab = ref('cryptos')
const marketTabs = [
    { label: '加密货币', value: 'cryptos' },
    { label: '股票', value: 'US-stocks' },
    { label: 'ETF', value: 'indices' },
    { label: '外汇', value: 'forex' },
]
// 新闻列表,用于横向滚动轮播(与 news/index.vue 同源:_getUsHeadNews)
const newsList = ref([])
// Market Overview 使用 Trading Instruments 的前3条数据(保留完整 pair 用于展示图标)
const currencyPairs = computed(() => tradingPairs.value.slice(0, 3))
// 从外汇对取基础货币代码,如 EUR/USD -> eur,EURUSD -> eur(无斜杠取前3位)
function getForexBaseCurrency(symbol) {
    if (!symbol || typeof symbol !== 'string') return ''
    const s = symbol.trim()
    if (s.includes('/')) return s.split('/')[0].trim().toLowerCase()
    return s.slice(0, 3).toLowerCase()
}
// 从外汇对取计价货币代码,如 EUR/USD -> usd(右下角小图用)
function getForexQuoteCurrency(symbol) {
    if (!symbol || typeof symbol !== 'string') return ''
    const s = symbol.trim()
    if (s.includes('/')) return s.split('/')[1]?.trim().toLowerCase() || ''
    return s.length > 3 ? s.slice(3, 6).toLowerCase() : ''
}
// 列表项图标地址:外汇用国旗,加密货币用 symbol 图;股票、ETF 不展示图标
function getPairIconUrl(pair) {
    if (!pair) return ''
    if (activeTab.value === 'stock' || activeTab.value === 'etf') return ''
    if (activeTab.value === 'forex') {
        const code = CURRENCY_TO_FLAG[getForexBaseCurrency(pair.symbol)]
        return code ? `${FLAG_CDN}/${code}.png` : ''
    }
    if (activeTab.value === 'US-stocks' || activeTab.value === 'indices') return ''
    return pair.iconImg ? `${IMG_PATH}/symbol/${pair.iconImg}.png` : ''
}
// 小图用名字后面3位(计价货币)的国旗,仅外汇有效
function getPairIconUrlSm(pair) {
    if (!pair || activeTab.value !== 'forex') return ''
    const quote = getForexQuoteCurrency(pair.symbol)
    if (!quote) return ''
    const code = CURRENCY_TO_FLAG[quote]
    return code ? `${FLAG_CDN}/${code}.png` : ''
function switchTab(tab) {
    if (activeTab.value === tab) return
    activeTab.value = tab
    fetchTradingData()
}
// 获取交易数据
const fetchTradingData = async () => {
    let type = ''
    let category = null
    switch (activeTab.value) {
        case 'crypto':
            type = 'cryptos'
            break
        case 'etf':
            type = 'indices'
            break
        case 'stock':
            type = 'US-stocks'
            break
        case 'forex':
            type = 'forex'
            category = 'forex'
            break
        default:
            type = 'forex'
            category = 'forex'
    }
    const type = activeTab.value
    try {
        const params = {
            type: type,
            pageNo: 1
        }
        if (category) {
            params.category = category
        }
        const data = await _getRealtimeByType(params)
        if (data && Array.isArray(data)) {
            // 外汇 tab 只展示指定 symbol:EURUSD GBPUSD AUDUSD XAUUSD NZDUSD
            const forexAllowedSymbols = ['EURUSD', 'GBPUSD', 'AUDUSD', 'XAUUSD', 'NZDUSD']
            let list = data
            if (activeTab.value === 'forex') {
                list = data.filter(item => {
                    const raw = (item.symbol || item.enName || '').toString().trim()
                    const normalized = raw.replace(/\//g, '').toUpperCase()
                    return forexAllowedSymbols.includes(normalized)
                })
            }
            const list = data
            // 只取前5条数据,并转换为需要的格式
            tradingPairs.value = list.slice(0, 5).map(item => {
                const basePrice = parseFloat(item.close || item.lastPrice || 0)
@@ -454,19 +371,19 @@
                const spread = basePrice * 0.0001 // 很小的价差
                const sellPrice = (basePrice - spread).toFixed(4)
                const buyPrice = (basePrice + spread).toFixed(4)
                const symboltxt = item.enName
                const symboltxt = item.enName || item.name || item.symbol
                const symbolStr = item.symbol || '--'
                const iconImg = item.symbol_data || (symbolStr.includes('/') ? symbolStr.split('/')[0].toLowerCase() : symbolStr.replace(/USDT$/i, '').toLowerCase()) || symbolStr.toLowerCase()
                return {
                    symboltxt: symboltxt,
                    symboltxt,
                    symbol: symbolStr,
                    type: type,
                    iconImg: iconImg,
                    type,
                    iconImg,
                    price: basePrice.toFixed(4),
                    change: changeRatio,
                    sellPrice: sellPrice,
                    buyPrice: buyPrice,
                    klineData: klineData
                    sellPrice,
                    buyPrice,
                    klineData
                }
            })
        } else {
@@ -477,11 +394,6 @@
        tradingPairs.value = []
    }
}
// 监听 tab 切换
watch(activeTab, () => {
    fetchTradingData()
})
// 根据当前价与涨跌幅生成小型 K 线数据,每根 [open, close, low, high]
function generateMiniKlineData(basePrice, changeRatio) {