|
|
@@ -1,33 +1,179 @@
|
|
|
+<!-- 合约 - 持仓 - 平仓 -->
|
|
|
<template>
|
|
|
<app-modal direction="right-top" height="100%" width="100%" v-model:show="showModal" :refresh="refresh">
|
|
|
<app-view class="g-form">
|
|
|
<template #header>
|
|
|
- <app-navbar title="平仓" />
|
|
|
+ <app-navbar title="平仓" @back="closed" />
|
|
|
+ </template>
|
|
|
+ <Form ref="formRef" class="g-form__container" @submit="onCloseSumit">
|
|
|
+ <CellGroup title="持仓信息" inset>
|
|
|
+ <Cell title="代码/名称"
|
|
|
+ :value="`${selectedRow.goodsCode}/${selectedRow.goodsName}`" />
|
|
|
+ <Cell title="持仓方向" :value="getBuyOrSellName(selectedRow.tHDetailEx.buyOrSell)" />
|
|
|
+ <Cell title="持仓价格(USDT)" :value="formatDecimal(selectedRow.tHDetailEx.holderPrice, selectedRow.decimalPlace)" />
|
|
|
+ <Cell title="持仓量" :value="selectedRow.tHDetailEx.holderQty" />
|
|
|
+ <Cell title="冻结量" :value="selectedRow.tHDetailEx.freezeQty" />
|
|
|
+ <Cell title="浮动盈亏">
|
|
|
+ <template #value>
|
|
|
+ <span :class="handlePriceColor(closepl)">
|
|
|
+ {{ formatDecimal(closepl, selectedRow.decimalplace) }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </Cell>
|
|
|
+ <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
|
|
|
+ <template #input>
|
|
|
+ <app-stepper v-model="formData.OrderPrice" min="0.0" :decimal-length="quote?.decimalplace"
|
|
|
+ :step="quote?.decimalvalue" :auto-fixed="false" />
|
|
|
+ </template>
|
|
|
+ </Field>
|
|
|
+ <Field label="限单价" is-link>
|
|
|
+ <template #input>
|
|
|
+ <app-select v-model="formData.PriceMode" :options="options" />
|
|
|
+ </template>
|
|
|
+ </Field>
|
|
|
+ <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
|
|
|
+ <template #input>
|
|
|
+ <app-stepper v-model="formData.OrderQty" min="0.0" :max="maxQty" :auto-fixed="false" integer />
|
|
|
+ </template>
|
|
|
+ </Field>
|
|
|
+ </CellGroup>
|
|
|
+ </Form>
|
|
|
+ <template #footer>
|
|
|
+ <Button block square type="danger" @click="formRef?.submit">平仓</Button>
|
|
|
</template>
|
|
|
</app-view>
|
|
|
</app-modal>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { shallowRef } from 'vue'
|
|
|
+import { shallowRef, PropType, onMounted, computed } from 'vue'
|
|
|
import AppModal from '@/components/base/modal/index.vue'
|
|
|
+import { CellGroup, Cell, Button, FieldRule, Form, Field, FormInstance } from 'vant'
|
|
|
+import { getBuyOrSellName, BuyOrSell } from '@/constants/order'
|
|
|
+import { formatDecimal, handleRequestBigNumber, handlePriceColor } from '@/filters'
|
|
|
+import { useOrder } from '@/business/trade'
|
|
|
+import { dialog, fullloading } from '@/utils/vant'
|
|
|
+import { useFuturesStore, usePositionStore, i18n } from '@/stores'
|
|
|
+import { EBuildType, EDelistingType, EListingSelectType, EPriceMode, EValidType } from '@/constants/client'
|
|
|
+import AppStepper from '@mobile/components/base/stepper/index.vue'
|
|
|
+import AppSelect from '@mobile/components/base/select/index.vue'
|
|
|
|
|
|
-defineProps({
|
|
|
+const props = defineProps({
|
|
|
selectedRow: {
|
|
|
- type: Object,
|
|
|
- required: true
|
|
|
+ type: Object as PropType<Model.SBYJMyOrderRsp>,
|
|
|
+ required: true,
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+const options = computed(() => {
|
|
|
+ return [{
|
|
|
+ label: '限价单', value: EPriceMode.PRICEMODE_LIMIT
|
|
|
+ }, {
|
|
|
+ label: '市价单', value: EPriceMode.PRICEMODE_MARKET
|
|
|
+ }]
|
|
|
+})
|
|
|
+
|
|
|
+const futuresStore = useFuturesStore()
|
|
|
+const positionStore = usePositionStore()
|
|
|
+const quote = futuresStore.getGoodsQuote(props.selectedRow.goodsCode)
|
|
|
+const { global: { t } } = i18n
|
|
|
+
|
|
|
+// 可用数量
|
|
|
+const maxQty = computed(() => {
|
|
|
+ const { holderQty, freezeQty, goodsID, buyOrSell } = props.selectedRow.tHDetailEx
|
|
|
+ const record = positionStore.positionList.find((e) => e.goodsid === goodsID && e.buyorsell === buyOrSell)
|
|
|
+ const qty = holderQty - freezeQty
|
|
|
+ return Math.min(record?.enableqty ?? 0, qty)
|
|
|
+})
|
|
|
+
|
|
|
+// 损益
|
|
|
+const closepl = computed(() => {
|
|
|
+ const { holderQty, buyOrSell, holderAmount } = props.selectedRow.tHDetailEx
|
|
|
+ const { agreeUnit } = props.selectedRow
|
|
|
+ const { presettle = 0, last = 0 } = quote.value ?? {}
|
|
|
+ const price = last || presettle // 没有最新价取昨结价
|
|
|
+ // 计算市值 = 现价 * 数量 * 合约单位
|
|
|
+ const marketValue = price ? price * holderQty * agreeUnit : 0
|
|
|
+
|
|
|
+ return price ? (marketValue - holderAmount) * (buyOrSell === BuyOrSell.Buy ? 1 : -1) : 0
|
|
|
+})
|
|
|
+
|
|
|
+const formRef = shallowRef<FormInstance>()
|
|
|
const showModal = shallowRef(true)
|
|
|
-const refresh = shallowRef(false) // 是否刷新父组件数据
|
|
|
+// 是否刷新父组件数据
|
|
|
+const refresh = shallowRef(false)
|
|
|
+const { formSubmit, formData } = useOrder()
|
|
|
|
|
|
-// 关闭弹窗=
|
|
|
+// 表单验证规则
|
|
|
+const formRules: { [key: string]: FieldRule[] } = {
|
|
|
+ OrderPrice: [{
|
|
|
+ message: t('position.goods.tips1'),
|
|
|
+ validator: () => {
|
|
|
+ return !!formData.OrderPrice
|
|
|
+ }
|
|
|
+ }],
|
|
|
+ OrderQty: [{
|
|
|
+ message: t('position.goods.tips2'),
|
|
|
+ validator: () => {
|
|
|
+ return !!formData.OrderQty
|
|
|
+ }
|
|
|
+ }],
|
|
|
+}
|
|
|
+
|
|
|
+const onCloseSumit = () => {
|
|
|
+ dialog({
|
|
|
+ message: '确认要平仓吗?',
|
|
|
+ showCancelButton: true,
|
|
|
+ }).then(() => {
|
|
|
+
|
|
|
+ const { marketID, goodsID, buyOrSell, tradeID } = props.selectedRow.tHDetailEx
|
|
|
+ /// 市场ID
|
|
|
+ formData.Header = { GoodsID: goodsID }
|
|
|
+ formData.MarketID = marketID
|
|
|
+ formData.BuyOrSell = buyOrSell === BuyOrSell.Buy ? BuyOrSell.Sell : BuyOrSell.Buy
|
|
|
+ formData.GoodsID = goodsID
|
|
|
+ formData.ListingSelectType = EListingSelectType.LISTINGSELECTTYPE_DELISTINGTHENLISTING
|
|
|
+ formData.DelistingType = EDelistingType.DELISTINGTYPE_PRICE
|
|
|
+ formData.BuildType = EBuildType.BUILDTYPE_CLOSE
|
|
|
+ formData.TimevalidType = EValidType.VALIDTYPE_DR
|
|
|
+ formData.OperateType = 24
|
|
|
+ formData.RelatedID = handleRequestBigNumber(tradeID)
|
|
|
+
|
|
|
+ /// loding....
|
|
|
+ fullloading((hideLoading) => {
|
|
|
+ formSubmit().then(() => {
|
|
|
+ hideLoading(t('position.goods.tips4'), 'success')
|
|
|
+ closed(true)
|
|
|
+ }).catch((err) => {
|
|
|
+ hideLoading(err, 'fail')
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭弹窗
|
|
|
const closed = (isRefresh = false) => {
|
|
|
refresh.value = isRefresh
|
|
|
showModal.value = false
|
|
|
}
|
|
|
|
|
|
+onMounted(() => {
|
|
|
+ const { bid, ask, presettle = 0 } = quote.value ?? {}
|
|
|
+ const { buyOrSell } = props.selectedRow.tHDetailEx
|
|
|
+ switch (buyOrSell) {
|
|
|
+ case BuyOrSell.Buy:
|
|
|
+ formData.OrderPrice = ask || presettle
|
|
|
+ break
|
|
|
+ case BuyOrSell.Sell:
|
|
|
+ formData.OrderPrice = bid || presettle
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ formData.OrderPrice = presettle
|
|
|
+ }
|
|
|
+ formData.OrderQty = maxQty.value
|
|
|
+ formData.PriceMode = EPriceMode.PRICEMODE_LIMIT
|
|
|
+})
|
|
|
+
|
|
|
// 暴露组件属性给父组件调用
|
|
|
defineExpose({
|
|
|
closed,
|