Handy_Cao 1 gadu atpakaļ
vecāks
revīzija
20352871fd

+ 1 - 1
src/packages/mobile/router/section.ts

@@ -60,7 +60,7 @@ const pageRoutes: RouteRecordRaw[] = [
             {
                 path: 'trade',
                 name: 'pricing-trade',
-                component: () => import('@mobile/views/pricing/trade/Index.vue'),
+                component: () => import('@mobile/views/pricing/trade/v2/Index.vue'),
             }
         ]
     },

+ 292 - 0
src/packages/mobile/views/pricing/trade/v2/Index.vue

@@ -0,0 +1,292 @@
+<template>
+    <app-view class="pricing-trade">
+        <template #header>
+            <app-navbar :title="quote ? `${quote.goodscode}` : $t('quote.pricing.title')" >
+                <template #right>
+                    <Icon v-if="system_1012 != '0'" name="bars" size="20px" @click="openComponent('detail')" />
+                </template>
+            </app-navbar>
+        </template>
+        <div class="pricing-trade__form" v-if="quote">
+            <div class="form-buyorsell">
+                <Tabs class="van-tabs--list" v-model:active="formData.BuyOrSell" >
+                    <Tab :title="$t('quote.bid')" :name="BuyOrSell.Buy"></Tab>
+                    <Tab :title="$t('quote.ask')" :name="BuyOrSell.Sell"></Tab>
+                </Tabs>
+            </div>
+            <div class="form-price">
+                <dl v-if="formData.BuyOrSell === BuyOrSell.Buy">
+                    <dd :class="quote.bidColor">{{ handleNumberValue(formatDecimal(quote.ask, quote.decimalplace)) }}
+                    </dd>
+                </dl>
+                <dl v-if="formData.BuyOrSell === BuyOrSell.Sell">
+                    <dd :class="quote.askColor">{{ handleNumberValue(formatDecimal(quote.bid, quote.decimalplace)) }}
+                    </dd>
+                </dl>
+            </div>
+        </div>
+        <!-- 下单 -->
+        <Form ref="formRef" class="g-form__container" @submit="onSubmit">
+            <CellGroup inset>
+                <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="OrderQty" :label="$t('quote.pricing.orderqty')">
+                    <template #input>
+                        <div class="g-qty-group">
+                            <div class="g-qty-group__stepper">
+                                <Stepper v-model="formData.OrderQty" theme="round" button-size="22" :min="0"
+                                    :step="qtyStep" integer />
+                            </div>
+                            <RadioGroup v-model="qtyStep" direction="horizontal" @change="onRadioChange">
+                                <Radio v-for="(value, index) in qtyStepList" :key="index" :name="value">{{ value }}
+                                </Radio>
+                            </RadioGroup>
+                        </div>
+                    </template>
+                </Field> 
+                <!-- 限价 -->
+                <Field name="OrderPrice" :rules="formRules.OrderPrice" :label="$t('quote.pricing.price')" v-if="formData.PriceMode === PriceMode.Limit">
+                    <template #input>
+                        <Stepper v-model="formData.OrderPrice" theme="round" button-size="22" :min="0"
+                            :auto-fixed="false" :decimal-length="decimalplace" :step="decimalvalue" />
+                    </template>
+                </Field>
+            </CellGroup>
+        </Form> 
+        <div class="g-form__footer">
+            <template v-if="formData.BuyOrSell === BuyOrSell.Buy">
+                <Button type="danger" block square :disabled="!formData.OrderQty"
+                    @click="onBeforeSubmit(BuildType.Open)" v-if="!quote?.iscannotbuy">{{ $t('operation.order') }}</Button>
+            </template>
+            <template v-if="formData.BuyOrSell === BuyOrSell.Sell">
+                <Button type="danger" block square :disabled="!formData.OrderQty"
+                    @click="onBeforeSubmit(BuildType.Open)"
+                    v-if="!isTrademode16 && !quote?.iscannotsell">{{ $t('operation.order') }}</Button>
+            </template>
+        </div>
+        <Tabs class="van-tabs--list" v-model:active="active" >
+            <template v-for="(item, index) in components.filter(e => e.show === true)" :key="index">
+                <Tab :title="item.title" :name="item.name">
+                    <component :is="item.component" v-bind="{ goodsCode, goodsid, fromTrade, pictureurl }" @callBack="itemBack"/>
+                </Tab>
+            </template>
+        </Tabs>
+        <template #footer>
+            <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ goodsCode, goodsid, selectedRow }"
+            @closed="closeComponent" v-if="componentId" />
+        </template> 
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { useFuturesStore, useUserStore, i18n } from '@/stores'
+import { useNavigation } from '@mobile/router/navigation'
+import { shallowRef, onMounted, computed, defineAsyncComponent } from 'vue'
+import { Form, Field, Button, FieldRule, FormInstance, Radio, RadioGroup, CellGroup, Icon, Tab, Tabs } from 'vant'
+import { useOrder } from '@/business/trade'
+import { BuyOrSell, BuildType, getPricemode2List, PriceMode } from '@/constants/order'
+import { useComponent } from '@/hooks/component'
+import { fullloading, dialog } from '@/utils/vant'
+import { formatDecimal, handleNumberValue } from '@/filters'
+import Stepper from '@mobile/components/base/stepper/index.vue'
+import eventBus from '@/services/bus'
+
+const { getQueryString, getQueryStringToNumber } = useNavigation()
+const { global: { t } } = i18n
+
+const goodsCode = getQueryString('goodscode') ?? ''
+const goodsid = getQueryStringToNumber('goodsid')
+const buyOrSell = getQueryStringToNumber('buyOrSell')
+const buildType = getQueryStringToNumber('buildType')
+const orderQty = getQueryStringToNumber('orderQty')
+const futuresStore = useFuturesStore()
+const quote = futuresStore.getGoodsQuote(goodsCode)
+const { pictureurl } = futuresStore.getGoods(goodsCode) ?? {}
+// 小数位以及步进值
+const { decimalplace = 0.0 } = quote.value ?? {}
+const quoteminunit = quote.value?.quoteminunit ?? 1.0
+const decimalvalue = Math.pow(10.0, -decimalplace)*(quoteminunit == 0 ? 1 : quoteminunit)
+const isTrademode16 = computed(() => quote.value?.trademode === 16)
+
+const selectedRow = shallowRef<Model.SBYJMyOrderRsp>()
+
+const { getSystemParamValue } = useUserStore()
+const system_1012 = getSystemParamValue('1012') ?? '1'
+
+const { formData, formSubmit } = useOrder()
+const formRef = shallowRef<FormInstance>()
+// 数量步长列表
+const qtyStepList = computed(() => {
+    const system_1009 = Number(getSystemParamValue('1009')) ?? 1
+    return [1*system_1009, 5*system_1009, 10*system_1009, 20*system_1009, 30*system_1009, 50*system_1009]
+}) 
+const qtyStep = shallowRef(qtyStepList.value[0]) // 数量步长
+const fromTrade = true
+
+// 持仓汇总
+const position = shallowRef<Model.TradePositionRsp[]>([]) 
+
+// 点击返回
+const itemBack = (isPosition: number, buyorsell: BuyOrSell, tradeId: string, item: Model.SBYJMyOrderRsp) => {
+    formData.BuyOrSell = buyorsell === BuyOrSell.Buy ? BuyOrSell.Sell : BuyOrSell.Buy
+    if (isPosition === 2) { 
+        selectedRow.value = item
+        // 打开退订
+        openComponent('transfer')
+    }
+}
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+
+const active = shallowRef(pictureurl != '' ? 'images' : 'cancel')
+
+const components = [
+    {
+        name: 'images',
+        title: t('operation.details'),
+        component: defineAsyncComponent(() => import('../images/Index.vue')),
+        show: pictureurl != ''
+    },
+    {
+        name: 'cancel',
+        title: t('quote.pricing.ordercancel'),
+        component: defineAsyncComponent(() => import('../components/cancel/Index.vue')),
+        show: true
+    },
+    {
+        name: 'position',
+        title: t('quote.pricing.position'),
+        component: defineAsyncComponent(() => import('@mobile/views/order/position/components/pricing/list/Index.vue')),
+        show: true
+    },
+    {
+        name: 'holdlb2',
+        title: t('quote.pricing.orderdetails'),
+        component: defineAsyncComponent(() => import('../holdlb2/Index.vue')),
+        detail: defineAsyncComponent(() => import('@mobile/views/order/position/components/pricing/detail2/Index.vue')),
+        show: true
+    }
+]
+    
+const componentMap = new Map<string, unknown>([
+    ['detail', defineAsyncComponent(() => import('../components/detail/Index.vue'))],
+    ['transfer', defineAsyncComponent(() => import('@mobile/views/order/position/components/pricing/detail2/components/transfer/Index.vue'))]
+])
+
+// 计算市价
+const marketPrice = computed(() => {
+    const { ask = 0, bid = 0 } = quote.value ?? {}
+    return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+})
+
+// 表单验证规则
+const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
+    OrderQty: [{
+        message: t('quote.pricing.tips1'),
+        validator: () => {
+            return !!formData.OrderQty
+        }
+    }],
+    // 限价
+    MarketMaxSub: [{
+        message: t('quote.pricing.tips3'),
+        validator: (val) => {
+            if (formData.PriceMode === PriceMode.Market) {
+                if (val < 0) {
+                    return t('quote.pricing.tips3')
+                }
+                return true
+            }
+            return !!formData.MarketMaxSub
+        }
+    }],
+    // 限价
+    OrderPrice: [{
+        message: t('quote.pricing.tips2'),
+        validator: () => {
+            if (formData.PriceMode === PriceMode.Limit) {
+                return !!formData.OrderPrice
+            }
+            return true
+        }
+    }],
+}
+
+const onPriceModeChanged = () => {
+    if (formData.PriceMode === PriceMode.Limit) {
+        const { ask = 0, bid = 0 } = quote.value ?? {}
+        formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+    }
+}
+
+const onBeforeSubmit = (buildType: BuildType) => {
+    formData.BuildType = buildType
+    if (buildType === BuildType.Close) {
+        const { ask = 0, bid = 0 } = quote.value ?? {}
+        formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+
+        const datas = position.value.filter(item => formData.BuyOrSell === BuyOrSell.Buy ? item.buyorsell === BuyOrSell.Sell : item.buyorsell === BuyOrSell.Buy) // 反方向持仓
+        if (datas.length > 0) {
+            formData.OrderQty = datas[0].enableqty
+        }
+    } else {
+        formData.RelatedID = undefined
+    }
+    formRef.value?.submit()
+}
+
+// 委托下单
+const onSubmit = () => {
+    const { goodsid, marketid } = quote.value ?? {}
+    formData.GoodsID = goodsid
+    formData.MarketID = marketid
+    // 市价
+    if (formData.PriceMode === PriceMode.Market) { formData.OrderPrice = marketPrice.value }
+
+    fullloading((hideLoading) => {
+        formSubmit().then(() => {
+            hideLoading()
+            dialog({ message: t('common.submitsuccess'), confirmButtonText: t('operation.confirm') }).then(() => {
+                // 成交通知
+                eventBus.$emit('OrderDealedNtf')
+            })
+        }).catch((err) => {
+            hideLoading(err, 'fail')
+        })
+    })
+}
+
+const onRadioChange = (value: number) => {
+    formData.OrderQty = value
+}
+
+ onMounted(() => {
+    formData.BuyOrSell = BuyOrSell.Buy
+    formData.BuildType = BuildType.Open
+    formData.PriceMode = PriceMode.Market
+    formData.MarketMaxSub = 100.0
+    /// 默认价格和数量
+    const { last = 0, presettle = 0 } = quote.value ?? {}
+    formData.OrderPrice = last || presettle
+    formData.OrderQty = qtyStep.value
+
+    /// 如果是从头寸点进来的
+    if ( buildType === BuildType.Close) {
+        formData.OrderQty = orderQty
+        formData.BuyOrSell = buyOrSell
+        formData.BuildType = buildType
+    }
+ })
+
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 27 - 0
src/packages/mobile/views/pricing/trade/v2/index.css

@@ -0,0 +1,27 @@
+.pricing-trade__form {
+  background-color: #fff;
+  border-radius: 8px;
+  margin: 15px 15px 0px 15px;
+  margin-bottom: 0;
+}
+.pricing-trade__form .form-buyorsell {
+  margin: 5px 8px;
+}
+.pricing-trade__form .form-price {
+  display: flex;
+  padding: 16px 0;
+}
+.pricing-trade__form .form-price dl {
+  flex: 1;
+  text-align: center;
+}
+.pricing-trade__form .form-price dl dt {
+  margin-bottom: 5px;
+}
+.pricing-trade__form .form-price dl dd {
+  font-size: 28px;
+  font-weight: bold;
+}
+.pricing-trade .g-form__footer {
+  margin-bottom: 10px;
+}

+ 35 - 0
src/packages/mobile/views/pricing/trade/v2/index.less

@@ -0,0 +1,35 @@
+.pricing-trade {
+    &__form {
+        background-color: #fff;
+        border-radius: 8px;
+        margin: 15px 15px 0px 15px;
+        margin-bottom: 0;
+
+        .form-buyorsell {
+            margin: 5px 8px;
+        }
+
+        .form-price {
+            display: flex;
+            padding: 16px 0;
+
+            dl {
+                flex: 1;
+                text-align: center;
+
+                dt {
+                    margin-bottom: 5px;
+                }
+
+                dd {
+                    font-size: 28px;
+                    font-weight: bold;
+                }
+            }
+        }
+    }
+
+    .g-form__footer {
+        margin-bottom: 10px;
+    }
+}

+ 1 - 1
src/packages/pc/views/footer/pricing/detail2/components/delivery/index.vue

@@ -53,7 +53,7 @@
         <app-address v-model:show="showAddress" @change="onAddressChange" />
         <template #footer>
             <el-button type="info" @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
-            <el-button type="primary" @click="onSubmit">{{ t('operation.delivery') }}</el-button>
+            <el-button type="primary" :disabled="enableqty === 0" @click="onSubmit">{{ t('operation.delivery') }}</el-button>
         </template> 
     </app-drawer>
 </template>