Handy_Cao преди 2 месеца
родител
ревизия
7a86584c58

+ 1 - 1
public/config/appconfig.json

@@ -4,7 +4,7 @@
   "appTitle": "多元世纪交易中心",
   "version": "1.0.8",
   "versionCode": "10008",
-  "apiUrl": "http://192.168.31.204:8080/cfg?key=test_204",
+  "apiUrl": "http://192.168.31.210:8080/cfg?key=test_210",
   "tradeChannel": "ws",
   "modules": [
     "register",

+ 11 - 6
src/packages/digital/views/contract/components/account/index.vue

@@ -4,7 +4,7 @@
             <tbody>
                 <tr>
                     <td colspan="2">
-                        <span>资金(250000000011)</span>
+                        <span>资金({{ currentAccount.accountid }})</span>
                     </td>
                     <td>
                         <Icon name="arrow" />
@@ -13,25 +13,25 @@
                 <tr>
                     <td colspan="2">
                         <span class="text-small">账户权益(USDT)</span>
-                        <span>1000.00</span>
+                        <span>{{ currentAccount.balance }}</span>
                     </td>
                     <td>
                         <span class="text-small">浮动盈亏</span>
-                        <span>+2.87</span>
+                        <span>{{ currentAccount.closepl }}</span>
                     </td>
                 </tr>
                 <tr>
                     <td>
                         <span class="text-small">可用(USDT)</span>
-                        <span>100</span>
+                        <span>{{ currentAccount.currentbalance }}</span>
                     </td>
                     <td>
                         <span class="text-small">占用(USDT)</span>
-                        <span>34,808.80</span>
+                        <span>{{ currentAccount.usedmargin }}</span>
                     </td>
                     <td>
                         <span class="text-small">冻结(USDT)</span>
-                        <span>97.21</span>
+                        <span>{{ currentAccount.freezeMargin }}</span>
                     </td>
                 </tr>
             </tbody>
@@ -41,6 +41,11 @@
 
 <script lang="ts" setup>
 import { Icon } from 'vant'
+import { useAccountStore } from '@/stores'
+
+const accountStore = useAccountStore()
+const { currentAccount } = accountStore.$toRefs()
+
 </script>
 
 <style lang="less">

+ 24 - 4
src/packages/digital/views/contract/components/order/cancel/index.vue

@@ -1,22 +1,27 @@
 <template>
-    <Dialog v-model:show="showDialog" title="提示" show-cancel-button :before-close="onBeforeClose" @closed="onClosed">
+    <Dialog v-model:show="showDialog" title="提示" show-cancel-button :before-close="onBeforeClose" @closed="onClosed" @confirm="onCancelSumit">
         <span>是否撤销?</span>
     </Dialog>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, onMounted } from 'vue'
+import { shallowRef, PropType, onMounted } from 'vue'
 import { Dialog } from 'vant'
+import { useCancelOrder } from '@/business/trade'
+import { handleRequestBigNumber } from '@/filters'
+import { fullloading } from '@/utils/vant'
 
-defineProps({
+const props = defineProps({
     selectedRow: {
-        type: Object,
+        type: Object as PropType<Model.TradeOrderDetailRsp>,
         required: true
     }
 })
 
 const emit = defineEmits(['closed'])
 
+const { cancelSubmit, formData } = useCancelOrder()
+const pullRefreshRef = shallowRef()
 const showDialog = shallowRef(false)
 const refresh = shallowRef(false) // 是否刷新父组件数据
 
@@ -28,6 +33,21 @@ const onBeforeClose = (action: string) => {
     return true
 }
 
+const onCancelSumit = () => {
+    formData.Header = { MarketID: props.selectedRow.marketid, GoodsID: props.selectedRow.goodsid }
+    formData.OldOrderId = handleRequestBigNumber(props.selectedRow.orderid)
+
+    /// loding....
+    fullloading((hideLoading) => {
+        cancelSubmit().then(() => {
+            hideLoading(t('order.pricingorder.tips2'))
+            pullRefreshRef.value?.refresh()
+        }).catch((err) => {
+            hideLoading(err, 'fail')
+        })
+    })
+}
+
 const onClosed = () => {
     emit('closed', refresh.value)
 }

+ 64 - 42
src/packages/digital/views/contract/components/order/index.vue

@@ -1,46 +1,46 @@
 <template>
     <div class="contract-order">
         <table class="card" cellspacing="0" cellpadding="0" border="1">
-            <thead>
-                <tr>
-                    <th>
-                        <span>Gold黄金</span>
-                        <time>2025-09-01 11:11:11</time>
-                    </th>
-                    <th>
-                        <span>开多</span>
-                    </th>
-                </tr>
-            </thead>
             <tbody>
-                <tr>
-                    <td>
-                        <span>委托单号</span>
-                        <span>1001718728455010011</span>
-                    </td>
-                    <td>
-                        <span>委托状态</span>
-                        <span>委托成功</span>
-                    </td>
-                </tr>
-                <tr>
-                    <td>
-                        <span>委托价格(USDT)</span>
-                        <span>3,480.88</span>
-                    </td>
-                    <td>
-                        <span>委托数量(Gold)</span>
-                        <span>100</span>
-                    </td>
-                </tr>
+                <template v-for="(item, index) in dataList" :key="index">
+                    <tr>
+                        <th>
+                            <span>{{ item.goodscode }}/ {{ item.goodsname }}</span>
+                            <time>{{ formatDate(item.ordertime) }}</time>
+                        </th>
+                        <th>
+                            <span>{{ getBuyOrSellName(item.buyorsell) }}</span>
+                        </th>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>委托单号</span>
+                            <span>{{ item.orderid }}</span>
+                        </td>
+                        <td>
+                            <span>委托状态</span>
+                            <span>{{ getWRTradeOrderStatusName(item.orderstatus) }}</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>委托价格(USDT)</span>
+                            <span>{{ formatDecimal(item.orderprice, item.decimalplace) }}</span>
+                        </td>
+                        <td>
+                            <span>委托数量({{ item.goodscode }})</span>
+                            <span>{{ item.orderqty }}</span>
+                        </td>
+                    </tr>
+                    <tfoot>
+                        <tr>
+                            <td colspan="2">
+                                <Button type="danger" @click="cancelOrder(item)">撤销</Button>
+                            </td>
+                        </tr>
+                    </tfoot>
+                </template>
             </tbody>
-            <tfoot>
-                <tr>
-                    <td colspan="2">
-                        <Button type="danger" @click="cancelOrder()">撤销</Button>
-                    </td>
-                </tr>
-            </tfoot>
         </table>
         <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)"
             @closed="closeComponent" v-if="componentId" />
@@ -49,24 +49,46 @@
 
 <script lang="ts" setup>
 import { shallowRef, defineAsyncComponent } from 'vue'
+import { useRequest } from '@/hooks/request'
 import { Button } from 'vant'
 import { useComponent } from '@/hooks/component'
+import { queryTradeOrderDetail } from '@/services/api/order'
+import { formatDate, formatDecimal } from '@/filters'
+import { getBuyOrSellName, getWRTradeOrderStatusName } from '@/constants/order'
 
-defineProps({
+const props = defineProps({
     goodsId: Number
 })
 
+const error = shallowRef(false)
+const dataList = shallowRef<Model.TradeOrderDetailRsp[]>([])
+
 const componentMap = new Map<string, unknown>([
     ['Cancel', defineAsyncComponent(() => import('./cancel/index.vue'))], // 撤销
 ])
 
-const selectedRow = shallowRef()
+const { loading, pageIndex, pageCount, run } = useRequest(queryTradeOrderDetail, {
+    defaultParams: {
+        pagesize: 20,
+        tradeMode: '10',
+        orderStatus: '3,7'
+    },
+    onSuccess: (res) => {
+        dataList.value = []
+        dataList.value.push(...res.data.filter(e => e.goodsid === props.goodsId))
+    },
+    onError: () => {
+        error.value = true
+    }
+})
+
+const selectedRow = shallowRef<Model.TradeOrderDetailRsp>()
 
 const { componentRef, componentId, openComponent, closeComponent } = useComponent()
 
 // 撤销
-const cancelOrder = () => {
-    selectedRow.value = {}
+const cancelOrder = (item: Model.TradeOrderDetailRsp) => {
+    selectedRow.value = item
     openComponent('Cancel')
 }
 </script>

+ 66 - 55
src/packages/digital/views/contract/components/position/index.vue

@@ -1,56 +1,61 @@
+<!--  合约 - 商品交易 - 持仓单 -->
 <template>
     <div class="contract-position">
         <table class="card" cellspacing="0" cellpadding="0" border="1">
-            <thead>
-                <tr>
-                    <th colspan="2">
-                        <span>Gold黄金</span>
-                        <time>2025-09-01 11:11:11</time>
-                    </th>
-                    <th>
-                        <span>开多</span>
-                    </th>
-                </tr>
-            </thead>
             <tbody>
-                <tr>
-                    <td colspan="2">
-                        <span>浮动盈亏(USDT)</span>
-                        <span>+1000.00</span>
-                    </td>
-                    <td>
-                        <span>回报率(%)</span>
-                        <span>+2.87%</span>
-                    </td>
-                </tr>
-                <tr>
-                    <td>
-                        <span>持仓量(Gold)</span>
-                        <span>100</span>
-                    </td>
-                    <td>
-                        <span>保证金(USDT)</span>
-                        <span>34,808.80</span>
-                    </td>
-                    <td>
-                        <span>风险率(%)</span>
-                        <span>97.21%</span>
-                    </td>
-                </tr>
-                <tr>
-                    <td>
-                        <span>冻结量(Gold)</span>
-                        <span>100</span>
-                    </td>
-                    <td>
-                        <span>持仓价格(USDT)</span>
-                        <span>34,808.80</span>
-                    </td>
-                    <td>
-                        <span>持金额(USDT)</span>
-                        <span>97.21%</span>
-                    </td>
-                </tr>
+                <template v-for="(item, index) in orderComputedList" :key="index">
+                    <tr>
+                        <th colspan="2">
+                            <span>{{ item.goodsCode }}/ {{ item.goodsName }}</span>
+                            <time>{{ formatDate(item.tHDetailEx.tradeTime) }}</time>
+                        </th>
+                        <th>
+                            <span :class="!item.buyorsell ? 'g-price-up' : 'g-price-down'">
+                                {{ getBuyOrSellName(item.tHDetailEx.buyOrSell) }}
+                            </span>
+                        </th>
+                    </tr>
+                    <tr>
+                        <td colspan="2">
+                            <span>浮动盈亏( {{ getCurrencyName(item.currencyid) }})</span>
+                            <span :class="item.closeplColor">
+                                {{ formatDecimal(item.tHDetailEx.floatPL, item.decimalPlace) }}
+                            </span>
+                        </td>
+                        <td>
+                            <span>回报率(%)</span>
+                            <span>{{ parsePercent(calReturnRate(item)) }}</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>持仓量({{ item.goodsCode }})</span>
+                            <span>{{ item.tHDetailEx.holderQty }}</span>
+                        </td>
+                        <td>
+                            <span>保证金( {{ getCurrencyName(item.currencyid) }} )</span>
+                            <span>{{ formatAmount(calUseMargin(item)) }}</span>
+                        </td>
+                        <td>
+                            <span>风险率(%)</span>
+                            <span>{{ parsePercent(calRiskRate(item)) }}</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>冻结量({{ item.goodsCode }})</span>
+                            <span>{{ item.tHDetailEx.freezeQty }}</span>
+                        </td>
+                        <td>
+                            <span>持仓价格( {{ getCurrencyName(item.currencyid) }})</span>
+                            <span>{{ formatDecimal(item.tHDetailEx.holderPrice, item.decimalPlace) }}</span>
+                        </td>
+                        <td>
+                            <span>持金额( {{ getCurrencyName(item.currencyid) }} )</span>
+                            <span>{{ formatAmount(item.tHDetailEx.holderAmount) }}</span>
+                        </td>
+                    </tr>
+                </template>
             </tbody>
             <tfoot>
                 <tr>
@@ -69,7 +74,11 @@
 <script lang="ts" setup>
 import { shallowRef, defineAsyncComponent } from 'vue'
 import { Button } from 'vant'
+import { getBuyOrSellName } from '@/constants/order'
 import { useComponent } from '@/hooks/component'
+import { useSBYJOrderStore } from '@/stores'
+import { formatDate, formatDecimal, formatAmount, parsePercent } from '@/filters'
+import { getCurrencyName } from '@/constants/order'
 
 defineProps({
     goodsId: Number
@@ -80,19 +89,21 @@ const componentMap = new Map<string, unknown>([
     ['MarketClose', defineAsyncComponent(() => import('./market-close/index.vue'))], // 市价平仓
 ])
 
-const selectedRow = shallowRef()
+const selectedRow = shallowRef<Model.SBYJMyOrderRsp>()
+const { getSBYJMyOrders, $toRefs, calRiskRate, calReturnRate, calUseMargin } = useSBYJOrderStore()
+const { orderComputedList, loading, error } = $toRefs()
 
-const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => getSBYJMyOrders())
 
 // 平仓
-const closePosition = () => {
-    selectedRow.value = {}
+const closePosition = (row: Model.SBYJMyOrderRsp) => {
+    selectedRow.value = row
     openComponent('Close')
 }
 
 // 市价平仓
-const closePositionAtMarket = () => {
-    selectedRow.value = {}
+const closePositionAtMarket = (row: Model.SBYJMyOrderRsp) => {
+    selectedRow.value = row
     openComponent('MarketClose')
 }
 </script>

+ 19 - 2
src/packages/digital/views/contract/goods/chart/index.vue

@@ -1,20 +1,37 @@
+<!-- 合约 - 交易下单 - 图表 -->
 <template>
     <app-view class="contract-detail g-form">
         <template #header>
-            <app-navbar :title="quote?.goodscode" />
-            图表
+            <app-navbar :title="futuresStore.getGoodsName(goodsCode) ?? '图表'" />
+        </template>
+        <component :is="Price" v-bind="{ goodsCode }" />
+        <component :is="Chart" v-bind="{ goodsCode }" />
+        <component :is="Tik" v-bind="{ goodsCode}" />
+         <template #footer v-if="quote">
+            <div class="g-form__footer inset">
+                <Button type="primary">买入</Button>
+                <Button type="danger">卖出</Button>
+            </div>
         </template>
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { computed } from 'vue'
+import { defineAsyncComponent } from 'vue'
+import { Button } from 'vant'
 import { useNavigation } from '@mobile/router/navigation'
 import { useFuturesStore } from '@/stores'
 
+const Price = defineAsyncComponent(() => import('@mobile/components/modules/quote/price/index.vue'))
+const Chart = defineAsyncComponent(() => import('@mobile/components/modules/hqchart/index.vue'))
+const Tik = defineAsyncComponent(() => import('@mobile/components/modules/quote/tik/index.vue'))
+
 const { getQueryStringToNumber } = useNavigation()
 const goodsid = getQueryStringToNumber('id')
 const futuresStore = useFuturesStore()
 
 const quote = computed(() => futuresStore.getQuoteInfo({ goodsid }))
+
+const goodsCode = computed(() => quote.value?.goodscode ?? '')
 </script>

+ 86 - 9
src/packages/digital/views/contract/goods/detail/index.vue

@@ -20,17 +20,20 @@
             <CellGroup inset>
                 <Field label="限单价">
                     <template #input>
-                        <app-select :options="[]" />
+                        <app-select v-model="formData.PriceMode" :options="options" />
                     </template>
                 </Field>
-                <Field label="价格">
+                 <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
                     <template #input>
-                        <app-stepper theme="round" />
+                        <Stepper v-model="formData.OrderPrice" theme="round" min="0.0"
+                            :decimal-length="quote?.decimalplace" :step="quote?.decimalvalue" :auto-fixed="false"
+                            button-size="22" />
                     </template>
                 </Field>
-                <Field label="数量">
+                <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
                     <template #input>
-                        <app-stepper theme="round" />
+                        <Stepper v-model="formData.OrderQty" theme="round" min="0.0" button-size="22"
+                            :auto-fixed="false" integer />
                     </template>
                 </Field>
                 <Field label="开仓价值">
@@ -42,7 +45,7 @@
                 <Cell title="预估手续费" value="0" />
             </CellGroup>
         </Form>
-        <Button type="danger">开多</Button>
+        <Button type="danger" @click="onSubmit">开多</Button>
         <Tabs v-model:active="tabIndex">
             <Tab title="持仓">
                 <contract-position v-bind="{ goodsId }" />
@@ -58,24 +61,38 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed } from 'vue'
-import { Form, Button, CellGroup, Field, Cell, Tab, Tabs, } from 'vant'
+import { shallowRef, computed, onMounted } from 'vue'
+import { Form, Button, CellGroup, Field, Cell, Tab, Tabs, FieldRule } from 'vant'
+import { EPriceMode, EValidType, EOrderOperateType, EBuildType } from '@/constants/client'
 import { parsePercent } from '@/filters'
 import { useNavigation } from '@mobile/router/navigation'
 import { useFuturesStore } from '@/stores'
+import { fullloading, dialog } from '@/utils/vant'
+import { useOrder } from '@/business/trade'
+import Stepper from '@mobile/components/base/stepper/index.vue'
 import AppSelect from '@mobile/components/base/select/index.vue'
-import AppStepper from '@mobile/components/base/stepper/index.vue'
 import ContractPosition from '../../components/position/index.vue'
 import ContractOrder from '../../components/order/index.vue'
 import ContractAccount from '../../components/account/index.vue'
+import { BuyOrSell } from '@/constants/order'
 
 const { router, getQueryStringToNumber } = useNavigation()
 const goodsId = getQueryStringToNumber('id')
 const futuresStore = useFuturesStore()
 const tabIndex = shallowRef(0)
 
+const { formData, formSubmit } = useOrder()
+
 const quote = computed(() => futuresStore.getQuoteInfo({ goodsid: goodsId }))
 
+const options = computed(() => {
+    return [{
+        label: '限价单', value: EPriceMode.PRICEMODE_LIMIT
+    }, {
+        label: '市价单', value: EPriceMode.PRICEMODE_MARKET
+    }]
+})
+
 const routerToChart = () => {
     router.push({
         name: 'contract-goods-chart',
@@ -84,6 +101,66 @@ const routerToChart = () => {
         }
     })
 }
+
+// 表单验证规则
+const formRules: { [key: string]: FieldRule[] } = {
+    OrderPrice: [{
+        message:'请输入价格',
+        validator: () => {
+            return !!formData.OrderPrice
+        }
+    }],
+    OrderQty: [{
+        message: '请输入数量',
+        validator: () => {
+            return !!formData.OrderQty
+        }
+    }],
+}
+
+// 下单
+const onSubmit = () => {
+    // 计算提示信息
+    // const { marketid = 0, goodsid = 0, goodunitid = 0 } = quote.value ?? {}
+    // const { marginalgorithm = 0, transferdepositratio = 0.0 } = goods ?? {}
+    // const totalamount = orderQty.value*(formData.OrderPrice ?? 0)
+    // const orderPrice = `定价价格:${formData.OrderPrice ?? 0}\n`
+    // const qty = `订单数量:${orderQty.value}${getGoodsUnitName(goodunitid)}\n`
+    // const orderamount = `订单总额:${formatDecimal(totalamount)}\n`
+    // console.log(marginalgorithm, transferdepositratio)
+    // const margin = `预付定金:${formatDecimal(marginalgorithm === 1 ? totalamount*transferdepositratio : orderQty.value*transferdepositratio)}\n`
+    // const message = orderPrice + qty + orderamount + margin
+
+    const { marketid = 0, goodsid = 0 } = quote.value ?? {}
+    dialog({
+        message: '确认要提交吗?',
+        showCancelButton: true,
+    }).then(() => {
+        /// 获取对应的市场ID
+        formData.MarketID = marketid
+        formData.GoodsID = goodsid
+        formData.TimevalidType = EValidType.VALIDTYPE_DR
+        formData.OperateType = EOrderOperateType.ORDEROPERATETYPE_NORMAL
+        formData.BuildType = EBuildType.BUILDTYPE_OPEN
+
+        fullloading((hideLoading) => {
+            formSubmit().then(() => {
+                hideLoading('提交成功。', 'success')
+                // 刷新订单列表
+                // getSBYJMyOrders()
+            }).catch((err) => {
+                hideLoading(err, 'fail')
+            })
+        })
+    })
+}
+
+onMounted(() => {
+    if(quote.value) {
+        formData.BuyOrSell = BuyOrSell.Buy
+        formData.PriceMode = EPriceMode.PRICEMODE_MARKET
+    }
+})
 </script>
 
 <style lang="less">

+ 27 - 0
src/stores/modules/position.ts

@@ -166,6 +166,13 @@ export const useSBYJOrderStore = defineStore(() => {
         return depositRate
     }
 
+    // 计算保证金
+    const calUseMargin = (e: Model.SBYJMyOrderRsp) => {
+        // 已付定金+补充定金
+        const useMargin = e.tHDetailEx.payedDeposit + e.tHDetailEx.restockDeposit
+        return useMargin
+    }
+
     // 计算风险率 
     const calRiskRate = (e: Model.SBYJMyOrderRsp) => {
         // 已付定金+补充定金
@@ -183,6 +190,23 @@ export const useSBYJOrderStore = defineStore(() => {
         return riskRate
     }
 
+    // 计算回报率 
+    const calReturnRate = (e: Model.SBYJMyOrderRsp) => {
+        // 已付定金+补充定金
+        const useMargin = e.tHDetailEx.payedDeposit + e.tHDetailEx.restockDeposit
+
+        const quote = futuresStore.getGoodsQuote(e.tHDetailEx.goodsID)
+        const { ask = 0, bid = 0, agreeunit = 0 } = quote.value ?? {}
+        const price = e.tHDetailEx.buyOrSell === BuyOrSell.Buy ? bid : ask // 根据方向取买卖价
+
+        // 计算浮动盈亏 (价格 * 手数 * 合约乘数 - 持仓金额) * 方向标识
+        const float = price ? price * e.tHDetailEx.holderQty * agreeunit - e.tHDetailEx.holderAmount : 0
+        const floatpl = float * (e.tHDetailEx.buyOrSell === BuyOrSell.Buy ? 1 : -1)
+        // 计算风险率 占用/占用+浮动盈亏
+        const returnRate = floatpl / useMargin
+        return returnRate
+    }
+
     // 获取订单列表
     const getSBYJMyOrders = async () => {
         if (!state.loading) {
@@ -222,6 +246,9 @@ export const useSBYJOrderStore = defineStore(() => {
         ...toRefs(state),
         orderComputedList,
         getSBYJMyOrders,
+        calRiskRate,
+        calUseMargin,
+        calReturnRate,
         getOrderListByGoodsId,
         calcFloatpl,
         eventNotify,