10.10综合交易所原始源码_移动端
1
7 days ago 543735d5141ce80b5f48c1a0d777fc29b0b34c86
1
11 files modified
1 files deleted
307 ■■■■ changed files
favicon.ico patch | view | raw | blame | history
index.html 2 ●●● patch | view | raw | blame | history
package.json 8 ●●●● patch | view | raw | blame | history
src/assets/image/login_logo.png patch | view | raw | blame | history
src/components/fx-footer/index.vue 4 ●●●● patch | view | raw | blame | history
src/config/index.js 6 ●●●● patch | view | raw | blame | history
src/main.js 12 ●●●●● patch | view | raw | blame | history
src/views/home/index.vue 51 ●●●● patch | view | raw | blame | history
src/views/quotes/Market.vue 52 ●●●●● patch | view | raw | blame | history
src/views/trade/Options.vue 80 ●●●● patch | view | raw | blame | history
vite.config.js 4 ●●●● patch | view | raw | blame | history
vite.config.js.timestamp-1775042120961.mjs 88 ●●●●● patch | view | raw | blame | history
favicon.ico

index.html
@@ -12,7 +12,7 @@
  <meta name="theme-color" content="#131A2E">
  <meta name="apple-mobile-web-app-status-bar-style" content="#131A2E" />
  <link rel="apple-touch-icon" href="./favicon.ico">
  <title>Crypto</title>
  <title>Bitget</title>
</head>
<body>
package.json
@@ -6,10 +6,10 @@
  "scripts": {
    "lint": "eslint --ext .vue,.js ./",
    "lint:fix": "eslint --fix --ext .vue,.js ./",
    "dev": "vite",
    "build": "vite build",
    "build:visualizer": "NODE_ENV=production VISUALIZER=show vite build && node ./fixDistPath.js",
    "preview": "vite preview"
    "dev": "node ./node_modules/vite/bin/vite.js",
    "build": "node ./node_modules/vite/bin/vite.js build",
    "build:visualizer": "set NODE_ENV=production&& set VISUALIZER=show&& node ./node_modules/vite/bin/vite.js build && node ./fixDistPath.js",
    "preview": "node ./node_modules/vite/bin/vite.js preview"
  },
  "dependencies": {
    "@vueuse/components": "9.4.0",
src/assets/image/login_logo.png

src/components/fx-footer/index.vue
@@ -19,11 +19,11 @@
        </template>
      </van-tabbar-item>
      <!-- <van-tabbar-item name="fund" to="/cryptos/fund">
      <van-tabbar-item name="fund" to="/cryptos/fund">
        <template #icon>
          <img :src="active == 'fund' ? icon.fund.active : icon.fund.inactive" alt="fund" />
        </template>
      </van-tabbar-item> -->
      </van-tabbar-item>
      <van-tabbar-item name="personal" to="/personal">
        <template #icon>
src/config/index.js
@@ -43,12 +43,12 @@
// const ENV_DEV = '127.0.0.1' // dev
// const ENV_DEV = '192.168.10.11:8848' // dev
const ENV_DEV = 'api.dpcex.com' // dev
const ENV_DEV = 'zhapi.bitget-jp-us.cyou' // dev
// const ENV_PRO = window.location.hostname // 接口域名跟随 H5
// const ENV_PRO = "127.0.0.1"
// const ENV_PRO = "192.168.10.11:8848"
const ENV_PRO = "api.dpcex.com"
const ENV_PRO = "zhapi.bitget-jp-us.cyou"
// 避免打包出错务必把 app域名的注释要放在在本地ENV_PRO的下面
// const ENV_PRO = 'foilwm.com' //  app域名
@@ -66,7 +66,7 @@
}
export const BASE_URL = base_url
export const WS_URL = ws_url
export const IMG_PATH = 'https://img.dpcex.com'
export const IMG_PATH = 'https://zhimg.bitget-jp-us.cyou'
export const HOST_URL = host_url
export default {
src/main.js
@@ -14,17 +14,6 @@
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
pinia.use(piniaPluginPersistedstate)
// 生产环境且为 PC 端时跳转到 PC 站
const PC_SITE_URL = 'https://pc.dpcex.com'
function isPc() {
  if (typeof navigator === 'undefined') return false
  const ua = navigator.userAgent || ''
  const mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile/i.test(ua)
  return !mobile
}
if (import.meta.env.PROD && isPc()) {
  window.location.href = PC_SITE_URL
} else {
  const app = createApp(App)
  const title = import.meta.env.VITE_APP__TITLE
  app.config.globalProperties.$title = title
@@ -36,4 +25,3 @@
  app.use(store)
  app.mount('#app')
}
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">1m</span>
                <span class="logo-text">Bitget</span>
            </div>
            <div class="header-right">
                <div class="lang-selector" @click="$router.push('/language')">
@@ -93,6 +93,12 @@
                </div>
                <span>{{ $t('withdraw') }}</span>
            </div>
            <div class="quick-item" @click="$router.push('/cryptos/loan')">
                <div class="quick-icon">
                    <img src="@/assets/image/dk.png" alt="loan" />
                </div>
                <span>{{ $t('home.loan') }}</span>
            </div>
            <div class="quick-item" @click="$router.push('/customerService')">
                <div class="quick-icon">
                    <img src="@/assets/image/lxkf.png" alt="service" />
@@ -123,9 +129,10 @@
        <!-- Trading Instruments -->
        <div class="trading-section">
            <div class="trading-tabs trading-tabs--single">
                <div class="tab-item active">
                    {{ $t('加密货币') }}
            <div class="trading-tabs">
                <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">
@@ -135,7 +142,7 @@
                        <div class="pair-symbol">
                            <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) }}%
@@ -281,7 +288,7 @@
    if (!symbol) return
    router.push({
        path: '/trade/options',
        query: { symbol, activeTab: type || 'cryptos' }
        query: { symbol, activeTab: type || activeTab.value }
    })
}
@@ -313,6 +320,13 @@
})
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([])
@@ -321,12 +335,19 @@
function getPairIconUrl(pair) {
    if (!pair) return ''
    if (activeTab.value === 'US-stocks' || activeTab.value === 'indices') return ''
    return pair.iconImg ? `${IMG_PATH}/symbol/${pair.iconImg}.png` : ''
}
// 获取交易数据(仅数字货币)
function switchTab(tab) {
    if (activeTab.value === tab) return
    activeTab.value = tab
    fetchTradingData()
}
// 获取交易数据
const fetchTradingData = async () => {
    const type = 'cryptos'
    const type = activeTab.value
    try {
        const params = {
@@ -350,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 {
src/views/quotes/Market.vue
@@ -1,9 +1,10 @@
<template>
    <div class="quotes-market-page">
        <!-- Top Tabs -->
        <div class="market-tabs market-tabs--single">
            <div class="tab-item active">
                {{ $t('加密货币') }}
        <div class="market-tabs">
            <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>
@@ -12,12 +13,12 @@
            <van-list v-model:loading="marketLoading" :finished="marketFinished" :immediate-check="false"
                :scroll-target="marketListRef" :finished-text="$t('没有更多了') || '没有更多了'" @load="loadMoreMarket">
                <div class="pair-item" v-for="pair in tradingPairs" :key="pair.symbol"
                    @click="goToOptions(pair.symbol)">
                    @click="goToOptions(pair.symbol, pair.type)">
                    <div class="pair-header">
                        <div class="pair-symbol">
                            <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) }}%
@@ -60,7 +61,13 @@
const useStore = useUserStore()
const quotesStore = useQuotesStore()
const activeTab = ref('crypto')
const activeTab = ref('cryptos')
const marketTabs = [
    { label: '加密货币', value: 'cryptos' },
    { label: '股票', value: 'US-stocks' },
    { label: 'ETF', value: 'indices' },
    { label: '外汇', value: 'forex' },
]
const tradingPairs = ref([])
const interval = ref(null)
const marketPage = ref(1)
@@ -73,8 +80,15 @@
function getPairIconUrl(pair) {
    if (!pair) return ''
    const tab = activeTab.value
    if (tab === 'US-stocks' || tab === 'indices') return ''
    if (tab === 'optional' && (pair.type === 'US-stocks' || pair.type === 'indices')) return ''
    return pair.iconImg ? `${IMG_PATH}/symbol/${pair.iconImg}.png` : ''
}
function switchTab(tab) {
    if (activeTab.value === tab) return
    activeTab.value = tab
    fetchData()
}
// 根据当前价与涨跌幅生成小型 K 线数据,与首页一致
@@ -201,7 +215,7 @@
// 获取交易数据;pageNo 页码,append 是否追加
const fetchTradingData = async (pageNo = 1, append = false) => {
    const type = 'cryptos'
    const type = activeTab.value
    try {
        const params = {
@@ -217,7 +231,7 @@
                const basePrice = parseFloat(item.close || item.lastPrice || 0)
                const changeRatio = item.changeRatio || 0
                const symbolStr = item.symbol || '--'
                const symboltxt = item.enName
                const symboltxt = item.enName || item.name || symbolStr
                const iconImg = item.symbol_data || (symbolStr.includes('/') ? symbolStr.split('/')[0].toLowerCase() : symbolStr.replace(/USDT$/i, '').toLowerCase()) || symbolStr.toLowerCase()
                const klineData = generateMiniKlineData(basePrice, changeRatio)
                const spread = basePrice * 0.0001
@@ -226,20 +240,14 @@
                return {
                    symbol: symbolStr,
                    symboltxt: symboltxt,
                    symboltxt,
                    price: basePrice.toFixed(4),
                    change: changeRatio,
                    sellPrice: sellPrice,
                    buyPrice: buyPrice,
                    klineData: klineData,
                    symbol: symbolStr,
                    type: type,
                    iconImg: iconImg,
                    price: basePrice.toFixed(4),
                    change: changeRatio,
                    sellPrice: sellPrice,
                    buyPrice: buyPrice,
                    klineData: klineData
                    sellPrice,
                    buyPrice,
                    klineData,
                    type,
                    iconImg
                }
            })
            if (append) {
@@ -284,11 +292,11 @@
}
// 跳转到交易页 Options,与首页一致:/trade/options?symbol=xxx&activeTab=xxx
function goToOptions(symbol) {
function goToOptions(symbol, type) {
    if (!symbol) return
    router.push({
        path: '/trade/options',
        query: { symbol, activeTab: 'cryptos' }
        query: { symbol, activeTab: type || activeTab.value }
    })
}
src/views/trade/Options.vue
@@ -35,7 +35,7 @@
                <!-- Modal Tabs:同一 activeTab 的 label 与 value 统一配置 -->
                <div v-if="modalTabs.length > 1" class="modal-tabs">
                    <div class="tab-item" v-for="tab in modalTabs" :key="tab.value"
                        :class="{ active: activeTab === tab.value }" @click="activeTab = tab.value">
                        :class="{ active: activeTab === tab.value }" @click="switchTab(tab.value)">
                        {{ $t(tab.label) }}
                    </div>
                </div>
@@ -54,7 +54,7 @@
                            @click="selectSymbol(item)">
                            <div class="symbol-left">
                                <div class="symbol-info">
                                    <div class="symbol-name">{{ (item.symbol).toUpperCase() }}</div>
                                    <div class="symbol-name">{{ getSymbolDisplayName(item) }}</div>
                                </div>
                            </div>
                            <div class="symbol-change" :class="item.change_ratio >= 0 ? 'up' : 'down'">
@@ -98,20 +98,33 @@
const symbolListRef = ref(null)
const symbolInitialLoading = ref(false) // tab 切换时首屏请求中,避免 @load 重复请求 pageNo=1
const SYMBOL_PAGE_SIZE = 10
const TAB_TYPES = ['cryptos', 'US-stocks', 'indices', 'forex']
const DEFAULT_SYMBOL = {
    cryptos: 'btc',
    'US-stocks': 'AAPL',
    indices: 'GlobalETF500',
    forex: 'EURUSD',
}
// 从路由 path(params) 或 query 同步 symbol(品种固定为数字货币)
// 从路由 path(params) 或 query 同步 symbol、activeTab
function applyFromRoute() {
    const p = route.params || {}
    const q = route.query || {}
    const symbol = q.symbol ?? p.symbol
    const tab = q.activeTab ?? p.activeTab
    if (tab && TAB_TYPES.includes(String(tab))) {
        activeTab.value = String(tab)
    }
    if (symbol != null && String(symbol).trim()) {
        currentSymbol.value = String(symbol).trim()
    }
    activeTab.value = 'cryptos'
}
const modalTabs = [
    { label: '加密货币', value: 'cryptos' },
    { label: '股票', value: 'US-stocks' },
    { label: 'ETF', value: 'indices' },
    { label: '外汇', value: 'forex' },
]
// 头部显示:关联选择项的 name,无则用 symbol
@@ -124,8 +137,32 @@
// 嵌入合约:1=永续(合约交易),2=交割(期权交易)
const embedSelectIndex = computed(() => tradeType.value === 'contract' ? 1 : 2)
// 嵌入合约品种类型(value 已与接口类型统一,仅 optional 需映射)
const embedType = computed(() => 'cryptos')
// 嵌入合约品种类型
const embedType = computed(() => activeTab.value)
function getSymbolDisplayName(item) {
    if (!item) return ''
    const name = item.name || item.enName || item.symbol || ''
    if (activeTab.value === 'forex') return String(name).toUpperCase()
    if (activeTab.value === 'cryptos') return String(item.symbol || name).toUpperCase()
    return name
}
function mapSymbolItem(item) {
    return {
        symbol: item.symbol,
        name: item.enName || item.name || item.symbol,
        close: item.close ?? item.lastPrice ?? '--',
        change_ratio: item.changeRatio ?? item.change_ratio ?? 0,
    }
}
function switchTab(tab) {
    if (activeTab.value === tab) return
    activeTab.value = tab
    currentSymbol.value = DEFAULT_SYMBOL[tab] || 'btc'
    fetchData()
}
// 图标路径
const starIcon = new URL('@/assets/image/icon-star.png', import.meta.url).href
@@ -141,8 +178,9 @@
// 获取交易数据;pageNo 页码,append 是否追加
const fetchTradingData = async (pageNo = 1, append = false) => {
    try {
        const type = activeTab.value
        const params = {
            type: 'cryptos',
            type,
            pageNo: pageNo,
            pageSize: SYMBOL_PAGE_SIZE
        }
@@ -151,19 +189,21 @@
        if (data && Array.isArray(data)) {
            const symbols = data.map(item => item.symbol).join(',')
            let list = []
            if (symbols) {
                const homeData = await _getHomeList(symbols)
                if (homeData && Array.isArray(homeData)) {
                    if (append) {
                        symbolList.value = [...symbolList.value, ...homeData]
                if (homeData && Array.isArray(homeData) && homeData.length) {
                    list = homeData
                    } else {
                        symbolList.value = homeData
                    list = data.map(mapSymbolItem)
                    }
                } else if (!append) {
                    symbolList.value = []
            } else {
                list = data.map(mapSymbolItem)
                }
            } else if (!append) {
                symbolList.value = []
            if (append) {
                symbolList.value = [...symbolList.value, ...list]
            } else {
                symbolList.value = list
            }
            if (data.length <= 0) {
                symbolFinished.value = true
@@ -219,7 +259,8 @@
    const keyword = searchKeyword.value.toLowerCase()
    return symbolList.value.filter(item =>
        item.symbol.toLowerCase().includes(keyword) ||
        (item.name && item.name.toLowerCase().includes(keyword))
        (item.name && item.name.toLowerCase().includes(keyword)) ||
        (item.enName && item.enName.toLowerCase().includes(keyword))
    )
})
@@ -229,8 +270,6 @@
    showSymbolModal.value = false
    searchKeyword.value = ''
}
// 查询当前交易对是否已收藏(与 add-currency / trade-head 一致)
function checkFavorite() {
    if (!useStore.userInfo?.token || !currentSymbol.value) {
        isFavorite.value = false
@@ -271,7 +310,10 @@
})
// 监听路由 query 变化(同一页带不同 query 时同步)
watch(() => route.query, () => applyFromRoute(), { deep: true })
watch(() => route.query, () => {
    applyFromRoute()
    fetchData()
}, { deep: true })
// 组件挂载时:先从 path/query 取 symbol、activeTab,再拉数据并刷新收藏状态
onMounted(() => {
vite.config.js
@@ -61,8 +61,8 @@
            // 关键:用正则表达式匹配所有含/api的路径(忽略大小写)
            '^/api.*': { // 匹配以/api开头的任何路径(如/api、/api/xxx、/api?xx等)
                // target: 'http://154.23.189.28:8086',
                target:'https://api.dpcex.com',
                // target:'https://api.dpcex.com',
                target:'https://zhapi.bitget-jp-us.cyou',
                // target:'https://zhapi.bitget-jp-us.cyou',
                // target: 'https://by2.cccxxx.cc',
                changeOrigin: true,
                secure: false,
vite.config.js.timestamp-1775042120961.mjs
File was deleted