li.shaoyi vor 4 Jahren
Ursprung
Commit
3189edcc64

+ 33 - 30
src/assets/styles/mixin.less

@@ -194,10 +194,10 @@
 }
 
 .commonInput {
-    background   : @m-grey21;
-    border       : 1px solid @m-grey14;
-    border-radius: 3px;
-    color        : @m-white1;
+    background-color: @m-grey21  !important;
+    border          : 1px solid @m-grey14;
+    border-radius   : 3px;
+    color           : @m-white1;
 
     .ant-input {
         color     : @m-white1;
@@ -213,7 +213,8 @@
 
     &:hover,
     &:focus {
-        border-color: @m-blue10;
+        border-color    : @m-blue10;
+        background-color: @m-grey21  !important;
     }
 }
 
@@ -223,7 +224,7 @@
 }
 
 .tableConditionInput {
-    margin-left:10px;
+    margin-left: 10px;
     width      : 140px;
     height     : 30px;
     line-height: 30px;
@@ -922,31 +923,33 @@
     }
 }
 
-.inlineFormSelect.ant-select-single {
-    .rounded-corners(3px);
-    border: 1px solid @m-grey14;
+.inlineFormSelect {
+    &.ant-select-single {
+        .rounded-corners(3px);
+        border: 1px solid @m-grey14;
 
-    &:hover,
-    &:focus {
-        border-color: @m-blue10;
-    }
+        &:hover,
+        &:focus {
+            border-color: @m-blue10;
+        }
 
-    .ant-select-selector {
-        height    : 30px;
-        padding   : 0 8px;
-        background: @m-grey21;
-        border    : 0;
-        color     : @m-white1;
+        .ant-select-selector {
+            height          : 30px;
+            padding         : 0 8px;
+            background-color: @m-grey21  !important;
+            border          : 0;
+            color           : @m-white1;
 
-        .ant-select-selection-placeholder {
-            color: @m-grey10;
-        }
+            .ant-select-selection-placeholder {
+                color: @m-grey10;
+            }
 
-    }
+        }
 
-    .ant-select-arrow {
-        right: 8px;
-        color: @m-blue0  !important;
+        .ant-select-arrow {
+            right: 8px;
+            color: @m-blue0  !important;
+        }
     }
 }
 
@@ -3111,10 +3114,10 @@ input:-internal-autofill-selected {
 
 // 表格按钮列表固定在右边
 .btn-list-sticky {
-    position: sticky;
-    position: -webkit-sticky;
-    right   : 2px;
-    margin-top:7px;
+    position  : sticky;
+    position  : -webkit-sticky;
+    right     : 2px;
+    margin-top: 7px;
 }
 
 // 步骤条

+ 4 - 4
src/common/constants/enumCommon.ts

@@ -2,8 +2,8 @@
  * 买卖方向
  */
 export enum BuyOrSell {
-    buy, // 买
-    sell, // 卖
+    buy = 0, // 买
+    sell = 1, // 卖
 }
 
 /**
@@ -52,9 +52,9 @@ export const enum OperateType {
 /**
  * 价格类型
  */
-export const enum PriceType {
+export enum PriceType {
     market = 1, // 市价
-    limit, // 限价
+    limit = 2, // 限价
 }
 
 /**

+ 5 - 3
src/services/proto/futures/interface.ts

@@ -1,3 +1,5 @@
+import { BuyOrSell, BuildType, PriceType } from '@/common/constants/enumCommon';
+
 // 交易委托请求 0 3 31
 export interface ChannelOrderReq {
     ClientSerialNo: string; // string 客户端流水号
@@ -14,10 +16,10 @@ export interface ChannelOrderReq {
     OperatorID: number; // uint64 操作员账号ID
     OrderPrice: number; // double 委托价格
     OrderQty: number; // uint64 委托数量
-    BuyOrSell: number; // uint32 买卖方向(买卖 - 0:买 1:卖 )
-    ChannelBuildType: number; // uint32 下单类型(开平标志 - 0:无 1:建仓 2:平仓)
+    BuyOrSell: BuyOrSell; // uint32 买卖方向(买卖 - 0:买 1:卖 )
+    ChannelBuildType: BuildType; // uint32 下单类型(开平标志 - 0:无 1:建仓 2:平仓)
     CloseType: number; // uint32 平仓方式(平仓方式 - 0:无 1:平今 2:平昨)
-    PriceMode: number; // uint32 取价方式 - 1:市价 2: 限价
+    PriceMode: PriceType; // uint32 取价方式 - 1:市价 2: 限价
     TimeValidType: number; // uint32 时间有效类型
     RelatedID?: number; // uint64 关联单号
     ServiceTime?: string; // string 服务端时间

+ 53 - 89
src/views/market/futures/compoments/futures-trade/index.vue

@@ -3,35 +3,39 @@
   <Drawer :title="'期货交易'" :placement="'right'" :visible="visible" @cancel="cancel" class="top">
     <div class="futures_trade">
       <div class="futures_trade__left">
-        <a-form class="inlineForm">
+        <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>
           </a-form-item>
           <a-form-item label="合约">
-            <a-select class="inlineFormSelect" placeholder="请选择" v-model:value="formData.GoodsID">
+            <a-select class="inlineFormSelect" placeholder="请选择" v-model:value="formData.GoodsID" @change="goodsChange">
               <a-select-option v-for="item in tableList" :value="item.goodsid" :key="item.goodsid">{{ item.goodsname }}</a-select-option>
             </a-select>
           </a-form-item>
-          <a-form-item label="交易价格">
+          <a-form-item class="inputIconBox" label="交易价格" name="OrderPrice">
             <!-- 限价类型不可修改 -->
-            <a-input-number class="commonInput" :value="selectedRow.last" disabled v-if="formData.PriceMode === 2" />
-            <a-input-number class="commonInput" v-model:value="formData.OrderPrice" v-else />
-            <MinusOutlined />
-            <PlusOutlined />
-            <a-select class="inlineFormSelect" placeholder="请选择" v-model:value="selectedPriceMode">
+            <template v-if="formData.PriceMode === PriceType.limit">
+              <a-input-number class="commonInput" :value="selectedGoods.last" disabled />
+            </template>
+            <template v-else>
+              <a-input-number class="commonInput" v-model:value="formData.OrderPrice" />
+              <MinusOutlined />
+              <PlusOutlined />
+            </template>
+            <a-select class="inlineFormSelect" placeholder="请选择" v-model:value="selectedPriceMode" @change="priceModeChange">
               <a-select-option v-for="item in priceModeList" :value="item.priceType" :key="item.priceType">{{ item.priceName }}</a-select-option>
             </a-select>
           </a-form-item>
-          <a-form-item label="交易数量">
+          <a-form-item class="inputIconBox" label="交易数量" name="OrderQty">
             <a-input-number class="commonInput" :min="1" v-model:value="formData.OrderQty" />
             <MinusOutlined />
             <PlusOutlined />
             <a-button @click="formData.OrderQty = 1">复位</a-button>
           </a-form-item>
         </a-form>
-        <div>
+        <div v-show="selectedGoods.last">
           <a-button :loading="loading" @click="submit('buy')">买入</a-button>
           <a-button :loading="loading" @click="submit('sell')">卖出</a-button>
           <a-button :loading="loading" @click="submit('close')">平仓</a-button>
@@ -40,38 +44,6 @@
       <div class="futures_trade__right">
 
       </div>
-      <!-- <a-form class="inlineForm dialogForm" ref="formRef" :model="formState" :rules="rules">
-        <div class="formBar">
-          <a-row :gutter="24">
-            <a-col :span="24">
-              <a-form-item label="交易账户" name="accountid">
-                <a-select class="inlineFormSelect" style="width: 260px" v-model:value="formState.accountid" placeholder="请选择">
-                  <a-select-option v-for="item in accountList" :value="item.accountid" :key="item.accountid">{{ item.accountid }}</a-select-option>
-                </a-select>
-              </a-form-item>
-            </a-col>
-            <a-col :span="24">
-              <a-form-item label="挂牌价格" name="FixedPrice">
-                <a-input-number class="commonInput" style="width: 260px" :min="0" v-model:value="formState.FixedPrice" />
-              </a-form-item>
-            </a-col>
-            <a-col :span="24">
-              <a-form-item label="挂牌数量" name="OrderQty">
-                <a-input-number class="commonInput" style="width: 260px" :min="0" v-model:value="formState.OrderQty" />
-                <span class="input-enumdicname">{{ selectedRow.enumdicname }}</span>
-              </a-form-item>
-            </a-col>
-          </a-row>
-        </div>
-        <a-row :gutter="24">
-          <a-col :span="24" class="fixedBtns">
-            <a-form-item class="btnCenter">
-              <a-button class="listedBtn" @click="submit" :loading="loading">买入</a-button>
-              <a-button class="ml10 cancelBtn" @click="cancel" :disabled="loading">取消</a-button>
-            </a-form-item>
-          </a-col>
-        </a-row>
-      </a-form> -->
     </div>
   </Drawer>
 </template>
@@ -80,18 +52,14 @@
 import { Des } from '@/common/components/commonDes';
 import Drawer from '@/common/components/drawer/index.vue';
 import { _closeModal } from '@/common/setup/modal/modal';
-import { getAccountTypeList } from '@/services/bus/account';
 import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue';
-import moment from 'moment';
-import { defineComponent, PropType, ref, reactive } from 'vue';
-import { TempTableQuoteDetail } from './interface';
+import { defineComponent, PropType, ref } from 'vue';
 import { handleForm } from './setup';
 import { channelOrderReq } from '@/services/proto/futures';
-import { ChannelOrderReq } from '@/services/proto/futures/interface';
-import { getUserId } from '@/services/bus/user';
-import { geLoginID_number } from '@/services/bus/login';
 import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
-import { v4 as uuidv4 } from 'uuid';
+import { BuyOrSell, BuildType, PriceType } from '@/common/constants/enumCommon';
+import { TableQuote } from '@/common/setup/table/interface';
+import { validateAction } from '@/common/setup/form';
 
 export default defineComponent({
     emits: ['cancel', 'update'],
@@ -99,19 +67,22 @@ export default defineComponent({
     components: { Des, Drawer, PlusOutlined, MinusOutlined },
     props: {
         selectedRow: {
-            type: Object as PropType<TempTableQuoteDetail>,
+            type: Object as PropType<TableQuote>,
             default: {},
         },
         tableList: {
-            type: Array as PropType<TempTableQuoteDetail[]>,
+            type: Array as PropType<TableQuote[]>,
             default: [],
         },
     },
     setup(props, context) {
         const { visible, cancel } = _closeModal(context);
-        const { rules, formState, formRef } = handleForm(props.selectedRow);
+        const { rules, formData, accountList } = handleForm(props.selectedRow);
+        const formRef = ref();
         const loading = ref<boolean>(false);
 
+        // 选中的商品合约
+        const selectedGoods = ref<TableQuote>(props.selectedRow);
         // 选中的价格类型
         const selectedPriceMode = ref(0);
         // 价格类型列表
@@ -130,59 +101,49 @@ export default defineComponent({
             },
         ];
 
-        const formData = reactive<ChannelOrderReq>({
-            ClientSerialNo: uuidv4(), // string 客户端流水号
-            ClientOrderTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), // string 客户端委托时间
-            ClientType: 4, // uint32 终端类型
-            LoginID: geLoginID_number()!, // uint64 登陆账号
-            AccountID: 0, // uint64 交易账号
-            GoodsID: props.selectedRow.goodsid, // uint32 商品ID
-            MarketID: props.selectedRow.marketid, // uint32 市场ID
-            ValidType: 1, // int32 有效类型 - 1当日有效
-            ChannelOperateType: 1, // uint32 操作类型:
-            ChannelOrderSrc: 1, // uint32 单据来源委托来源 -  1:客户端 2:管理端 3:风控服务
-            HedgeFlag: 0, // uint32 投机套保标志 - 0:无 1:投机 2:套保 3:套利 4:套期保值 5:单边 6:移仓 7:错单处理 8:跨期套利
-            OperatorID: getUserId(), // uint64 操作员账号ID
-            OrderPrice: 0, // double 委托价格
-            OrderQty: 1, // uint64 委托数量
-            BuyOrSell: 0, // uint32 买卖方向(买卖 - 0:买 1:卖 )
-            ChannelBuildType: 0, // uint32 下单类型(开平标志 - 0:无 1:建仓 2:平仓)
-            CloseType: 0, // uint32 平仓方式(平仓方式 - 0:无 1:平今 2:平昨)
-            PriceMode: 2, // uint32 取价方式 - 1:市价 2: 限价
-            TimeValidType: 1, // uint32 时间有效类型
-        });
+        // 选择商品合约
+        function goodsChange(value: number) {
+            selectedGoods.value = props.tableList.find((item) => item.goodsid === value)!;
+        }
 
-        // 账号列表
-        const accountList = getAccountTypeList([1]);
-        if (accountList.length) {
-            formData.AccountID = accountList[0].accountid;
+        // 选择价格类型
+        function priceModeChange(value: number) {
+            if (value === 1) {
+                formData.PriceMode = PriceType.market;
+            } else {
+                formData.PriceMode = PriceType.limit;
+            }
         }
 
         function submit(submitType: 'buy' | 'sell' | 'close') {
+            // 按钮提交类型
             switch (submitType) {
                 case 'buy': {
-                    formData.BuyOrSell = 0;
-                    formData.ChannelBuildType = 1;
+                    formData.BuyOrSell = BuyOrSell.buy;
+                    formData.ChannelBuildType = BuildType.open;
                     break;
                 }
                 case 'sell': {
-                    formData.BuyOrSell = 1;
-                    formData.ChannelBuildType = 1;
+                    formData.BuyOrSell = BuyOrSell.sell;
+                    formData.ChannelBuildType = BuildType.open;
                     break;
                 }
                 case 'close': {
-                    formData.ChannelBuildType = 2;
+                    formData.ChannelBuildType = BuildType.close;
                     break;
                 }
             }
 
-            if (formData.PriceMode === 2) {
-                const { last } = props.selectedRow;
-                formData.OrderPrice = last!;
+            if (formData.PriceMode === PriceType.limit) {
+                const { last } = selectedGoods.value;
+                formData.OrderPrice = last;
             }
 
-            requestResultLoadingAndInfo(channelOrderReq, formData, loading, ['成功', '失败:']).then(() => {
-                cancel(true);
+            // 表单验证
+            validateAction(formRef, formData).then((res) => {
+                requestResultLoadingAndInfo(channelOrderReq, res, loading, ['成功', '失败:']).then(() => {
+                    cancel(true);
+                });
             });
         }
         return {
@@ -192,11 +153,14 @@ export default defineComponent({
             visible,
             accountList,
             rules,
-            formState,
             formRef,
             formData,
+            selectedGoods,
+            goodsChange,
             priceModeList,
+            PriceType,
             selectedPriceMode,
+            priceModeChange,
         };
     },
 });

+ 53 - 28
src/views/market/futures/compoments/futures-trade/setup.ts

@@ -1,38 +1,63 @@
-import { useVerifyListingBasis, useVerifyListingNum } from '@/hooks/form/verify';
 import moment from "moment";
-import { onBeforeUnmount, reactive, ref, UnwrapRef } from "vue";
-import { FormParam, TempTableQuoteDetail } from "./interface";
+import { reactive } from "vue";
+import { TableQuote } from '@/common/setup/table/interface';
+import { ChannelOrderReq } from '@/services/proto/futures/interface';
+import { v4 as uuidv4 } from 'uuid';
+import { PriceType } from '@/common/constants/enumCommon';
+import { geLoginID_number } from '@/services/bus/login';
+import { getUserId } from '@/services/bus/user';
+import { RuleObject } from 'ant-design-vue/es/form/interface';
+import { getAccountTypeList } from '@/services/bus/account';
 
-function initFormData(): FormParam {
-    return {
-        accountid: undefined,
-        goodscode: undefined,
-        FixedPrice: 0,
-        OrderQty: 0,
-        PriceMove: 0,
-        DelistMinQty: 0,
-        DeliveryMonth: moment()
+export function handleForm(selectedRow: TableQuote) {
+    // 数据初始化
+    const formData = reactive<ChannelOrderReq>({
+        ClientSerialNo: uuidv4(), // string 客户端流水号
+        ClientOrderTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), // string 客户端委托时间
+        ClientType: 4, // uint32 终端类型
+        LoginID: geLoginID_number()!, // uint64 登陆账号
+        AccountID: 0, // uint64 交易账号
+        GoodsID: selectedRow.goodsid, // uint32 商品ID
+        MarketID: selectedRow.marketid, // uint32 市场ID
+        ValidType: 1, // int32 有效类型 - 1当日有效
+        ChannelOperateType: 1, // uint32 操作类型:
+        ChannelOrderSrc: 1, // uint32 单据来源委托来源 -  1:客户端 2:管理端 3:风控服务
+        HedgeFlag: 0, // uint32 投机套保标志 - 0:无 1:投机 2:套保 3:套利 4:套期保值 5:单边 6:移仓 7:错单处理 8:跨期套利
+        OperatorID: getUserId(), // uint64 操作员账号ID
+        OrderPrice: 0, // double 委托价格
+        OrderQty: 1, // uint64 委托数量
+        BuyOrSell: 0, // uint32 买卖方向(买卖 - 0:买 1:卖 )
+        ChannelBuildType: 0, // uint32 下单类型(开平标志 - 0:无 1:建仓 2:平仓)
+        CloseType: 0, // uint32 平仓方式(平仓方式 - 0:无 1:平今 2:平昨)
+        PriceMode: PriceType.limit, // uint32 取价方式 - 1:市价 2: 限价
+        TimeValidType: 1, // uint32 时间有效类型
+    })
+
+    // 账号列表
+    const accountList = getAccountTypeList([1]);
+    if (accountList.length) {
+        formData.AccountID = accountList[0].accountid;
     }
-}
-const formState: UnwrapRef<FormParam> = reactive(initFormData())
-export function handleForm(selectedRow: TempTableQuoteDetail) {
-    const formRef = ref();
-    formState.OrderQty = selectedRow.decimalplace;
-    formState.goodscode = selectedRow.goodscode;
 
-    const { v_num } = useVerifyListingNum<FormParam, 'DelistMinQty'>(formState, 'DelistMinQty', selectedRow.decimalplace);
-    const { v_basis } = useVerifyListingBasis(selectedRow, 'goodscode');
+    // 验证交易价格
+    const verifyOrderPrice = async (rule: RuleObject, value: number) => {
+        if (value) {
+            return Promise.resolve();
+        } else {
+            return Promise.reject('交易价格不能小于0')
+        }
+    }
 
     const rules = {
-        FixedPrice: [{ required: true, message: '请输入挂牌价格', trigger: 'blur', type: 'number', }],
-        OrderQty: [{ required: true, validator: v_num, trigger: 'change', type: 'number' }],
-        PriceMove: [{ required: true, validator: v_basis, trigger: 'blur', type: 'number', }],
-        accountid: [{ required: true, message: '请输入交易账号' }],
+        OrderPrice: [{ required: true, trigger: 'blur', type: 'number', validator: verifyOrderPrice, }],
+        OrderQty: [{ required: true, trigger: 'blur', type: 'number', message: '请输入交易数量' }],
+    }
+
+    return {
+        rules,
+        accountList,
+        formData,
     }
-    onBeforeUnmount(() => {
-        Object.assign(formState, initFormData(), { OrderQty: selectedRow.decimalplace })
-    })
-    return { rules, formState, formRef }
 }
 
 

+ 9 - 3
src/views/market/futures/index.vue

@@ -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" :selectedRow="selectedRow" @cancel="closeComponent"></component>
+    <component :is="componentId" v-if="componentId" :tableList="tableList.filter((item) => item.last)" :selectedRow="selectedRow" @cancel="closeComponent"></component>
   </div>
 </template>
 
@@ -28,6 +28,7 @@ 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',
@@ -70,8 +71,13 @@ export default defineComponent({
         const { componentId, closeComponent, openComponent } = handleModalComponent(() => {}, selectedRow);
         // 关闭右键
         function closeContext(value: BtnListType | null) {
-            // 打开对应的弹窗组件
-            if (value) openComponent(value, selectedRow.value);
+            const last = selectedRow.value?.last;
+            if (last) {
+                // 打开对应的弹窗组件
+                if (value) openComponent(value, selectedRow.value);
+            } else {
+                message.warn('非交易时间段,不能下单');
+            }
             // 关闭右键
             closeContextAction();
         }