huangbin 4 jaren geleden
bovenliggende
commit
c2e1f1f798

+ 18 - 0
public/proto/mtp.proto

@@ -439,6 +439,24 @@ message SearchReceiverRsp {
 		repeated ReceiverInfo InfoList = 5; // 用户收货信息
 }
 
+// 按单协议平仓申请 0 29 213
+message TradeHoldTransferApplyReq {
+	optional MessageHead Header = 1; // MessageHead
+	optional uint64 TradeID = 2; // uint64 申请人的持仓单表ID
+	optional uint32 BuyorSell = 3; // uint32 持仓单方向  卖 - 0:买 1:卖
+	optional double TransferPrice = 4; // double 转让价格
+	optional uint32 ApplySrc = 5; // uint32 申请来源 - 1:管理端 2:终端
+	optional uint64 ApplicantID = 6; // uint64 登录账号
+	optional string Remark = 7; // string 申请备注
+}
+// 按单协议平仓申请响应 0 29 214
+message TradeHoldTransferApplyRsp {
+	optional MessageHead Header = 1; // MessageHead 消息头
+	optional int32 RetCode = 2; // int32 返回码
+	optional string RetDesc = 3; // string 描述信息
+	optional uint64 applyid = 4; // uint64 申请ID
+}
+
 // 新增修改收货地址请求
 message UserReceiveInfoReq {
 	optional MessageHead Header = 1;

+ 13 - 2
src/services/bus/goods.ts

@@ -4,7 +4,7 @@ import APP from '@/services';
 import { Ref, ref } from 'vue';
 import { Goods } from '../go/ermcp/goodsInfo/interface';
 import { QueryQuoteDayRsp } from '../go/quote/interface';
-import { Goodsgroup } from '../go/useInfo/interface';
+import { Goodsgroup, Market } from '../go/useInfo/interface';
 import { getMarketByTradeMode } from './market';
 
 // 获取全部商品信息
@@ -99,8 +99,19 @@ export function getGoodsGroupsByTradeMode(trademode: TradeMode): Goodsgroup[] {
     return result
 }
 
+// 通过 goodsid 查找 商品
+export function getGoodsById(goodsid: number) {
+    return getGoodsList().find(el => el.goodsid === goodsid)
+}
+
 // 通过goodsid 获取商品合约单位
 export function getGoodsAgreeunitByGoodsId(goodsid: number): number | null {
-    const result = getGoodsList().find(el => el.goodsid === goodsid)
+    const result = getGoodsById(goodsid)
     return result ? result.agreeunit : null
+}
+
+// 通过 goodsid 查找 trademode
+export function findGoodsTradeModeById(goodsid: number) {
+    const marketid = getGoodsById(goodsid)!.marketid
+    return APP.get('markets').find((el: Market) => el.marketid === marketid).trademode
 }

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

@@ -12,6 +12,7 @@ export function getMarketsByTradeMode(trademode: TradeMode): Market[] {
     return APP.get('markets').filter((el: Market) => el.trademode === trademode)
 }
 
+
 //  通过 trademode 获取市场ids
 export function getMarketIdsByTradeMode(trademode: TradeMode): string {
     const arr = getMarketsByTradeMode(trademode)

+ 3 - 0
src/services/funcode/index.ts

@@ -30,6 +30,9 @@ export const funCode: Code = {
     SearchReceiverReq: 1900575, // 查询用户收货信息表请求
     SearchReceiverRsp: 1900576, // 查询用户收货信息表应答
 
+    TradeHoldTransferApplyReq: 1900757, // /按单协议平仓申请
+    TradeHoldTransferApplyRsp: 1900758, // /按单协议平仓申请
+
     UserReceiveInfoReq: 1900545, // 新增修改收货地址请求
     UserReceiveInfoRsp: 1900546, // 新增修改收货地址请求响应
     DelUserReceiveInfoReq: 1900547, // 删除收货地址请求请求

+ 11 - 0
src/services/go/order/index.ts

@@ -0,0 +1,11 @@
+import { commonSearch_go } from "@/services/go";
+import * as type from './interface';
+
+/**
+ * 查询持仓明细  /Order/QueryTradeHolderDetail
+ */
+export function queryTradeHolderDetail(req: type.QueryTradeHolderDetailReq): Promise<type.QueryTradeHolderDetailRsp[]> {
+    return commonSearch_go('/Order/QueryTradeHolderDetail', req).catch((err) => {
+        throw new Error(`查询持仓明细 : ${err}`);
+    });
+}

+ 61 - 0
src/services/go/order/interface.ts

@@ -0,0 +1,61 @@
+export interface QueryTradeHolderDetailReq {
+    userid?: number; // 用户id
+    accids?: string; // 资金账号, 格式 1,2,3
+    trademodes?: string; // 交易模式, 格式 1,2,3
+    marketids?: string; // 市场id, 格式 1,2,3
+    goodsid?: number; // 商品id
+    buyorsell?: number; // 买卖方向 0-买 1-卖
+}
+
+export interface QueryTradeHolderDetailRsp {
+    accountid: number;//账号ID
+    agreeunit: number;//合约乘数
+    buyorsell: number;//方向 - number;
+    //:买 1:卖
+    currencyid: number;//商品币种id
+    currencyname: string;//币种名称
+    decimalplace: number;//商品价格小数位
+    enumdicname: string;//商品单位名称
+    expirecycle: number;//行权周期(天) - 1:滚动行权时填写
+    expiredate: string;//行权日(yyyyMMdd) - 到期日
+    expiretype: number;//行权日类型 - 1:滚动行权 2:固定日行权
+    freezeqty: number;//冻结数量
+    goodscode: string;//商品代码
+    goodsid: number;//商品ID
+    goodsname: string;//商品名称
+    goodunitid: number;//商品单位id
+    holderamount: number;//持仓金额
+    holdercredit: number;//持仓授信金额
+    holderdays: number;//剩余冻结天数
+    holderprice: number;//持仓价格
+    holderqty: number;//持仓数量
+    isconfirmexercise: number;//是否确认行权- number;
+    //:否 1:是
+    ispreexercise: number;//是否预申报- number;
+    //:否 1:是 2:不可行权
+    marketid: number;//市场id
+    marketname: string;//市场名称
+    openprice: number;//建仓价格
+    openqty: number;//建仓数量
+    optiontype: number;//期权类型 - 1:认购(看涨) 2:认沽(看跌)
+    preexerciseprice: number;//预申报价格
+    premium: number;//权利金
+    qtydecimalplace: number;//商品成交量小数位
+    refgoodscode: string;//标的合约代码
+    refgoodsid: number;//标的合约id
+    releaseamount: number;//释放持仓金额
+    releaseholdercredit: number;//释放持仓授信金额
+    taname: string;//资金账号名称
+    tradeamount: number;//成交金额
+    tradedate: string;//交易日(yyyyMMdd)
+    tradeid: string;//成交单号(1number;
+    //1+Unix秒时间戳(1number;
+    //位)+2位(MarketServiceID)+xxxx)
+    trademode: number;//交易模式 - 1number;
+    //:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 2number;
+    //:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价 46:掉期
+    tradeproperty: number;//交易属性
+    tradetime: string;//交易时间
+    userid: number;//用户id
+    username: string;//用户名称
+}

+ 12 - 1
src/services/proto/warehousetrade/index.ts

@@ -1,7 +1,7 @@
 import {
     DeliveryOrderReq,
     HdWRDealOrderReq,
-    HdWROrderReq, PaymentArrearsReq, WarehouseRepurchaseReq, WrBargainApplyReq, WRListingCancelOrderReq, WROutApplyCancelReq,
+    HdWROrderReq, PaymentArrearsReq, TradeHoldTransferApplyReq, WarehouseRepurchaseReq, WrBargainApplyReq, WRListingCancelOrderReq, WROutApplyCancelReq,
     WROutApplyReq, WROutCancelReq, WROutConfirmReq, WRTradeFinanceBuyCancelReq
 } from "@/services/proto/warehousetrade/interface";
 import { protoMiddleware } from "@/services/socket/protobuf/buildReq";
@@ -116,6 +116,17 @@ export const DeliveryOrder = (param: DeliveryOrderReq): Promise<any> => {
     return protoMiddleware<DeliveryOrderReq>(param, 'DeliveryOrderReq', 'DeliveryOrderRsp', HeadEnum.tradeMode17)
 }
 
+/**
+ * 单协议平仓
+ * @param param
+ * @constructor
+ */
+export const tradeHoldTransferApply = (param: TradeHoldTransferApplyReq): Promise<any> => {
+    return protoMiddleware<TradeHoldTransferApplyReq>(param, 'TradeHoldTransferApplyReq', 'TradeHoldTransferApplyRsp', HeadEnum.tradeMode17)
+}
+
+
+
 // /**
 //  * 议价申请拒绝请求
 //  * @param param

+ 10 - 0
src/services/proto/warehousetrade/interface.ts

@@ -1,3 +1,4 @@
+
 // 持仓单挂牌请求 0 22 15
 export interface HdWROrderReq {
     LadingBillId: number; // uint64 提单id(wrholdlb的LadingBillId字段),卖的时候填写
@@ -308,6 +309,15 @@ export interface DeliveryOrderDetail {
     WRFactorTypeID: number // uint64 仓单要素类型ID
 }
 
+export interface TradeHoldTransferApplyReq {
+    TradeID: number; //  申请人的持仓单表ID
+    BuyorSell: number; // 持仓单方向  卖 - 0:买 1:卖
+    TransferPrice: number; // 转让价格
+    ApplySrc: number; // 申请来源 - 1:管理端 2:终端
+    ApplicantID: number; // 登录账号
+    Remark: string; // 申请备注
+}
+
 // // 议价申请审核请求 0 29 59
 // export interface WrBargainNoAgreeReq {
 //     WrBargainID: number // uint64 申请ID

+ 445 - 0
src/views/order/commodity_contract/components/commodity_contract_summary/components/commodity_contract_summary_deal_closed/index.vue

@@ -0,0 +1,445 @@
+<template>
+  <!-- 协议平仓-->
+  <Drawer :title="'协议平仓'"
+          :placement="'right'"
+          class="bottom486"
+          :visible="visible"
+          @cancel="cancel">
+    <div class="listed c_c_s_s">
+      <a-form class="inlineForm dialogForm"
+              ref="formRef">
+        <div class="formBar">
+          <div class="formtop">
+            <div class="firstTitle">
+              <span>合约:{{selectedRow.goodscode}}/{{selectedRow.goodsname}}</span>
+            </div>
+            <div class="secondLine">
+              <div class="left">持有人/商品/仓库</div>
+              <div class="middle">升贴水/数量</div>
+              <div class="right">选择数量</div>
+            </div>
+            <a-checkbox-group class="commonCheckboxGroup"
+                              v-model:value="checked"
+                              @change="checkGroupChange">
+              <div class="lineBar"
+                   v-for="(item, index) in tableList"
+                   :key="index + '11'">
+                <div class="line1">
+                  <div class>
+                    <a-checkbox @change="checkboxChange(item)"
+                                :value="item.ladingbillid"></a-checkbox>
+                  </div>
+                  <div class="name">{{item.username}}</div>
+                </div>
+                <div class="line2">
+                  <div class="left">
+                    <div>{{item.wrtypename}}</div>
+                    <div>{{item.warehousename}}</div>
+                  </div>
+                  <div class="middle">
+                    <div>{{item.pricemove}}</div>
+                    <div>{{toFixed0(item.avalidqty)}}{{item.enumdicname}}</div>
+                  </div>
+                  <div class="right">
+                    <template class="inputNumberBlock"
+                              :class="isChecked(item.ladingbillid) ? '' : 'disabled'">
+                      <a-input-number class="dialogInput dialogInput34"
+                                      v-model:value="item.num"
+                                      style="width: 130px !important; height: 34px;"
+                                      :disabled="!isChecked(item.ladingbillid)"
+                                      :max="toFixed0(item.avalidqty)"
+                                      :min="0"></a-input-number>
+                      <MinusOutlined @click="decrease(item)" />
+                      <PlusOutlined @click="increase(item)" />
+                    </template>
+                  </div>
+                </div>
+              </div>
+            </a-checkbox-group>
+          </div>
+        </div>
+        <div class="fixedBtns">
+          <div class="formbottom">
+            <div class="line1">
+              <div>
+                <span>已点选数量</span>
+                <span class="white">{{selctedNum()}} {{selectedRow.goodunit}}</span>
+                <span>,需合约数量</span>
+                <span class="white">{{getNeedContractNum()}}</span>
+              </div>
+              <div class="yellow">升贴水{{selected ? selected.pricemove * selected.num : '--'}}</div>
+            </div>
+            <div class="line2"
+                 v-if="isBaseSpread()">
+              <div>点价合约</div>
+              <div class="right">
+                <div>{{selected.pgoodscode ? selected.pgoodscode : ''}}</div>
+                <div>{{getDeliveryGoodsPrice()}}</div>
+              </div>
+            </div>
+            <div v-if="isBaseSpread()"
+                 class="line3">预估货款:{{getEstimatedPayment()}}</div>
+          </div>
+
+          <a-form-item class="btnCenter mt10">
+            <a-button class="listedBtn"
+                      :loading="loading"
+                      :disabled="loading"
+                      @click="submit">提交</a-button>
+          </a-form-item>
+        </div>
+      </a-form>
+    </div>
+  </Drawer>
+</template>
+
+<script lang="ts">
+import { defineComponent, PropType, ref } from 'vue';
+import Drawer from '@/common/components/drawer/index.vue';
+import { ModalEnum } from '@/common/constants/modalNameEnum';
+import { _closeModal } from '@/common/setup/modal/modal';
+
+import UploadImg from '@/common/components/uploadImg/index.vue';
+import { getSelectedAccountId } from '@/services/bus/account';
+
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import Long from 'long';
+import { QueryTradePositionRsp } from '@/services/go/ermcp/order/interface';
+import { PlusOutlined, MinusOutlined } from '@ant-design/icons-vue';
+import { handleCheck, getTableList, handleCalculation } from './setup';
+import { DeliveryOrder } from '@/services/proto/warehousetrade';
+import { v4 } from 'uuid';
+import moment from 'moment';
+import { DeliveryOrderReq, TradeHoldTransferApplyReq } from '@/services/proto/warehousetrade/interface';
+import { geLoginID_number, getLoginData } from '@/services/bus/login';
+import { message } from 'ant-design-vue';
+import { getGoodsByCode } from '@/services/bus/goods';
+import { queryTableList } from '@/common/setup/table';
+import { queryTjmdTransferApply } from '@/services/go/Tjmd';
+import { QueryTjmdTransferApplyRsp } from '@/services/go/Tjmd/interface';
+import { GetLoginID } from '@/services/go/useInfo';
+
+export default defineComponent({
+    name: ModalEnum.commodity_contract_summary_settlement,
+    components: { Drawer, UploadImg, PlusOutlined, MinusOutlined },
+    emits: ['cancel', 'update'],
+    props: {
+        selectedRow: {
+            type: Object as PropType<QueryTradePositionRsp>,
+            default: {},
+        },
+        buyOrSell: {
+            type: Number as PropType<BuyOrSell>,
+            default: BuyOrSell.buy,
+        },
+    },
+    setup(props, context) {
+        const { visible, cancel } = _closeModal(context);
+        // 表格列表数据
+        const { loading, tableList, queryTable } = queryTableList<QueryTjmdTransferApplyRsp>();
+        const param = {
+            applytype: 1,
+        };
+        queryTable(queryTjmdTransferApply, param);
+
+        const { goodsid } = props.selectedRow;
+        // 合约交收可点选仓单
+        // const { tableList } = getTableList(goodsid);
+        // check 是否选中逻辑
+        const { checked, selected, deliveryGoods, checkGroupChange, isChecked, checkboxChange, isBaseSpread } = handleCheck();
+        // 各种计算
+        const { getStepValue, getCanSettlementNum, getNeedContractNum, getEstimatedPayment, XQty, PQty, getDeliveryGoodsPrice, increase, decrease, selctedNum } = handleCalculation(props.selectedRow);
+
+        const toFixed0 = (value: number) => +value.toFixed(0);
+
+        function submit() {
+            const param: TradeHoldTransferApplyReq = {
+                TradeID: 111,
+                BuyorSell: 1,
+                TransferPrice: 11,
+                ApplySrc: 2,
+                ApplicantID: geLoginID_number()!,
+                Remark: '',
+            };
+
+            if (!selected.value) {
+                message.warn('请选择合约');
+                return;
+            }
+            if (!selected.value.num) {
+                message.warn('请输入选择数量');
+                return;
+            }
+
+            if (deliveryGoods.value) {
+                loading.value = true;
+                console.log(deliveryGoods.value);
+                const param: DeliveryOrderReq = {
+                    ClientSerialNo: v4(), // 客户端流水号
+                    ClientOrderTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), // 客户端委托时间
+                    ClientType: 4, // 终端类型
+                    // goodsID: props.selectedRow.goodsid,
+                    // market
+                    AccountID: getSelectedAccountId(),
+                    XGoodsID: getGoodsByCode(selected.value.xgoodscode)!.goodsid,
+                    DeliveryGoodsID: deliveryGoods.value.deliverygoodsid,
+                    XQty: Long.fromNumber(XQty()),
+                    PQty: Long.fromNumber(PQty()),
+                    OperateType: 0,
+                    OrderSrc: 0,
+                    OperatorID: Number(geLoginID_number()),
+                    DeliveryQty: selected.value.num,
+                    DeliveryOrderDetail: {
+                        AccountID: selected.value.accountid,
+                        Qty: selected.value.num,
+                        LadingBillID: Long.fromString(selected.value.ladingbillid),
+                        WRFactorTypeID: Long.fromString(selected.value.wrfactortypeid),
+                        SubNum: selected.value.subnum,
+                    },
+                };
+                if (isBaseSpread()) {
+                    param.PGoodsID = deliveryGoods.value.pgoodsid;
+                } else {
+                    // param.PGoodsID = 0;
+                    param.PQty = 0;
+                }
+                console.log('param', param);
+                DeliveryOrder(param)
+                    .then((res) => {
+                        console.log('res', res);
+                        message.success('提交成功');
+                        cancel(true);
+                    })
+                    .catch((err) => {
+                        console.log('err', err);
+                        message.error(err);
+                    })
+                    .finally(() => {
+                        loading.value = false;
+                    });
+            } else {
+                message.warn('未找到对应的交割商品');
+            }
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            tableList,
+            loading,
+            checkGroupChange,
+            checkboxChange,
+            checked,
+            isChecked,
+            isBaseSpread,
+            getStepValue,
+            getCanSettlementNum,
+            getNeedContractNum,
+            getEstimatedPayment,
+            getDeliveryGoodsPrice,
+            increase,
+            decrease,
+            selctedNum,
+            selected,
+            toFixed0,
+        };
+    },
+});
+</script>
+
+<style lang="less" scoped>
+.c_c_s_s {
+    background: @m-black40;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    .formBar {
+        padding: 0;
+        height: calc(100% - 172px);
+        background: @m-black41;
+        .formtop {
+            width: 100%;
+            padding: 0 20px;
+            .flex;
+            flex-direction: column;
+            .firstTitle {
+                width: calc(100% + 40px);
+                height: 40px;
+                line-height: 40px;
+                margin-left: -20px;
+                padding: 0 20px;
+                font-size: 14px;
+                color: @m-white6;
+                border-bottom: 1px solid @m-black42;
+            }
+            .secondLine {
+                width: 100%;
+                height: 40px;
+                line-height: 40px;
+                display: inline-flex;
+                > div {
+                    flex: 1;
+                    font-size: 14px;
+                    color: @m-grey1;
+                }
+                .left {
+                    text-align: left;
+                }
+                .middle {
+                    text-align: center;
+                }
+                .right {
+                    text-align: right;
+                }
+            }
+            .lineBar {
+                width: 100%;
+                min-height: 100px;
+                padding-left: 15px;
+                padding-right: 10px;
+                background: @m-blue19;
+                margin-bottom: 10px;
+                .rounded-corners(5px);
+                .line1 {
+                    display: inline-flex;
+                    user-select: none;
+                    width: 100%;
+                    height: 40px;
+                    line-height: 40px;
+                    font-size: 16px;
+                    color: @m-white6;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                    overflow: hidden;
+                    border-bottom: 1px solid @m-blue20;
+                    > div {
+                        align-self: center;
+                        align-items: center;
+                    }
+                    .name {
+                        margin-left: 10px;
+                    }
+                }
+                .line2 {
+                    width: 100%;
+                    user-select: none;
+                    padding: 12px 0 14px 0;
+                    display: inline-flex;
+                    > div {
+                        flex: 2;
+                    }
+                    .left {
+                        .flex;
+                        flex-direction: column;
+                        max-width: 40%;
+                        > div {
+                            width: 100%;
+                            height: 17px;
+                            line-height: 17px;
+                            color: @m-white6;
+                            font-size: 14px;
+                            white-space: nowrap;
+                            text-overflow: ellipsis;
+                            overflow: hidden;
+                        }
+                    }
+                    .middle {
+                        flex: 1;
+                        display: inline-flex;
+                        justify-content: space-between;
+                        padding: 0 10px;
+                        font-size: 16px;
+                        color: @m-white6;
+                        line-height: 34px;
+                        > div {
+                            white-space: nowrap;
+                        }
+                    }
+                    .right {
+                        .inputNumberBlock {
+                            float: right;
+                            display: block;
+                            width: 130px;
+                            position: relative;
+                            .anticon {
+                                color: @m-blue15;
+                                font-size: 15px;
+                                z-index: 2;
+                                line-height: 34px;
+                                cursor: pointer;
+                            }
+                            .anticon-minus {
+                                .position(absolute, 0, auto, 0, 10px);
+                            }
+                            .anticon-plus {
+                                .position(absolute, 0, 10px, 0, auto);
+                            }
+                        }
+                        .disabled {
+                            .anticon {
+                                color: @m-grey51;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    .fixedBtns {
+        padding-top: 0;
+        left: 0;
+        right: 0;
+    }
+    .formbottom {
+        width: 100%;
+        .flex;
+        flex-direction: column;
+        background: @m-black40;
+        padding: 0 18px 0 20px;
+        .line1 {
+            width: 100%;
+            padding: 0 12px 0 16px;
+            height: 36px;
+            line-height: 36px;
+            display: inline-flex;
+            justify-content: space-between;
+            color: @m-grey1;
+            font-size: 14px;
+        }
+        .line2 {
+            width: 100%;
+            height: 35px;
+            line-height: 34px;
+            padding-left: 15px;
+            padding-right: 10px;
+            background: @m-black43;
+            .rounded-corners(5px);
+            font-size: 14px;
+            color: @m-grey1;
+            display: inline-flex;
+            justify-content: space-between;
+            > div {
+                align-self: baseline;
+                align-items: baseline;
+            }
+            .right {
+                display: inline-flex;
+                color: @m-yellow6;
+                div:last-child {
+                    font-size: 16px;
+                    margin-left: 2px;
+                }
+            }
+        }
+        .line3 {
+            margin-top: 16px;
+            width: 100%;
+            height: 15px;
+            line-height: 15px;
+            font-size: 14px;
+            text-align: right;
+            color: @m-white6;
+        }
+    }
+}
+</style>;

+ 11 - 0
src/views/order/commodity_contract/components/commodity_contract_summary/components/commodity_contract_summary_deal_closed/interface.ts

@@ -0,0 +1,11 @@
+import { WrDeliveryAvalidHoldLB } from "@/services/go/wrtrade/interface";
+
+export interface FormState {
+    // price: number,
+    num: number,
+}
+
+export interface DBType extends WrDeliveryAvalidHoldLB {
+    checked: boolean;
+    num: number;
+}

+ 209 - 0
src/views/order/commodity_contract/components/commodity_contract_summary/components/commodity_contract_summary_deal_closed/setup.ts

@@ -0,0 +1,209 @@
+import { handleDeliveryRelation } from "@/common/setup/deliveryRelation";
+import { getSelectedAccountId } from "@/services/bus/account";
+import { getGoodsByCode, getQuoteDayInfoByCode } from "@/services/bus/goods";
+import { QueryDeliveryRelationRsp } from "@/services/go/delivery/interface";
+import { QueryTradePositionRsp } from "@/services/go/ermcp/order/interface";
+import { queryWrDeliveryAvalidHoldLB } from "@/services/go/wrtrade";
+import { QueryWrDeliveryAvalidHoldLBReq } from "@/services/go/wrtrade/interface";
+import { ref } from "vue";
+import { DBType } from "./interface";
+
+// 选中的交收合约
+const selected = ref<DBType>()
+const checked = ref<string>();
+// 交割商品
+const deliveryGoods = ref<QueryDeliveryRelationRsp | undefined>();
+
+// 查询合约交收可点选仓单
+export function getTableList(goodsid: number) {
+    // 交割商品
+    const { getItemDeliveryRelationByGoodsId } = handleDeliveryRelation()
+    const param: QueryWrDeliveryAvalidHoldLBReq = {
+        goodsid,
+        accountid: getSelectedAccountId(),
+    };
+    const tableList = ref<DBType[]>([]);
+    queryWrDeliveryAvalidHoldLB(param).then((res) => {
+        tableList.value = res.map((e, i) => {
+            if (i) {
+                return { ...e, checked: false, num: 0 };
+            } else {
+                // 默认勾选第一个
+                checked.value = e.ladingbillid
+                const result = { ...e, checked: true, num: 0 };
+                selected.value = result
+                deliveryGoods.value = getItemDeliveryRelationByGoodsId(e.goodsid).value
+                return result
+            }
+        });
+    });
+    return { tableList }
+}
+
+
+
+export function handleCheck() {
+    // 交割商品
+    const { getItemDeliveryRelationByGoodsId } = handleDeliveryRelation()
+
+    function checkGroupChange(checkedValue: string[]) {
+        checked.value = checkedValue[checkedValue.length - 1];
+    }
+    function isChecked(value: string) {
+        return value === checked.value;
+    }
+    function checkboxChange(item: DBType) {
+        selected.value = item;
+        deliveryGoods.value = getItemDeliveryRelationByGoodsId(item.goodsid).value
+    }
+    // true 基差点价; false 挂牌点选
+    function isBaseSpread() {
+        if (deliveryGoods.value) {
+            // 1和3是订单交易 挂牌转让
+            // 2和4是基差点价
+            const arr = [2, 4]
+            return arr.includes(deliveryGoods.value.deliverytype)
+        } else {
+            return false
+        }
+    }
+    return { checked, selected, deliveryGoods, checkGroupChange, isChecked, checkboxChange, isBaseSpread }
+}
+
+export function handleCalculation(selectedRow: QueryTradePositionRsp) {
+    // 商品合约单位
+    const { enableqty } = selectedRow
+    function getDecimalplace() {
+        let result = 2;
+        const goods = selected.value?.pgoodscode
+        if (goods) {
+            const item = getGoodsByCode(goods)
+            item && (result = item.decimalplace)
+        }
+        return result
+    }
+    function getAgreeunit(goodscode: string) {
+        let result = 1
+        // const goodscode = selectedRow.goodscode
+        // if (goodscode) {
+        const item = getGoodsByCode(goodscode)
+        if (item) {
+            result = item.agreeunit
+        }
+        // }
+        return result
+    }
+
+
+    function selctedNum() {
+        return selected.value ? selected.value.num.toFixed(0) : '--'
+    }
+    // 选中数量的 最小变动值 = 合约单位 * 最小交割系数 * 仓单商品的单位r2
+    function getStepValue() {
+        const agreeunit = getAgreeunit(selectedRow.goodscode)
+        if (deliveryGoods.value) {
+            const { rratio2, mindeliveryqty } = deliveryGoods.value
+            return agreeunit * mindeliveryqty * rratio2
+        } else {
+            return agreeunit
+        }
+    }
+    // 可交收数量 = 合约可用手数 * 合约单位 * 最小交割系数 * (仓单商品的单位r2/合约商品的单位r1)
+    function getCanSettlementNum() {
+        if (deliveryGoods.value) {
+            const agreeunit = getAgreeunit(selectedRow.goodscode)
+            const { rratio1, rratio2, mindeliveryqty } = deliveryGoods.value
+            const result = enableqty * agreeunit * mindeliveryqty * (rratio2 / rratio1)
+            return result.toFixed(0)
+        } else {
+            return '--'
+        }
+    }
+    // (选中的数量 / (合约单位 * 最小交割系数 * (仓单商品的单位r2/合约商品的单位r1)))
+    function XQty() {
+        let result = 0
+        if (selected.value?.num) {
+            if (deliveryGoods.value) {
+                const agreeunit = getAgreeunit(selectedRow.goodscode)
+                const { rratio1, rratio2, mindeliveryqty, xdeliveryratio, pdeliveryratio } = deliveryGoods.value
+                result = selected.value.num / (agreeunit * mindeliveryqty * (rratio2 / rratio1))
+            }
+        }
+        return result
+    }
+    // 需要合约手数 = (选中的数量 / (合约单位 * 最小交割系数 * (仓单商品的单位r2/合约商品的单位r1))) / (p1合约系数 / x合约系数)
+    function PQty() {
+        let result = XQty()
+        if (result) {
+            if (deliveryGoods.value) {
+                const { xdeliveryratio, pdeliveryratio } = deliveryGoods.value
+                result = result / pdeliveryratio / xdeliveryratio
+            }
+        }
+        return result
+    }
+    // 需要合约手数 = (选中的数量 / (合约单位 * 最小交割系数 * (仓单商品的单位r2/合约商品的单位r1))) / (p1合约系数 / x合约系数)
+    function getNeedContractNum() {
+        const result = PQty()
+        return result ? result.toFixed(0) : '--'
+    }
+    // 预估货款 = 需要合约手数  * 合约交割价 * 合约单位 + 升贴水
+    function getEstimatedPayment() {
+        const num = getNeedContractNum()
+        const price = getDeliveryGoodsPrice()
+        let result = 0
+        if (selected.value) {
+            if (num !== '--' && price !== '--') {
+                if (deliveryGoods.value) {
+                    const agreeunit = getAgreeunit(selected.value.pgoodscode)
+                    result = (Number(num) * Number(price) * agreeunit) + (selected.value.pricemove * selected.value.num)
+                }
+            }
+        }
+        return result ? result.toFixed(getDecimalplace()) : '--'
+    }
+    /**
+     * 合约交割价取价规则
+     * 1.优先实时结算价
+     * 2.其次卖一价
+     * 3.再次是买一价与成交价中的最高价
+     * 4.最后取昨日结算价
+     * 所有权(X): 不取交割价,默认设为0,不影响交割流程
+     */
+    function getDeliveryGoodsPrice() {
+        const goodscode = selected.value?.pgoodscode
+        if (!goodscode) return '--'
+        const item = getQuoteDayInfoByCode(goodscode);
+        const has = (value: any) => value && value !== '--'
+        let result = 0
+        if (item) {
+            const { settle, ask, bid, last, presettle } = item
+            if (has(settle)) {
+                result = settle
+            } else if (has(ask)) {
+                result = ask
+            } else if (has(bid) && has(last)) {
+                result = Math.max(bid, last)
+            } else if (has(presettle)) {
+                result = presettle
+            }
+        }
+        return has(result) ? result.toFixed(getDecimalplace()) : '--'
+    }
+
+    // 增加
+    function increase(value: DBType) {
+        if (value.num < value.avalidqty) {
+            value.num += getStepValue()
+            value.num = +value.num.toFixed(getDecimalplace())
+        }
+    }
+    // 减少
+    function decrease(value: DBType) {
+        if (value.num > 0) {
+            value.num -= getStepValue()
+            value.num = +value.num.toFixed(getDecimalplace())
+        }
+    }
+    return { getStepValue, getCanSettlementNum, getNeedContractNum, getEstimatedPayment, XQty, PQty, getDeliveryGoodsPrice, increase, decrease, selctedNum }
+}

+ 13 - 2
src/views/order/commodity_contract/components/commodity_contract_summary/index.vue

@@ -15,7 +15,7 @@
       <!-- 额外的展开行 -->
       <template v-if="btnList.length"
                 #expandedRowRender="{ record }">
-        <BtnList :btnList="btnList"
+        <BtnList :btnList="handleBtnList(record, btnList)"
                  :record="record"
                  class="btn-list-sticky"
                  @click="openComponent" />
@@ -55,8 +55,10 @@ import { expandIcon } from '@/common/setup/table/clolumn';
 import { queryTradePosition } from '@/services/go/ermcp/order';
 import { QueryTradePositionRsp } from '@/services/go/ermcp/order/interface';
 import { handleSubcriteQuote } from '@/common/setup/table/tableQuote';
-import { getQuoteDayInfoByCode } from '@/services/bus/goods';
+import { findGoodsTradeModeById, getQuoteDayInfoByCode } from '@/services/bus/goods';
 import { handleDeliveryRelation } from '@/common/setup/deliveryRelation';
+import { TradeMode } from '@/common/constants/enumCommon';
+import { BtnListType } from '@/common/components/btnList/interface';
 
 export default defineComponent({
     name: enumOrderComponents.commodity_contract_summary,
@@ -64,6 +66,7 @@ export default defineComponent({
         BtnList,
         [ModalEnum.commodity_contract_summary_settlement]: defineAsyncComponent(() => import('./components/commodity_contract_summary_settlement/index.vue')),
         [ModalEnum.commodity_contract_summary_transfer]: defineAsyncComponent(() => import('./components/commodity_contract_summary_transfer/index.vue')),
+        commodity_contract_summary_deal_closed: defineAsyncComponent(() => import('./components/commodity_contract_summary_deal_closed/index.vue')),
     },
     setup() {
         // 表格列表数据
@@ -121,6 +124,13 @@ export default defineComponent({
                 return price;
             }
         }
+        function handleBtnList(record: QueryTradePositionRsp, btnList: BtnListType[]) {
+            if (findGoodsTradeModeById(record.goodsid) === TradeMode.DiaoQi) {
+                return btnList.filter((e) => e.code === 'commodity_contract_summary_deal_closed');
+            } else {
+                return btnList.filter((e) => e.code !== 'commodity_contract_summary_deal_closed');
+            }
+        }
         return {
             ...handleComposeOrderTable<QueryTradePositionRsp>(param),
             loading,
@@ -130,6 +140,7 @@ export default defineComponent({
             getLastprice,
             getHolderprice,
             getProfitloss,
+            handleBtnList,
         };
     },
 });

+ 46 - 11
swagger-to-ts/swagger.ts

@@ -1,17 +1,52 @@
 export interface Name{
-    applyid	:number;//申请ID(自增ID SEQ_TRADE_HOLDTRANSFERAPPLY)
-applystatus	:number;//状态 - number;
-//:未提交 1:待审核 2:审核中 3:审核通过 4:审核拒绝 5:审核失败 6:已撤销
-applytime	:string;//申请时间(时间)
-auditremark	:string;//审核备注(拒绝原因?)
-buyorsell	:number;//买卖 - number;
+    accountid	:number;//账号ID
+agreeunit	:number;//合约乘数
+buyorsell	:number;//方向 - number;
 //:买 1:卖
+currencyid	:number;//商品币种id
+currencyname	:string;//币种名称
+decimalplace	:number;//商品价格小数位
+enumdicname	:string;//商品单位名称
+expirecycle	:number;//行权周期(天) - 1:滚动行权时填写
+expiredate	:string;//行权日(yyyyMMdd) - 到期日
+expiretype	:number;//行权日类型 - 1:滚动行权 2:固定日行权
+freezeqty	:number;//冻结数量
 goodscode	:string;//商品代码
 goodsid	:number;//商品ID
 goodsname	:string;//商品名称
-marketid	:number;//市场ID
-qty	:number;//转让数量(数量)
-tradeid	:string;//成交单号(关联持仓)
-transferamount	:number;//转让总金额(金额)
-transferprice	:number;//转让价格(协议价格)
+goodunitid	:number;//商品单位id
+holderamount	:number;//持仓金额
+holdercredit	:number;//持仓授信金额
+holderdays	:number;//剩余冻结天数
+holderprice	:number;//持仓价格
+holderqty	:number;//持仓数量
+isconfirmexercise	:number;//是否确认行权- number;
+//:否 1:是
+ispreexercise	:number;//是否预申报- number;
+//:否 1:是 2:不可行权
+marketid	:number;//市场id
+marketname	:string;//市场名称
+openprice	:number;//建仓价格
+openqty	:number;//建仓数量
+optiontype	:number;//期权类型 - 1:认购(看涨) 2:认沽(看跌)
+preexerciseprice	:number;//预申报价格
+premium	:number;//权利金
+qtydecimalplace	:number;//商品成交量小数位
+refgoodscode	:string;//标的合约代码
+refgoodsid	:number;//标的合约id
+releaseamount	:number;//释放持仓金额
+releaseholdercredit	:number;//释放持仓授信金额
+taname	:string;//资金账号名称
+tradeamount	:number;//成交金额
+tradedate	:string;//交易日(yyyyMMdd)
+tradeid	:string;//成交单号(1number;
+//1+Unix秒时间戳(1number;
+//位)+2位(MarketServiceID)+xxxx)
+trademode	:number;//交易模式 - 1number;
+//:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 2number;
+//:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价 46:掉期
+tradeproperty	:number;//交易属性
+tradetime	:string;//交易时间
+userid	:number;//用户id
+username	:string;//用户名称
 }

+ 108 - 18
swagger-to-ts/swagger.txt

@@ -1,18 +1,36 @@
 {
-    applyid	integer
-申请ID(自增ID SEQ_TRADE_HOLDTRANSFERAPPLY)
+    accountid	integer
+账号ID
 
-applystatus	integer
-状态 - 0:未提交 1:待审核 2:审核中 3:审核通过 4:审核拒绝 5:审核失败 6:已撤销
+agreeunit	number
+合约乘数
 
-applytime	string
-申请时间(时间)
+buyorsell	integer
+方向 - 0:买 1:卖
 
-auditremark	string
-审核备注(拒绝原因?)
+currencyid	integer
+商品币种id
 
-buyorsell	integer
-买卖 - 0:买 1:卖
+currencyname	string
+币种名称
+
+decimalplace	integer
+商品价格小数位
+
+enumdicname	string
+商品单位名称
+
+expirecycle	integer
+行权周期(天) - 1:滚动行权时填写
+
+expiredate	string
+行权日(yyyyMMdd) - 到期日
+
+expiretype	integer
+行权日类型 - 1:滚动行权 2:固定日行权
+
+freezeqty	number
+冻结数量
 
 goodscode	string
 商品代码
@@ -23,18 +41,90 @@ goodsid	integer
 goodsname	string
 商品名称
 
+goodunitid	integer
+商品单位id
+
+holderamount	number
+持仓金额
+
+holdercredit	number
+持仓授信金额
+
+holderdays	integer
+剩余冻结天数
+
+holderprice	number
+持仓价格
+
+holderqty	number
+持仓数量
+
+isconfirmexercise	integer
+是否确认行权- 0:否 1:是
+
+ispreexercise	integer
+是否预申报- 0:否 1:是 2:不可行权
+
 marketid	integer
-市场ID
+市场id
 
-qty	number
-转让数量(数量)
+marketname	string
+市场名称
+
+openprice	number
+建仓价格
+
+openqty	number
+建仓数量
+
+optiontype	integer
+期权类型 - 1:认购(看涨) 2:认沽(看跌)
+
+preexerciseprice	number
+预申报价格
+
+premium	number
+权利金
+
+qtydecimalplace	integer
+商品成交量小数位
+
+refgoodscode	string
+标的合约代码
+
+refgoodsid	integer
+标的合约id
+
+releaseamount	number
+释放持仓金额
+
+releaseholdercredit	number
+释放持仓授信金额
+
+taname	string
+资金账号名称
+
+tradeamount	number
+成交金额
+
+tradedate	string
+交易日(yyyyMMdd)
 
 tradeid	string
-成交单号(关联持仓)
+成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
+
+trademode	integer
+交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价 46:掉期
+
+tradeproperty	integer
+交易属性
+
+tradetime	string
+交易时间
 
-transferamount	number
-转让总金额(金额)
+userid	integer
+用户id
 
-transferprice	number
-转让价格(协议价格)
+username	string
+用户名称
 }