Handy_Cao před 1 rokem
rodič
revize
0d31c309e1

+ 200 - 0
src/packages/mobile/views/pricing/trade/fullpayment/Index.vue

@@ -0,0 +1,200 @@
+<!-- 挂牌点价 - 商品详细 - 全款 -->
+<template>
+    <app-modal direction="right-top" height="100%" width="100%" v-model:show="showModal" :refresh="refresh">
+        <app-view class="pricing-detail g-form">
+            <template #header>
+                <app-navbar :title="collection ? collectionName : $t('quote.listinghall')" @back="closed" />
+            </template>
+            <div class="goods-image">
+                <img :src="getFileUrl(collection?.thumurls)" v-if="collection?.thumurls" />
+                <Image width="100%" height="160px" v-else />
+            </div>
+            <div class="order-info">
+                <span>小计:{{ orderQty }}</span>
+            </div>
+            <div class="goods-info">
+                <span>{{ collectionName }}</span>
+                <span>规格:{{ quote?.agreeunit+getGoodsUnitName(quote?.goodunitid) }}</span>
+                <span>数量:{{ handleNumberValue(orderQty) }}</span>
+                <span>{{ handleNumberValue(formatDecimal(marketPrice, quote?.decimalplace)) }}</span>
+            </div>
+            <Form ref="formRef" class="g-form__container" @submit="onSubmit">
+                <div class="amount-info">
+                    <Field v-if="quote?.trademode != 10" name="Receive" :label="$t('performance.address')" type="textarea"
+                        autosize v-model="formData.AddrInfo" :rules="formRules.AddrInfo"
+                        :placeholder="$t('performance.pleaseentertheaddress')" right-icon="add-o"
+                        @click-right-icon="showContact = true" />
+                    <span>订单金额:{{ handleNumberValue(formatDecimal(totalAmount)) }}</span>
+                    <span>订单服务费:{{ handleNumberValue(formatDecimal(serivcefee)) }}</span>
+                    <span>合计总额:{{ handleNumberValue(formatDecimal(totalAmount+serivcefee)) }}</span>
+                </div>
+            </Form>
+            <template #footer v-if="collection">
+                <div class="g-form__footer inset">
+                    <Button type="danger" block round :disabled="orderQty === 0" @click="onSubmit">
+                        {{ $t('operation.buynow') }}
+                    </Button>
+                </div>
+                <app-contact v-model:show="showContact" @change="contactChange" />
+            </template> 
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { useFuturesStore, i18n } from '@/stores'
+import { shallowRef, computed, onMounted } from 'vue'
+import { onBeforeRouteLeave } from 'vue-router'
+import { Button, Image, Field, FieldRule, FormInstance, Form } from 'vant'
+import { useOrder } from '@/business/trade'
+import { fullloading, dialog } from '@/utils/vant'
+import { BuildType, BuyOrSell, PriceMode } from '@/constants/order'
+import { formatDecimal, getFileUrl, handleNumberValue } from '@/filters'
+import { getGoodsUnitName } from '@/constants/unit'
+import AppModal from '@/components/base/modal/index.vue'
+import eventBus from '@/services/bus'
+import AppContact from '@mobile/components/modules/contact/index.vue'
+
+const props = defineProps({
+    goodsid: {
+        type: Number,
+        required: true
+    },
+    collectionid: {
+        type: Number,
+        required: true
+    },
+    orderType: {
+        type: Number,
+        required: true
+    },
+    orderQty: {
+        type: Number,
+        required: true
+    }
+})
+
+// // 是否刷新父组件数据
+const refresh = shallowRef(true) 
+const showModal = shallowRef(true)
+const futuresStore = useFuturesStore()
+const quote = futuresStore.getGoodsQuote(props.goodsid)
+const collection = futuresStore.collections.find(e => e.collectionid === props.collectionid)
+const { global: { t } } = i18n
+// 显示联系人选择列表
+const showContact = shallowRef(false) 
+const formRef = shallowRef<FormInstance>()
+
+const { formData, formSubmit } = useOrder()
+
+// 商品名称
+const collectionName = computed(() => {
+    switch (i18n.global.locale) {
+        case 'zh-CN':
+            return collection?.collectionname
+        case 'en-US':
+            return collection?.collectionnameen
+        case 'zh-TW':
+            return collection?.collectionnametw
+        default:
+            return collection?.collectiondescth
+    }
+})
+
+// 计算市价
+const marketPrice = computed(() => {
+    const { ask = 0, bid = 0 } = quote.value ?? {}
+    return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+})
+
+// 订单金额
+const totalAmount = computed(() => {
+    const { agreeunit = 0.0 } = quote.value ?? {}
+    return agreeunit*props.orderQty*marketPrice.value
+})
+
+// 提货费 = 取交易费用配置 105
+// 固定: 可用量*合约单位*配置值
+// 比率:订单金额*配置值
+const serivcefee = computed(() => {
+    const { tradefees = [], agreeunit = 0 } = quote.value ?? {}
+    const { FeeAlgorithm = 1, ExchangeValue = 0.0 } = tradefees.find((e) => e.FeeID === 105) ?? {}
+    // 比例
+    if (FeeAlgorithm === 1) {
+        return props.orderQty * agreeunit * ExchangeValue
+    } 
+    // 固定
+    return  totalAmount.value * ExchangeValue
+})
+
+// 委托下单
+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')
+                // 返回上层试图
+                closed(true)
+            })
+        }).catch((err) => {
+            hideLoading(err, 'fail')
+        })
+    })
+}
+
+// 选择联系信息
+const contactChange = (item: Model.UserReceiveInfoRsp) => {
+    const contact = `${item.receivername} ${item.phonenum}`
+    const address = `${item.provincename} ${item.cityname} ${item.districtname} ${item.address}`
+    formData.AddrInfo = [contact, address].join('\n')
+    formRef.value?.validate('Region')
+}
+
+// 表单验证规则
+const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
+    AddrInfo: [{
+        required: true,
+        message: t('performance.tips3'),
+    }],
+}
+
+// 关闭弹窗
+const closed = (isRefresh = false) => {
+    refresh.value = isRefresh
+    showModal.value = false
+}
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+
+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 = props.orderQty
+ })
+
+ // 阻止页面离开
+onBeforeRouteLeave((to, from, next) => {
+    if (showContact.value) {
+        showContact.value = false
+        next(false)
+    } else {
+        next(true)
+    }
+})
+</script>

+ 193 - 0
src/packages/mobile/views/pricing/trade/prepayment/Index.vue

@@ -0,0 +1,193 @@
+<!-- 挂牌点价 - 商品详细 - 预付款 -->
+<template>
+    <app-modal direction="right-top" height="100%" width="100%" v-model:show="showModal" :refresh="refresh">
+        <app-view class="pricing-detail g-form">
+            <template #header>
+                <app-navbar :title="collection ? collectionName : $t('quote.listinghall')" @back="closed" />
+            </template>
+            <div class="goods-image">
+                <img :src="getFileUrl(collection?.thumurls)" v-if="collection?.thumurls" />
+                <Image width="100%" height="160px" v-else />
+            </div>
+            <div class="goods-info">
+                <span>{{ collectionName }}</span>
+                <span>规格:{{ quote?.agreeunit+getGoodsUnitName(quote?.goodunitid) }}</span>
+                <span>数量:{{ handleNumberValue(orderQty) }}</span>
+                <span>{{ handleNumberValue(formatDecimal(marketPrice, quote?.decimalplace)) }}</span>
+            </div>
+            <div class="order-info">
+                <span>小计:{{ orderQty }}</span>
+            </div>
+            <div class="amount-info">
+                <span>订单金额:{{  handleNumberValue(formatDecimal(totalAmount)) }}</span>
+                <span>订单服务费:{{ handleNumberValue(formatDecimal(serivcefee)) }}</span>
+                <span>预付款:{{ handleNumberValue(formatDecimal(usedMargin.deposit)) }}</span>
+                <span>合计总额:{{ handleNumberValue(formatDecimal(serivcefee+usedMargin.deposit)) }}</span>
+            </div>
+            <template #footer v-if="collection">
+                <div class="g-form__footer inset">
+                    <Button type="danger" block round :disabled="orderQty === 0" @click="onSubmit">
+                        {{ orderType === 2 ? '预付款' : '回购' }}
+                    </Button>
+                </div>
+            </template> 
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { useFuturesStore, i18n, useAccountStore } from '@/stores'
+import { shallowRef, computed, onMounted } from 'vue'
+import { Button, Image } from 'vant'
+import { useOrder } from '@/business/trade'
+import { fullloading, dialog } from '@/utils/vant'
+import { BuildType, BuyOrSell, PriceMode } from '@/constants/order'
+import { formatDecimal, getFileUrl, handleNumberValue } from '@/filters'
+import { getGoodsUnitName } from '@/constants/unit'
+import AppModal from '@/components/base/modal/index.vue'
+import eventBus from '@/services/bus'
+
+const props = defineProps({
+    goodsid: {
+        type: Number,
+        required: true
+    },
+    collectionid: {
+        type: Number,
+        required: true
+    },
+    orderType: {
+        type: Number,
+        required: true
+    },
+    orderQty: {
+        type: Number,
+        required: true
+    }
+})
+
+// // 是否刷新父组件数据
+const refresh = shallowRef(true) 
+const showModal = shallowRef(true)
+const futuresStore = useFuturesStore()
+const accountStore = useAccountStore()
+const quote = futuresStore.getGoodsQuote(props.goodsid)
+const collection = futuresStore.collections.find(e => e.collectionid === props.collectionid)
+const { global: { t } } = i18n
+
+const { formData, formSubmit } = useOrder()
+
+// 商品名称
+const collectionName = computed(() => {
+    switch (i18n.global.locale) {
+        case 'zh-CN':
+            return collection?.collectionname
+        case 'en-US':
+            return collection?.collectionnameen
+        case 'zh-TW':
+            return collection?.collectionnametw
+        default:
+            return collection?.collectiondescth
+    }
+})
+
+// 计算市价
+const marketPrice = computed(() => {
+    const { ask = 0, bid = 0 } = quote.value ?? {}
+    return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+})
+
+// 订单金额
+const totalAmount = computed(() => {
+    const { agreeunit = 0.0 } = quote.value ?? {}
+    return agreeunit*props.orderQty*marketPrice.value
+})
+
+// 提货费 = 取交易费用配置 105
+// 固定: 可用量*合约单位*配置值
+// 比率:订单金额*配置值
+const serivcefee = computed(() => {
+    const { tradefees = [], agreeunit = 0 } = quote.value ?? {}
+    const { FeeAlgorithm = 1, ExchangeValue = 0.0 } = tradefees.find((e) => e.FeeID === (props.orderType === 1 ? 105 : 106)) ?? {}
+    // 比例
+    if (FeeAlgorithm === 1) {
+        return props.orderQty * agreeunit * ExchangeValue
+    } 
+    // 固定
+    return  totalAmount.value * ExchangeValue
+})
+
+// 预付款
+const usedMargin = computed(() => {
+    const { avaiableMoney = 0 } = accountStore.currentAccount
+    const { marketmarginalgorithm = 0, marketmarginvalue = 0, agreeunit = 0 } = quote.value ?? {}
+
+    // 结果集合
+    const result = {
+        enableQty: 0,
+        deposit: 0
+    }
+
+    const fixed = agreeunit * marketmarginvalue
+    const ratio = fixed * marketPrice.value
+
+    if (fixed && ratio) {
+        if (marketmarginalgorithm === 1) {
+            const qty = Math.trunc(avaiableMoney / ratio)
+            result.deposit = props.orderQty * ratio
+            result.enableQty = qty > 0 ? qty : 0
+        }
+        if (marketmarginalgorithm === 2) {
+            const qty = Math.trunc(avaiableMoney / fixed)
+            result.deposit = props.orderQty * fixed
+            result.enableQty = qty > 0 ? qty : 0
+        }
+    }
+    return result
+})
+
+// 委托下单
+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')
+                // 返回上层试图
+                closed(true)
+            })
+        }).catch((err) => {
+            hideLoading(err, 'fail')
+        })
+    })
+}
+
+// 关闭弹窗
+const closed = (isRefresh = false) => {
+    refresh.value = isRefresh
+    showModal.value = false
+}
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+
+onMounted(() => {
+    formData.BuyOrSell = props.orderType === 2 ? BuyOrSell.Buy : BuyOrSell.Sell
+    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 = props.orderQty
+ })
+</script>

+ 30 - 74
src/packages/mobile/views/pricing/trade/v2/Index.vue

@@ -57,18 +57,11 @@
             <Field name="OrderQty" label="自定义">
                 <template #input>
                     <div class="g-qty-group__stepper">
-                            <Stepper v-model="formData.OrderQty" theme="round" button-size="22" :min="1" :step="qtyStep" integer />
+                            <Stepper v-model="orderQty" theme="round" button-size="22" :min="1" :step="qtyStep" integer />
                         </div>
                 </template>
             </Field>
         </Form>
-        <template #footer v-if="collection">
-            <div class="g-form__footer inset">
-                <Button type="danger" block round :disabled="formData.OrderQty === 0" @click="onBeforeSubmit(BuildType.Open)">
-                    {{ $t('operation.buynow') }}
-                </Button>
-            </div>
-        </template>
         <Tabs 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">
@@ -76,7 +69,16 @@
                     <component :is="item.component" v-bind="{ pictureurl }" />
                 </Tab>
             </template>
-        </Tabs>        
+        </Tabs>  
+        <template #footer v-if="collection">
+            <div class="g-form__footer inset">
+                <Button type="danger" block round :disabled="orderQty === 0" @click="onSubmit">
+                    {{ orderType === 1 ? $t('operation.buynow') : orderTypeStepList.find(e => e.value === orderType)?.label }}
+                </Button>
+            </div>
+            <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ goodsid, collectionid, orderType, orderQty }"
+            @closed="closeComponent" v-if="componentId" />
+        </template>      
     </app-view>
 </template>
 
@@ -85,13 +87,12 @@ import { shallowRef, onMounted, onUnmounted, computed, defineAsyncComponent } fr
 import { Form, Field, Button, FormInstance, Radio, RadioGroup, Tab, Tabs } from 'vant'
 import { useFuturesStore, useUserStore, i18n, useAccountStore } from '@/stores'
 import { useNavigation } from '@mobile/router/navigation'
-import { useOrder } from '@/business/trade'
-import { BuildType } from '@/constants/order'
 import { formatDecimal, handleNumberValue } from '@/filters'
+import { getGoodsUnitName } from '@/constants/unit'
+import { useComponent } from '@/hooks/component'
 import quoteSocket from '@/services/websocket/quote'
 import Stepper from '@mobile/components/base/stepper/index.vue'
 import Banner from '@mobile/components/base/banner/index.vue'
-import { getGoodsUnitName } from '@/constants/unit'
 
 const { getQueryStringToNumber } = useNavigation()
 const futuresStore = useFuturesStore()
@@ -103,12 +104,12 @@ const collection = futuresStore.collections.find(e => e.collectionid === collect
 const { global: { t } } = i18n
 const subscribe = quoteSocket.createSubscribe()
 
-const { formData, formSubmit } = useOrder()
 const formRef = shallowRef<FormInstance>()
 
 const { getSystemParamValue } = useUserStore()
 
 const active = shallowRef('images')
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
 
 // 数量步长列表
 const qtyStepList = computed(() => {
@@ -117,6 +118,7 @@ const qtyStepList = computed(() => {
     return result.map((value) => +system_1009 * value)
 })
 const qtyStep = shallowRef(qtyStepList.value[0]) // 数量步长
+const orderQty = shallowRef(qtyStepList.value[0]) // 默认数量
 
 // 订单模型列表
 const orderTypeStepList = computed(() => {
@@ -174,7 +176,7 @@ const pictureurl = computed(() => {
 
 // 数量切换
 const onQtyRadioChange = (value: number) => {
-    formData.OrderQty = value
+    orderQty.value = value
 }
 
 // 订单类型切换
@@ -238,12 +240,12 @@ const usedMargin = computed(() => {
     if (fixed && ratio) {
         if (marketmarginalgorithm === 1) {
             const qty = Math.trunc(avaiableMoney / ratio)
-            result.deposit = (formData.OrderQty ?? 0) * ratio
+            result.deposit = (orderQty.value ?? 0) * ratio
             result.enableQty = qty > 0 ? qty : 0
         }
         if (marketmarginalgorithm === 2) {
             const qty = Math.trunc(avaiableMoney / fixed)
-            result.deposit = (formData.OrderQty ?? 0) * fixed
+            result.deposit = (orderQty.value ?? 0) * fixed
             result.enableQty = qty > 0 ? qty : 0
         }
     }
@@ -259,70 +261,24 @@ const components = [
     },
 ]
 
-// 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 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 componentMap = new Map<string, unknown>([
+    ['fullpayment', defineAsyncComponent(() => import('../fullpayment/Index.vue'))],
+    ['prepayment', defineAsyncComponent(() => import('../prepayment/Index.vue'))],
+])
 
 // 委托下单
 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')
-    //     })
-    // })
+    console.log(orderType.value)
+    if (orderType.value === 1) {
+        // 全款购买
+        openComponent('fullpayment')
+    } else {
+        // 预付款以及回购
+        openComponent('prepayment') 
+    }
 }
 
-
-
 onMounted(() => {
-    // quote.value = futuresStore.getGoodsQuote(goodsCode.value).value
-    // console.log(quote.value)
-    // 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
-    // }
-
-    // 
     // 默认第一个商品集合的第一个商品
     onOrderTypeRadioChange(1)
     // 订阅商品行情