7e55ca7470a21a93402c4c8e410eeef7c7d1da0c..09cd59e111da050db1e26621a231c7e2eb7a415b
2026-01-21 李凌
1
09cd59 diff | tree
2026-01-21 李凌
1
e01cee diff | tree
18 files modified
1 files added
996 ■■■■ changed files
src/components/Transform/trade-order-area/index.vue 20 ●●●●● patch | view | raw | blame | history
src/components/fx-footer/index.vue 12 ●●●● patch | view | raw | blame | history
src/i18n/Deutsch.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/Italy.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/Japanese.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/Portuguese.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/Spanish.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/cn.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/en.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/fa.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/korean.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/th.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/vi.js 16 ●●●●● patch | view | raw | blame | history
src/i18n/zhcn.js 16 ●●●●● patch | view | raw | blame | history
src/service/ico.api.js 16 ●●●●● patch | view | raw | blame | history
src/views/ICO/ico-old.vue 157 ●●●●● patch | view | raw | blame | history
src/views/ICO/ico.vue 514 ●●●● patch | view | raw | blame | history
src/views/ICO/icoRecord.vue 80 ●●●● patch | view | raw | blame | history
src/views/homePage/index.vue 5 ●●●●● patch | view | raw | blame | history
src/components/Transform/trade-order-area/index.vue
@@ -91,6 +91,7 @@
import TradeApi from "@/service/trading.js";
import { strToArr } from '@/utils/utis'
import { mapGetters } from "vuex";
import { getStorage, setStorage } from '@/utils/index.js';
// import PopupConfirmOrder from '@/components/popup-confirm-order'
export default {
  name: "perpetualPosition",
@@ -136,6 +137,8 @@
    this.title = this.selectData[0].title
    this.type = this.selectData[0].type
    this.form.order_price_type = 'opponent'
    // 检查是否有从其他页面传递的卖出参数
    this.checkSellParams()
  },
  watch: {
    initOpen: { // 处理滚动条初始值
@@ -191,9 +194,26 @@
    this.title = this.selectData[0].title
    this.type = this.selectData[0].type
    this.form.order_price_type = 'opponent'
    // 检查是否有从其他页面传递的卖出参数
    this.checkSellParams()
  },
  methods: {
    strToArr,
    // 检查是否有从其他页面传递的卖出参数
    checkSellParams() {
      const sellParams = getStorage('tradeSellParams')
      if (sellParams && sellParams.mode === 'close' && sellParams.volume) {
        // 切换到卖出模式
        this.changeTab('close')
        // 设置数量
        this.$nextTick(() => {
          this.form.volume = sellParams.volume
          this.isTotal = false
        })
        // 清除存储的参数
        window.localStorage.removeItem('tradeSellParams')
      }
    },
    checkIsTotal(val) {
      this.isTotal = val
      this.percentageVal = 0
src/components/fx-footer/index.vue
@@ -21,10 +21,10 @@
        </template>
      </van-tabbar-item>
      <van-tabbar-item name="STO" to="/ICO/ico">
        <span :class="[active === 'STO' ? 'active' : '']">STO</span>
      <van-tabbar-item name="ICO" to="/ICO/ico">
        <span :class="[active === 'ICO' ? 'active' : '']">ICO</span>
        <template #icon="props">
          <img :src="props.active ? icon.sto.active : icon.sto.inactive" />
          <img :src="props.active ? icon.ICO.active : icon.ICO.inactive" />
        </template>
      </van-tabbar-item>
@@ -115,7 +115,7 @@
} else if (route.path == "/documentation/index") {
  active.value = 'documentation'
} else if (route.path == "/ICO/ico") {
  active.value = 'sto'
  active.value = 'ICO'
}
let quotesStore = useQuotesStore()
@@ -137,7 +137,7 @@
  } else if (route.path == "/documentation/index") {
    active.value = 'documentation'
  } else if (route.path == "/ICO/ico") {
    active.value = 'sto'
    active.value = 'ICO'
  }
})
// 底部列表
@@ -158,7 +158,7 @@
  //   active: new URL('@/assets/imgs/footer/news-active.png', import.meta.url),
  //   inactive: new URL('@/assets/imgs/footer/news.png', import.meta.url),
  // },
  sto: {
  ICO: {
    active: new URL('@/assets/imgs/footer/sto-active.png', import.meta.url),
    inactive: new URL('@/assets/imgs/footer/sto.png', import.meta.url),
  },
src/i18n/Deutsch.js
@@ -2870,4 +2870,20 @@
    "DXCN白皮书":'DXCN-Whitepaper',
    "发售": "Verkauf",
    "资格": "Qualifikation",
    "中签时间": "Zuteilungszeit",
    "发行价": "Ausgabepreis",
    "利润": "Gewinn",
    "申购总额": "Gesamter Zeichnungsbetrag",
    "现价总额": "Gesamter aktueller Preis",
    "利润百分比": "Gewinnprozentsatz",
    "ICO申购": "ICO-Zeichnung",
    "发掘最热、最新币种,及时捕捉市场机会": "Entdecken Sie die heißesten und neuesten Kryptowährungen und nutzen Sie Marktchancen rechtzeitig",
    "募集价格": "Zeichnungspreis",
    "实际支付": "Tatsächliche Zahlung",
    "限售时间": "Verkaufsbeschränkungszeit",
    "持仓市值": "Marktwert der Bestände",
    "购买总额": "Gesamtkaufbetrag",
    "持仓信息": "Bestandsinformationen",
    "此币还没有发行时间": "Diese Münze hat noch keine Ausgabezeit",
    "请输入申购数量": "Bitte geben Sie die Zeichnungsmenge ein",
}
src/i18n/Italy.js
@@ -2960,4 +2960,20 @@
    "DXCN白皮书":'Libro bianco DXCN',
    "发售": "Vendita",
    "资格": "Qualifica",
    "中签时间": "Ora di assegnazione",
    "发行价": "Prezzo di emissione",
    "利润": "Profitto",
    "申购总额": "Importo totale di sottoscrizione",
    "现价总额": "Prezzo corrente totale",
    "利润百分比": "Percentuale di profitto",
    "ICO申购": "Sottoscrizione ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "Scopri le criptovalute più calde e recenti, cogli le opportunità di mercato in tempo",
    "募集价格": "Prezzo di sottoscrizione",
    "实际支付": "Pagamento effettivo",
    "限售时间": "Tempo di restrizione di vendita",
    "持仓市值": "Valore di mercato delle partecipazioni",
    "购买总额": "Importo totale di acquisto",
    "持仓信息": "Informazioni sulle partecipazioni",
    "此币还没有发行时间": "Questa moneta non ha ancora un tempo di emissione",
    "请输入申购数量": "Inserisci la quantità di sottoscrizione",
}
src/i18n/Japanese.js
@@ -2728,4 +2728,20 @@
    "DXCN白皮书":'DXCNホワイトペーパー',
    "发售": "発売",
    "资格": "資格",
    "中签时间": "抽選時間",
    "发行价": "発行価格",
    "利润": "利益",
    "申购总额": "申込総額",
    "现价总额": "現在価格総額",
    "利润百分比": "利益率",
    "ICO申购": "ICO申込",
    "发掘最热、最新币种,及时捕捉市场机会": "最も人気のある最新の暗号通貨を発見し、市場の機会をタイムリーに捉える",
    "募集价格": "募集価格",
    "实际支付": "実際の支払い",
    "限售时间": "制限時間",
    "持仓市值": "保有時価総額",
    "购买总额": "購入総額",
    "持仓信息": "保有情報",
    "此币还没有发行时间": "このコインにはまだ発行時間がありません",
    "请输入申购数量": "申込数量を入力してください",
}
src/i18n/Portuguese.js
@@ -679,4 +679,20 @@
    "DXCN白皮书":'Livro Branco do DXCN',
    "发售": "Venda",
    "资格": "Qualificação",
    "中签时间": "Hora de alocação",
    "发行价": "Preço de emissão",
    "利润": "Lucro",
    "申购总额": "Valor total da subscrição",
    "现价总额": "Preço atual total",
    "利润百分比": "Percentagem de lucro",
    "ICO申购": "Subscrição ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "Descubra as criptomoedas mais quentes e recentes, aproveite as oportunidades de mercado em tempo hábil",
    "募集价格": "Preço de subscrição",
    "实际支付": "Pagamento real",
    "限售时间": "Tempo de restrição de venda",
    "持仓市值": "Valor de mercado das participações",
    "购买总额": "Valor total da compra",
    "持仓信息": "Informações das participações",
    "此币还没有发行时间": "Esta moeda ainda não tem tempo de emissão",
    "请输入申购数量": "Por favor, insira a quantidade de subscrição",
}
src/i18n/Spanish.js
@@ -2643,4 +2643,20 @@
    "DXCN白皮书":'Libro blanco de DXCN',
    "发售": "Venta",
    "资格": "Calificación",
    "中签时间": "Hora de asignación",
    "发行价": "Precio de emisión",
    "利润": "Beneficio",
    "申购总额": "Importe total de suscripción",
    "现价总额": "Precio actual total",
    "利润百分比": "Porcentaje de beneficio",
    "ICO申购": "Suscripción ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "Descubra las criptomonedas más populares y recientes, aproveche las oportunidades del mercado a tiempo",
    "募集价格": "Precio de suscripción",
    "实际支付": "Pago real",
    "限售时间": "Tiempo de restricción de venta",
    "持仓市值": "Valor de mercado de las participaciones",
    "购买总额": "Importe total de compra",
    "持仓信息": "Información de participaciones",
    "此币还没有发行时间": "Esta moneda aún no tiene tiempo de emisión",
    "请输入申购数量": "Por favor, ingrese la cantidad de suscripción",
}
src/i18n/cn.js
@@ -2849,4 +2849,20 @@
    "DXCN白皮书":'DXCN白皮書',
    "发售": "發售",
    "资格": "資格",
    "中签时间": "中籤時間",
    "发行价": "發行價",
    "利润": "利潤",
    "申购总额": "申購總額",
    "现价总额": "現價總額",
    "利润百分比": "利潤百分比",
    "ICO申购": "ICO申購",
    "发掘最热、最新币种,及时捕捉市场机会": "發掘最熱、最新幣種,及時捕捉市場機會",
    "募集价格": "募集價格",
    "实际支付": "實際支付",
    "限售时间": "限售時間",
    "持仓市值": "持倉市值",
    "购买总额": "購買總額",
    "持仓信息": "持倉信息",
    "此币还没有发行时间": "此幣還沒有發行時間",
    "请输入申购数量": "請輸入申購數量",
}
src/i18n/en.js
@@ -2824,4 +2824,20 @@
    "DXCN白皮书":'DXCN White Paper',
    "发售": "Sale",
    "资格": "Qualification",
    "中签时间": "Allocation Time",
    "发行价": "Issue Price",
    "利润": "Profit",
    "申购总额": "Total Subscription Amount",
    "现价总额": "Total Current Price",
    "利润百分比": "Profit Percentage",
    "ICO申购": "ICO Subscription",
    "发掘最热、最新币种,及时捕捉市场机会": "Discover the hottest and latest cryptocurrencies, seize market opportunities in time",
    "募集价格": "Subscription Price",
    "实际支付": "Actual Payment",
    "限售时间": "Restriction Time",
    "持仓市值": "Market Value of Holdings",
    "购买总额": "Total Purchase Amount",
    "持仓信息": "Holding Information",
    "此币还没有发行时间": "This coin has no issue time yet",
    "请输入申购数量": "Please enter subscription quantity",
}
src/i18n/fa.js
@@ -2767,4 +2767,20 @@
    "DXCN白皮书":'Livre blanc du DXCN',
    "发售": "Vente",
    "资格": "Qualification",
    "中签时间": "Heure d'allocation",
    "发行价": "Prix d'émission",
    "利润": "Profit",
    "申购总额": "Montant total de souscription",
    "现价总额": "Prix actuel total",
    "利润百分比": "Pourcentage de profit",
    "ICO申购": "Souscription ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "Découvrez les cryptomonnaies les plus chaudes et les plus récentes, saisissez les opportunités du marché en temps opportun",
    "募集价格": "Prix de souscription",
    "实际支付": "Paiement réel",
    "限售时间": "Temps de restriction de vente",
    "持仓市值": "Valeur marchande des avoirs",
    "购买总额": "Montant total d'achat",
    "持仓信息": "Informations sur les avoirs",
    "此币还没有发行时间": "Cette pièce n'a pas encore de temps d'émission",
    "请输入申购数量": "Veuillez saisir la quantité de souscription",
}
src/i18n/korean.js
@@ -2864,4 +2864,20 @@
    "DXCN白皮书":'DXCN 백서',
    "发售": "판매",
    "资格": "자격",
    "中签时间": "배정 시간",
    "发行价": "발행가",
    "利润": "이익",
    "申购总额": "청약 총액",
    "现价总额": "현재가 총액",
    "利润百分比": "이익률",
    "ICO申购": "ICO 청약",
    "发掘最热、最新币种,及时捕捉市场机会": "가장 인기 있고 최신 암호화폐를 발견하고 시장 기회를 적시에 포착하세요",
    "募集价格": "모집 가격",
    "实际支付": "실제 지불",
    "限售时间": "제한 판매 시간",
    "持仓市值": "보유 시가총액",
    "购买总额": "구매 총액",
    "持仓信息": "보유 정보",
    "此币还没有发行时间": "이 코인은 아직 발행 시간이 없습니다",
    "请输入申购数量": "청약 수량을 입력하세요",
}
src/i18n/th.js
@@ -2834,4 +2834,20 @@
    "DXCN白皮书":'เอกสารไวท์เปเปอร์ของ DXCN',
    "发售": "ขาย",
    "资格": "คุณสมบัติ",
    "中签时间": "เวลาการจัดสรร",
    "发行价": "ราคาออก",
    "利润": "กำไร",
    "申购总额": "จำนวนเงินสมัครซื้อทั้งหมด",
    "现价总额": "ราคาปัจจุบันรวม",
    "利润百分比": "เปอร์เซ็นต์กำไร",
    "ICO申购": "การสมัครซื้อ ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "ค้นพบสกุลเงินดิจิทัลที่ร้อนแรงและใหม่ล่าสุด จับโอกาสในตลาดอย่างทันท่วงที",
    "募集价格": "ราคาการสมัครซื้อ",
    "实际支付": "การชำระเงินจริง",
    "限售时间": "เวลาจำกัดการขาย",
    "持仓市值": "มูลค่าตลาดของสินทรัพย์",
    "购买总额": "จำนวนเงินซื้อทั้งหมด",
    "持仓信息": "ข้อมูลสินทรัพย์",
    "此币还没有发行时间": "เหรียญนี้ยังไม่มีเวลาออกจำหน่าย",
    "请输入申购数量": "กรุณากรอกจำนวนการสมัครซื้อ",
}
src/i18n/vi.js
@@ -2814,4 +2814,20 @@
    "DXCN白皮书":'Sách trắng DXCN',
    "发售": "Bán",
    "资格": "Tư cách",
    "中签时间": "Thời gian phân bổ",
    "发行价": "Giá phát hành",
    "利润": "Lợi nhuận",
    "申购总额": "Tổng số tiền đăng ký mua",
    "现价总额": "Tổng giá hiện tại",
    "利润百分比": "Tỷ lệ lợi nhuận",
    "ICO申购": "Đăng ký mua ICO",
    "发掘最热、最新币种,及时捕捉市场机会": "Khám phá các loại tiền điện tử nóng nhất và mới nhất, nắm bắt cơ hội thị trường kịp thời",
    "募集价格": "Giá đăng ký mua",
    "实际支付": "Thanh toán thực tế",
    "限售时间": "Thời gian hạn chế bán",
    "持仓市值": "Giá trị thị trường nắm giữ",
    "购买总额": "Tổng số tiền mua",
    "持仓信息": "Thông tin nắm giữ",
    "此币还没有发行时间": "Đồng xu này chưa có thời gian phát hành",
    "请输入申购数量": "Vui lòng nhập số lượng đăng ký mua",
}
src/i18n/zhcn.js
@@ -2829,4 +2829,20 @@
    "DXCN白皮书":'DXCN白皮书',
    "发售": "发售",
    "资格": "資格",
    "中签时间": "中签时间",
    "发行价": "发行价",
    "利润": "利润",
    "申购总额": "申购总额",
    "现价总额": "现价总额",
    "利润百分比": "利润百分比",
    "ICO申购": "ICO申购",
    "发掘最热、最新币种,及时捕捉市场机会": "发掘最热、最新币种,及时捕捉市场机会",
    "募集价格": "募集价格",
    "实际支付": "实际支付",
    "限售时间": "限售时间",
    "持仓市值": "持仓市值",
    "购买总额": "购买总额",
    "持仓信息": "持仓信息",
    "此币还没有发行时间": "此币还没有发行时间",
    "请输入申购数量": "请输入申购数量",
}
src/service/ico.api.js
@@ -30,3 +30,19 @@
        data: params
    })
};
//ico查询持仓
export const _get_ico_position = (params) => {
    return request({
        url: `${API_PREFIX}/exchangeapplyorder!get_ico_position.action`,
        method: METHODS.GET,
        data: params
    })
};
//ico申购new
export const _ico_buy = (params) => {
    return request({
        url: `${API_PREFIX}/exchangeapplyorder!ico_buy.action`,
        method: METHODS.GET,
        data: params
    })
};
src/views/ICO/ico-old.vue
New file
@@ -0,0 +1,157 @@
<template>
    <div class="ico">
        <fx-header :showLeft="false">
            <template v-slot:title>
                <div>ICO</div>
            </template>
            <template v-slot:right>
                <van-icon name="todo-list-o" @click="$router.push('/ICO/icoRecord')" />
            </template>
        </fx-header>
        <div class="ico_list">
            <div class="ico_item mb-5" v-for="i in icoList" :key="i.id">
                <div class="item_1">
                    {{ i.name }}
                </div>
                <div class="item_2 flex justify-between">
                    <div class="mr-5">{{ $t('申购时间') }}</div>
                    <div>{{ i.startDate }} ~ {{ i.endDate }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('最低认购') }}</div>
                    <div>{{ i.minContribution }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('币种数量') }}</div>
                    <div>{{ i.maxContribution }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('IssuePrice') }}</div>
                    <div>{{ i.unitAmount }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('listingDate') }}</div>
                    <div>{{ i.marketDate }}</div>
                </div>
                <div class="item_2 flex justify-between align-center">
                    <div>{{ $t('进度') }}</div>
                    <div style="width: 70%;padding-top: 1rem;">
                        <van-progress :percentage="i.progressRate || 0" track-color="#ccc" />
                    </div>
                </div>
                <div class="item_3 flex justify-center">
                    <van-button type="default" round size="large" @click="openBuy(i)">{{$t('申购')}}</van-button>
                </div>
            </div>
        </div>
        <!-- 购买弹窗 -->
        <van-popup v-model:show="show" round>
            <div class="buy_popup">
                <div class="buy_title flex justify-center">{{ itemObj.symbol }}</div>
                <van-field v-model="sgNum" type="digit" :label="$t('申购数量')" />
                <div class="flex justify-center mt-5">
                    <van-button type="default" size="large" round @click="buy">{{ $t('confirm') }}</van-button>
                </div>
            </div>
        </van-popup>
    </div>
</template>
<script setup>
import { ref } from "vue";
import { showToast } from 'vant'
import { _icoList, _icoSubscribe } from "@/service/ico.api.js";
import { useI18n } from "vue-i18n";
const { t } = useI18n()
// 获取列表
const icoList = ref([])
_icoList().then(res => {
    icoList.value = res.records
}).catch(err => {
    // showToast(err.msg)
})
// 打开申购弹窗
const show = ref(false) // 控制弹窗显示
const itemObj = ref({}) // ico列表项
const sgNum = ref(0) // 申购数量
const openBuy = (i) => {
    show.value = true
    itemObj.value = i
}
// 申购
const buy = () => {
    let opt = {
        icoProjectId: itemObj.value.id,
        subscribeNums: sgNum.value,
        subscriptionType: 1,
    }
    _icoSubscribe(opt).then(res => {
        showToast(t('submitSuccess'))
        show.value = false
    }).catch(err => {
        showToast(err)
    })
}
</script>
<style lang="scss" scoped>
.ico {
    padding: 0rem 1.2rem 5rem 1.2rem;
    font-size: 1.5rem;
    .buy_popup {
        width: 40rem;
        padding: 1rem;
        .buy_title {
            font-size: 2.5rem;
            font-weight: 700;
            border-bottom: #aaa solid 1px;
            padding: 1rem;
        }
    }
    .ico_list {
        padding: 1rem 0rem;
        .ico_item {
            background-color: #333;
            padding: .5rem 1rem;
            border: #aaa solid 1px;
            border-radius: 1rem;
            .item_1 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 2rem;
                font-weight: 700;
            }
            .item_2 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 1.6rem;
                font-weight: 500;
                &>div:last-child {
                    color: #999;
                }
            }
            .item_3 {
                padding: .5rem;
            }
        }
    }
}
</style>
src/views/ICO/ico.vue
@@ -2,154 +2,476 @@
    <div class="ico">
        <fx-header :showLeft="false">
            <template v-slot:title>
                <div>STO</div>
                <div>{{ $t('ICO申购') }}</div>
            </template>
            <!-- <template v-slot:right>
                <van-icon name="todo-list-o" @click="$router.push('/ICO/icoRecord')" />
            </template> -->
        </fx-header>
        <div class="ico_list">
            <div class="ico_item mb-5" v-for="i in icoList" :key="i.id">
                <div class="item_1">
                    {{ i.name }}
                </div>
                <div class="item_2 flex justify-between">
                    <div class="mr-5">{{ $t('申购时间') }}</div>
                    <div>{{ i.startDate }} ~ {{ i.endDate }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('最低认购') }}</div>
                    <div>{{ i.minContribution }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('币种数量') }}</div>
                    <div>{{ i.maxContribution }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('IssuePrice') }}</div>
                    <div>{{ i.unitAmount }}</div>
                </div>
        <div class="ico-intro">
            {{ $t('发掘最热、最新币种,及时捕捉市场机会') }}
        </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('listingDate') }}</div>
                    <div>{{ i.marketDate }}</div>
        <!-- ICO申购卡片 -->
        <div class="ico-card">
            <div class="card-header">
                <div class="token-info">
                    <div class="token-symbol">CLK</div>
                </div>
                <div class="item_2 flex justify-between align-center">
                    <div>{{ $t('进度') }}</div>
                    <div style="width: 70%;padding-top: 1rem;">
                        <van-progress :percentage="i.progressRate || 0" track-color="#ccc" />
            </div>
            <div class="card-content">
                <div class="price-row">
                    <div class="price-item">
                        <div class="price-label">{{ $t('募集价格') }}</div>
                        <div class="price-value green">{{ closePrice || '0' }} USDT</div>
                    </div>
                    <div class="price-item">
                        <div class="price-label">{{ $t('实际支付') }}</div>
                        <div class="price-value">{{ actualPayment }} USDT</div>
                    </div>
                </div>
                <!-- <div class="item_3 flex justify-center">
                    <van-button type="default" round size="large" @click="openBuy(i)">{{$t('申购')}}</van-button>
                </div> -->
                <div class="input-row">
                    <div class="input-label">{{ $t('申购数量') }}</div>
                    <div class="input-wrapper">
                        <van-field v-model="sgNum" type="digit" :placeholder="$t('请输入申购数量')" class="subscribe-input" />
                        <van-button size="small" type="default" @click="setAll" class="all-btn">{{ $t('全部')
                        }}</van-button>
                    </div>
                </div>
                <div class="balance-row">
                    <div class="balance-label">{{ $t('可用余额') }}</div>
                    <div class="balance-value">{{ initOpen.volume || '0' }} USDT</div>
                </div>
                <van-button type="primary" block round class="buy-btn" @click="buy">
                    {{ $t('买入') }}
                </van-button>
            </div>
        </div>
        <!-- 购买弹窗 -->
        <van-popup v-model:show="show" round>
            <div class="buy_popup">
                <div class="buy_title flex justify-center">{{ itemObj.symbol }}</div>
                <van-field v-model="sgNum" type="digit" :label="$t('申购数量')" />
                <div class="flex justify-center mt-5">
                    <van-button type="default" size="large" round @click="buy">{{ $t('confirm') }}</van-button>
        <!-- 持仓信息卡片 -->
        <div class="holding-card" v-if="recordData">
            <div class="card-title">{{ $t('持仓信息') }}</div>
            <div class="card-header">
                <div class="token-info">
                    <div class="token-symbol">CLK</div>
                </div>
            </div>
        </van-popup>
            <div class="card-content">
                <div class="info-row">
                    <div class="info-label">{{ $t('限售时间') }}</div>
                    <div class="info-value">{{ recordData.lockingTime }}</div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('申购数量') }}</div>
                    <div class="info-value">{{ recordData.purchaseQuantity || '0' }}</div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('现价') }}</div>
                    <div class="info-value">{{ recordData.currentPrice || '--' }}</div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('购买价') }}</div>
                    <div class="info-value">{{ recordData.purchasePrice || '--' }}</div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('持仓市值') }}</div>
                    <div class="info-value">{{ recordData.positionvalue || '0.00' }}</div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('购买总额') }}</div>
                    <div class="info-value">{{ (recordData.purchaseQuantity * recordData.purchasePrice).toFixed(4) ||
                        '--' }}
                    </div>
                </div>
                <div class="info-row">
                    <div class="info-label">{{ $t('盈亏') }}</div>
                    <div class="info-value red">
                        {{ recordData.profitPercent ? (recordData.profitPercent + '%') : '--%' }}
                        ({{ recordData.profit || '0.00' }}USDT)
                    </div>
                </div>
                <div class="sell-btn-wrapper" v-if="canSell">
                    <van-button type="primary" block round class="sell-btn" @click="goToSell(recordData)">
                        {{ $t('卖出') }}
                    </van-button>
                </div>
            </div>
        </div>
    </div>
</template>
<script setup>
import { ref } from "vue";
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import { showToast } from 'vant'
import { _icoList, _icoSubscribe } from "@/service/ico.api.js";
import { _icoList, _ico_buy, _get_ico_position } from "@/service/ico.api.js";
import { _getBalance } from "@/service/user.api.js";
import { useI18n } from "vue-i18n";
import { useUserStore } from '@/store/user';
import { useRouter } from "vue-router";
import { setStorage } from "@/utils/index.js";
import trading from '@/service/trading'
import { WS_URL } from '@/config'
const { t } = useI18n()
const userStore = useUserStore()
const router = useRouter()
// 获取列表
const icoList = ref([])
_icoList().then(res => {
    icoList.value = res.records
}).catch(err => {
    // showToast(err.msg)
// 记录数据
const recordData = ref(null)
// 申购数量
const sgNum = ref('')
// 开仓数据
const initOpen = ref({})
// ws
const socket = ref(null)
// 价格
const closePrice = ref(0)
// 计算实际支付
const actualPayment = computed(() => {
    if (!sgNum.value || !closePrice.value) return '0'
    return (parseFloat(sgNum.value) * parseFloat(closePrice.value)).toFixed(4)
})
// 打开申购弹窗
const show = ref(false) // 控制弹窗显示
const itemObj = ref({}) // ico列表项
const sgNum = ref(0) // 申购数量
const openBuy = (i) => {
    show.value = true
    itemObj.value = i
// 判断是否可以卖出(限售时间是否已过)
const canSell = computed(() => {
    if (!recordData.value || !recordData.value.lockingTime) return false
    try {
        // 将 lockingTime 格式 "2026-02-09" 转换为 Date 对象(设置为当天的 00:00:00)
        const lockingDate = new Date(recordData.value.lockingTime + ' 00:00:00')
        const now = new Date()
        // 如果限售时间早于当前时间,则可以卖出
        return lockingDate < now
    } catch (error) {
        console.error('时间解析错误', error)
        return false
    }
})
// 获取持仓
const getRecordList = () => {
    _get_ico_position({
        session_token: initOpen.value.session_token,
    }).then(res => {
        recordData.value = res
    }).catch(err => {
        console.error('获取持仓失败', err)
    })
}
// 获取开仓数据
const getInitOpen = () => {
    if (userStore.userInfo && userStore.userInfo.token) {
        trading.tradeBuyToken().then(res => {
            initOpen.value = res || {}
            getRecordList()
        }).catch(err => {
            console.error('获取开仓数据失败', err)
        })
    }
}
// 设置全部
const setAll = () => {
    if (!closePrice.value || !initOpen.value.volume) {
        showToast(t('余额不足'))
        return
    }
    // 计算最大可申购数量(基于可用余额)
    const maxNum = Math.floor((parseFloat(initOpen.value.volume) / parseFloat(closePrice.value)) * 10000) / 10000
    sgNum.value = maxNum.toString()
}
// 最新价格获取
const handleQoutes = (data) => {
    if (data && data.length) {
        const cur = data[0]
        closePrice.value = cur.close
        // this.range = cur.change_ratio + ''
        // this.quote = cur
    }
}
// 行情socket
const startQuoteSocket = () => {
    socket.value = new WebSocket(`${WS_URL}/1/pendleusdt`)
    socket.value.onmessage = (evt) => {
        const { data } = evt
        const { code, data: _data } = JSON.parse(data)
        if (code / 1 === 0) {
            handleQoutes(_data)
        }
    }
}
// 关闭清空ws
const closeSocket = () => {
    socket.value && socket.value.close()
    socket.value = null
}
// 申购
const buy = () => {
    let opt = {
        icoProjectId: itemObj.value.id,
        subscribeNums: sgNum.value,
        subscriptionType: 1,
    if (!sgNum.value || parseFloat(sgNum.value) <= 0) {
        showToast(t('请输入申购数量'))
        return
    }
    _icoSubscribe(opt).then(res => {
    let opt = {
        volume: actualPayment.value,
        session_token: initOpen.value.session_token,
        symbol: "pendleusdt", // 币种
        price: closePrice.value,
        total: sgNum.value,
        order_price_type: "opponent", // 市价or限价
    }
    _ico_buy(opt).then(res => {
        showToast(t('submitSuccess'))
        show.value = false
        sgNum.value = ''
        getInitOpen()
    }).catch(err => {
        showToast(err)
        showToast(err.msg || err || t('申购失败'))
    })
}
// 卖出
const goToSell = (item) => {
    if (!item) {
        showToast(t('数据加载中,请稍候'))
        return
    }
    // 将卖出参数存储到 localStorage,供交易页面读取
    setStorage('tradeSellParams', {
        volume: item.purchaseQuantity || '0',
        mode: 'close' // 卖出模式
    })
    router.push(`/cryptos/trade/pendleusdt`)
}
onMounted(() => {
    getInitOpen()
    startQuoteSocket()
})
onBeforeUnmount(() => {
    closeSocket()
})
</script>
<style lang="scss" scoped>
.ico {
    padding: 0rem 1.2rem 5rem 1.2rem;
    font-size: 1.5rem;
    min-height: 100vh;
    background: #1a1a1a;
    .buy_popup {
        width: 40rem;
        padding: 1rem;
        .buy_title {
            font-size: 2.5rem;
            font-weight: 700;
            border-bottom: #aaa solid 1px;
            padding: 1rem;
        }
    .ico-intro {
        padding: 1.5rem 0;
        font-size: 1.4rem;
        color: #999;
        text-align: center;
    }
    .ico_list {
        padding: 1rem 0rem;
    .ico-card,
    .holding-card {
        background-color: #333;
        border-radius: 1rem;
        padding: 1.5rem;
        margin-bottom: 2rem;
        border: 1px solid #444;
        .ico_item {
            background-color: #333;
            padding: .5rem 1rem;
            border: #aaa solid 1px;
            border-radius: 1rem;
        .card-title {
            font-size: 1.8rem;
            font-weight: 700;
            margin-bottom: 1.5rem;
            color: #fff;
        }
            .item_1 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 2rem;
                font-weight: 700;
        .card-header {
            margin-bottom: 1.5rem;
            padding-bottom: 1rem;
            border-bottom: 1px solid #555;
            .token-info {
                display: flex;
                align-items: center;
                gap: 1rem;
                .token-logo {
                    width: 4rem;
                    height: 4rem;
                    border-radius: 50%;
                    background: #444;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    overflow: hidden;
                    img {
                        width: 100%;
                        height: 100%;
                        object-fit: cover;
                    }
                    .token-placeholder {
                        font-size: 2rem;
                        font-weight: 700;
                        color: #fff;
                    }
                }
                .token-symbol {
                    font-size: 2rem;
                    font-weight: 700;
                    color: #fff;
                }
            }
        }
            .item_2 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 1.6rem;
                font-weight: 500;
        .card-content {
            .price-row {
                display: flex;
                justify-content: space-between;
                margin-bottom: 1.5rem;
                &>div:last-child {
                    color: #999;
                .price-item {
                    flex: 1;
                    .price-label {
                        font-size: 1.4rem;
                        color: #999;
                        margin-bottom: 0.5rem;
                    }
                    .price-value {
                        font-size: 1.8rem;
                        font-weight: 600;
                        color: #fff;
                        &.green {
                            color: #06CDA5;
                        }
                    }
                }
            }
            .item_3 {
                padding: .5rem;
            .input-row {
                margin-bottom: 1.5rem;
                .input-label {
                    font-size: 1.4rem;
                    color: #999;
                    margin-bottom: 0.5rem;
                }
                .input-wrapper {
                    display: flex;
                    align-items: center;
                    gap: 1rem;
                    .subscribe-input {
                        flex: 1;
                        background: #222;
                        border-radius: 0.5rem;
                        padding: 0;
                        :deep(.van-field__control) {
                            color: #fff;
                            font-size: 1.6rem;
                            padding: 0 1rem;
                        }
                        :deep(.van-field__label) {
                            display: none;
                        }
                    }
                    .all-btn {
                        min-width: 6rem;
                        height: 3.5rem;
                        border-radius: 0.5rem;
                        background: #444;
                        color: #fff;
                        border: 1px solid #555;
                    }
                }
            }
            .balance-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 1.5rem;
                padding: 1rem;
                background: #222;
                border-radius: 0.5rem;
                .balance-label {
                    font-size: 1.4rem;
                    color: #999;
                }
                .balance-value {
                    font-size: 1.6rem;
                    color: #fff;
                }
            }
            .buy-btn {
                height: 4.5rem;
                font-size: 1.8rem;
                font-weight: 600;
                background: #555;
                border: none;
                color: #fff;
            }
            .info-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 1rem 0;
                border-bottom: 1px solid #444;
                &:last-child {
                    border-bottom: none;
                }
                .info-label {
                    font-size: 1.4rem;
                    color: #999;
                }
                .info-value {
                    font-size: 1.6rem;
                    color: #fff;
                    font-weight: 500;
                    &.red {
                        color: #f43368;
                    }
                }
            }
            .sell-btn-wrapper {
                margin-top: 1.5rem;
                padding-top: 1.5rem;
                border-top: 1px solid #444;
            }
            .sell-btn {
                height: 4.5rem;
                font-size: 1.8rem;
                font-weight: 600;
                background: #555;
                border: none;
                color: #fff;
            }
        }
    }
src/views/ICO/icoRecord.vue
@@ -2,7 +2,7 @@
    <div class="icoRecord">
        <fx-header>
            <template v-slot:title>
                <div>{{$t('申购记录')}}</div>
                <div>{{ $t('申购记录') }}</div>
            </template>
        </fx-header>
@@ -16,7 +16,7 @@
        </van-tabs>
        <div class="icoRecord_list">
            <div class="icoRecord_item mb-5" v-for="(item,index) in recordLIst" :key="index">
            <div class="icoRecord_item mb-5" v-for="(item, index) in recordLIst" :key="index">
                <div class="item_1">
                    {{ item.symbol }} ({{ item.name }})
                </div>
@@ -32,6 +32,38 @@
                    <div>{{ $t('中签数量') }}</div>
                    <div>{{ item.ballotNumber }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('中签时间') }}</div>
                    <div>{{ item.endTime }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('发行价') }}</div>
                    <div>{{ item.issuePrice }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('现价') }}</div>
                    <div>{{ item.currentPrice }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('利润') }}</div>
                    <div>{{ item.profit }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('申购总额') }}</div>
                    <div>{{ item.subscriptionTotalAmount }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('现价总额') }}</div>
                    <div>{{ item.currentTotalPrice }}</div>
                </div>
                <div class="item_2 flex justify-between">
                    <div>{{ $t('利润百分比') }}</div>
                    <div>{{ item.profitPercent ? (item.profitPercent + '%') : '0' }}</div>
                </div>
                <div class="item_3" v-if="item.status == 5">
                    <van-button type="primary" block round @click="goToSell(item)">{{ $t('卖出') }}</van-button>
                </div>
            </div>
        </div>
    </div>
@@ -42,7 +74,10 @@
import { showToast } from 'vant'
import { _icoRecordList } from "@/service/ico.api.js";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { setStorage } from "@/utils/index.js";
const { t } = useI18n()
const router = useRouter()
// tab切换
const active = ref('0');
@@ -56,7 +91,7 @@
    let opt = {
        status: active.value
    }
    if(opt.status == '0') delete opt.status
    if (opt.status == '0') delete opt.status
    _icoRecordList(opt).then((res) => {
        console.log(res);
        recordLIst.value = res.records
@@ -88,38 +123,57 @@
    }
    return str
}
// 跳转到卖出页面
const goToSell = (item) => {
    // 将卖出参数存储到 localStorage,供交易页面读取
    setStorage('tradeSellParams', {
        volume: item.ballotNumber || '0',
        mode: 'close' // 卖出模式
    })
    if (item.symbol) {
        router.push(`/cryptos/trade/${item.symbol}`)
    } else {
        showToast(t('交易对信息错误'))
    }
}
</script>
<style lang="scss" scoped>
.icoRecord{
.icoRecord {
    padding: 0rem 1.2rem 2rem 1.2rem;
    font-size: 1.5rem;
    .icoRecord_list{
    .icoRecord_list {
        padding: 1rem 0rem;
        .icoRecord_item{
            background-color: #eee;
            padding:.5rem 1rem;
        .icoRecord_item {
            background-color: #333;
            padding: .5rem 1rem;
            border: #aaa solid 1px;
            border-radius: 1rem;
            .item_1{
            .item_1 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 2rem;
                font-weight: 700;
            }
            .item_2{
            .item_2 {
                padding: 1rem .5rem;
                border-bottom: #ccc solid 1px;
                font-size: 1.6rem;
                font-weight: 500;
                &>div:last-child{
                &>div:last-child {
                    color: #999;
                }
            }
            .item_3{
                padding: .5rem;
            .item_3 {
                padding: 1rem .5rem;
                margin-top: 1rem;
            }
        }
    }
src/views/homePage/index.vue
@@ -131,12 +131,11 @@
    // { 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: 'DXCM PDF', icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: 'https://www.dexm-whitepaper.com/' },
    { key: 11, name: "ICO", icon: new URL('@/assets/imgs/home/home_1.png', import.meta.url), path: '/ICO/ico' },
]
// 获取公告数据
@@ -365,7 +364,7 @@
        width: 100%;
        .grid_item {
            width: 33%;
            width: 25%;
            color: $tab-c;
            font-size: 1.6rem;