Browse Source

完成大部分挂牌点价功能。

zhou.xiaoning 2 years ago
parent
commit
eadcc2654c

+ 6 - 4
src/packages/mobile/views/goods/detail/components/listing/Index.vue

@@ -25,12 +25,14 @@
             </Field>
             </Field>
             <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
             <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
                 <template #input>
                 <template #input>
-                    <Stepper v-model="formData.OrderPrice" input-width="100" theme="round" button-size="22" :auto-fixed="false" :step="0.01" />
+                    <Stepper v-model="formData.OrderPrice" input-width="100" theme="round" button-size="22"
+                        :auto-fixed="false" :step="0.01" />
                 </template>
                 </template>
             </Field>
             </Field>
             <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
             <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
                 <template #input>
                 <template #input>
-                    <Stepper v-model="formData.OrderQty" input-width="100" theme="round" button-size="22" :auto-fixed="false" integer />
+                    <Stepper v-model="formData.OrderQty" input-width="100" theme="round" button-size="22"
+                        :auto-fixed="false" integer />
                 </template>
                 </template>
             </Field>
             </Field>
         </Form>
         </Form>
@@ -81,8 +83,8 @@ const onSubmit = () => {
     /// 获取对应的市场ID
     /// 获取对应的市场ID
     formData.MarketID = useFuturesStore().getGoods(goodsid).value?.marketid ?? 0
     formData.MarketID = useFuturesStore().getGoods(goodsid).value?.marketid ?? 0
     formData.BuyOrSell = buyOrSell.value,
     formData.BuyOrSell = buyOrSell.value,
-    formData.PriceMode = EPriceMode.PRICEMODE_LIMIT
-    formData.MarketMaxSub = 0.0 
+        formData.PriceMode = EPriceMode.PRICEMODE_LIMIT
+    formData.MarketMaxSub = 0.0
     formData.GoodsID = goodsid
     formData.GoodsID = goodsid
     formData.ListingSelectType = EListingSelectType.LISTINGSELECTTYPE_LISTING
     formData.ListingSelectType = EListingSelectType.LISTINGSELECTTYPE_LISTING
     formData.DelistingType = EDelistingType.DELISTINGTYPE_SELECTED
     formData.DelistingType = EDelistingType.DELISTINGTYPE_SELECTED

+ 8 - 0
src/packages/mobile/views/order/list/Index.vue

@@ -35,6 +35,12 @@
             </Tab>
             </Tab>
             <Tab title="挂牌成交">
             <Tab title="挂牌成交">
             </Tab>
             </Tab>
+            <Tab title="点价委托">
+                <component :is="componentMap.get('pricingorder')" />
+            </Tab>
+            <Tab title="点价成交">
+                <component :is="componentMap.get('pricingtrade')" />
+            </Tab>
         </Tabs>
         </Tabs>
         <component ref="componentRef" :is="componentMap.get(componentId)" @closed="closeComponent" v-if="componentId" />
         <component ref="componentRef" :is="componentMap.get(componentId)" @closed="closeComponent" v-if="componentId" />
     </app-view>
     </app-view>
@@ -60,6 +66,8 @@ const componentMap = new Map<string, unknown>([
     ['hisswaptrade', defineAsyncComponent(() => import('./components/hisswaptrade/list/Index.vue'))], // 历史掉期成交
     ['hisswaptrade', defineAsyncComponent(() => import('./components/hisswaptrade/list/Index.vue'))], // 历史掉期成交
     ['hisgoodsorder', defineAsyncComponent(() => import('./components/hisgoodsorder/list/Index.vue'))], // 历史订单委托
     ['hisgoodsorder', defineAsyncComponent(() => import('./components/hisgoodsorder/list/Index.vue'))], // 历史订单委托
     ['hisgoodstrade', defineAsyncComponent(() => import('./components/hisgoodstrade/list/Index.vue'))], // 历史订单成交
     ['hisgoodstrade', defineAsyncComponent(() => import('./components/hisgoodstrade/list/Index.vue'))], // 历史订单成交
+    ['pricingorder', defineAsyncComponent(() => import('./components/pricingorder/list/Index.vue'))], // 挂牌点价委托
+    ['pricingtrade', defineAsyncComponent(() => import('./components/pricingtrade/list/Index.vue'))], // 挂牌点价成交
 ])
 ])
 
 
 const onMoreClick = () => {
 const onMoreClick = () => {

+ 79 - 0
src/packages/mobile/views/order/list/components/pricingorder/detail/Index.vue

@@ -0,0 +1,79 @@
+<!-- 我的订单- 订单委托 - 详情 -->
+<template>
+    <app-modal direction="right" height="100%" v-model:show="showModal" :refresh="refresh">
+        <app-view class="g-form">
+            <template #header>
+                <app-navbar title="详细" @back="closed" />
+            </template>
+            <div v-if="props" class="order-detail__container g-form__container">
+                <CellGroup title="挂牌点价委托信息">
+                    <Cell title="商品代码/名称" :value="selectedRow.goodscode + '/' + selectedRow.goodsname" />
+                    <Cell title="方向" :value="getBuyOrSellName(selectedRow.buyorsell)" />
+                    <Cell title="委托数量" :value="formatDecimal(selectedRow.orderqty)" />
+                    <Cell title="委托价格" :value="formatDecimal(selectedRow.orderprice)" />
+                    <Cell title="成交数量" :value="formatDecimal(selectedRow.tradeqty)" />
+                    <Cell title="委托状态" :value="getWRTradeOrderStatusName(selectedRow.orderstatus)" />
+                    <Cell title="委托时间" :value="formatDate(selectedRow.ordertime)" />
+                    <Cell title="委托单号" :value="selectedRow.orderid" />
+                </CellGroup>
+            </div>
+            <template #footer v-if="selectedRow.orderstatus === 3 || selectedRow.orderstatus === 7">
+                <Button type="primary" block round @click="onCancelSumit">撤销</Button>
+            </template>
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import AppModal from '@/components/base/modal/index.vue'
+import { CellGroup, Cell, Button } from 'vant'
+import { getBuyOrSellName, getWRTradeOrderStatusName } from '@/constants/order'
+import { formatDate, formatDecimal } from '@/filters'
+import { useCancelOrder } from '@/business/trade'
+import { dialog, fullloading } from '@/utils/vant'
+
+const showModal = shallowRef(true)
+// 是否刷新父组件数据
+const refresh = shallowRef(false)
+const { cancelSubmit, formData } = useCancelOrder()
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.TradeOrderDetailRsp>,
+        required: true,
+    }
+})
+
+const onCancelSumit = () => {
+    dialog({
+        message: '确认要撤销吗?',
+        showCancelButton: true,
+    }).then(() => {
+        /// 市场ID
+        formData.Header = { MarketID: props.selectedRow.marketid }
+        formData.OldOrderId = props.selectedRow.orderid
+
+        /// loding....
+        fullloading((hideLoading) => {
+            cancelSubmit().then(() => {
+                hideLoading('撤销成功')
+                closed(true)
+            }).catch((err) => {
+                hideLoading(err, 'fail')
+            })
+        })
+    })
+}
+
+// 关闭弹窗
+const closed = (isRefresh = false) => {
+    refresh.value = isRefresh
+    showModal.value = false
+}
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+</script>

+ 122 - 0
src/packages/mobile/views/order/list/components/pricingorder/list/Index.vue

@@ -0,0 +1,122 @@
+<!-- 我的订单-订单委托 -->
+<template>
+    <app-pull-refresh ref="pullRefreshRef" v-model:loading="loading" v-model:error="error" v-model:pageIndex="pageIndex"
+        :page-count="pageCount" @refresh="run">
+        <div class="g-order-list">
+            <div class="g-order-list__box" v-for="(item, index) in dataList" :key="index">
+                <div class="g-order-list__titlebar">
+                    <div class="left">
+                        <h5>{{ item.goodscode }}/{{ item.goodsname }}</h5>
+                    </div>
+                    <div class="right">
+                        <span>{{ item.orderid }}</span>
+                    </div>
+                </div>
+                <div class="g-order-list__content">
+                    <ul>
+                        <li>
+                            <span>时间:</span>
+                            <span>{{ formatDate(item.ordertime, 'HH:mm:ss') }}</span>
+                        </li>
+                        <li>
+                            <span>方向:</span>
+                            <span>{{ getBuyOrSellName(item.buyorsell) }}</span>
+                        </li>
+                        <li>
+                            <span>委托数量:</span>
+                            <span>{{ formatDecimal(item.orderqty) }}</span>
+                        </li>
+                        <li>
+                            <span>委托价格:</span>
+                            <span>{{ formatDecimal(item.orderprice) }}</span>
+                        </li>
+                        <li>
+                            <span>成交数量:</span>
+                            <span>{{ formatDecimal(item.tradeqty) }}</span>
+                        </li>
+                        <li>
+                            <span>委托状态:</span>
+                            <span>{{ getWRTradeOrderStatusName(item.orderstatus) }}</span>
+                        </li>
+                    </ul>
+                </div>
+                <div class="g-order-list__btnbar">
+                    <Button size="small" @click="showComponent('detail', item)" round>详情</Button>
+                    <Button size="small" v-if="(item.orderstatus === 3 || item.orderstatus === 7)"
+                        @click="onCancelSumit(item)" round>撤销</Button>
+                </div>
+            </div>
+        </div>
+        <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
+    </app-pull-refresh>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { Button } from 'vant'
+import { useComponent } from '@/hooks/component'
+import { useRequest } from '@/hooks/request'
+import { queryTradeOrderDetail } from '@/services/api/order'
+import { getBuyOrSellName, getWRTradeOrderStatusName } from '@/constants/order'
+import { formatDate, formatDecimal } from '@/filters'
+import { useCancelOrder } from '@/business/trade'
+import { dialog } from '@/utils/vant'
+import { fullloading } from '@/utils/vant'
+
+import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
+
+const componentMap = new Map<string, unknown>([
+    ['detail', defineAsyncComponent(() => import('../detail/Index.vue'))]
+])
+
+const { cancelSubmit, formData } = useCancelOrder()
+const dataList = shallowRef<Model.TradeOrderDetailRsp[]>([])
+const selectedRow = shallowRef<Model.TradeOrderDetailRsp>()
+const error = shallowRef(false)
+const pullRefreshRef = shallowRef()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    pullRefreshRef.value?.refresh()
+})
+
+const { loading, pageIndex, pageCount, run } = useRequest(queryTradeOrderDetail, {
+    params: {
+        pagesize: 20,
+        tradeMode: '10'
+    },
+    onSuccess: (res) => {
+        if (pageIndex.value === 1) {
+            dataList.value = []
+        }
+        dataList.value.push(...res.data)
+    },
+    onError: () => {
+        error.value = true
+    }
+})
+
+const onCancelSumit = (item: Model.TradeOrderDetailRsp) => {
+    dialog({
+        message: '确认要撤销吗?',
+        showCancelButton: true,
+    }).then(() => {
+        formData.Header = { MarketID: item.marketid }
+        formData.OldOrderId = item.orderid
+
+        /// loding....
+        fullloading((hideLoading) => {
+            cancelSubmit().then(() => {
+                hideLoading('撤销成功')
+            }).catch((err) => {
+                hideLoading(err, 'fail')
+            })
+        })
+    })
+}
+
+const showComponent = (componentName: string, row: Model.TradeOrderDetailRsp) => {
+    selectedRow.value = row
+    openComponent(componentName)
+}
+</script>

+ 56 - 0
src/packages/mobile/views/order/list/components/pricingtrade/detail/Index.vue

@@ -0,0 +1,56 @@
+<!-- 我的订单- 点价成交 - 详情 -->
+<template>
+    <app-modal direction="right" height="100%" v-model:show="showModal" :refresh="refresh">
+        <app-view class="g-form">
+            <template #header>
+                <app-navbar title="详细" @back="closed" />
+            </template>
+            <div v-if="props" class="order-detail__container g-form__container">
+                <CellGroup title="挂牌点价成交信息">
+                    <Cell title="商品代码/名称" :value="selectedRow.goodscode+'/'+selectedRow.goodsname"/>
+                    <Cell title="方向" :value="getBuyOrSellName(selectedRow.buyorsell)" />
+                    <Cell title="类型" :value="getBuildTypeName(selectedRow.buildtype)" />
+                    <Cell title="成交数量" :value="formatDecimal(selectedRow.tradeqty)" />
+                    <Cell title="成交价格" :value="formatDecimal(selectedRow.tradeprice)" />
+                    <Cell title="手续费" :value="formatDecimal(selectedRow.charge)" />
+                    <Cell title="平仓损益" :value="formatDecimal(selectedRow.closepl)" />
+                    <!-- <Cell title="对手方" :value="selectedRow.matchaccountid" /> -->
+                    <Cell title="成交时间" :value="formatDate(selectedRow.tradetime)" />
+                    <Cell title="成交单号" :value="selectedRow.tradeid" />
+                </CellGroup>
+            </div>
+            <div v-else>
+                <Empty />
+            </div>
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { CellGroup, Cell } from 'vant'
+import { formatDate, formatDecimal } from '@/filters'
+import AppModal from '@/components/base/modal/index.vue'
+import { getBuyOrSellName, getBuildTypeName } from '@/constants/order'
+
+const showModal = shallowRef(true)
+const refresh = shallowRef(false) // 是否刷新父组件数据
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.TradeDetailRsp>,
+        required: true,
+    }
+})
+
+// 关闭弹窗
+const closed = (isRefresh = false) => {
+    refresh.value = isRefresh
+    showModal.value = false
+}
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+</script>

+ 96 - 0
src/packages/mobile/views/order/list/components/pricingtrade/list/Index.vue

@@ -0,0 +1,96 @@
+<!-- 我的订单-订单成交 -->
+<template>
+    <app-pull-refresh ref="pullRefreshRef" v-model:loading="loading" v-model:error="error" v-model:pageIndex="pageIndex"
+        :page-count="pageCount" @refresh="run">
+        <div class="g-order-list">
+            <div class="g-order-list__box" v-for="(item, index) in dataList" :key="index">
+                <div class="g-order-list__titlebar">
+                    <div class="left">
+                        <h5>{{ item.goodscode }}/{{ item.goodsname }}</h5>
+                    </div>
+                    <div class="right">
+                        <span>{{ item.tradeid }}</span>
+                    </div>
+                </div>
+                <div class="g-order-list__content">
+                    <ul>
+                        <li>
+                            <span>时间:</span>
+                            <span>{{ formatDate(item.tradetime, 'HH:mm:ss') }}</span>
+                        </li>
+                        <li>
+                            <span>类型:</span>
+                            <span>{{ getBuildTypeName(item.buildtype) }}{{ getBuyOrSellName(item.buyorsell) }}</span>
+                        </li>
+                        <li>
+                            <span>成交价格:</span>
+                            <span>{{ formatDecimal(item.tradeprice) }}</span>
+                        </li>
+                        <li>
+                            <span>手续费:</span>
+                            <span>{{ formatDecimal(item.charge)}}</span>
+                        </li>
+                        <li>
+                            <span>成交数量:</span>
+                            <span>{{ formatDecimal(item.tradeqty) }}</span>
+                        </li>
+                        <li>
+                            <span>平仓盈亏:</span>
+                            <span>{{ formatDecimal(item.closepl) }}</span>
+                        </li>
+                    </ul>
+                </div>
+                <div class="g-order-list__btnbar">
+                    <Button size="small" @click="showComponent('detail', item)" round>详情</Button>
+                </div>
+            </div>
+        </div>
+        <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
+    </app-pull-refresh>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { Button } from 'vant'
+import { useComponent } from '@/hooks/component'
+import { useRequest } from '@/hooks/request'
+import { queryTradeDetail } from '@/services/api/order'
+import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
+import { getBuyOrSellName, getBuildTypeName } from '@/constants/order'
+import { formatDate, formatDecimal } from '@/filters'
+
+const componentMap = new Map<string, unknown>([
+    ['detail', defineAsyncComponent(() => import('../detail/Index.vue'))],
+])
+
+const dataList = shallowRef<Model.TradeDetailRsp[]>([])
+const selectedRow = shallowRef<Model.TradeDetailRsp>()
+const error = shallowRef(false)
+const pullRefreshRef = shallowRef()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    pullRefreshRef.value?.refresh()
+})
+
+const { loading, pageIndex, pageCount, run } = useRequest(queryTradeDetail, {
+    params: {
+        pagesize: 20,
+        tradeMode: '10'
+    },
+    onSuccess: (res) => {
+        if (pageIndex.value === 1) {
+            dataList.value = []
+        }
+        dataList.value.push(...res.data)
+    },
+    onError: () => {
+        error.value = true
+    }
+})
+
+const showComponent = (componentName: string, row: Model.TradeDetailRsp) => {
+    selectedRow.value = row
+    openComponent(componentName)
+}
+</script>

+ 4 - 0
src/packages/mobile/views/order/position/Index.vue

@@ -19,6 +19,9 @@
             <Tab title="现货持仓">
             <Tab title="现货持仓">
                 <component :is="componentMap.get('spot')" />
                 <component :is="componentMap.get('spot')" />
             </Tab>
             </Tab>
+            <Tab title="点价持仓">
+                <component :is="componentMap.get('pricing')" />
+            </Tab>
         </Tabs>
         </Tabs>
     </app-view>
     </app-view>
 </template>
 </template>
@@ -33,6 +36,7 @@ const componentMap = new Map<string, unknown>([
     ['spot', defineAsyncComponent(() => import('./components/spot/list/Index.vue'))], // 现货持仓
     ['spot', defineAsyncComponent(() => import('./components/spot/list/Index.vue'))], // 现货持仓
     ['swap', defineAsyncComponent(() => import('./components/swap/list/Index.vue'))], // 掉期持仓
     ['swap', defineAsyncComponent(() => import('./components/swap/list/Index.vue'))], // 掉期持仓
     ['goods', defineAsyncComponent(() => import('./components/goods/list/Index.vue'))], // 订单持仓
     ['goods', defineAsyncComponent(() => import('./components/goods/list/Index.vue'))], // 订单持仓
+    ['pricing', defineAsyncComponent(() => import('./components/pricing/list/Index.vue'))], // 挂牌点价持仓
 ])
 ])
 
 
 const active = shallowRef(0)
 const active = shallowRef(0)

+ 108 - 0
src/packages/mobile/views/order/position/components/pricing/list/Index.vue

@@ -0,0 +1,108 @@
+<!-- 我的持仓-挂牌点价持仓 -->
+<template>
+    <app-pull-refresh ref="pullRefreshRef" v-model:loading="loading" v-model:error="error" v-model:pageIndex="pageIndex"
+        :page-count="pageCount" @refresh="run">
+        <div class="g-order-list">
+            <div class="g-order-list__box" v-for="(item, index) in dataList" :key="index">
+                <div class="g-order-list__titlebar">
+                    <div class="left">
+                        <h4>{{ item.goodscode }}/{{ item.goodsname }}</h4>
+                        <span>--</span>
+                    </div>
+                    <div class="right">
+                        <span>{{ getBuyOrSellName(item.buyorsell) }}</span>
+                    </div>
+                </div>
+                <div class="g-order-list__content">
+                    <ul>
+                        <li>
+                            <span>持有数量:</span>
+                            <span>{{ formatDecimal(item.curpositionqty) }}</span>
+                        </li>
+                        <li>
+                            <span>持仓均价:</span>
+                            <span>{{ item.averageprice === 0.0 ? '--' : formatDecimal(item.averageprice) }}</span>
+                        </li>
+                        <li>
+                            <span>冻结数量:</span>
+                            <span>{{ formatDecimal(item.frozenqty) }}</span>
+                        </li>
+                        <li>
+                            <span>持仓金额:</span>
+                            <span>{{ formatDecimal(item.curholderamount) }}</span>
+                        </li>
+                        <li>
+                            <span>可用数量:</span>
+                            <span>{{ formatDecimal(item.enableqty) }}</span>
+                        </li>
+                        <li>
+                            <span>参考损益:</span>
+                            <span>--</span>
+                        </li>
+                    </ul>
+                </div>
+                <div class="g-order-list__btnbar">
+                    <!-- <Button size="small" @click="showComponent('close', item)" round>平仓</Button> -->
+                    <!-- <Button size="small" v-if="userStore.userType === 5" @click="showComponent('delivery', item)" round>交收</Button> -->
+                    <Button size="small" @click="onClosed(item)" round>平仓</Button>
+                </div>
+            </div>
+        </div>
+        <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
+    </app-pull-refresh>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { Button } from 'vant'
+import { useComponent } from '@/hooks/component'
+import { useRequest } from '@/hooks/request'
+import { queryTradePosition } from '@/services/api/order'
+import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
+import { getBuyOrSellName } from '@/constants/order'
+import { formatDecimal } from '@/filters'
+import { useUserStore } from '@/stores'
+import { useNavigation } from '@/hooks/navigation'
+import { BuyOrSell, BuildType, PriceMode } from '@/constants/order'
+
+const componentMap = new Map<string, unknown>([
+    // ['close', defineAsyncComponent(() => import('../close/Index.vue'))],
+    // ['delivery', defineAsyncComponent(() => import('../delivery/Index.vue'))]
+])
+
+const {router} = useNavigation()
+const userStore = useUserStore()
+const dataList = shallowRef<Model.TradePositionRsp[]>([])
+const selectedRow = shallowRef<Model.TradePositionRsp>()
+const error = shallowRef(false)
+const pullRefreshRef = shallowRef()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    pullRefreshRef.value?.refresh()
+})
+
+const { loading, pageIndex, pageCount, run } = useRequest(queryTradePosition, {
+    params: {
+        pagesize: 20,
+        tradeMode: '10'
+    },
+    onSuccess: (res) => {
+        if (pageIndex.value === 1) {
+            dataList.value = []
+        }
+        dataList.value.push(...res.data)
+    },
+    onError: () => {
+        error.value = true
+    }
+})
+
+// 平仓
+const onClosed = (item: Model.TradePositionRsp) => {
+    const buyOrSell = item.buyorsell === BuyOrSell.Buy ? BuyOrSell.Sell : BuyOrSell.Buy
+    router.push({ name: 'pricing-detail', query: { goodscode: item.goodscode, buyOrSell: buyOrSell, buildType: BuildType.Close } })
+}
+
+
+</script>

+ 134 - 20
src/packages/mobile/views/pricing/detail/Index.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-    <app-view>
+    <app-view class="pricing-detail">
         <template #header>
         <template #header>
             <app-navbar title="点价详情" />
             <app-navbar title="点价详情" />
         </template>
         </template>
@@ -16,12 +16,12 @@
                     <tr>
                     <tr>
                         <td style="width: calc(`100% / 3`);">
                         <td style="width: calc(`100% / 3`);">
                             <span>幅度</span>
                             <span>幅度</span>
-                            <span :class="quote.lastColor" style="margin-left: .2rem;">{{ handleNumberValue(quote.amplitude)
+                            <span :class="quote.lastColor" style="margin-left: .2rem;">{{ parsePercent(quote.amplitude)
                             }}</span>
                             }}</span>
                         </td>
                         </td>
                         <td style="width: calc(`100% / 3`);">
                         <td style="width: calc(`100% / 3`);">
                             <span>涨跌</span>
                             <span>涨跌</span>
-                            <span :class="quote.lastColor" style="margin-left: .2rem;">{{ handleNumberValue(quote.change)
+                            <span :class="quote.lastColor" style="margin-left: .2rem;">{{ parsePercent(quote.change)
                             }}</span>
                             }}</span>
                         </td>
                         </td>
                         <td style="width: calc(`100% / 3`);" rowspan="3">
                         <td style="width: calc(`100% / 3`);" rowspan="3">
@@ -63,10 +63,10 @@
                 </table>
                 </table>
             </div>
             </div>
             <!-- 下单 -->
             <!-- 下单 -->
-            <Form ref="formRef" style="padding: 0.2rem; background-color: white;" @submit="onSubmit">
+            <Form class="pricing-detail__form" ref="formRef" style="padding: 0.2rem; background-color: white;" @submit="onSubmit">
                 <Field label="方向">
                 <Field label="方向">
                     <template #input>
                     <template #input>
-                        <RadioGroup v-model="formData.BuyOrSell" direction="horizontal">
+                        <RadioGroup v-model="formData.BuyOrSell" direction="horizontal" @click="onBuyOrSellChanged">
                             <Radio v-for="(item, index) in getBuyOrSellList()" :key="index" :name="item.value">{{ item.label
                             <Radio v-for="(item, index) in getBuyOrSellList()" :key="index" :name="item.value">{{ item.label
                             }}</Radio>
                             }}</Radio>
                         </RadioGroup>
                         </RadioGroup>
@@ -74,7 +74,7 @@
                 </Field>
                 </Field>
                 <Field label="类型">
                 <Field label="类型">
                     <template #input>
                     <template #input>
-                        <RadioGroup v-model="formData.BuildType" direction="horizontal">
+                        <RadioGroup v-model="formData.BuildType" direction="horizontal" @click="onBuildTypeChanged">
                             <Radio :name="BuildType.Open">{{ getBuildTypeName(BuildType.Open) }}</Radio>
                             <Radio :name="BuildType.Open">{{ getBuildTypeName(BuildType.Open) }}</Radio>
                             <Radio :name="BuildType.Close">{{ getBuildTypeName(BuildType.Close) }}</Radio>
                             <Radio :name="BuildType.Close">{{ getBuildTypeName(BuildType.Close) }}</Radio>
                         </RadioGroup>
                         </RadioGroup>
@@ -82,16 +82,16 @@
                 </Field>
                 </Field>
                 <Field label="价格方式">
                 <Field label="价格方式">
                     <template #input>
                     <template #input>
-                        <RadioGroup v-model="formData.PriceMode" direction="horizontal">
+                        <RadioGroup v-model="formData.PriceMode" direction="horizontal" @click="onPriceModeChanged">
                             <Radio v-for="(item, index) in getPricemode2List()" :key="index" :name="item.value">{{
                             <Radio v-for="(item, index) in getPricemode2List()" :key="index" :name="item.value">{{
                                 item.label
                                 item.label
                             }}</Radio>
                             }}</Radio>
                         </RadioGroup>
                         </RadioGroup>
                     </template>
                     </template>
                 </Field>
                 </Field>
-                <Field name="OrderQty" label="挂牌数量">
+                <Field name="OrderQty" label="数量">
                     <template #input>
                     <template #input>
-                        <Stepper v-model="formData.OrderQty" theme="round" button-size="22" :auto-fixed="false" integer />
+                        <Stepper v-model="formData.OrderQty" :rules="formRules.OrderQty"  theme="round" button-size="22" :auto-fixed="false" integer />
                     </template>
                     </template>
                 </Field>
                 </Field>
                 <!-- 市价 -->
                 <!-- 市价 -->
@@ -106,7 +106,27 @@
                     </template>
                     </template>
                 </Field>
                 </Field>
                 <!-- 限价 -->
                 <!-- 限价 -->
-                
+                <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格" v-if="formData.PriceMode === PriceMode.Limit">
+                    <template #input>
+                        <Stepper v-model="formData.OrderPrice" theme="round" button-size="22" :auto-fixed="false" />
+                    </template>
+                </Field>
+                <Field name="SlPrice" :rules="formRules.SlPrice" v-if="formData.PriceMode === PriceMode.Limit && formData.BuildType === BuildType.Open">
+                    <template #label>
+                        <Checkbox v-model="sl" shape="square">止损</Checkbox>
+                    </template>
+                    <template #input>
+                        <Stepper v-model="formData.SlPrice" :disabled="!sl" theme="round" button-size="22" allow-empty :default-value="0" :min="0" integer />
+                    </template>
+                </Field>
+                <Field name="SpPrice" :rules="formRules.SpPrice" v-if="formData.PriceMode === PriceMode.Limit && formData.BuildType === BuildType.Open">
+                    <template #label>
+                        <Checkbox v-model="sp" shape="square">止盈</Checkbox>
+                    </template>
+                    <template #input>
+                        <Stepper v-model="formData.SpPrice" :disabled="!sp" theme="round" button-size="22" allow-empty :default-value="0" :min="0" integer />
+                    </template>
+                </Field>
             </Form>
             </Form>
         </div>
         </div>
         <template #footer>
         <template #footer>
@@ -118,28 +138,72 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
 import { useFuturesStore } from '@/stores'
 import { useFuturesStore } from '@/stores'
 import { useNavigation } from '@/hooks/navigation'
 import { useNavigation } from '@/hooks/navigation'
-import { handleNumberValue } from '@/filters'
+import { parsePercent, handleNumberValue } from '@/filters'
 import quoteSocket from '@/services/websocket/quote'
 import quoteSocket from '@/services/websocket/quote'
 import { shallowRef, onMounted, onUnmounted, computed } from 'vue'
 import { shallowRef, onMounted, onUnmounted, computed } from 'vue'
-import { Form, Field, Stepper, Button, FieldRule, FormInstance, Radio, RadioGroup } from 'vant'
+import { Form, Field, Stepper, Button, FieldRule, FormInstance, Radio, RadioGroup, Checkbox } from 'vant'
 import { useOrder } from '@/business/trade'
 import { useOrder } from '@/business/trade'
 import { BuyOrSell, getBuyOrSellList, BuildType, getBuildTypeName, getPricemode2List, PriceMode } from '@/constants/order'
 import { BuyOrSell, getBuyOrSellList, BuildType, getBuildTypeName, getPricemode2List, PriceMode } from '@/constants/order'
 import { fullloading, dialog } from '@/utils/vant'
 import { fullloading, dialog } from '@/utils/vant'
+import { useRequest } from '@/hooks/request'
+import { queryTradePosition } from '@/services/api/order'
 
 
+const { router } = useNavigation()
 const futuresStore = useFuturesStore()
 const futuresStore = useFuturesStore()
 const { getQueryString, getQueryStringToNumber } = useNavigation()
 const { getQueryString, getQueryStringToNumber } = useNavigation()
-
-const goodscode = getQueryString('goodscode')
-const buyOrSell = getQueryStringToNumber('buyOrSell')
-const buildType = getQueryStringToNumber('buildType')
-const quote = futuresStore.getQuoteInfo(goodscode)
-const subscribe = quoteSocket.addSubscribe([goodscode])
 const formRef = shallowRef<FormInstance>()
 const formRef = shallowRef<FormInstance>()
 const { formData, formSubmit } = useOrder()
 const { formData, formSubmit } = useOrder()
+
 const marketPrice = computed(() => {
 const marketPrice = computed(() => {
     const { ask = 0, bid = 0 } = quote.value ?? {}
     const { ask = 0, bid = 0 } = quote.value ?? {}
     return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
     return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
 })
 })
+const goodscode = getQueryString('goodscode')
+const buyOrSell = getQueryStringToNumber('buyOrSell')
+const buildType = getQueryStringToNumber('buildType')
+const quote = futuresStore.getQuoteInfo(goodscode)
+const subscribe = quoteSocket.addSubscribe([goodscode])
+const sl = shallowRef(false) // 止损
+const sp = shallowRef(false) // 止盈
+const position = shallowRef<Model.TradePositionRsp[]>([]) // 持仓汇总
+
+// 表单验证规则
+const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
+    OrderQty: [{
+        message: '请输入数量',
+        validator: () => {
+            return !!formData.OrderQty
+        }
+    }],
+    // 限价
+    OrderPrice: [{
+        message: '请输入价格',
+        validator: () => {
+            if (formData.PriceMode === PriceMode.Limit) {
+                return !!formData.OrderPrice
+            }
+            return true
+        }
+    }],
+    SlPrice :[{
+        message: '请输入止损价',
+        validator: () => {
+            if (sl.value) {
+                return !!formData.SlPrice
+            }
+            return true
+        }
+    }],
+    SpPrice :[{
+        message: '请输入止盈价',
+        validator: () => {
+            if (sp.value) {
+                return !!formData.SpPrice
+            }
+            return true
+        }
+    }],
+}
 
 
 onMounted(() => {
 onMounted(() => {
     subscribe.start()
     subscribe.start()
@@ -154,20 +218,70 @@ onUnmounted(() => {
     subscribe.stop()
     subscribe.stop()
 })
 })
 
 
+// 获取当前商品持仓汇总
+useRequest(queryTradePosition, {
+    params: {
+        tradeMode: '10'
+    },
+    onSuccess: (res) => {
+        position.value = res.data.filter(item => item.goodscode === goodscode)
+        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
+        }
+    },
+})
+
+const onBuyOrSellChanged = () => {
+    if (formData.PriceMode === PriceMode.Limit) {
+        const { ask = 0, bid = 0 } = quote.value ?? {}
+        formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+    }
+}
+const onPriceModeChanged = () => {
+    if (formData.PriceMode === PriceMode.Limit) {
+        const { ask = 0, bid = 0 } = quote.value ?? {}
+        formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+    }
+}
+
+const onBuildTypeChanged = () => {
+    if (formData.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
+        }
+    }
+}
+
 // 委托下单
 // 委托下单
 const onSubmit = () => {
 const onSubmit = () => {
     const { goodsid, marketid } = quote.value ?? {}
     const { goodsid, marketid } = quote.value ?? {}
     formData.GoodsID = goodsid
     formData.GoodsID = goodsid
     formData.MarketID = marketid
     formData.MarketID = marketid
+    // 市价
+    if (formData.PriceMode === PriceMode.Market) { formData.OrderPrice = marketPrice.value }
+    // 限价
+    if (!sl.value) { formData.SlPrice = undefined }
+    if (!sp.value) { formData.SpPrice = undefined }
 
 
     fullloading((hideLoading) => {
     fullloading((hideLoading) => {
         formSubmit().then(() => {
         formSubmit().then(() => {
             hideLoading()
             hideLoading()
-            dialog('委托成功。')
+            dialog('委托成功。').then(() => {
+                router.back()
+            })
         }).catch((err) => {
         }).catch((err) => {
             hideLoading(err, 'fail')
             hideLoading(err, 'fail')
         })
         })
     })
     })
 }
 }
 
 
-</script>
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 13 - 0
src/packages/mobile/views/pricing/detail/index.less

@@ -0,0 +1,13 @@
+.pricing-detail {
+    &__form {
+        .van-stepper {
+            display: flex;
+            align-items: center;
+            width: 100%;
+
+            &__input {
+                flex: 1;
+            }
+        }
+    }
+}