li.shaoyi 4 gadi atpakaļ
vecāks
revīzija
698838f9f6

+ 10 - 10
src/layout/components/main.vue

@@ -1,15 +1,15 @@
 <template>
-    <div class="exposure">
-        <div class="first-menu">
-            <a-menu class="a-menu_container" theme="dark" v-model:selectedKeys="selectedKey" @click="selectMenu" mode="horizontal">
-                <a-menu-item :key="String(index)" v-for="(item, index) in list">{{ item.title }}</a-menu-item>
-            </a-menu>
-            <div class="menu_right">
-                <!-- <slot></slot> -->
-            </div>
-        </div>
-        <router-view :key="$route.fullPath" />
+  <div class="exposure">
+    <div class="first-menu">
+      <a-menu class="a-menu_container" theme="dark" v-model:selectedKeys="selectedKey" @click="selectMenu" mode="horizontal">
+        <a-menu-item :key="String(index)" v-for="(item, index) in list">{{ item.title }}</a-menu-item>
+      </a-menu>
+      <div class="menu_right">
+        <!-- <slot></slot> -->
+      </div>
     </div>
+    <router-view :key="$route.fullPath" />
+  </div>
 </template>
 
 <script lang="ts">

+ 1 - 0
src/services/bus/system.ts

@@ -17,6 +17,7 @@ export const notice = (logout: Function) => {
     });
     // 注册头寸变化通知; => 请求头寸数据,计算持仓盈亏
     eventBus.$onOnly('posChangedNtf', (msg: string) => {
+        eventBus.$emit('posChangedNtf_UI', msg);
         console.warn(msg);
     });
     // 注册资金变化通知; => 请求资金账户信息,计算资金账户盈亏,可用,净值等

+ 1 - 0
src/utils/eventBus/index.ts

@@ -4,6 +4,7 @@ interface EnentNames {
     spotTrade: string;  // 挂牌成功,通知报价大厅更新数据
     blocsTrade: string; // 贸易圈 挂牌成功
     moneyChangedNtf_UI: string; // /接收到资金变化通知 UI 成 使用
+    posChangedNtf_UI: string; //接收到头寸变化通知
     financing_manager: string; // 融资摘牌
     changeTheme: string; // 切换主题
 }

+ 9 - 5
src/views/market/futures/compoments/futures-trade/index.less

@@ -30,11 +30,15 @@
         align-items: center;
 
         .ant-btn {
-            height       : auto;
-            color        : #fff;
-            border       : 0;
-            border-radius: 4px;
-            padding      : 16px 16px;
+            display        : flex;
+            justify-content: center;
+            flex-direction : column;
+            align-items    : center;
+            width          : 96px;
+            height         : 72px;
+            color          : #fff;
+            border         : 0;
+            border-radius  : 4px;
 
             &:not(:last-child) {
                 margin-right: 10px;

+ 49 - 15
src/views/market/futures/compoments/futures-trade/index.vue

@@ -7,7 +7,7 @@
           <a-form class="inlineForm" ref="formRef" :model="formData" :rules="rules">
             <a-form-item label="账号">
               <a-select class="inlineFormSelect" placeholder="请选择" v-model:value="formData.AccountID">
-                <a-select-option v-for="item in accountList" :value="item.accountid" :key="item.accountid">{{ item.accountname }}</a-select-option>
+                <a-select-option v-for="item in accountList" :value="item.accountid" :key="item.accountid">{{ item.accountname }} - {{item.accountid}}</a-select-option>
               </a-select>
             </a-form-item>
             <a-form-item label="合约">
@@ -21,15 +21,15 @@
               </a-select>
             </a-form-item>
             <a-form-item class="inputIconBox" label="交易价格" name="OrderPrice">
-              <!-- 限价类型不可修改 -->
-              <template v-if="formData.PriceMode === PriceType.limit">
-                <a-input-number class="commonInput" :value="selectedGoods.last" style="width:100%" disabled />
-              </template>
-              <template v-else>
+              <!-- 限价可修改 -->
+              <template v-if="selectedPriceMode === 3">
                 <a-input-number class="commonInput" v-model:value="formData.OrderPrice" style="width:100%" />
                 <MinusOutlined />
                 <PlusOutlined />
               </template>
+              <template v-else>
+                <a-input-number class="commonInput" :value="selectedGoods.last" style="width:100%" disabled />
+              </template>
             </a-form-item>
             <a-form-item class="inputIconBox" label="交易数量" name="OrderQty">
               <a-input-number class="commonInput" :min="1" v-model:value="formData.OrderQty" style="width:100%" />
@@ -38,14 +38,17 @@
             </a-form-item>
           </a-form>
         </div>
-        <div class="futures_trade__submit" v-show="selectedGoods.last">
+        <div class="futures_trade__submit">
           <a-button :loading="loading" @click="submit('buy')">
+            <span>{{buyPrice}}</span>
             <span>买入</span>
           </a-button>
           <a-button :loading="loading" @click="submit('sell')">
+            <span>{{sellPrice}}</span>
             <span>卖出</span>
           </a-button>
           <a-button :loading="loading" @click="submit('close')">
+            <span>优先平今</span>
             <span>平仓</span>
           </a-button>
         </div>
@@ -88,6 +91,11 @@ export default defineComponent({
         const formRef = ref();
         const loading = ref<boolean>(false);
 
+        // 买价
+        const buyPrice = ref(0);
+        // 卖价
+        const sellPrice = ref(0);
+
         // 选中的商品合约
         const selectedGoods = ref<TableQuote>(props.selectedRow);
         // 选中的价格类型
@@ -104,8 +112,16 @@ export default defineComponent({
             },
             {
                 priceType: 2,
+                priceName: '对手价',
+            },
+            {
+                priceType: 3,
                 priceName: '限价',
             },
+            {
+                priceType: 4,
+                priceName: '超价',
+            },
         ];
 
         // 选择商品合约
@@ -114,12 +130,34 @@ export default defineComponent({
         }
 
         // 选择价格类型
-        function priceModeChange(value: number) {
-            if (value === 1) {
+        function priceModeChange(priceType: number) {
+            // 除了市价,其它价格类型都属于限价
+            if (priceType === 1) {
                 formData.PriceMode = PriceType.market;
             } else {
                 formData.PriceMode = PriceType.limit;
             }
+
+            const { last } = selectedGoods.value;
+            switch (priceType) {
+                // 最新价
+                case 1: {
+                    formData.OrderPrice = last;
+                    break;
+                }
+                // 市价
+                case 2: {
+                }
+                // 对手价
+                case 3: {
+                }
+                // 限价
+                case 4: {
+                }
+                // 超价
+                case 5: {
+                }
+            }
         }
 
         function submit(submitType: 'buy' | 'sell' | 'close') {
@@ -140,12 +178,6 @@ export default defineComponent({
                     break;
                 }
             }
-
-            if (formData.PriceMode === PriceType.limit) {
-                const { last } = selectedGoods.value;
-                formData.OrderPrice = last;
-            }
-
             // 表单验证
             validateAction(formRef, formData).then((res) => {
                 requestResultLoadingAndInfo(channelOrderReq, res, loading, ['成功', '失败:']).then(() => {
@@ -162,6 +194,8 @@ export default defineComponent({
             rules,
             formRef,
             formData,
+            buyPrice,
+            sellPrice,
             selectedGoods,
             goodsChange,
             priceModeList,

+ 25 - 0
src/views/market/futures/index.less

@@ -0,0 +1,25 @@
+.futures {
+    &-table-up {
+        .ant-table {
+            .ant-table-body {
+                min-height: calc(100vh - 405px) !important;
+                max-height: calc(100vh - 405px) !important;
+            }
+
+            .ant-table-placeholder {
+                height: calc(100vh - 405px) !important;
+            }
+        }
+    }
+
+    &-table-down {
+        .ant-table-body {
+            min-height: calc(100vh - 165px) !important;
+            max-height: calc(100vh - 165px) !important;
+        }
+
+        .ant-table-placeholder {
+            height: calc(100vh - 165px) !important;
+        }
+    }
+}

+ 6 - 11
src/views/market/futures/index.vue

@@ -1,7 +1,7 @@
 <template>
   <!--期货-->
-  <div class="topTableHeight">
-    <a-table :columns="getColumnsList()" :class="['srcollYTable', isBottom ? 'condSecondTabTable' : 'condSecondTabTableNoBottom', tableList.length ? 'noPlaceHolder' : 'hasPlaceHolder']" :scroll="{ x: '100%', y: isBottom ? 'calc(100vh- 443px)' : 'calc(100vh - 196px)' }" :pagination="false" :loading="loading" :customRow="Rowclick" rowKey="goodscode" :data-source="tableList">
+  <div class="futures topTableHeight">
+    <a-table :columns="getColumnsList()" :class="['srcollYTable', isBottom ? 'futures-table-up' : 'futures-table-down', tableList.length ? 'noPlaceHolder' : 'hasPlaceHolder']" :scroll="{ x: '100%', y: 'auto' }" :pagination="false" :loading="loading" :customRow="Rowclick" rowKey="goodscode" :data-source="tableList">
       <template #index="{ index }">
         <span>{{index + 1}}</span>
       </template>
@@ -9,7 +9,7 @@
     <ThridMenu :list="tabList" :selectedKey="index" @selectMenu="changeTab" />
     <!-- 右键 -->
     <contextMenu :contextMenu="contextMenu" @cancel="closeContext" :list="buttons"></contextMenu>
-    <component :is="componentId" v-if="componentId" :tableList="tableList.filter((item) => item.last)" :selectedRow="selectedRow" @cancel="closeComponent"></component>
+    <component :is="componentId" v-if="componentId" :tableList="tableList" :selectedRow="selectedRow" @cancel="closeComponent"></component>
   </div>
 </template>
 
@@ -28,7 +28,6 @@ import { TableEventCB } from '@/common/setup/table/interface';
 import { getTableEvent } from '@/common/export/table';
 import { ContextMenuTemp } from '@/common/components/contextMenu/interface';
 import { BtnListType } from '@/common/components/btnList/interface';
-import { message } from 'ant-design-vue';
 
 export default defineComponent({
     name: 'spot_trade_order_transaction_swap',
@@ -71,13 +70,8 @@ export default defineComponent({
         const { componentId, closeComponent, openComponent } = handleModalComponent(() => {}, selectedRow);
         // 关闭右键
         function closeContext(value: BtnListType | null) {
-            const last = selectedRow.value?.last;
-            if (last) {
-                // 打开对应的弹窗组件
-                if (value) openComponent(value, selectedRow.value);
-            } else {
-                message.warn('非交易时间段,不能下单');
-            }
+            // 打开对应的弹窗组件
+            if (value) openComponent(value, selectedRow.value);
             // 关闭右键
             closeContextAction();
         }
@@ -102,6 +96,7 @@ export default defineComponent({
 });
 </script>
 <style lang="less">
+@import './index.less';
 .noData {
     .position(absolute, 28px, 0, 0, 0);
 }

+ 79 - 5
src/views/order/futures_information/components/futures_information_position/columns.tsx

@@ -1,6 +1,7 @@
-import { computed } from 'vue';
 import { QueryErmcpTradePositionRsp } from '@/services/go/ermcp/futures/interface';
+import { BuyOrSell } from '@/common/constants/enumCommon';
 import { getBuyOrSellName } from '@/common/constants/enumsName';
+import { getQuoteDayInfoByCode } from "@/services/bus/goods";
 
 export function getColumns() {
     const columns = [
@@ -28,19 +29,35 @@ export function getColumns() {
         },
         {
             title: '开仓均价',
-            key: 'openaverageprice'
+            key: 'openaverageprice',
+            customRender: ({ record }: { record: QueryErmcpTradePositionRsp }) => {
+                return calcOpenAveragePrice(record).toFixed(2);
+            }
         },
         {
             title: '持仓均价',
-            key: 'positionaverageprice'
+            key: 'positionaverageprice',
+            customRender: ({ record }: { record: QueryErmcpTradePositionRsp }) => {
+                return calcPositionAveragePrice(record).toFixed(2);
+            }
         },
         {
             title: '浮动盈亏',
-            key: 'positionpl'
+            key: 'positionpl',
+            customRender: ({ record }: { record: QueryErmcpTradePositionRsp }) => {
+                const result = calcPositionPl(record);
+                if (result === 0) return result;
+                return handlePriceColor(result, result.toFixed(2));
+            }
         },
         {
             title: '盈亏比例',
-            key: 'positionplrate'
+            key: 'positionplrate',
+            customRender: ({ record }: { record: QueryErmcpTradePositionRsp }) => {
+                const result = calcPositionPlRate(record);
+                if (result === 0) return result;
+                return handlePriceColor(result, result.toFixed(2) + '%');
+            }
         },
     ];
 
@@ -53,4 +70,61 @@ export function getColumns() {
             ...el
         }
     })
+}
+
+/**
+ * 计算开仓均价
+ */
+function calcOpenAveragePrice(record: QueryErmcpTradePositionRsp) {
+    const { opencost, curpositionqty, agreeunit } = record
+    // 开仓成本 ÷ 期末头寸 ÷ 合约单位
+    return opencost / curpositionqty / agreeunit;
+}
+
+/**
+ * 计算持仓均价
+ */
+function calcPositionAveragePrice(record: QueryErmcpTradePositionRsp) {
+    const { positioncost, curpositionqty, agreeunit } = record
+    // 持仓成本 ÷ 期末头寸 ÷ 合约单位
+    return positioncost / curpositionqty / agreeunit;
+}
+
+/**
+ * 计算浮动盈亏
+ */
+function calcPositionPl(record: QueryErmcpTradePositionRsp) {
+    const { goodscode, curpositionqty, agreeunit } = record
+    // 获取对应的商品行情
+    const quote = getQuoteDayInfoByCode(goodscode);
+
+    if (quote?.last) {
+        if (record.buyorsell === BuyOrSell.buy) {
+            // 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位
+            return (quote.last - calcPositionAveragePrice(record)) * curpositionqty * agreeunit
+        } else {
+            // 卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位
+            return (calcPositionAveragePrice(record) - quote.last) * curpositionqty * agreeunit
+        }
+    }
+    return record.positionpl
+}
+
+function calcPositionPlRate(record: QueryErmcpTradePositionRsp) {
+    const { opencost } = record
+    // 持仓盈亏 ÷ 开仓成本
+    return calcPositionPl(record) / opencost * 100
+}
+
+/**
+ * 处理显示颜色
+ */
+function handlePriceColor(value: number, text: string) {
+    let className = ''
+    if (value > 0) {
+        className = 'up-quote-color'
+    } else {
+        className = 'down-quote-color'
+    }
+    return <span class={className}>{text}</span>;
 }

+ 11 - 1
src/views/order/futures_information/components/futures_information_position/index.vue

@@ -21,6 +21,7 @@ import { getRecordItemTab } from '@/common/setup/order/orderData';
 import { queryErmcpTradePosition } from '@/services/go/ermcp/futures';
 import { QueryErmcpTradePositionRsp } from '@/services/go/ermcp/futures/interface';
 import { getColumns } from './columns';
+import Bus from '@/utils/eventBus/index';
 
 export default defineComponent({
     components: {
@@ -30,12 +31,21 @@ export default defineComponent({
         // 表格列表数据
         const { loading, tableList, queryTable } = queryTableList<QueryErmcpTradePositionRsp>();
 
+        // 获取列表数据
+        const queryTableAction = () => queryTable(queryErmcpTradePosition);
+
         // 表格通用逻辑
         const param: ComposeOrderTableParam = {
-            queryFn: () => queryTable(queryErmcpTradePosition),
+            queryFn: queryTableAction,
             recordList: getRecordItemTab(),
         };
 
+        // 注册头寸变化事件,待通知调用
+        Bus.$on('posChangedNtf_UI', () => {
+            // 重新加载数据
+            queryTableAction();
+        });
+
         return {
             ...handleComposeOrderTable(param),
             getColumns,