<template>
|
<div class="options-contract no_touch">
|
<div :key="symbol" v-if="symbol">
|
<p class="status-info" v-if="type !== 'cryptos' && chartData.market && chartData.market.status">
|
<span>{{ chartData.market.status && $t(chartData.market.status) }},</span>
|
<span class="time">{{ chartData.market.time_str }}</span>
|
<span>{{ chartData.market.time_zone && $t(chartData.market.time_zone) }}</span>
|
</p>
|
|
<!-- 永续 -->
|
<div :class="{ slide2: animated1 }" v-if="selectIndex === 1">
|
<section class="value-container" v-if="showMore">
|
<div class="flex-l">
|
<p class="first-line red">{{ chartData?.close ?? '--' }}</p>
|
<p class="second-line">
|
<span class="red">{{ chartData?.netChange }}</span>
|
<span class="red">{{ `${chartData?.change_ratio}%` }}</span>
|
</p>
|
</div>
|
<div class="flex-r">
|
<div class="flex-r-item">
|
<p><span class="label">{{ $t('high') }}</span><span class="value">{{ chartData?.high ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('Low') }}</span><span class="value">{{ chartData?.low ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('open') }}</span><span class="value">{{ chartData?.open ?? '--' }}</span></p>
|
</div>
|
<div class="flex-r-item">
|
<p><span class="label">{{ $t('marketValue') }}</span><span class="value">{{ chartData?.marketCapital ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('share') }}</span><span class="value">{{ chartData?.open ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('amplitude') }}</span><span class="value">{{ chartData?.changeRatio ?? '--' }}</span></p>
|
</div>
|
<div class="flex-r-item">
|
<p><span class="label">{{ $t('quantity') }}</span><span class="value">{{ chartData?.volume ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('Change') }}</span><span class="value">{{ chartData?.turnoverRate ?? '--' }}</span></p>
|
<p><span class="label">{{ $t('Forehead') }}</span><span class="value">{{ chartData?.volume ?? '--' }}</span></p>
|
</div>
|
</div>
|
</section>
|
<div class="mainBackground rounded-view">
|
<PerpetualOpen class="pl-8 pr-8" :key="keyIndex + 'a'" :selectIndex="selectIndex" :symbol="symbol"
|
:query-type-prop="type" :green-data="bids" :red-data="asks" :price="price" :init-open="initOpen"
|
:init-close="initClose" :init-futrue="initFutrue" :currentType="currentType"
|
@changeValueBack="changeValueBack" @changeCurrentType="changeCurrentType" @ordered="onOrdered" />
|
<div class="line"></div>
|
<PerpetualOrder class="pl-8 pr-8" :key="keyIndex + 'b'" :symbol="symbol" :order-cur="orderCur"
|
:order-hold="orderHold" :topIndex="selectIndex" :futrue-hold="futrueHold" :futrue-histroy="futrueHistroy"
|
@tab="onTab" @recall="onRecall" />
|
</div>
|
</div>
|
|
<!-- 交割:图1样式 -->
|
<div :class="{ slide1: animated2 }" class="delivery-section" v-else>
|
<!-- 开收高低 % -->
|
<div class="delivery-chart-header">
|
<div class="delivery-ohlc">
|
<span class="delivery-pct" :class="(chartData?.change_ratio || 0) >= 0 ? 'up' : 'down'">{{ chartData?.close || '--' }}{{
|
chartData?.change_ratio != null ? ` ${chartData.change_ratio}%` : ' --' }}</span>
|
<div class="delivery-ohlc-grid">
|
<div class="delivery-ohlc-row">
|
<span class="label">{{ $t('开') }}</span>
|
<span class="val">{{ chartData?.open || '--' }}</span>
|
<span class="label">{{ $t('收') }}</span>
|
<span class="val">{{ chartData?.close || '--' }}</span>
|
</div>
|
<div class="delivery-ohlc-row">
|
<span class="label">{{ $t('高') }}</span>
|
<span class="val">{{ chartData?.high || '--' }}</span>
|
<span class="label">{{ $t('低') }}</span>
|
<span class="val">{{ chartData?.low || '--' }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
<!-- K 线图 -->
|
<div class="delivery-kline-wrap">
|
<k-line-charts v-if="symbol" :update-key="updateKey" :update-data="quote" :symbol="symbol"
|
:showBottom="true" />
|
</div>
|
<!-- 交割 持仓/历史持仓:与永续合约委托区一致样式(修改图一之前) -->
|
<div class="delivery-order-wrap items-center mt-4">
|
<div class="flex justify-between border-b-color">
|
<div class="flex">
|
<div class="px-2 py-2 flex items-center textColor1 text-28" @click="onDeliveryTab('hold')"
|
:class="deliveryPositionTab === 'hold' ? 'active-line' : ''">{{ $t('持有仓位') }}<span
|
v-if="deliveryPositionTab === 'hold'">({{ futrueHold.length }})</span></div>
|
<div class="px-2 ml-12 py-2 flex items-center textColor1 text-28" @click="onDeliveryTab('history')"
|
:class="deliveryPositionTab === 'history' ? 'active-line' : ''">{{ $t('历史仓位') }}</div>
|
</div>
|
<img src="@/assets/image/public/record.png" alt="record-img" class="w-16 h-9 pr-8 record-img"
|
@click="goDeliveryHistory" />
|
</div>
|
<template v-if="deliveryPositionTab === 'hold'">
|
<futrue-hold-list :price="price" :list-data="futrueHold" />
|
<div class="text-grey text-center py-72 text-30" v-if="futrueHold.length === 0">{{ $t('您目前没有持仓') }}</div>
|
</template>
|
<template v-else>
|
<futrue-histroy-position :price="price" :list-data="futrueHistroy" />
|
<div class="text-grey text-center py-72 text-30" v-if="futrueHistroy.length === 0">{{ $t('您目前没有持仓') }}</div>
|
</template>
|
</div>
|
<div class="delivery-actions">
|
<button class="btn-buy btn-up" @click="openOptionsPopup('up')">{{ $t('开多') }}</button>
|
<button class="btn-buy btn-down" @click="openOptionsPopup('down')">{{ $t('开空') }}</button>
|
</div>
|
</div>
|
</div>
|
|
<!-- <div class="fixed-box" v-if="selectIndex === 1">
|
<div class="flex justify-between items-center px-8 py-5" @click.stop="showCharts = !showCharts">
|
<span class="text-30 textColor">
|
{{ type === 'cryptos' ? (symbol_data || symbol).toUpperCase() + '/USDT' : symbol.toUpperCase()
|
}} {{ $t('k线图表') }}
|
</span>
|
<van-icon class="textColor text-28" :name="showCharts ? 'arrow-down' : 'arrow-up'" />
|
</div>
|
<div class="kline-container flex" v-if="showCharts">
|
<div class="chart-index">
|
<k-line-charts v-if="symbol" :update-key="updateKey" :update-data="quote" :symbol="symbol"
|
:showBottom="true" />
|
</div>
|
</div>
|
</div> -->
|
|
<!-- 期权交易弹窗 图2(尺寸放大 1/3) -->
|
<van-popup v-model:show="showOptionsModal" round closeable close-icon-position="top-right">
|
<div class="options-modal">
|
<h2 class="modal-title">{{ $t('期权交易') }}</h2>
|
<div class="modal-symbol">
|
{{ symbolDisplayName != null && symbolDisplayName !== '' ? symbolDisplayName : (type === 'cryptos' ?
|
(symbol_data
|
|| symbol) : symbol) || '' }}{{ (symbolDisplayName == null || symbolDisplayName === '') && type === 'cryptos'
|
?
|
'USDT' : '' }}
|
|
<span class="pct-badge" :class="(chartData?.change_ratio || 0) >= 0 ? 'up' : 'down'">{{ chartData?.close || '--' }}{{
|
chartData?.change_ratio != null ? ` ${chartData.change_ratio}%` : ' --' }}</span>
|
</div>
|
<div class="modal-section">
|
<div class="section-label">{{ $t('交割时间') }}</div>
|
<div class="period-btns">
|
<button v-for="p in deliveryParaList" :key="p.para_id" class="period-btn"
|
:class="{ active: optionsForm.period === p.para_id }" @click="optionsForm.period = p.para_id">
|
<div>{{ p.time_num }}{{ (p.time_unit || '').substr(0, 1) }}</div>
|
<div>{{ p.profit_ratio }}%</div>
|
</button>
|
</div>
|
</div>
|
<div class="modal-section">
|
<div class="section-label">{{ $t('选择类型') }}</div>
|
<div class="type-btns">
|
<button class="type-btn up" :class="{ active: optionsForm.type === 'up' }"
|
@click="optionsForm.type = 'up'">{{
|
$t('开多') }}</button>
|
<button class="type-btn down" :class="{ active: optionsForm.type === 'down' }"
|
@click="optionsForm.type = 'down'">{{ $t('开空') }}</button>
|
</div>
|
</div>
|
<div class="modal-section">
|
<van-field v-model="optionsForm.qty" type="number" :placeholder="qtyPlaceholder" />
|
</div>
|
<div class="modal-available">
|
{{ $t('可用') }}: <strong>{{ availableBalance }}</strong>
|
</div>
|
<button class="modal-submit" @click="confirmOptionsOrder">{{ $t('确认下单') }}</button>
|
</div>
|
</van-popup>
|
|
<!-- 交割订单详情弹窗(与永续交割下单后一致) -->
|
<van-popup v-model:show="showDeliveryDetailPopup" round position="bottom">
|
<popup-delivery v-if="deliveryOrderDetail.order_no" showBtns :price="price" :detail-data="deliveryOrderDetail"
|
:key="deliveryOrderDetail.order_no" @close="showDeliveryDetailPopup = false" />
|
</van-popup>
|
</div>
|
</template>
|
|
<script>
|
import PerpetualOpen from '@/components/Transform/perpetual-open/index.vue'
|
import PerpetualOrder from '@/components/Transform/perpetual-order/index.vue'
|
import KLineCharts from '@/components/Transform/kline-charts/index.vue'
|
import futrueHoldList from '@/components/Transform/deliveryContract/hold.vue'
|
import futrueHistroyPosition from '@/components/Transform/deliveryContract/position.vue'
|
import PopupDelivery from '@/components/Transform/popup-delivery/index.vue'
|
import { Icon, showToast } from 'vant'
|
import { mapActions, mapGetters } from 'vuex'
|
import { SET_COIN_LIST } from '@/store/const.store'
|
import { _getDeepData, _initOpen, _initClose, _futrueOrderInit, _futrueOrder, _futrueOrderDetail, _contractApplyOrderList, contractOrder, _futrueOrderList } from '@/service/trade.api'
|
import { _getBalance } from '@/service/user.api'
|
import { _getHomeList } from '@/service/home.api'
|
import { WS_URL } from '@/config'
|
|
const SHOW_LENGTH = 7
|
|
function initDepthArr(len = SHOW_LENGTH) {
|
const arr = []
|
for (let i = 0; i < len; i++) arr.push({ amount: '--', price: '--' })
|
return arr
|
}
|
|
export default {
|
name: 'OptionsContract',
|
components: { PerpetualOpen, PerpetualOrder, KLineCharts, futrueHoldList, futrueHistroyPosition, PopupDelivery, [Icon.name]: Icon },
|
props: {
|
symbol: { type: String, default: '' },
|
symbolDisplayName: { type: String, default: '' },
|
selectIndex: { type: Number, default: 1 },
|
type: { type: String, default: 'cryptos' }
|
},
|
data() {
|
return {
|
_lastSymbol: '',
|
quote: {},
|
keyIndex: 0,
|
price: '',
|
initOpen: {},
|
initClose: {},
|
asks: initDepthArr(),
|
bids: initDepthArr(),
|
orderCur: [],
|
orderHold: [],
|
futrueHold: [],
|
futrueHistroy: [],
|
curTab: 'fetchOrderListHold',
|
initFutrue: {},
|
animated1: false,
|
animated2: false,
|
currentType: 'long',
|
showCharts: false,
|
chartData: {},
|
showMore: false,
|
updateKey: 1,
|
symbolName: '',
|
symbol_data: '',
|
timer: null,
|
timer1: null,
|
timerMoeny: null,
|
initFunTimer1: null,
|
initFunTimer2: null,
|
sockets: { quotes: null, deep: null },
|
deliveryPeriod: '1m',
|
deliveryTimeTabs: [
|
{ id: '1m', text: '1分' },
|
{ id: '5m', text: '5分' },
|
{ id: '15m', text: '15分' },
|
{ id: '30m', text: '30分' },
|
{ id: '1h', text: '1时' },
|
{ id: '1d', text: '1天' },
|
{ id: '1w', text: '1周' }
|
],
|
deliveryPositionTab: 'hold',
|
showOptionsModal: false,
|
optionsForm: { period: '', type: 'up', qty: '' },
|
deliveryOrderDetail: {},
|
showDeliveryDetailPopup: false
|
}
|
},
|
computed: {
|
...mapGetters('user', ['userInfo']),
|
...mapGetters({ coinList: 'home/coinList' }),
|
availableBalance() {
|
return this.userInfo?.balance ?? this.initFutrue?.amount ?? 0
|
},
|
// 交割时间列表(与 PerpetualContract/contract-futrue 一致,来自 initFutrue.para)
|
deliveryParaList() {
|
const para = this.initFutrue && this.initFutrue.para
|
return Array.isArray(para) ? para : []
|
},
|
// 当前选中的交割周期(用于 placeholder 最小金额、下单校验)
|
selectedDeliveryPara() {
|
const id = this.optionsForm.period
|
if (!id) return null
|
return this.deliveryParaList.find(p => p.para_id === id) || null
|
},
|
// 数量占位文案(与 perpetual-open 一致:最少 + 最小金额 + buy_min)
|
qtyPlaceholder() {
|
const para = this.selectedDeliveryPara
|
if (para && para.buy_min != null && para.buy_min !== '') {
|
return (this.$t('最少') || '最少') + (this.$t('最小金额') || '最小金额') + para.buy_min
|
}
|
return this.$t('数量') || '数量'
|
}
|
},
|
watch: {
|
// 交割周期列表有数据时默认选中第一项
|
deliveryParaList(list) {
|
if (list && list.length > 0) {
|
const current = this.optionsForm.period
|
const found = current && list.some(p => p.para_id === current)
|
if (!found) this.optionsForm.period = list[0].para_id
|
}
|
},
|
symbol(val) {
|
if (val && val !== this._lastSymbol) {
|
this._lastSymbol = val
|
this.closeSocket()
|
this.init(val)
|
}
|
},
|
selectIndex(val) {
|
const idx = val ?? 1
|
this.curTab = idx === 2 ? 'fetchFutrueHoldList' : 'fetchOrderListHold'
|
this.clearTimer()
|
if (this.symbol) this[this.curTab](this.symbol)
|
},
|
type(val) {
|
if (val) this.SET_COIN_LIST(val)
|
}
|
},
|
async created() {
|
const type = this.type || 'cryptos'
|
await this.SET_COIN_LIST(type)
|
this._lastSymbol = this.symbol
|
this.curTab = (this.selectIndex ?? 1) === 2 ? 'fetchFutrueHoldList' : 'fetchOrderListHold'
|
if (this.userInfo && this.userInfo.token) {
|
this.getBalance()
|
this.timerMoeny = setInterval(() => this.getBalance(), 3000)
|
}
|
},
|
mounted() {
|
if (this.symbol) this.$nextTick(() => this.init(this.symbol))
|
},
|
beforeUnmount() {
|
this.closeSocket()
|
this.clearTimer()
|
if (this.timerMoeny) {
|
clearInterval(this.timerMoeny)
|
this.timerMoeny = null
|
}
|
},
|
methods: {
|
...mapActions('home', [SET_COIN_LIST]),
|
getBalance() {
|
_getBalance().then(data => {
|
this.$store.commit('user/SET_USERINFO', { balance: data.money })
|
this.initFutrue.amount = data.money
|
})
|
},
|
changeCurrentType(type) {
|
this.currentType = type
|
},
|
changeValueBack(val) {
|
// 可扩展:切换深度条数时更新 showLength
|
},
|
onRecall() {
|
this.clearTimer()
|
const symbolType = this.type || 'cryptos'
|
contractOrder({ symbol: this.symbol, type: 'orders', page_no: 1, symbolType }).then(data => {
|
this.orderHold = (data || []).sort(this.sortData)
|
})
|
this[this.curTab](this.symbol)
|
_initOpen({ symbol: this.symbol }).then(data => { this.initOpen = data })
|
},
|
onDeliveryTab(tab) {
|
this.deliveryPositionTab = tab
|
if (tab === 'hold') this.fetchFutrueHoldList(this.symbol)
|
else this.fetchFutrueHistory(this.symbol)
|
},
|
goDeliveryHistory() {
|
if (this.userInfo && this.userInfo.token) {
|
const type = this.type || 'cryptos'
|
this.$router.push({ path: '/cryptos/deliveryContractHistory', query: { symbol: this.symbol, type } })
|
} else {
|
this.$router.push('/login')
|
}
|
},
|
onTab(evt) {
|
this.clearTimer()
|
this.curTab = evt
|
this[evt](this.symbol)
|
},
|
onOrdered(evt) {
|
this.clearTimer()
|
this.initParam(this.symbol, evt)
|
this[this.curTab](this.symbol)
|
},
|
fetchQoutes(symbol) {
|
_getHomeList(symbol).then(data => {
|
if (data && data[0]) {
|
this.symbolName = data[0].name
|
this.symbol_data = (data[0].symbol_data || '').trim() || symbol
|
this.handleQoutes(data)
|
this.startQuoteSocket()
|
}
|
})
|
},
|
handleQoutes(data) {
|
if (data && data.length) {
|
const cur = data[0]
|
this.price = cur.close
|
this.quote = cur
|
this.chartData = cur
|
this.updateKey++
|
}
|
},
|
fetchDeepData(symbol) {
|
_getDeepData(symbol).then(data => {
|
this.handleDeep(data)
|
this.startDeepSocket()
|
})
|
},
|
handleDeep(data) {
|
if (!data || !data.asks || !data.bids) return
|
const { asks, bids } = data
|
this.asks = asks.sort((a, b) => b.price - a.price).slice(0, SHOW_LENGTH)
|
this.bids = bids.sort((a, b) => b.price - a.price).slice(0, SHOW_LENGTH)
|
},
|
startQuoteSocket() {
|
if (this.sockets.quotes) return
|
this.sockets.quotes = new WebSocket(`${WS_URL}/1/${this.symbol}`)
|
this.sockets.quotes.onmessage = (evt) => {
|
try {
|
const { code, data: _data } = JSON.parse(evt.data)
|
if (code == 0 && _data) {
|
this.handleQoutes(_data)
|
this.chartData = _data[0] ?? {}
|
}
|
} catch (_) { }
|
}
|
},
|
startDeepSocket() {
|
if (this.sockets.deep) return
|
this.sockets.deep = new WebSocket(`${WS_URL}/3/${this.symbol}`)
|
this.sockets.deep.onmessage = (evt) => {
|
try {
|
const { code, data: _data } = JSON.parse(evt.data)
|
if (code == 0 && _data) {
|
this.handleDeep(_data)
|
}
|
} catch (_) { }
|
}
|
},
|
initParam(symbol, type) {
|
if (type === 'open' || type === 'long' || type === 'short' || !type) {
|
const initFun = () => {
|
_initOpen({ symbol }).then(data => {
|
this.initOpen = data
|
if (this.initFunTimer1) { clearTimeout(this.initFunTimer1); this.initFunTimer1 = null }
|
}).catch(() => {
|
this.initFunTimer1 = setTimeout(initFun, 1000)
|
})
|
}
|
initFun()
|
}
|
if (type === 'close' || !type) {
|
const initFun = () => {
|
_initClose({ symbol }).then(data => {
|
this.initClose = data
|
if (this.initFunTimer2) { clearTimeout(this.initFunTimer2); this.initFunTimer2 = null }
|
}).catch(() => {
|
this.initFunTimer2 = setTimeout(initFun, 1000)
|
})
|
}
|
this.initFunTimer2 = setTimeout(initFun, 600)
|
}
|
if (type === 'futrue' || !type) {
|
_futrueOrderInit(symbol).then(data => { this.initFutrue = data || {} })
|
}
|
},
|
fetchOrderListCur(symbol) {
|
if (!this.userInfo || !this.userInfo.token) return
|
const params = { symbol, type: 'orders', page_no: 1 }
|
_contractApplyOrderList(params).then(data => { this.orderCur = data || [] })
|
this.clearTimer()
|
this.timer = setInterval(() => {
|
_contractApplyOrderList(params).then(data => { this.orderCur = data || [] })
|
}, 1000)
|
},
|
fetchOrderListHold(symbol) {
|
if (!this.userInfo || !this.userInfo.token) return
|
const symbolType = this.type || 'cryptos'
|
const obj = { symbol, type: 'orders', page_no: 1, symbolType }
|
contractOrder(obj).then(data => {
|
this.orderHold = (data || []).sort(this.sortData)
|
})
|
this.clearTimer()
|
this.timer = setInterval(() => {
|
contractOrder(obj).then(data => {
|
this.orderHold = (data || []).sort(this.sortData)
|
})
|
}, 1000)
|
},
|
fetchFutrueHoldList(symbol) {
|
if (!this.userInfo || !this.userInfo.token) return
|
const symbolType = this.type || 'cryptos'
|
_futrueOrderList(symbol, 'orders', 1, symbolType).then(data => {
|
this.futrueHold = (data || []).sort(this.sortData)
|
})
|
this.clearTimer()
|
this.timer = setInterval(() => {
|
_futrueOrderList(symbol, 'orders', 1, symbolType).then(data => {
|
this.futrueHold = (data || []).sort(this.sortData)
|
})
|
}, 1000)
|
},
|
fetchFutrueHistory(symbol) {
|
const symbolType = this.type || 'cryptos'
|
_futrueOrderList(symbol, 'hisorders', 1, symbolType).then(data => {
|
this.futrueHistroy = data || []
|
})
|
},
|
init(symbol) {
|
if (!symbol) return
|
this.fetchQoutes(symbol)
|
this.fetchDeepData(symbol)
|
this.initParam(symbol)
|
this.clearTimer()
|
if (this.curTab === 'fetchOrderListHold') {
|
this.fetchOrderListHold(symbol)
|
} else {
|
this.fetchFutrueHoldList(symbol)
|
}
|
},
|
closeSocket() {
|
if (this.sockets.quotes) { this.sockets.quotes.close(); this.sockets.quotes = null }
|
if (this.sockets.deep) { this.sockets.deep.close(); this.sockets.deep = null }
|
},
|
clearTimer() {
|
if (this.initFunTimer1) { clearTimeout(this.initFunTimer1); this.initFunTimer1 = null }
|
if (this.initFunTimer2) { clearTimeout(this.initFunTimer2); this.initFunTimer2 = null }
|
if (this.timer) { clearInterval(this.timer); this.timer = null }
|
},
|
sortData(a, b) {
|
return new Date(b.open_time).getTime() - new Date(a.open_time).getTime()
|
},
|
openOptionsPopup(type) {
|
this.optionsForm.type = type
|
if (this.deliveryParaList.length && !this.optionsForm.period) {
|
this.optionsForm.period = this.deliveryParaList[0].para_id
|
}
|
this.showOptionsModal = true
|
},
|
confirmOptionsOrder() {
|
if (!this.userInfo || !this.userInfo.token) {
|
this.$router.push('/login')
|
return
|
}
|
const amount = (this.optionsForm.qty || '').toString().trim()
|
if (!amount || Number(amount) <= 0) {
|
showToast(this.$t('请输入金额') || '请输入金额')
|
return
|
}
|
const para = this.selectedDeliveryPara
|
const buyMin = para && para.buy_min != null && para.buy_min !== '' ? Number(para.buy_min) : 0
|
if (buyMin > 0 && Number(amount) < buyMin) {
|
showToast((this.$t('最少') || '最少') + (this.$t('最小金额') || '最小金额') + buyMin)
|
return
|
}
|
const para_id = (this.optionsForm.period || '').toString().trim()
|
if (!para_id) {
|
showToast(this.$t('请选择有效周期') || '请选择有效周期')
|
return
|
}
|
const doOrder = (sessionToken) => {
|
_futrueOrder({
|
symbol: this.symbol,
|
session_token: sessionToken,
|
direction: this.optionsForm.type === 'up' ? 'buy' : 'sell',
|
amount,
|
para_id
|
}).then((res) => {
|
showToast(this.$t('操作成功') || '操作成功')
|
this.showOptionsModal = false
|
this.optionsForm.qty = ''
|
_getBalance().then(data => {
|
this.$store.commit('user/SET_USERINFO', { balance: data.money })
|
})
|
this.initParam(this.symbol, 'futrue')
|
this.fetchFutrueHoldList(this.symbol)
|
if (res && res.order_no) {
|
_futrueOrderDetail(res.order_no).then(data => {
|
this.deliveryOrderDetail = data
|
this.showDeliveryDetailPopup = true
|
})
|
}
|
}).catch((err) => {
|
if (err && err.code === 'ECONNABORTED') {
|
showToast(this.$t('网络超时!') || '网络超时!')
|
} else if (err && err.msg) {
|
showToast(err.msg)
|
}
|
})
|
}
|
const session_token = this.initFutrue.session_token
|
if (!session_token) {
|
_futrueOrderInit(this.symbol).then(data => {
|
this.initFutrue = { ...this.initFutrue, ...(data || {}) }
|
doOrder(data && data.session_token)
|
}).catch(() => {
|
doOrder()
|
})
|
} else {
|
doOrder(session_token)
|
}
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
@import '@/assets/css/variable.scss';
|
|
.options-contract {
|
min-height: 12.5rem;
|
-webkit-user-select: none;
|
user-select: none;
|
padding-bottom: 18rem;
|
}
|
|
.status-info {
|
margin-top: 1.25rem;
|
padding: 0 1.875rem;
|
font-size: 1.5rem;
|
line-height: 4rem;
|
height: 4rem;
|
border-top: 0.0625rem solid $border_color;
|
border-bottom: 0.0625rem solid $border_color;
|
|
.time {
|
width: 13.75rem;
|
display: inline-block;
|
}
|
}
|
|
.rounded-view {
|
border-top-left-radius: 1.25rem;
|
border-top-right-radius: 1.25rem;
|
box-sizing: border-box;
|
}
|
|
.line {
|
height: 0.8125rem;
|
background: $tab_background;
|
}
|
|
@keyframes animate1 {
|
0% {
|
opacity: 1;
|
transform: translate3d(100%, 0, 0);
|
}
|
|
100% {
|
opacity: 1;
|
transform: translate3d(0%, 0, 0);
|
}
|
}
|
|
@keyframes animate2 {
|
0% {
|
opacity: 1;
|
transform: translate3d(-100%, 0, 0);
|
}
|
|
100% {
|
opacity: 1;
|
transform: translate3d(0%, 0, 0);
|
}
|
}
|
|
.slide1 {
|
animation: animate1 200ms linear;
|
}
|
|
.slide2 {
|
animation: animate2 200ms linear;
|
}
|
|
.value-container {
|
padding: 0.625rem 0.75rem;
|
margin-top: 0.25rem;
|
display: flex;
|
justify-content: space-between;
|
font-size: 0.75rem;
|
color: #747A8F;
|
border-bottom: 0.0625rem solid $border_color;
|
|
.flex-l {
|
display: flex;
|
flex-direction: column;
|
justify-content: center;
|
width: 15rem;
|
|
.first-line {
|
font-weight: 700;
|
font-size: 2rem;
|
color: $red;
|
}
|
|
.second-line {
|
margin-top: 0.5rem;
|
text-align: left;
|
}
|
}
|
|
.flex-r {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
color: $text_color;
|
}
|
|
.flex-r-item {
|
flex: 1;
|
|
.label {
|
color: $lable_color;
|
margin-right: 0.625rem;
|
}
|
}
|
}
|
|
.fixed-box {
|
position: fixed;
|
width: 100%;
|
bottom: 0;
|
left: 0;
|
z-index: 1000;
|
background: $tab_background;
|
}
|
|
.kline-container {
|
margin-top: 0.625rem;
|
|
.chart-index {
|
flex: 1;
|
min-width: 12.5rem;
|
}
|
}
|
|
/* 交割 图1(尺寸缩小 1/4) */
|
.delivery-section {
|
padding-bottom: 4.6875rem;
|
background: $tab_background;
|
}
|
|
.delivery-chart-header {
|
padding: 0.5625rem 0.75rem;
|
background: #fff;
|
border-bottom: 0.0625rem solid $border_color;
|
}
|
|
.delivery-ohlc {
|
display: flex;
|
align-items: flex-start;
|
gap: 0.5625rem;
|
|
.delivery-pct {
|
font-size: 2.2rem;
|
font-weight: 700;
|
width: 40%;
|
|
&.up {
|
color: $green;
|
}
|
|
&.down {
|
color: $red;
|
}
|
}
|
|
.delivery-ohlc-grid {
|
font-size: 2rem;
|
color: $text_color;
|
width: 66%;
|
|
.delivery-ohlc-row {
|
display: flex;
|
align-items: center;
|
gap: 0.75rem;
|
margin-bottom: 0.1875rem;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
|
.label {
|
color: $lable_color;
|
margin-right: 0.25rem;
|
}
|
|
.val {
|
margin-right: 4rem;
|
}
|
}
|
}
|
|
.delivery-kline-wrap {
|
background: #fff;
|
margin-top: 0.125rem;
|
min-height: 15rem;
|
|
.kline-charts {
|
min-height: 15rem;
|
}
|
}
|
|
/* 交割 持仓/历史持仓:与 PerpetualOrder 一致样式(尺寸放大一倍) */
|
.delivery-order-wrap {
|
background-color: $main_background;
|
padding: 0 1rem 1rem;
|
box-sizing: border-box;
|
|
.active-line {
|
position: relative;
|
color: $white !important;
|
border-radius: 1rem;
|
background-color: $color_main;
|
}
|
|
.record-img {
|
margin-top: 1.25rem;
|
}
|
|
.textColor1 {
|
color: $text_color;
|
}
|
}
|
|
.delivery-actions {
|
position: fixed;
|
bottom: 12rem;
|
left: 0;
|
right: 0;
|
display: flex;
|
justify-content: space-between;
|
gap: 2rem;
|
padding: 1rem 3rem;
|
background: #fff;
|
border-top: 0.0625rem solid $border_color;
|
z-index: 100;
|
|
.btn-buy {
|
flex: 1;
|
height: 7rem;
|
font-size: 2.2rem;
|
font-weight: 600;
|
color: #fff;
|
border: none;
|
border-radius: 0.5625rem;
|
|
&.btn-up {
|
background: $green;
|
}
|
|
&.btn-down {
|
background: $red;
|
}
|
}
|
}
|
|
/* 期权弹窗 图2(尺寸放大 1/3) */
|
.options-modal {
|
padding: 1.5rem;
|
padding-top: 3rem;
|
|
.modal-title {
|
font-size: 2.4rem;
|
font-weight: 700;
|
color: $text_color;
|
padding-bottom: 1rem;
|
margin-bottom: 2rem;
|
border-bottom: 1px solid $border_color;
|
}
|
|
.modal-symbol {
|
font-size: 2.8rem;
|
font-weight: 700;
|
color: $text_color;
|
margin-bottom: 1.5rem;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
|
.pct-badge {
|
display: inline-block;
|
margin-left: 0.5rem;
|
padding: 0.167rem 0.5rem;
|
font-size: 2.8rem;
|
color: #fff;
|
border-radius: 0.25rem;
|
|
&.up {
|
color: $green;
|
}
|
|
&.down {
|
color: $red;
|
}
|
}
|
}
|
|
.modal-section {
|
margin-bottom: 1.5rem;
|
|
.section-label {
|
font-size: 2rem;
|
color: $text_color;
|
margin-bottom: 2rem;
|
}
|
|
.period-btns {
|
display: flex;
|
flex-wrap: nowrap;
|
gap: 1rem;
|
overflow-x: auto;
|
overflow-y: hidden;
|
-webkit-overflow-scrolling: touch;
|
padding-bottom: 0.25rem;
|
|
&::-webkit-scrollbar {
|
height: 0.2rem;
|
}
|
&::-webkit-scrollbar-thumb {
|
background: #ddd;
|
border-radius: 0.1rem;
|
}
|
|
.period-btn {
|
flex-shrink: 0;
|
padding: 1.5rem 1.25rem;
|
font-size: 2rem;
|
font-weight: 700;
|
border-radius: 0.5rem;
|
background: #f5f5f5;
|
color: $text_color;
|
|
&.active {
|
background: #0a6bfa;
|
color: #fff;
|
}
|
}
|
}
|
|
.type-btns {
|
display: flex;
|
gap: 1rem;
|
|
.type-btn {
|
flex: 1;
|
padding: 1rem;
|
font-size: 1.75rem;
|
font-weight: 600;
|
border-radius: 0.5rem;
|
border: 0.083rem solid #ddd;
|
background: #fff;
|
color: $text_color;
|
|
&.up.active {
|
background: $green;
|
color: #fff;
|
border-color: $green;
|
}
|
|
&.down.active {
|
background: $red;
|
color: #fff;
|
border-color: $red;
|
}
|
}
|
}
|
}
|
|
.modal-available {
|
font-size: 1.667rem;
|
color: $lable_color;
|
margin-bottom: 1.5rem;
|
|
strong {
|
color: $text_color;
|
}
|
}
|
|
.modal-submit {
|
width: 100%;
|
height: 5.5rem;
|
font-size: 2rem;
|
font-weight: 600;
|
color: #fff;
|
background: #1989fa;
|
border: none;
|
border-radius: 0.75rem;
|
}
|
}
|
</style>
|