|
@@ -0,0 +1,215 @@
|
|
|
|
|
+<!-- 挂牌点价- 订单明细 - 平仓 -->
|
|
|
|
|
+<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="$t('operation.close')" @back="closed" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <Form ref="formRef" class="g-form__container" @submit="onCloseSumit">
|
|
|
|
|
+ <CellGroup :title="$t('position.goods.subtitle')" inset>
|
|
|
|
|
+ <Cell :title="$t('position.goods.goodsname')" :value="`${selectedRow.goodsCode}/${selectedRow.goodsName}`" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.buyorsell')" :value="getBuyOrSellName(selectedRow.tHDetailEx.buyOrSell)" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.holderprice')" :value="formatDecimal(selectedRow.tHDetailEx.holderPrice, selectedRow.decimalPlace)" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.curholderamount')" :value="formatDecimal(selectedRow.tHDetailEx.holderAmount)" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.curpositionqty')" :value="selectedRow.tHDetailEx.holderQty" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.freezeqty')" :value="selectedRow.tHDetailEx.freezeQty" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.enableqty')" :value="maxQty" />
|
|
|
|
|
+ <Cell :title="$t('position.goods.closepl')">
|
|
|
|
|
+ <template #value>
|
|
|
|
|
+ <span :class="handlePriceColor(closepl)">
|
|
|
|
|
+ {{ formatDecimal(closepl, selectedRow.decimalPlace) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Cell>
|
|
|
|
|
+ <Cell :title="$t('position.goods.tradetime')" :value="selectedRow.tHDetailEx.tradeTime" />
|
|
|
|
|
+ </CellGroup>
|
|
|
|
|
+ <CellGroup :title="$t('position.goods.subtitle3')" inset>
|
|
|
|
|
+ <Field :label="$t('position.goods.last')">
|
|
|
|
|
+ <template #input>
|
|
|
|
|
+ <span :class="quote?.lastColor">{{ handleNumberValue(quote?.last) }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Field>
|
|
|
|
|
+ <Field :label="$t('quote.pricing.pricemode')">
|
|
|
|
|
+ <template #input>
|
|
|
|
|
+ <RadioGroup v-model="formData.PriceMode" direction="horizontal" @click="onPriceModeChanged">
|
|
|
|
|
+ <Radio v-for="(item, index) in getPricemode2List()" :key="index" :name="item.value">{{
|
|
|
|
|
+ item.label
|
|
|
|
|
+ }}</Radio>
|
|
|
|
|
+ </RadioGroup>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Field>
|
|
|
|
|
+ <Field name="MarketMaxSub" :rules="formRules.MarketMaxSub" :label="$t('quote.pricing.marketmaxsub1')" v-if="formData.PriceMode === PriceMode.Market">
|
|
|
|
|
+ <template #input>
|
|
|
|
|
+ <Stepper v-model="formData.MarketMaxSub" theme="round" button-size="22" :min="0" :max="999" :auto-fixed="false" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Field>
|
|
|
|
|
+ <Field name="OrderPrice" :rules="formRules.OrderPrice" :label="$t('position.goods.transferprice')" v-if="formData.PriceMode === PriceMode.Limit">
|
|
|
|
|
+ <template #input>
|
|
|
|
|
+ <Stepper v-model="formData.OrderPrice" theme="round" button-size="22" :min="0"
|
|
|
|
|
+ :decimal-length="quote?.decimalplace" :step="quote?.decimalvalue" :auto-fixed="false" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Field>
|
|
|
|
|
+ <Field name="OrderQty" :rules="formRules.OrderQty" :label="$t('position.goods.orderqty')">
|
|
|
|
|
+ <template #input>
|
|
|
|
|
+ <Stepper v-model="formData.OrderQty" theme="round" button-size="22" :min="0" :max="maxQty"
|
|
|
|
|
+ :auto-fixed="false" integer />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Field>
|
|
|
|
|
+ </CellGroup>
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <Button block square type="danger" @click="formRef?.submit">{{ $t('operation.close') }}</Button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </app-view>
|
|
|
|
|
+ </app-modal>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import { shallowRef, PropType, onMounted, computed } from 'vue'
|
|
|
|
|
+import AppModal from '@/components/base/modal/index.vue'
|
|
|
|
|
+import { CellGroup, Cell, Button, FieldRule, Form, Field, Stepper, FormInstance, RadioGroup, Radio } from 'vant'
|
|
|
|
|
+import { getBuyOrSellName, BuyOrSell, PriceMode, getPricemode2List } from '@/constants/order'
|
|
|
|
|
+import { formatDecimal, handleNumberValue, handleRequestBigNumber, handlePriceColor } from '@/filters'
|
|
|
|
|
+import { useOrder } from '@/business/trade'
|
|
|
|
|
+import { dialog, fullloading } from '@/utils/vant'
|
|
|
|
|
+import { useFuturesStore, usePositionStore, i18n, useAccountStore, useUserStore } from '@/stores'
|
|
|
|
|
+import { EBuildType, EDelistingType, EListingSelectType, EPriceMode, EValidType } from '@/constants/client'
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ selectedRow: {
|
|
|
|
|
+ type: Object as PropType<Model.SBYJMyOrderRsp>,
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const futuresStore = useFuturesStore()
|
|
|
|
|
+const positionStore = usePositionStore()
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
|
|
+const accountStore = useAccountStore()
|
|
|
|
|
+const quote = futuresStore.getGoodsQuote(props.selectedRow.goodsCode)
|
|
|
|
|
+const { global: { t } } = i18n
|
|
|
|
|
+
|
|
|
|
|
+const formRef = shallowRef<FormInstance>()
|
|
|
|
|
+const showModal = shallowRef(true)
|
|
|
|
|
+// 是否刷新父组件数据
|
|
|
|
|
+const refresh = shallowRef(false)
|
|
|
|
|
+const { formSubmit, formData } = useOrder()
|
|
|
|
|
+
|
|
|
|
|
+// 可用数量
|
|
|
|
|
+const maxQty = computed(() => {
|
|
|
|
|
+ const record = positionStore.positionList.find((e) => e.goodsid === props.selectedRow.tHDetailEx.goodsID && e.buyorsell === props.selectedRow.tHDetailEx.buyOrSell)
|
|
|
|
|
+ const qty = props.selectedRow.tHDetailEx.holderQty - props.selectedRow.tHDetailEx.freezeQty
|
|
|
|
|
+ return Math.min(record?.enableqty ?? 0, qty)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 损益
|
|
|
|
|
+const closepl = computed(() => {
|
|
|
|
|
+ const { presettle = 0, last = 0 } = quote.value ?? {}
|
|
|
|
|
+ const { agreeUnit } = props.selectedRow
|
|
|
|
|
+ const { holderQty, holderAmount, buyOrSell } = props.selectedRow.tHDetailEx
|
|
|
|
|
+ const goods = futuresStore.getGoods(props.selectedRow.goodsCode)
|
|
|
|
|
+ const { currencyid } = goods ?? {}
|
|
|
|
|
+ const { currencyid: tacurrencyid } = accountStore.currentAccount
|
|
|
|
|
+ const price = last || presettle // 没有最新价取昨结价
|
|
|
|
|
+
|
|
|
|
|
+ // 查找汇率
|
|
|
|
|
+ let exchangerate = 1
|
|
|
|
|
+ if (currencyid !== tacurrencyid) {
|
|
|
|
|
+ const currency = userStore.userData.exchangeRateConfigs.find((e) => e.descurrencyid === tacurrencyid && e.oricurrencyid === currencyid)
|
|
|
|
|
+ exchangerate = currency?.exchangerate ?? 0
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 计算市值 = 现价 * 数量 * 合约单位
|
|
|
|
|
+ const marketValue = price ? price * holderQty * agreeUnit * exchangerate : 0
|
|
|
|
|
+ return price ? (marketValue - holderAmount) * (buyOrSell === BuyOrSell.Buy ? 1 : -1) : 0
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const onPriceModeChanged = () => {
|
|
|
|
|
+ if (formData.PriceMode === PriceMode.Limit) {
|
|
|
|
|
+ const { ask = 0, bid = 0 } = quote.value ?? {}
|
|
|
|
|
+ formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 表单验证规则
|
|
|
|
|
+const formRules: { [key: string]: FieldRule[] } = {
|
|
|
|
|
+ MarketMaxSub: [{
|
|
|
|
|
+ message: t('position.pricing.tips3'),
|
|
|
|
|
+ validator: () => {
|
|
|
|
|
+ return !!formData.MarketMaxSub
|
|
|
|
|
+ }
|
|
|
|
|
+ }],
|
|
|
|
|
+ OrderPrice: [{
|
|
|
|
|
+ message: t('position.transfer.tips3'),
|
|
|
|
|
+ validator: () => {
|
|
|
|
|
+ return !!formData.OrderPrice
|
|
|
|
|
+ }
|
|
|
|
|
+ }],
|
|
|
|
|
+ OrderQty: [{
|
|
|
|
|
+ message: t('position.transfer.tips4'),
|
|
|
|
|
+ validator: () => {
|
|
|
|
|
+ return !!formData.OrderQty
|
|
|
|
|
+ }
|
|
|
|
|
+ }],
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const onCloseSumit = () => {
|
|
|
|
|
+ dialog({
|
|
|
|
|
+ message: t('position.goods.tips3'),
|
|
|
|
|
+ showCancelButton: true,
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+
|
|
|
|
|
+ const { marketID, goodsID, buyOrSell, tradeID } = props.selectedRow.tHDetailEx
|
|
|
|
|
+ /// 市场ID
|
|
|
|
|
+ formData.Header = { GoodsID: goodsID }
|
|
|
|
|
+ formData.MarketID = marketID
|
|
|
|
|
+ formData.PriceMode = EPriceMode.PRICEMODE_LIMIT
|
|
|
|
|
+ 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 ?? {}
|
|
|
|
|
+ switch (props.selectedRow.tHDetailEx.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 = PriceMode.Market
|
|
|
|
|
+ formData.MarketMaxSub = 100.0
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 暴露组件属性给父组件调用
|
|
|
|
|
+defineExpose({
|
|
|
|
|
+ closed,
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|