huangbin 4 سال پیش
والد
کامیت
722f325b7a

+ 140 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/components/buy/index.vue

@@ -0,0 +1,140 @@
+<template>
+    <!--  现货贸易 - 买卖大厅 - 卖报价牌 -->
+    <a-table
+        :columns="handleColumn(columns)"
+        :class="['buyHallTable', isBottom ? '' : 'buyHallTableHigh', tableList.length ? '' : 'noDataTable']"
+        :scroll="{ x: '100%', y: isBottom ? 'calc(100vh- 470px)' : 'calc(100vh - 180px)' }"
+        :pagination="false"
+        :loading="loading"
+        :expandedRowKeys="expandedRowKeys"
+        :customRow="Rowclick"
+        :expandIcon="expandIcon"
+        :expandIconAsCell="false"
+        rowKey="key"
+        :data-source="tableList"
+    >
+        <!-- ,  -->
+        <!-- 额外的展开行 -->
+        <template #expandedRowRender="{ record }">
+            <BtnList
+                :btnList="btnList"
+                :record="record"
+                class="btn-list-sticky"
+                @click="openComponent"
+            />
+        </template>
+        <template #username="{text, record }">
+            <span>{{record.userid + " "}}{{text}}</span>
+        </template>
+    </a-table>
+    <component
+        :is="componentId"
+        v-if="componentId"
+        :selectedRow="selectedRow"
+        :buyOrSell="BuyOrSell.buy"
+        :enumName="enumName"
+        :parantSelectedRow="parantSelectedRow"
+        @cancel="closeComponent"
+    ></component>
+</template>
+
+<script lang="ts">
+import { EnumRouterName } from '@/common/constants/enumRouterName';
+import { ComposeTableParam, BtnList, defineComponent, handleComposeTable, queryTableList, ModalEnum } from '@/common/export/commonTable';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { queryOrderQuoteDetail } from '@/services/go/wrtrade';
+import { QueryOrderQuoteDetailReq, WrOrderQuote, WrOrderQuoteDetail } from '@/services/go/wrtrade/interface';
+import { defineAsyncComponent, PropType } from 'vue';
+import { BtnList as btnListType } from '@/common/components/btnList/interface';
+import { getBuyMarketParam } from '../../setup';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { ColumnType } from '@/common/methods/table/interface';
+import { Moment } from 'moment';
+import moment from 'moment';
+import { getShowBottomValue } from '@/common/config/constrolBottom';
+
+export default defineComponent({
+    emits: ['cancel', 'openComponent'],
+    name: 'warehouse_receipt_trade_price_delisting_buy',
+    props: {
+        enumName: {
+            default: '',
+            type: String as PropType<EnumRouterName>,
+        },
+        btnList: {
+            default: [],
+            type: Array as PropType<btnListType[]>,
+        },
+        parantSelectedRow: {
+            type: Object as PropType<WrOrderQuote>,
+            default: {},
+        },
+        time: {
+            type: Object as PropType<Moment>,
+            default: moment(),
+        },
+    },
+    components: {
+        BtnList,
+        [ModalEnum.spot_trade_warehouse_delisting]: defineAsyncComponent(() => import('../delisting/index.vue')),
+    },
+    setup(props, context) {
+        const isBottom = getShowBottomValue();
+        console.log(isBottom.value, 'isBottom');
+        // 表格列表数据
+        const { loading, tableList, queryTable } = queryTableList<WrOrderQuoteDetail>();
+        const { wrpricetype, haswr, tableKey } = getBuyMarketParam(props.enumName);
+        // 获取列表数据
+        const queryTableAction = () => {
+            const param: QueryOrderQuoteDetailReq = {
+                buyorsell: 0,
+                wrpricetype,
+                haswr,
+                wrfactortypeid: props.parantSelectedRow.wrfactortypeid,
+                goodsid: props.parantSelectedRow.goodsid,
+            };
+            if (!haswr) {
+                // 无仓单 需要交收月过滤数据
+                param.deliverymonth = moment(props.time).format('YYYY-MM');
+            }
+            queryTable(queryOrderQuoteDetail, param);
+        };
+        // 表格通用逻辑
+        const param: ComposeTableParam = {
+            queryFn: queryTableAction,
+            menuType: props.enumName,
+            tableName: tableKey,
+            tableFilterKey: [],
+            isDetail: false,
+        };
+        function handleColumn(columns: ColumnType[]) {
+            columns.forEach((item) => {
+                if (item.dataIndex == 'username') {
+                    delete item.width;
+                }
+            });
+            return columns;
+        }
+        function handleBtnList() {}
+        return {
+            isBottom,
+            ...handleComposeTable<WrOrderQuoteDetail>(param),
+            queryTableAction,
+            BuyOrSell,
+            loading,
+            tableList,
+            enumName: props.enumName,
+            expandIcon,
+            handleColumn,
+        };
+    },
+});
+</script>
+<style lang="less">
+.buy-sell-market {
+    .btnDeafault.ant-btn {
+        height: 30px;
+    }
+}
+</style>

+ 401 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/components/delisting/index.vue

@@ -0,0 +1,401 @@
+<template>
+  <!-- 仓单贸易&仓单预售 买/卖 摘牌 -->
+  <Drawer :title="'摘牌'"
+          :placement="'right'"
+          :visible="visible"
+          width="486px"
+          height="479px"
+          @cancel="cancel"
+          class="top">
+    <div class="delisting">
+      <div class="formBar">
+        <a-form class="inlineForm dialogForm"
+                ref="formRef"
+                :model="formState"
+                :rules="rules">
+          <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-row>
+          <a-row :gutter="24">
+            <a-col :span="24">
+              <a-form-item label="挂牌方">
+                <span class="white ml8">{{selectedRow.username}}</span>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24">
+              <a-form-item label="基差"
+                           v-if="isFloat()">
+                <span class="yellow ml8">{{selectedRow.pricemove}}</span>
+              </a-form-item>
+              <a-form-item label="挂牌价格"
+                           v-if="!isFloat()">
+                <span class="yellow ml8">{{selectedRow.fixedprice}}</span>
+              </a-form-item>
+              <a-row :gutter="24">
+                <a-col :span="24"></a-col>
+              </a-row>
+              <a-form-item label="挂牌数量">
+                <span class="white ml8">{{selectedRow.orderqty}}{{selectedRow.enumdicname}}</span>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24"
+                 v-if="isBuy() && isWR()">
+            <a-col :span="24">
+              <a-form-item label="现货仓单"
+                           name="LadingBillId">
+                <a-select class="inlineFormSelect"
+                          style="width: 260px"
+                          v-model:value="formState.LadingBillId"
+                          placeholder="请选择">
+                  <a-select-option v-for="item in wrHoldList"
+                                   :value="item.id"
+                                   :key="item.id">{{item.name}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24">
+              <a-form-item label="摘牌数量"
+                           class="relative"
+                           name="num">
+                <a-input-number class="dialogInput yellowInput"
+                                style="width: 260px"
+                                :min="0"
+                                :max="getMaxNum()"
+                                v-model:value="formState.num" />
+                <span class="input-enumdicname-absolute">{{selectedRow.enumdicname}}</span>
+                <div class="labelTip">({{selectedRow.minivalue}}{{selectedRow.enumdicname}}起)</div>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24"
+                   class="mt-20">
+              <a-form-item>
+                <a-slider ::min="0"
+                          v-model:value="formState.num"
+                          :max="selectedRow.orderqty"
+                          class="formSlider" />
+                <div class="unit">
+                  <span>0</span>
+                  <span>{{getMaxNum()}}{{selectedRow.enumdicname}}</span>
+                </div>
+              </a-form-item>
+            </a-col>
+            <a-col :span="12">&nbsp;</a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24"
+                   class="mt-20">
+              <a-form-item :label="isFloat() ? '估算金额' : '摘牌金额'">
+                <span class="white ml8">{{getMoney()}}</span>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24"
+                   class="mt-20">
+              <a-form-item :label="getMargin() ? '履约保证金' : ''">
+                <a-row>
+                  <a-col :span="8"
+                         v-if="getMargin()">
+                    <span class="white ml8">{{getMargin()}}</span>
+                  </a-col>
+                  <a-col :span="4"
+                         class="tr">
+                    <span class="grey1">可用资金</span>
+                  </a-col>
+                  <a-col :span="12">
+                    <span class="white ml8">{{getCanUseMoney(getSelectedAccount())}}</span>
+                  </a-col>
+                </a-row>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="24">
+            <a-col :span="24">
+              <a-form-item class="tc">
+                <a-button class="listedBtn"
+                          :loading="loading"
+                          :disabled="loading"
+                          @click="submit">{{isBuy() ? '卖出' : '买入'}}</a-button>
+                <a-button class="ml10 cancelBtn"
+                          @click="cancel">取消</a-button>
+              </a-form-item>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+    </div>
+  </Drawer>
+</template>
+
+<script lang="ts">
+import { PlusOutlined, MinusOutlined } from '@ant-design/icons-vue';
+import { defineComponent, PropType, ref } from 'vue';
+import Drawer from '@/common/components/drawer/index.vue';
+import { WrOrderQuote, WrOrderQuoteDetail } from '@/services/go/wrtrade/interface';
+import { getAccountTypeList, getSelectedAccountId, getUserId } from '@/services/bus/account';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { HdWRDealOrder } from '@/services/proto/warehousetrade';
+import { v4 as uuidv4 } from 'uuid';
+import moment from 'moment';
+import { ModalEnum } from '@/common/constants/modalNameEnum';
+import { HdWRDealOrderReq } from '@/services/proto/warehousetrade/interface';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { handleForm, handleNumAndMoney, handleSpotWarrant, getWrPosition } from './setup';
+import { handleIs } from '../../setup';
+import { validateAction } from '@/common/setup/form';
+import { ListingForm, TempWrOrderQuoteDetail } from './interface';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { EnumRouterName } from '@/common/constants/enumRouterName';
+import { getCanUseMoney } from '@/services/bus/account';
+export default defineComponent({
+    name: ModalEnum.spot_trade_warehouse_financing_delisting,
+    components: { Drawer, PlusOutlined, MinusOutlined },
+    emits: ['cancel', 'update'],
+    props: {
+        enumName: {
+            default: '',
+            type: String as PropType<EnumRouterName>,
+        },
+        selectedRow: {
+            type: Object as PropType<TempWrOrderQuoteDetail>,
+            default: {},
+        },
+        parantSelectedRow: {
+            type: Object as PropType<WrOrderQuote>,
+            default: {},
+        },
+        buyOrSell: {
+            type: Number as PropType<BuyOrSell>,
+            default: BuyOrSell.buy,
+        },
+    },
+
+    setup(props, context) {
+        const { visible, cancel } = _closeModal(context);
+        // 资金账号
+        const accountList = getAccountTypeList([2]);
+        const { rules, formState, formRef } = handleForm(props.selectedRow);
+        if (accountList.length) {
+            formState.accountid = accountList[0].accountid;
+        }
+        function getSelectedAccount() {
+            return accountList.find((e) => e.accountid === formState.accountid);
+        }
+        const loading = ref<boolean>(false);
+        // 判断
+        const { isWR, isBuy, isFloat } = handleIs(props.enumName, props.buyOrSell);
+        // 现货仓单
+        const { wrHoldList } = handleSpotWarrant(props.enumName, props.buyOrSell, props.parantSelectedRow, loading);
+        getWrPosition(props.enumName, props.buyOrSell, loading);
+        const { getMaxNum, getMoney, getMargin } = handleNumAndMoney(props.enumName, props.buyOrSell, props.selectedRow, props.parantSelectedRow, formState);
+        function submit() {
+            validateAction<ListingForm>(formRef, formState).then((res) => {
+                // 首先确定  这是仓单贸易的有仓单挂摘牌 HasWr = 1
+                // 其次判断  摘牌 1。摘买 (需要通过自己的仓单进行摘买)  2。摘卖 (不需要通过仓单)
+                const param: HdWRDealOrderReq = {
+                    UserID: getUserId(), // uint32 用户ID
+                    AccountID: getSelectedAccountId(), // uint64 资金账号
+                    RelatedWRTradeOrderID: props.selectedRow.wrtradeorderid, // uint64 关联委托单号(摘牌委托关联挂牌委托单ID)
+                    WRTransferUserID: props.selectedRow.userid, // uint32 仓单受让用户
+                    OrderQty: res.num as number, // uint64 委托数量
+                    OrderSrc: 0, // uint32 委托来源
+                    ClientSerialNo: uuidv4(), // string 客户端流水号
+                    ClientOrderTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), // string 客户端委托时间
+                    ClientType: 4, // uint32 终端类型
+                    OperatorID: getUserId(), // uint64 操作员账号ID
+                    BuyOrSell: 0, // uint32 买卖方向
+                    ApplyID: 0, // uint64 申请ID
+                    // LadingBillId: 0, // uint64 提单id(wrholdlb的LadingBillId字段),卖的时候填写
+                    SubNum: 0, // uint64 提单子单号(wrholdlb的SubNum字段),卖的时候填写
+                    WRFactorTypeId: props.parantSelectedRow.wrfactortypeid, // uint64 仓单要素ID(wrholdlb的WRFactorTypeId字段),卖的时候填写
+                    TradeDate: moment().format('YYYYMMDD'), // string 交易日
+                    DeliveryMonth: '', // string 交收月
+                    HasWr: isWR(), // uint32 是否有仓单-0:没有仓单 1:有仓单
+                    IsFinancing: 0, // uint32 是否融资购买(买摘牌时有效)-0:否 1:是
+                    ProductDetailID: 0, // uint64 金融机构产品组合ID(融资购买时有效)
+                };
+                // 摘买方向
+                if (isBuy()) {
+                    param.BuyOrSell = 1;
+                    param.LadingBillId = res.LadingBillId;
+                } else {
+                    param.BuyOrSell = 0;
+                }
+
+                requestResultLoadingAndInfo(HdWRDealOrder, param, loading, ['摘牌成功', '摘牌失败:']).then(() => {
+                    cancel(true);
+                });
+            });
+        }
+
+        return {
+            visible,
+            cancel,
+            accountList,
+            wrHoldList,
+            loading,
+            submit,
+            isWR,
+            isBuy,
+            isFloat,
+            rules,
+            formState,
+            formRef,
+            getCanUseMoney,
+            getSelectedAccount,
+            getMaxNum,
+            getMoney,
+            getMargin,
+        };
+    },
+});
+</script>
+
+<style lang="less" scoped>
+.delisting {
+    width: 100%;
+    height: 100%;
+    .flex;
+    flex-direction: column;
+    .condition {
+        width: 100%;
+        height: 48px;
+        margin: 0 16px;
+        padding: 10px 0;
+        border-bottom: 1px solid @m-black6;
+        .inlineflex;
+        .conditionBtn {
+            align-self: center;
+            align-items: center;
+            border: 0;
+            min-width: 80px;
+            height: 28px;
+            line-height: 28px;
+            background: @m-black7;
+            .rounded-corners(3px);
+            font-size: 14px;
+            color: @m-blue0;
+            &:hover {
+                background: @m-black7-hover;
+                color: @m-blue0-hover;
+            }
+        }
+        .conditionBtn + .conditionBtn {
+            margin-left: 10px;
+        }
+    }
+    .formBar {
+        width: 100%;
+        flex: 1;
+        padding: 28px 16px 7px;
+    }
+}
+::v-deep.ant-slider.formSlider {
+    width: 260px;
+}
+::v-deep.ant-input-suffix {
+    position: absolute;
+    right: -25px;
+}
+.unit {
+    margin-left: 70px;
+    width: 260px;
+    .flex;
+    justify-content: space-between;
+    font-size: 14px;
+    color: @m-grey1;
+    height: 14px;
+    line-height: 14px;
+}
+.listedBtn:first-child {
+    margin-left: -35px;
+}
+.listedBtn {
+    width: 120px;
+    height: 30px;
+    line-height: 30px;
+    background: linear-gradient(0deg, @m-blue2 0%, @m-blue0 100%);
+    border-radius: 3px;
+    color: @m-white0;
+    font-size: 14px;
+    text-align: center;
+    border: 0;
+    &:hover {
+        background: linear-gradient(0deg, @m-blue0-hover 0%, @m-blue2-hover 100%);
+        color: @m-white0-hover;
+    }
+}
+.cancelBtn:extend(.listedBtn) {
+    background: linear-gradient(0deg, @m-grey12 0%, @m-grey13 100%) !important;
+    &:hover {
+        background: linear-gradient(0deg, @m-grey12-hover 0%, @m-grey13-hover 100%) !important;
+        color: @m-white0-hover;
+    }
+}
+.ml10 {
+    margin-left: 10px;
+}
+.ant-form.dialogForm .ant-row.ant-form-item {
+    margin-bottom: 14px;
+}
+.mt20 {
+    margin-top: 20px;
+}
+.mt-20 {
+    margin-top: -20px;
+}
+.labelTip {
+    font-size: 14px;
+    color: @m-blue16;
+    position: absolute;
+    top: 15px;
+    left: -66px;
+}
+.minusBtn,
+.plusBtn {
+    width: 15px;
+    height: 32px;
+    line-height: 32px;
+    font-size: 15px;
+    color: @m-blue15;
+    cursor: pointer;
+}
+.minusBtn {
+    position: absolute;
+    top: -6px;
+    left: 14px;
+    z-index: 1;
+}
+.plusBtn {
+    position: absolute;
+    top: -6px;
+    right: 14px;
+    z-index: 1;
+}
+.stepper {
+    padding-left: 30px;
+    padding-right: 30px;
+    text-align: center;
+    color: @m-yellow1;
+    font-size: 16px;
+}
+</style>;

+ 16 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/components/delisting/interface.ts

@@ -0,0 +1,16 @@
+import { WrOrderQuoteDetail } from "@/services/go/wrtrade/interface";
+
+export interface ListingForm {
+    accountid: undefined | number,
+    num: number,
+    LadingBillId: string,
+}
+
+export interface Wrhold {
+    id: string,
+    name: string,
+}
+
+export interface TempWrOrderQuoteDetail extends WrOrderQuoteDetail {
+    wrResult: { dgfactoryitemtypeid: number; dgfactoryitemid: number }[]
+}

+ 154 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/components/delisting/setup.ts

@@ -0,0 +1,154 @@
+import { BuyOrSell } from "@/common/constants/enumCommon";
+import { EnumRouterName } from "@/common/constants/enumRouterName";
+import { queryResultLoadingAndInfo } from "@/common/methods/request/resultInfo";
+import { getAccountTypeList, getCanUseMoney } from "@/services/bus/account";
+import { getRules } from '@/services/bus/rules';
+import { AccountListItem } from "@/services/dataCenter/interafce/account";
+import { queryHoldLB, queryWrPosition } from '@/services/go/wrtrade';
+import { QueryWrPositionReq, WrHoldLB, WrOrderQuote, WrOrderQuoteDetail, WrPosition } from "@/services/go/wrtrade/interface";
+import { reactive, Ref, ref, UnwrapRef } from "vue";
+import { getGoodsPrice, handleIs } from "../../setup";
+import { ListingForm, Wrhold } from "./interface";
+
+export function handleForm(data: WrOrderQuoteDetail) {
+    const formRef = ref();
+    const formState: UnwrapRef<ListingForm> = reactive({
+        accountid: undefined,
+        num: 0,
+        LadingBillId: '',
+    })
+    const rules = {
+        accountid: [{ required: true, message: '请选择交易账户' }],
+        LadingBillId: [{ required: true, message: '请选择现货仓单' }],
+        num: [{ required: true, message: '请输入摘牌数量', trigger: 'blur', type: 'number', min: 1, ma: data.orderqty }],
+
+    }
+    return { rules, formState, formRef }
+}
+
+// 预售仓单汇总
+const wrPostion = ref<WrPosition[]>([])
+export function getWrPosition(enumName: EnumRouterName, buyOrSell: BuyOrSell, loading: Ref<boolean>) {
+    const { isWR, isBuy } = handleIs(enumName, buyOrSell)
+    if (isBuy() && !isWR()) {
+        const param: QueryWrPositionReq = {
+            haswr: 0,
+            querytype: 2,
+        };
+        queryResultLoadingAndInfo(queryWrPosition, loading, param).then(res => {
+            wrPostion.value = res;
+        })
+    }
+}
+
+const allWR = ref<WrHoldLB[]>([])
+// 处理现货仓单
+export function handleSpotWarrant(enumName: EnumRouterName, buyOrSell: BuyOrSell, selectedRow: WrOrderQuote, loading: Ref<boolean>) {
+    const { isWR, isBuy } = handleIs(enumName, buyOrSell)
+    const wrHoldList = ref<Wrhold[]>([])
+    if (isBuy()) {
+        if (isWR()) {
+            queryResultLoadingAndInfo(queryHoldLB, loading).then(res => {
+                allWR.value = res;
+                wrHoldList.value = res.filter((e: WrHoldLB) => e.wrfactortypeid === String(selectedRow.wrfactortypeid)).map((e: WrHoldLB) => {
+                    const { wrholdeno, enableqty, ladingbillid, enumdicname } = e
+                    return { id: ladingbillid, name: `${wrholdeno}(${enableqty}${enumdicname})` }
+                })
+            })
+        }
+    }
+    return { wrHoldList }
+}
+
+export function handleNumAndMoney(enumName: EnumRouterName, buyOrSell: BuyOrSell, selectedRow: WrOrderQuoteDetail, parantSelectedRow: WrOrderQuote, formState: UnwrapRef<ListingForm>) {
+    const { isWR, isBuy, isFloat } = handleIs(enumName, buyOrSell)
+    // 资金账号
+    const accountList = getAccountTypeList([2]);
+    // 获取选中的资金账号
+    const getSelectedAccount = () => accountList.find((e) => e.accountid === formState.accountid);
+    // 交易规则
+    const rules = getRules()
+    // 是否有规则
+    const hasRule = () => rules.length > 0;
+    const { buymarginvalue, buymarginalgorithm } = rules[0]
+    //保证金模式 1: 比率 2: 固定
+    const marginMethod = () => buymarginalgorithm === 1
+    const { fixedprice, orderqty, pricemove } = selectedRow;
+    // 获取摘牌最大可摘量
+    function getMaxNum() {
+        let result = 0;
+        if (hasRule()) {
+            // 可用资金
+            const canUseMoney = Number(getCanUseMoney(getSelectedAccount() as AccountListItem))
+            if (!isBuy()) {
+                if (isFloat()) {
+                    const goodsPrice = getGoodsPrice()
+                    // 估算总价=挂牌基差+期货合约价;
+                    if (goodsPrice.value && goodsPrice.value !== '--') {   // 有实时行情价格
+                        // 估算总价
+                        const predictTotal = pricemove + (goodsPrice.value as number);
+                        // 买方履约保证金比例*估算总价
+                        const marginMoney = marginMethod() ? (buymarginvalue * predictTotal) : (buymarginvalue + predictTotal)
+                        // 浮动价 摘买 最大数量=min{可用资金/(买方履约保证金比例*估算总价),挂牌数量}
+                        result = Math.min(orderqty, canUseMoney / marginMoney)
+                    }
+                } else {
+                    // 买方履约保证金比例*挂牌价格
+                    const marginMoney = marginMethod() ? (buymarginvalue * fixedprice) : (buymarginvalue + fixedprice)
+                    //  一口价 摘买 最大数量=min{挂牌数量,可用资金/(买方履约保证金比例*挂牌价格)
+                    result = Math.min(orderqty, canUseMoney / marginMoney)
+                }
+            } else {
+                if (isWR()) {
+                    if (formState.LadingBillId) {
+                        // 现货库存数量
+                        const warehouseNum = allWR.value.find((e) => e.ladingbillid === formState.LadingBillId)?.enableqty;
+                        // 仓单贸易 一口价/浮动价 摘卖 最大数量=min(现货库存可用数量,挂牌数量),现货库存数量为所选仓单数量
+                        if (warehouseNum) {
+                            result = Math.min(orderqty, warehouseNum)
+                        }
+                    }
+                } else {
+                    // 获取头寸
+                    const item = wrPostion.value.find(e => String(e.wrfactortypeid) === String(parantSelectedRow.wrfactortypeid))
+                    if (item) {
+                        result = item.enalbeqty
+                    }
+                }
+            }
+        }
+        return Math.floor(result)
+    }
+    //  摘牌金额
+    function getMoney() {
+        let result = 0
+        if (isFloat()) {
+            const goodsPrice = getGoodsPrice()
+            if (goodsPrice.value && goodsPrice.value !== '--') {   // 有实时行情价格
+                // 估算总价=挂牌基差+期货合约价;
+                const predictTotal = pricemove + (goodsPrice.value as number);
+                // 估算总额=估算总价*摘牌数量;
+                result = predictTotal * formState.num
+            }
+        } else {
+            // 摘牌金额=挂牌价格*摘牌数量
+            result = formState.num * fixedprice
+        }
+        return Number(result.toFixed(2))
+    }
+    // 履约保证金
+    function getMargin() {
+        // fixed sell  履约保证金=卖方履约保证金比例*摘牌金额
+        // fixed bull  履约保证金=买方履约保证金比例*摘牌金额
+        // floor sell  履约保证金=卖方履约保证金比例*估算总额,履约保证金为0则括号内容不显示
+        //  floor  buy 履约保证金=买方履约保证金比例*估算总额
+        let result = 0
+        if (hasRule()) {
+            const { buymarginvalue, sellmarginvalue } = rules[0]
+            const margin = isBuy() ? sellmarginvalue : buymarginvalue
+            result = marginMethod() ? margin * getMoney() : margin + getMoney()
+        }
+        return Number(result.toFixed(2))
+    }
+    return { getMaxNum, getMoney, getMargin }
+}

+ 134 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/components/sell/index.vue

@@ -0,0 +1,134 @@
+<template>
+  <!-- 现货贸易 - 买卖大厅 - 买报价牌 -->
+  <a-table :columns="handleColumn(columns)"
+           :class="['sellHallTable', isBottom ? '' : 'sellHallTableHigh', tableList.length ? '' : 'noDataTable']"
+           :scroll="{ x: '100%', y: isBottom ? 'calc(100vh- 470px)' : 'calc(100vh - 180px)' }"
+           :pagination="false"
+           :loading="loading"
+           :expandedRowKeys="expandedRowKeys"
+           :customRow="Rowclick"
+           :expandIcon="expandIcon"
+           :expandIconAsCell="false"
+           rowKey="key"
+           :data-source="tableList">
+    <!-- 额外的展开行 -->
+    <template #expandedRowRender="{ record }">
+      <BtnList :btnList="btnList"
+               :record="record"
+               @click="openComponent" />
+    </template>
+    <template #username="{text, record }">
+      <span>{{record.userid + " " }}{{text}}</span>
+    </template>
+  </a-table>
+  <component :is="componentId"
+             v-if="componentId"
+             :selectedRow="selectedRow"
+             :enumName="enumName"
+             :buyOrSell="BuyOrSell.sell"
+             :parantSelectedRow="parantSelectedRow"
+             @cancel="closeComponent"></component>
+</template>
+
+<script lang="ts">
+import { EnumRouterName } from '@/common/constants/enumRouterName';
+import { ComposeTableParam, BtnList, defineComponent, handleComposeTable, queryTableList, ModalEnum } from '@/common/export/commonTable';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { queryOrderQuoteDetail } from '@/services/go/wrtrade';
+import { QueryOrderQuoteDetailReq, WrOrderQuote, WrOrderQuoteDetail } from '@/services/go/wrtrade/interface';
+import { defineAsyncComponent, PropType } from 'vue';
+import { BtnList as btnListType } from '@/common/components/btnList/interface';
+import { getSellMarketParam } from '../../setup';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { ColumnType } from '@/common/methods/table/interface';
+import { Moment } from 'moment';
+import moment from 'moment';
+import { getShowBottomValue } from '@/common/config/constrolBottom';
+
+export default defineComponent({
+    emits: ['cancel', 'openComponent'],
+    name: 'warehouse_receipt_trade_price_delisting_sell',
+    props: {
+        enumName: {
+            default: '',
+            type: String as PropType<EnumRouterName>,
+        },
+        btnList: {
+            default: [],
+            type: Array as PropType<btnListType[]>,
+        },
+        parantSelectedRow: {
+            type: Object as PropType<WrOrderQuote>,
+            default: {},
+        },
+        time: {
+            type: Object as PropType<Moment>,
+            default: moment(),
+        },
+    },
+    components: {
+        BtnList,
+        [ModalEnum.spot_trade_warehouse_delisting]: defineAsyncComponent(() => import('../delisting/index.vue')),
+    },
+    setup(props, context) {
+        const isBottom = getShowBottomValue();
+        console.log(isBottom.value, 'isBottom');
+        // 表格列表数据
+        const { loading, tableList, queryTable } = queryTableList<WrOrderQuoteDetail>();
+
+        const { wrpricetype, haswr, tableKey } = getSellMarketParam(props.enumName);
+        // 获取列表数据
+        const queryTableAction = () => {
+            const param: QueryOrderQuoteDetailReq = {
+                buyorsell: 1,
+                wrpricetype,
+                haswr,
+                wrfactortypeid: props.parantSelectedRow.wrfactortypeid,
+                goodsid: props.parantSelectedRow.goodsid,
+            };
+            if (!haswr) {
+                // 无仓单 需要交收月过滤数据
+                param.deliverymonth = moment(props.time).format('YYYY-MM');
+            }
+            queryTable(queryOrderQuoteDetail, param);
+        };
+        // 表格通用逻辑
+        const param: ComposeTableParam = {
+            queryFn: queryTableAction,
+            menuType: EnumRouterName.warehouse_receipt_trade_floating_price,
+            tableName: tableKey,
+            tableFilterKey: [],
+            isDetail: false,
+        };
+        function handleColumn(columns: ColumnType[]) {
+            columns.forEach((item) => {
+                columns.forEach((item) => {
+                    if (item.dataIndex == 'username') {
+                        delete item.width;
+                    }
+                });
+            });
+            return columns;
+        }
+        return {
+            isBottom,
+            ...handleComposeTable<WrOrderQuoteDetail>(param),
+            queryTableAction,
+            loading,
+            tableList,
+            BuyOrSell,
+            enumName: props.enumName,
+            expandIcon,
+            handleColumn,
+        };
+    },
+});
+</script>
+<style lang="less">
+.buy-sell-market {
+    .btnDeafault.ant-btn {
+        height: 30px;
+    }
+}
+</style>

+ 204 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/index.vue

@@ -0,0 +1,204 @@
+<template>
+  <!-- 买卖大厅 -->
+  <div class="buy-sell-market">
+    <div class="buy-sell-market-title">
+      <a class="backIcon"
+         @click="cancel">
+        <LeftOutlined />
+      </a>
+      <div class="titleBtn">
+        <div class="name">{{selectedRow.deliverygoodsname}}</div>
+        <div class="arrowRightIcon"></div>
+      </div>
+      <div class="titleBtn titleBtn2">
+        <div class="arrowLeftIcon"></div>
+        <div class="name">{{selectedRow.wrgoodsname}}</div>
+        <div class="arrowRightIcon"></div>
+      </div>
+      <div class="titleBtn titleBtn2">
+        <div class="arrowLeftIcon"></div>
+        <div class="name">{{selectedRow.warehousename}}</div>
+        <div class="arrowRightIcon"></div>
+      </div>
+      <div class="green bdf1 ml20">
+        <div class="numBlock ml15">
+          <div class="first">卖价</div>
+          <div class="last">{{selectedRow.sellprice}}</div>
+        </div>
+        <div class="numBlock">
+          <div class="first">卖量</div>
+          <div class="last">{{selectedRow.sellqty}}</div>
+        </div>
+      </div>
+      <div class="red ml35">
+        <div class="numBlock">
+          <div class="first">买价</div>
+          <div class="last">{{selectedRow.buyprice}}</div>
+        </div>
+        <div class="numBlock">
+          <div class="first">买量</div>
+          <div class="last">{{selectedRow.buyqty}}</div>
+        </div>
+      </div>
+      <BtnList :btnList="firstBtn"
+               :record="selectedRow"
+               @click="openComponent" />
+    </div>
+    <a-row class="buySellHall">
+      <a-col :span="12"
+             v-if="sellMarket.isMarket">
+        <Sell :enumName="enumName"
+              ref="sellRef"
+              :parantSelectedRow="selectedRow"
+              :time="time"
+              :btnList="handleBtnList(sellMarket.btnList)" />
+      </a-col>
+      <a-col :span="12"
+             v-if="buyMarket.isMarket">
+        <Buy :enumName="enumName"
+             ref="buyRef"
+             :time="time"
+             :parantSelectedRow="selectedRow"
+             :btnList="handleBtnList(buyMarket.btnList)" />
+      </a-col>
+    </a-row>
+    <component :is="componentId"
+               v-if="componentId"
+               :selectedRow="selectedRow"
+               :goodsPrice="getGoodsPrice()"
+               :enumName="enumName"
+               :time="time"
+               @cancel="closeComponent"></component>
+  </div>
+</template>
+
+<script lang="ts">
+import { EnumRouterName } from '@/common/constants/enumRouterName';
+import { defineAsyncComponent, defineComponent, BtnList, ModalEnum } from '@/common/export/commonTable';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { WrOrderQuote } from '@/services/go/wrtrade/interface';
+import { LeftOutlined } from '@ant-design/icons-vue';
+import { handleFinacing, handleIs, setGoodsPrice } from './setup';
+import Buy from './components/buy/index.vue';
+import Sell from './components/sell/index.vue';
+import { LineChartOutlined, DownOutlined } from '@ant-design/icons-vue';
+import { handleModalComponent } from '@/common/setup/asyncComponent';
+import { onMounted, PropType, ref } from 'vue';
+import { handleSpotBtnList } from '../../../setup';
+import { v4 } from 'uuid';
+import { addSubscribeQuotation, removeSubscribeQuotation } from '@/services/socket/quota';
+import Bus from '@/utils/eventBus/index';
+import { getQuoteDayInfoByCodeFindPrice } from '@/services/bus/goods';
+import TimerUtils from '@/utils/timer/timerUtil';
+import { BtnList as BtnListType } from '@/common/components/btnList/interface';
+import moment, { Moment } from 'moment';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+
+export default defineComponent({
+    emits: ['cancel', 'update'],
+    name: 'buy-sell-market',
+    props: {
+        selectedRow: {
+            type: Object as PropType<WrOrderQuote>,
+            default: {},
+        },
+        enumName: {
+            default: '',
+            type: String as PropType<EnumRouterName>,
+        },
+    },
+    components: {
+        Buy,
+        Sell,
+        BtnList,
+        LeftOutlined,
+        DownOutlined,
+        LineChartOutlined,
+        // [ModalEnum.spot_trade_warehouse_detail]: defineAsyncComponent(() => import('../detail/index.vue')),
+        // [ModalEnum.spot_trade_warehouse_post_buying]: defineAsyncComponent(() => import('../post_buying/index.vue')),
+    },
+    setup(props, context) {
+        const time = ref<Moment>(moment(props.selectedRow.deliverymonth)); // string 交收月
+        const loading = ref<boolean>(false);
+        const { visible, cancel } = _closeModal(context);
+
+        const { isWR, isFloat } = handleIs(props.enumName, BuyOrSell.buy);
+        // 买卖大厅 配置数据
+        // 表格操作按钮列表
+        const { firstBtn, buyMarket, sellMarket } = handleSpotBtnList(props.enumName);
+        // 获取浮动价商品实时价格
+
+        function getGoodsPrice() {
+            const result = getQuoteDayInfoByCodeFindPrice(props.selectedRow.goodscode);
+            setGoodsPrice(result);
+            return result;
+        }
+        const uuid = v4();
+        if (isFloat()) {
+            // 如果是浮动价需要行情订阅
+            const arr = [{ exchangeCode: 250, goodsCode: props.selectedRow.goodscode, subState: 0 }];
+            addSubscribeQuotation(uuid, arr);
+        }
+        onMounted(() => {
+            removeSubscribeQuotation(uuid);
+            TimerUtils.clearInterval('buyAndSellMartet');
+            TimerUtils.clearTimeout('debounce');
+        });
+        const buyRef = ref<null | { queryTableAction: Function }>(null);
+        const sellRef = ref<null | { queryTableAction: Function }>(null);
+        const queryFn = () => {
+            buyRef.value?.queryTableAction();
+            sellRef.value?.queryTableAction();
+        };
+        const { componentId, closeComponent, openComponent } = handleModalComponent(queryFn, ref({}));
+        const { hasFinacing } = handleFinacing(loading, props.selectedRow.wrfactortypeid);
+        function handleBtnList(list: BtnListType[]) {
+            if (!hasFinacing()) {
+                return list.filter((e) => e.code !== 'spot_trade_warehouse_financing_delisting');
+            } else {
+                return list;
+            }
+        }
+        function timeChange() {
+            TimerUtils.setTimeout(
+                () => {
+                    queryFn();
+                },
+                200,
+                'debounce'
+            );
+        }
+        TimerUtils.setInterval(
+            () => {
+                queryFn();
+            },
+            10 * 1000,
+            'buyAndSellMartet'
+        );
+        // 单据挂牌成功 通知买大厅刷新数据
+        Bus.$on('spotTrade', queryFn);
+
+        return {
+            time,
+            buyRef,
+            sellRef,
+            cancel,
+            isFloat,
+            getGoodsPrice,
+            visible,
+            firstBtn,
+            buyMarket,
+            sellMarket,
+            componentId,
+            closeComponent,
+            openComponent,
+            enumName: props.enumName,
+            handleBtnList,
+            isWR,
+            timeChange,
+        };
+    },
+});
+</script>
+<style lang="less">
+</style>

+ 135 - 0
src/views/market/spot_trade/spot_trade_order_transaction/components/buy-sell-market/setup.ts

@@ -0,0 +1,135 @@
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { EnumRouterName } from '@/common/constants/enumRouterName';
+import { queryResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { TableKey } from '@/common/methods/table/interface';
+import { getTableColumns, getTableEvent, queryTableList } from "@/common/setup/table";
+import { queryFaProductDetail } from '@/services/go/wrtrade';
+import { WrFAProductDetail } from "@/services/go/wrtrade/interface";
+import { Ref, ref } from 'vue';
+
+
+export function handleBuyAndSellList<T>(menuType: EnumRouterName, isDetail: boolean, tableName: keyof TableKey) {
+    // 表格列表数据
+    const { loading, tableList, queryTable } = queryTableList<T>();
+    // 表头数据
+    const { columns, registerColumn } = getTableColumns();
+    // 表格事件
+    const { expandedRowKeys, selectedRow, Rowclick } = getTableEvent<T>({});
+    // 注册表头信息 过滤
+    registerColumn(tableName, []);
+    return {
+        loading, tableList, columns, expandedRowKeys, selectedRow, Rowclick, queryTable
+    }
+}
+
+// 根据 当前tab 的枚举,获取买大厅对应的 wrpricetype haswr tableKey
+export function getBuyMarketParam(enumName: EnumRouterName) {
+    let wrpricetype = 1, haswr = 0, tableKey: keyof TableKey = 'table_pcweb_spot_trade_warehouse_price_trading_hall_buy'
+    switch (enumName) {
+        case EnumRouterName.warehouse_receipt_trade_price:
+            wrpricetype = 1;
+            haswr = 1
+            tableKey = 'table_pcweb_spot_trade_warehouse_price_trading_hall_buy'
+            break
+        case EnumRouterName.warehouse_receipt_trade_floating_price:
+            wrpricetype = 2;
+            haswr = 1
+            tableKey = 'table_pcweb_spot_trade_warehouse_float_trading_hall_buy'
+            break
+        case EnumRouterName.warehouse_pre_sale_price:
+            wrpricetype = 1;
+            haswr = 0
+            tableKey = 'table_pcweb_spot_trade_warehouse_presale_price_trading_hall_buy'
+            break
+        case EnumRouterName.warehouse_pre_sale_floating_price:
+            wrpricetype = 2;
+            haswr = 0
+            tableKey = 'table_pcweb_spot_trade_warehouse_presale_float_trading_hall_buy'
+            break
+    }
+    return { wrpricetype, haswr, tableKey }
+}
+
+// 根据 当前tab 的枚举,获取卖大厅对应的 wrpricetype haswr tableKey
+export function getSellMarketParam(enumName: EnumRouterName) {
+    let wrpricetype = 1, haswr = 0, tableKey: keyof TableKey = 'table_pcweb_spot_trade_warehouse_price_trading_hall_sale'
+    switch (enumName) {
+        case EnumRouterName.warehouse_receipt_trade_price:
+            wrpricetype = 1;
+            haswr = 1
+            tableKey = 'table_pcweb_spot_trade_warehouse_price_trading_hall_sale'
+            break
+        case EnumRouterName.warehouse_receipt_trade_floating_price:
+            wrpricetype = 2;
+            haswr = 1
+            tableKey = 'table_pcweb_spot_trade_warehouse_float_trading_hall_sale'
+            break
+        case EnumRouterName.warehouse_pre_sale_price:
+            wrpricetype = 1;
+            haswr = 0
+            tableKey = 'table_pcweb_spot_trade_warehouse_presale_price_trading_hall_sale'
+            break
+        case EnumRouterName.warehouse_pre_sale_floating_price:
+            wrpricetype = 2;
+            haswr = 0
+            tableKey = 'table_pcweb_spot_trade_warehouse_presale_float_trading_hall_sale'
+            break
+    }
+    return { wrpricetype, haswr, tableKey }
+}
+
+export function handleIs(enumName: EnumRouterName, buyOrSell: BuyOrSell) {
+    /**
+     *
+     * @returns 1 => 仓单贸易; 0 => 仓单预售
+     */
+    function isWR(): 0 | 1 {
+        if (enumName === EnumRouterName.warehouse_receipt_trade_price || enumName === EnumRouterName.warehouse_receipt_trade_floating_price) {
+            return 1
+        } else {
+            return 0
+        }
+    }
+    /**
+     *
+     * @returns true => 买; false =>卖
+     */
+    function isBuy() {
+        return buyOrSell === BuyOrSell.buy
+    }
+    /**
+     *
+     * @returns  true => 浮动价; false =>一口价
+     */
+    function isFloat() {
+        return enumName === EnumRouterName.warehouse_receipt_trade_floating_price ||
+            enumName === EnumRouterName.warehouse_pre_sale_floating_price
+    }
+    return { isWR, isBuy, isFloat }
+}
+
+const list = ref<WrFAProductDetail[]>([]);
+// 获取融资摘牌
+export function handleFinacing(loading: Ref<boolean>, id: number) {
+    queryResultLoadingAndInfo(queryFaProductDetail, loading, { wrfactortypeid: id }).then((res) => {
+        list.value = res;
+        return res
+    });
+    function hasFinacing(): boolean {
+        return list.value.length > 0
+    }
+    return { hasFinacing }
+}
+
+export function getFinacingList(): WrFAProductDetail[] {
+    return list.value
+}
+
+// 商品实时价格
+const goodsPrice = ref<string | number>('--')
+export function setGoodsPrice(value: string | number) {
+    goodsPrice.value = value
+}
+export function getGoodsPrice(): Ref<string | number> {
+    return goodsPrice
+}

+ 2 - 2
src/views/market/spot_trade/spot_trade_order_transaction/spot_trade_order_transaction_listing_transfer/index.vue

@@ -37,7 +37,7 @@ export default defineComponent({
         contextMenu,
         // [ModalEnum.spot_trade_warehouse_detail]: defineAsyncComponent(() => import('../../components/detail/index.vue')),
         // [ModalEnum.spot_trade_warehouse_post_buying]: defineAsyncComponent(() => import('../../components/post_buying/index.vue')),
-        // buyAndSell: defineAsyncComponent(() => import('../../components/buy-sell-market/index.vue')),
+        buyAndSell: defineAsyncComponent(() => import('../components/buy-sell-market/index.vue')),
         // postBuying: defineAsyncComponent(() => import('../../components/post_buying/index.vue')),
     },
     setup() {
@@ -55,7 +55,7 @@ export default defineComponent({
         const param: ComposeTableParam = {
             queryFn: queryTableAction,
             menuType: EnumRouterName.warehouse_receipt_trade_price,
-            tableName: 'table_pcweb_financing_manage_order_transaction',
+            tableName: 'table_pcweb_spot_trade_warehouse_price',
             tableFilterKey: [],
             isDetail: false,
         };