li.shaoyi 3 роки тому
батько
коміт
f0614ad81a
26 змінених файлів з 2036 додано та 14 видалено
  1. 29 3
      src/@next/components/layout/footer-main/index.vue
  2. 26 0
      src/hooks/system/index.ts
  3. 23 0
      src/hooks/table/columns.ts
  4. 8 0
      src/hooks/table/interface.ts
  5. 2 11
      src/services/go/commonService/index.ts
  6. 208 0
      src/views/order/funding_information/components/funding_information_funding_summary/setup.tsx
  7. 61 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_cancel_order/index.vue
  8. 89 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/index.vue
  9. 4 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/interface.ts
  10. 15 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/setup.ts
  11. 62 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_submit_order/index.vue
  12. 123 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/index.vue
  13. 10 0
      src/views/order/swap_the_order/components/swap_commodity_contract_bargain/setup.ts
  14. 69 0
      src/views/order/swap_the_order/components/swap_commodity_contract_commission/components/cancel/index.vue
  15. 93 0
      src/views/order/swap_the_order/components/swap_commodity_contract_commission/index.vue
  16. 101 0
      src/views/order/swap_the_order/components/swap_commodity_contract_make_deal/index.vue
  17. 19 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/setup.ts
  18. 334 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/index.vue
  19. 10 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/interface.ts
  20. 35 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/setup.ts
  21. 339 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/index.vue
  22. 10 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/interface.ts
  23. 32 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/setup.ts
  24. 161 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/index.vue
  25. 128 0
      src/views/order/swap_the_order/components/swap_commodity_contract_summary/setup.ts
  26. 45 0
      src/views/order/swap_the_order/index.vue

+ 29 - 3
src/@next/components/layout/footer-main/index.vue

@@ -1,14 +1,23 @@
 <template>
   <div class="mtp-footer-main">
     <component :is="currentComponent.component" :parent-component="currentComponent" v-if="currentComponent"></component>
-    <mtp-tabbar class="mtp-tabbar--bottom" :data-source="components" label="title" @change="componentChange"></mtp-tabbar>
+    <mtp-tabbar class="mtp-tabbar--bottom" :data-source="components" label="title" @change="componentChange">
+      <!-- 议价单 -->
+      <div class="goods-apply" v-if="showBargainRadio">
+        <a-radio-group class="conditionCommonRadioGroup" v-model:value="bargainValue">
+          <a-radio @focus="changeBargain(ApplyType.my)" :value="ApplyType.my">我的申请</a-radio>
+          <a-radio @focus="changeBargain(ApplyType.counterpart)" :value="ApplyType.counterpart">对方申请</a-radio>
+        </a-radio-group>
+      </div>
+    </mtp-tabbar>
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, nextTick, PropType } from 'vue'
+import { defineComponent, nextTick, PropType, ref, computed } from 'vue'
 import { useDynamicComponent } from '@/@next/hooks/common'
 import { DynamicComponent } from '@/@next/hooks/common/interface'
+import { ApplyType } from '@/common/constants/enumCommon';
 import MtpTabbar from '@/@next/components/base/tabbar/index.vue'
 import Bus from '@/utils/eventBus/index'
 
@@ -24,6 +33,14 @@ export default defineComponent({
   },
   setup(props) {
     const { components, currentComponent, componentChange } = useDynamicComponent(props.parentComponent.code);
+    const bargainValue = ref<ApplyType>(ApplyType.my);
+
+    const showBargainRadio = computed(() => {
+      if (currentComponent.value) {
+        return ['bottom_swap_commodity_contract_bargain', 'bottom_commodity_contract_bargain'].includes(currentComponent.value.code)
+      }
+      return false;
+    })
 
     // 组件重载
     function componentReload() {
@@ -34,6 +51,11 @@ export default defineComponent({
       })
     }
 
+    // 切换 我的
+    function changeBargain(value: ApplyType) {
+      Bus.$emit('bargain', value);
+    }
+
     // 注册账户变化事件,待通知调用
     Bus.$onOnly('taAccountChangedNtf', () => {
       componentReload();
@@ -42,7 +64,11 @@ export default defineComponent({
     return {
       components,
       currentComponent,
-      componentChange
+      componentChange,
+      changeBargain,
+      ApplyType,
+      bargainValue,
+      showBargainRadio,
     }
   }
 })

+ 26 - 0
src/hooks/system/index.ts

@@ -0,0 +1,26 @@
+import APP from '@/services';
+import { Systemparam } from '@/services/go/useInfo/interface';
+
+// 获取全部系统配置
+export const getAllSystemParam = (): Systemparam[] => {
+    return APP.getRef('systemParams').value
+}
+
+// 通过 code 获取系统配置
+export const getSystemParamByCode = (paramcode: string): Systemparam | undefined => {
+    return getAllSystemParam().find(e => e.paramcode === paramcode)
+}
+// 通过 code 获取系统配置对应的值
+export const getSystemParamValueByCode = (paramcode: string) => {
+    return getSystemParamByCode(paramcode)?.paramvalue
+}
+
+/**
+ * 通过 code 查找 系统配置是否存在 value 值
+ * @param paramcode
+ * @param value
+ * @returns
+ */
+export const hasSystemParam = (paramcode: string, value: string) => {
+    return getSystemParamByCode(paramcode)?.paramvalue === value
+}

+ 23 - 0
src/hooks/table/columns.ts

@@ -0,0 +1,23 @@
+import { ItemColumns } from "./interface";
+
+// 设置表头
+export const useSetColumns = (colums: ItemColumns[]) => {
+    return colums.map(el => {
+        if (!el.dataIndex) {
+            el.dataIndex = el.key
+        }
+        if (!el.align) {
+            el.align = 'center'
+        }
+        if (!el.width) {
+            el.width = 120
+        }
+
+        if (!el.slots) {
+            el.slots = {
+                customRender: el.key,
+            }
+        }
+        return el
+    })
+}

+ 8 - 0
src/hooks/table/interface.ts

@@ -0,0 +1,8 @@
+export interface ItemColumns {
+    key: string
+    title: string
+    dataIndex?: string
+    align?: 'left' | 'right' | 'center'
+    slots?: Object
+    width?: number
+}

+ 2 - 11
src/services/go/commonService/index.ts

@@ -92,18 +92,9 @@ export function queryNotice(): Promise<type.QueryNoticeRsp[]> {
  * 获取PC交易端菜单
  */
 export function GetPCMenus(): Promise<type.OperationTabMenu[]> {
-    const oem = getOem();
-    const param: { loginID: number | null, name?: string } = {
+    const param = {
         loginID: geLoginID_number(),
-    }
-    switch (oem) {
-        // 目前只有平安期货需要 oem 这个参数 请求菜单数据,如后续添加需要根据name获取菜单,此处需要修改
-        case OemType.pingan: {
-            param.name = oem
-        }
-        case OemType.tian_jing_mai_dun: {
-            param.name = 'trade'
-        }
+        name: getOem()
     }
     return commonSearch_go('/Common/GetPCWebMenus', param)
         .then((res) => {

+ 208 - 0
src/views/order/funding_information/components/funding_information_funding_summary/setup.tsx

@@ -1,7 +1,26 @@
+import { ref, Ref } from 'vue';
 import { Taaccount } from '@/services/go/TaAccount/interface';
 import { getTaacountStatus, getPayCurrencyTypeEnumItemName } from '@/common/constants/enumsName';
 import { formatAmount } from '@/utils/number';
 
+import { hasSystemParam } from '@/hooks/system';
+import { findGoodsCode, useDetail } from '@/views/order/swap_the_order/components/swap_commodity_contract_summary/setup';
+import { TradeMode } from '@/common/constants/enumCommon';
+import { queryResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { queryTableList } from '@/common/setup/table';
+import { useHolderprice } from '@/services/bus/holdPosition';
+import { getMarketIdsByTradeMode, getMarketTradePropertyByGoodsId } from '@/services/bus/market';
+import { getUserAccountType, getUserId } from '@/services/bus/user';
+import { AccountListItem } from '@/services/dataCenter/interafce/account';
+import { queryTradePosition } from '@/services/go/ermcp/order';
+import { QueryTradePositionRsp } from '@/services/go/ermcp/order/interface';
+import { queryTradeHolderDetail } from "@/services/go/order";
+import { QueryTradeHolderDetailRsp } from "@/services/go/order/interface";
+import { queryQuoteGoodsList } from '@/services/go/Tjmd';
+import { QueryQuoteGoodsListReq, QueryQuoteGoodsListRsp } from '@/services/go/Tjmd/interface';
+import { handleSubcriteQuote } from '@/common/setup/table/tableQuote';
+import { formatDecimal } from '@/utils/number';
+
 export function getColumns() {
     const columns = [
         {
@@ -89,4 +108,193 @@ function handlePriceColor(value: number, text: string) {
         className = 'down-quote-color'
     }
     return <span class={className}>{text}</span>;
+}
+
+/**
+ * 这是旧的掉期资金账户数据计算------------------------待优化废除,资金计算需要最新持仓数据,因此每次资金变动都要重新请求接口,由于资金变动通知引用的页面太多,会导致大量接口重复请求
+ * 期货订单和掉期订单的资金计算有点区别,后期废除需整合到 @/hooks/account/index.ts
+ */
+export function useHazardRates() {
+    const { getDetailProfitloss } = useDetail();
+    const positionList = ref<QueryTradePositionRsp[]>([]); // 所有持仓汇总
+    const positionDetailList = ref<QueryTradeHolderDetailRsp[]>([]); // 所有持仓明细
+    const swapList = ref<QueryQuoteGoodsListRsp[]>([]); // 交割商品
+
+    const getHoldsList = async (loading: Ref<boolean>, tradeMode?: string) => {
+        // 获取头寸
+        await queryResultLoadingAndInfo(queryTradePosition, loading, tradeMode).then((res) => {
+            const goodsSet = new Set<string>();
+            positionList.value = res;
+
+            res.forEach((el) => {
+                // 商品掉期取参考行情最新价,挂牌点选取自己行情的最新价
+                const goodscode = findGoodsCode(el.goodsid, el.goodscode, swapList.value);
+                if (goodscode) {
+                    goodsSet.add(goodscode);
+                }
+            });
+
+            //  行情订阅
+            const { subscribeAction } = handleSubcriteQuote();
+            subscribeAction([...goodsSet]);
+        })
+        await queryResultLoadingAndInfo(queryTradeHolderDetail, loading, { userid: getUserId() }).then(res => {
+            positionDetailList.value = res
+        })
+    }
+
+    function getSwapList() {
+        const { queryTable } = queryTableList<QueryQuoteGoodsListRsp>();
+        // 组装 参数
+        const marketids = getMarketIdsByTradeMode(TradeMode.DiaoQi)
+        const param: QueryQuoteGoodsListReq = {
+            usertype: getUserAccountType(),
+        }
+        if (marketids) {
+            param.marketids = marketids
+        }
+        queryTable(queryQuoteGoodsList, param).then(res => swapList.value = res)
+    }
+
+    // 获取报价小数位
+    function getDecimalplace() {
+        return positionList.value.length > 0 ? positionList.value[0].decimalplace : 2
+    }
+
+    // 获取当前资金账号对应的头寸
+    function getTaaccountPosition(accountid: number) {
+        return positionList.value.filter(e => e.accountid === accountid)
+    }
+
+    // 获取持仓明细
+    function getTradeHolderDetail(record: QueryTradePositionRsp) {
+        const { accountid, trademode, marketid, goodsid, buyorsell } = record;
+        return positionDetailList.value.filter((e) => e.accountid === accountid && e.trademode === trademode && e.marketid === marketid && e.goodsid === goodsid && e.buyorsell === buyorsell);
+    }
+
+    // 持仓盈亏
+    // 浮动盈亏	持仓单:
+    // 收益权=(最新价-持仓价)*持仓数量*合约单位*方向(买[1]:卖[-1])(*汇率)
+    // 所有权=(最新价*持仓数量*合约单位(*汇率) - 持仓金额)
+    function useProfitloss(record: QueryTradePositionRsp) {
+        const detailList = getTradeHolderDetail(record);
+        const result = detailList.reduce((res, item) => {
+            const goodscode = findGoodsCode(item.goodsid, item.goodscode, swapList.value);
+            res += Number(getDetailProfitloss(item, goodscode));
+            return res;
+        }, 0)
+
+        return result.toFixed(record.decimalplace);
+    }
+
+    // 汇总资金账号 的 浮动盈亏
+    function handleProfitloss({ accountid }: Taaccount, isDecimalPace = true) {
+        const decimalplace = getDecimalplace()
+        const result = getTaaccountPosition(accountid).reduce((acc: number, current: QueryTradePositionRsp) => {
+            const tradeproperty = getMarketTradePropertyByGoodsId(current.goodsid);
+            // 资金 只算 收益权
+            if (tradeproperty === 1) {
+                acc += +useProfitloss(current);
+            }
+            return acc
+        }, 0)
+        return isDecimalPace ? result.toFixed(decimalplace) : result
+    }
+
+    // 计算 市值
+    function handleHoldPrice(accountid: number) {
+        return getTaaccountPosition(accountid).reduce((acc: number, current: QueryTradePositionRsp) => {
+            const price = useHolderprice(current)
+            const temp = price === '--' ? 0 : Number(price)
+            return acc + temp
+        }, 0)
+    }
+
+    // 风险净值
+    function handleRiskValue(taaccount: Taaccount) {
+        const { accountid, currentbalance, otherfreezemargin, outamountfreeze } = taaccount
+        // 浮动盈亏
+        const profitloss = handleProfitloss(taaccount, false) as number
+
+        // 市值
+        const price = hasSystemParam('087', '1') ? handleHoldPrice(accountid) : 0
+        // 风险净值	根据系统参数“087 风险净值是否加上市值 - 0:不加 1:加“
+        // 0. 风险净值=期末余额+浮动盈亏(收益权)-其他冻结-出金冻结
+        // 1. 风险净值=期末余额+市值+浮动盈亏(收益权)-其他冻结-出金冻结
+        return currentbalance + price + profitloss - otherfreezemargin - outamountfreeze
+    }
+
+    // 净值
+    // 根据系统参数“307 账户净值是否减冻结资金 - 0:不减 1:减“
+    //0.净值=期末余额+市值+浮动盈亏(收益权)
+    //1.净值=期末余额+市值+浮动盈亏(收益权)-其他冻结-出金冻结
+    function netWorth(taaccount: Taaccount) {
+        const { accountid, currentbalance, otherfreezemargin, outamountfreeze } = taaccount
+        // 浮动盈亏
+        const free = hasSystemParam('037', '1') ? (otherfreezemargin + outamountfreeze) : 0
+
+        const profitloss = handleProfitloss(taaccount, false) as number
+        // 市值
+        const price = handleHoldPrice(accountid)
+        const decimalplace = getDecimalplace()
+        return (currentbalance + profitloss + price - free).toFixed(decimalplace)
+    }
+
+    // 风险率
+    function hazardRates(taaccount: Taaccount) {
+        const { usedmargin, mortgagecredit } = taaccount
+        // 风险净值
+        const riskValue = handleRiskValue(taaccount)
+        //   风险率	根据系统参数“132   风险率计算公式”:
+        // 1. 风险率=占用/风险净值
+        // 2. 风险率=(占用-授信金额)/(风险净值-授信金额)
+        const credit = hasSystemParam('132', '1') ? 0 : mortgagecredit
+        let result = 0
+        if (riskValue && (riskValue - credit)) {
+            result = (usedmargin - credit) / (riskValue - credit)
+        }
+        result = result ? result * 100 : 0
+        return formatDecimal(result, 2, false) + '%'
+    }
+
+    // 可用资金
+    function canUseMoney(taaccount: Taaccount | AccountListItem) {
+        const { currentbalance, usedmargin, freezemargin, freezecharge, otherfreezemargin, outamountfreeze } = taaccount
+
+        // 浮动盈亏
+        const profitloss = handleProfitloss(taaccount as Taaccount, false) as number
+        // 占用+冻结+其它冻结+手续费冻结+出金冻结
+        const freeze = usedmargin + freezemargin + freezecharge + otherfreezemargin + outamountfreeze
+        let result = 0
+        if (profitloss < 0) {
+            // 账户总浮动盈亏为负:= 期末余额+总浮动盈亏-占用-冻结-其它冻结-手续费冻结-出金冻结
+            result = currentbalance + profitloss - freeze
+        } else {
+            // *系统参数”113“(当日浮动盈利是否可用) 0:不可用 1:可用
+            const isUse = hasSystemParam('113', '1')
+            if (isUse) {
+                // 账户总浮动盈亏为正 且 113 = 1 :=期末余额+总浮动盈亏-占用-冻结-其它冻结-手续费冻结-出金冻结
+                result = currentbalance + profitloss - freeze
+            } else {
+                // 账户总浮动盈亏为正 且 113 = 0 :=期末余额-占用-冻结-其它冻结-手续费冻结-出金冻结
+                result = currentbalance - freeze
+            }
+        }
+        const decimalplace = getDecimalplace()
+        return Number(result.toFixed(decimalplace))
+    }
+
+    return {
+        positionList,
+        swapList,
+        useProfitloss,
+        handleProfitloss,
+        getTradeHolderDetail,
+        getSwapList,
+        hazardRates,
+        netWorth,
+        canUseMoney,
+        getHoldsList,
+        handleHoldPrice
+    }
 }

+ 61 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_cancel_order/index.vue

@@ -0,0 +1,61 @@
+<template>
+  <!-- 商品合约 议价单 撤单 -->
+  <div></div>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTjmdTransferApplyRsp } from '@/services/go/Tjmd/interface';
+import { tradeHoldTransferApplyAuditReq } from '@/services/proto/warehousetrade';
+import { TradeHoldTransferApplyAuditReqType } from '@/services/proto/warehousetrade/interface';
+import { Modal } from 'ant-design-vue';
+import { defineComponent, PropType, ref } from 'vue';
+
+export default defineComponent({
+    name: 'commodity_contract_bargain_cancel_order',
+    components: { Drawer },
+    emits: ['cancel', 'update'],
+    props: {
+        selectedRow: {
+            type: Object as PropType<QueryTjmdTransferApplyRsp>,
+            default: {},
+        },
+    },
+    setup(props, context) {
+        const { visible, cancel } = _closeModal(context);
+        const loading = ref<boolean>(false);
+
+        function submit() {
+            const param: TradeHoldTransferApplyAuditReqType = {
+                ApplyID: props.selectedRow.applyid,
+                ApplyStatus: 1, // 1:撤销2:拒绝3:通过
+                AuditSrc: 2,
+                AuditorID: geLoginID_number()!.toString(),
+                AuditRemark: '',
+            };
+            requestResultLoadingAndInfo(tradeHoldTransferApplyAuditReq, param, loading, ['撤单成功', '撤单失败:']).then(() => {
+                // Bus.$emit('spotTrade', true);
+                cancel(true);
+            });
+        }
+
+        Modal.confirm({
+            title: '撤单',
+            content: '是否确认撤单!',
+            onOk: submit,
+            onCancel: cancel,
+        });
+
+        return {
+            visible,
+            cancel,
+        };
+    },
+});
+</script>
+
+<style lang="less" scoped>
+</style>;

+ 89 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/index.vue

@@ -0,0 +1,89 @@
+<template>
+  <!-- 商品合约 议价单 撤单 -->
+  <a-modal
+    class="commonModal reasonModal"
+    title="原因"
+    v-model:visible="visible"
+    centered
+    @click="cancel"
+    :maskClosable="false"
+  >
+    <template #footer>
+      <a-button key="submit" @click="cancel" class="cancelBtn">取消</a-button>
+      <a-button key="submit" type="primary" @click="submit">提交</a-button>
+    </template>
+    <a-form class="inlineForm" ref="formRef" :model="formState" :rules="rules">
+      <a-row :gutter="24">
+        <a-col :span="24">
+          <a-form-item label="原因" class="relative" name="AuditRemark">
+            <a-textarea
+              class="dialogInput"
+              style="width: 100%"
+              placeholder="请输入原因"
+              v-model:value="formState.AuditRemark"
+              :autosize="{ minRows: 8, maxRows: 24 }"
+            />
+          </a-form-item>
+        </a-col>
+      </a-row>
+    </a-form>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { validateAction } from '@/common/setup/form/validateAction';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTjmdTransferApplyRsp } from '@/services/go/Tjmd/interface';
+import { tradeHoldTransferApplyAuditReq } from '@/services/proto/warehousetrade';
+import { TradeHoldTransferApplyAuditReqType } from '@/services/proto/warehousetrade/interface';
+import { defineComponent, PropType, ref } from 'vue';
+import { FormState } from './interface';
+import { handleForm } from './setup';
+
+export default defineComponent({
+  name: 'commodity_contract_bargain_refuse_order',
+  components: { Drawer },
+  emits: ['cancel', 'update'],
+  props: {
+    selectedRow: {
+      type: Object as PropType<QueryTjmdTransferApplyRsp>,
+      default: {},
+    },
+  },
+  setup(props, context) {
+    const { visible, cancel } = _closeModal(context);
+    const loading = ref<boolean>(false);
+    const { rules, formState, formRef } = handleForm();
+    function submit() {
+      validateAction<FormState>(formRef, formState).then((res) => {
+        const param: TradeHoldTransferApplyAuditReqType = {
+          ApplyID: props.selectedRow.applyid,
+          ApplyStatus: 2, // 1:撤销2:拒绝3:通过
+          AuditSrc: 2,
+          AuditorID: geLoginID_number()!.toString(),
+          AuditRemark: res.AuditRemark,
+        };
+        requestResultLoadingAndInfo(tradeHoldTransferApplyAuditReq, param, loading, ['撤单成功', '撤单失败:']).then(() => {
+          // Bus.$emit('spotTrade', true);
+          cancel(true);
+        });
+      });
+    }
+
+    return {
+      visible,
+      cancel,
+      submit,
+      rules,
+      formState,
+      formRef,
+    };
+  },
+});
+</script>
+
+<style lang="less" scoped>
+</style>;

+ 4 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/interface.ts

@@ -0,0 +1,4 @@
+
+export interface FormState {
+    AuditRemark: string,
+}

+ 15 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_refuse_order/setup.ts

@@ -0,0 +1,15 @@
+import { reactive, ref, UnwrapRef } from "vue";
+import { FormState } from "./interface";
+
+export function handleForm() {
+    const formRef = ref();
+    const formState: UnwrapRef<FormState> = reactive({
+        AuditRemark: '',
+    })
+    const rules = {
+        AuditRemark: [
+            { require: true, message: '请输入拒绝原因', trigger: 'blur', },
+        ],
+    }
+    return { rules, formState, formRef }
+}

+ 62 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/components/commodity_contract_bargain_submit_order/index.vue

@@ -0,0 +1,62 @@
+<template>
+  <!-- 商品合约 议价单 撤单 -->
+  <div></div>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTjmdTransferApplyRsp } from '@/services/go/Tjmd/interface';
+import { tradeHoldTransferApplyAuditReq } from '@/services/proto/warehousetrade';
+import { TradeHoldTransferApplyAuditReqType } from '@/services/proto/warehousetrade/interface';
+import { Modal } from 'ant-design-vue';
+import { defineComponent, PropType, ref } from 'vue';
+
+export default defineComponent({
+    name: 'commodity_contract_bargain_submit_order',
+    components: { Drawer },
+    emits: ['cancel', 'update'],
+    props: {
+        selectedRow: {
+            type: Object as PropType<QueryTjmdTransferApplyRsp>,
+            default: {},
+        },
+    },
+    setup(props, context) {
+        const { visible, cancel } = _closeModal(context);
+        const loading = ref<boolean>(false);
+
+        function submit() {
+            console.log(geLoginID_number());
+            const param: TradeHoldTransferApplyAuditReqType = {
+                ApplyID: props.selectedRow.applyid,
+                ApplyStatus: 3, // 1:撤销2:拒绝3:通过
+                AuditSrc: 2,
+                AuditorID: geLoginID_number()!.toString(),
+                AuditRemark: '',
+            };
+            requestResultLoadingAndInfo(tradeHoldTransferApplyAuditReq, param, loading, ['同意成功', '同意失败:']).then(() => {
+                // Bus.$emit('spotTrade', true);
+                cancel(true);
+            });
+        }
+
+        Modal.confirm({
+            title: '撤单',
+            content: '是否确认撤单!',
+            onOk: submit,
+            onCancel: cancel,
+        });
+
+        return {
+            visible,
+            cancel,
+        };
+    },
+});
+</script>
+
+<style lang="less" scoped>
+</style>;

+ 123 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/index.vue

@@ -0,0 +1,123 @@
+<template>
+  <!-- 商品订单 - 议价单 -->
+  <mtp-table-scroll>
+    <template #default="{ scroll }">
+      <a-table :columns="columns" class="srcollYTable" :scroll="scroll" :pagination="false" :loading="loading" :expandedRowKeys="expandedRowKeys" :customRow="Rowclick" :expandIcon="expandIcon" :expandIconAsCell="false" rowKey="key" :data-source="tableList">
+        <!-- 额外的展开行 -->
+        <template v-if="btnList.length" #expandedRowRender="{ record }">
+          <BtnList :btnList="handleBtnList(record, btnList)" :record="record" class="btn-list-sticky" @click="openComponent" />
+        </template>
+        <template #applytime="{ text }">
+          <span>{{ formatTime(text) }}</span>
+        </template>
+        <template #transferamount="{ record, text }">
+          <div>
+            <!-- 审核拒绝 -->
+            <a-tooltip placement="bottom" v-if="record.applystatus === 4" overlayClassName="toolTipTableColumn">
+              <template #title>
+                <span>{{ getScfContractStatusName(text) }}</span>
+              </template>
+              <span :class="record.applystatus === 4 ? 'red' : 'white'">{{ record.transferamount }}</span>
+              <ExclamationCircleOutlined class="ml10 red" v-if="record.applystatus === 4" />
+            </a-tooltip>
+            <span v-else>{{ record.transferamount }}</span>
+          </div>
+        </template>
+        <template #buyorsell="{ text }">
+          <span>{{ getBuyOrSellName(text) }}</span>
+        </template>
+        <template #applystatus="{ text }">
+          <span>{{ getScfContractStatusName(text) }}</span>
+        </template>
+      </a-table>
+    </template>
+  </mtp-table-scroll>
+  <component :is="componentId" v-if="componentId" :selectedRow="selectedRow" :tableList="tableList" @cancel="closeComponent"></component>
+</template>
+
+<script lang="ts">
+import MtpTableScroll from '@/common/components/tableScroll/index.vue';
+import { BtnListType } from '@/common/components/btnList/interface';
+import { ApplyType } from '@/common/constants/enumCommon';
+import { getBuyOrSellName, getScfContractStatusName } from '@/common/constants/enumsName';
+import { BtnList, defineAsyncComponent, defineComponent, queryTableList } from '@/common/export/commonTable';
+import { formatTime } from '@/common/methods';
+import { handleDeliveryRelation } from '@/common/setup/deliveryRelation';
+import { getRecordItemTab } from '@/common/setup/order/orderData';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { handleComposeOrderTable } from '@/common/setup/table/compose';
+import { ComposeOrderTableParam } from '@/common/setup/table/interface';
+import { getAccoutIdList } from '@/services/bus/account';
+import { QueryTradePositionRsp } from '@/services/go/ermcp/order/interface';
+import { queryTjmdTransferApply } from '@/services/go/Tjmd';
+import { QueryTjmdTransferApplyReq, QueryTjmdTransferApplyRsp } from '@/services/go/Tjmd/interface';
+import Bus from '@/utils/eventBus/index';
+import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
+import { ref } from 'vue';
+import { columns } from './setup';
+
+export default defineComponent({
+  name: 'commodity_contract_bargain',
+  components: {
+    ExclamationCircleOutlined,
+    MtpTableScroll,
+    BtnList,
+    swap_commodity_contract_bargain_submit_order: defineAsyncComponent(() => import('./components/commodity_contract_bargain_submit_order/index.vue')),
+    swap_commodity_contract_bargain_cancel_order: defineAsyncComponent(() => import('./components/commodity_contract_bargain_cancel_order/index.vue')),
+    swap_commodity_contract_bargain_refuse_order: defineAsyncComponent(() => import('./components/commodity_contract_bargain_refuse_order/index.vue')),
+  },
+  setup() {
+    // 类型 1-我的申请 2-对方申请
+    const margainType = ref<ApplyType>(ApplyType.my);
+    // 表格列表数据
+    const { loading, tableList, queryTable } = queryTableList<QueryTjmdTransferApplyRsp>();
+    // 交割商品
+    handleDeliveryRelation();
+    // 获取列表数据
+    const queryTableAction = () => {
+      const param: QueryTjmdTransferApplyReq = {
+        applytype: margainType.value,
+        accountids: getAccoutIdList(),
+      };
+      queryTable(queryTjmdTransferApply, param);
+    };
+    // 表格通用逻辑
+    const param: ComposeOrderTableParam = {
+      queryFn: () => queryTableAction(),
+      recordList: getRecordItemTab(),
+    };
+    // 切换 我的申请和对方申请
+    Bus.$onOnly('bargain', (value: ApplyType) => {
+      margainType.value = value;
+      queryTableAction();
+    });
+    function handleBtnList(record: QueryTjmdTransferApplyRsp, btnList: BtnListType[]) {
+      if (record.applystatus === 1) {
+        if (margainType.value === ApplyType.my) {
+          // 我的申请
+          return btnList.filter((e) => e.code === 'swap_commodity_contract_bargain_cancel_order');
+        } else {
+          // 对方的申请
+          return btnList.filter((e) => e.code !== 'swap_commodity_contract_bargain_cancel_order');
+        }
+      } else {
+        return [];
+      }
+    }
+    return {
+      ...handleComposeOrderTable<QueryTradePositionRsp>(param),
+      columns,
+      loading,
+      tableList,
+      formatTime,
+      expandIcon,
+      handleBtnList,
+      getBuyOrSellName,
+      getScfContractStatusName,
+    };
+  },
+});
+</script>
+
+<style lang="less">
+</style>;

+ 10 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_bargain/setup.ts

@@ -0,0 +1,10 @@
+export const columns = [
+    { title: '订单合约', dataIndex: 'goodsname', key: 'goodsname', align: 'center', width: 120 },
+    { title: '方向', dataIndex: 'buyorsell', key: 'buyorsell', align: 'center', width: 120, slots: { customRender: 'buyorsell' } },
+    { title: '协议价', dataIndex: 'transferprice', key: 'transferprice', width: 120, align: 'center' },
+    { title: '数量', dataIndex: 'qty', key: 'qty', align: 'center', width: 120, slots: { customRender: 'qty' } },
+    { title: '金额', dataIndex: 'transferamount', key: 'transferamount', width: 120, align: 'center', slots: { customRender: 'transferamount' } },
+    { title: '状态', dataIndex: 'applystatus', key: 'applystatus', width: 120, align: 'center', slots: { customRender: 'applystatus' } },
+    { title: '关联持仓', dataIndex: 'tradeid', key: 'tradeid', width: 120, align: 'center', slots: { customRender: 'tradeid' } },
+    { title: '时间', dataIndex: 'applytime', key: 'applytime', width: 120, align: 'center', slots: { customRender: 'applytime' } },
+];

+ 69 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_commission/components/cancel/index.vue

@@ -0,0 +1,69 @@
+<template>
+    <!-- 现货仓单 现货明细 撤单 -->
+    <div></div>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import { ModalEnum } from '@/common/constants/modalNameEnum';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { getInTaAccount } from '@/services/bus/account';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTradeOrderDetailRsp } from '@/services/go/ermcp/order/interface';
+import { cancelOrderReq } from '@/services/socket/order';
+import Bus from '@/utils/eventBus/index';
+import { Modal } from 'ant-design-vue';
+import * as Long from 'long';
+import { defineComponent, PropType, ref } from 'vue';
+
+export default defineComponent({
+    name: ModalEnum.spot_warrant_pending_order_cancel_order,
+    components: { Drawer },
+    emits: ['cancel', 'update'],
+    props: {
+        selectedRow: {
+            type: Object as PropType<QueryTradeOrderDetailRsp>,
+            default: {},
+        },
+    },
+    setup(props, context) {
+        const { visible, cancel } = _closeModal(context);
+        const loading = ref<boolean>(false);
+
+        function submit() {
+            const param = {
+                // ClientSerialNo: uuidv4(), // string 客户端流水号
+                // ClientOrderTime: moment().format('YYYY-MM-DD HH:mm:ss'), // string 客户端委托时间
+                // ClientType: 4, // uint32 终端类型
+                // OperateType: 5, // 操作类型
+                OldOrderId: Long.fromString(props.selectedRow.orderid),
+                AccountID: getInTaAccount(), // uint64 资金账号
+                // OrderSrc: 1, // uint32 委托来源
+                OperatorID: Number(geLoginID_number()), // uint64 操作员账号ID
+                MarketID: props.selectedRow.marketid,
+                GoodsID: props.selectedRow.goodsid,
+            };
+            requestResultLoadingAndInfo(cancelOrderReq, param, loading, ['撤单成功', '撤单失败:']).then(() => {
+                Bus.$emit('spotTrade', true);
+                cancel(true);
+            });
+        }
+
+        Modal.confirm({
+            title: '撤单',
+            content: '是否确认撤单?',
+            onOk: submit,
+            onCancel: cancel,
+        });
+
+        return {
+            visible,
+            cancel,
+        };
+    },
+});
+</script>
+
+<style lang="less" scoped>
+</style>;

+ 93 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_commission/index.vue

@@ -0,0 +1,93 @@
+<template>
+  <!-- 商品订单 - 委托 -->
+  <mtp-table-scroll>
+    <template #default="{ scroll }">
+      <a-table :columns="columns" class="srcollYTable" :scroll="scroll" :pagination="false" :loading="loading" :expandedRowKeys="expandedRowKeys" :customRow="Rowclick" :expandIcon="expandIcon" :expandIconAsCell="false" rowKey="key" :data-source="tableList">
+        <!-- 额外的展开行 -->
+        <template v-if="btnList.length" #expandedRowRender="{ record }">
+          <BtnList :btnList="filterBtnList(btnList, record)" :record="record" class="btn-list-sticky" @click="openComponent" />
+        </template>
+        <!-- 类型 -->
+        <template #buildtype="{ record }">
+          <a>{{ getBuyOrSellTypeName(record.buyorsell) }}</a>
+        </template>
+        <!-- 状态 -->
+        <template #orderstatus="{ record }">
+          <a>{{ getOrderStatusName(record.orderstatus) }}</a>
+        </template>
+
+        <template #ordertime="{ text }">
+          <a>{{ formatTime(text) }}</a>
+        </template>
+      </a-table>
+    </template>
+  </mtp-table-scroll>
+  <component :is="componentId" v-if="componentId" :selectedRow="selectedRow" @cancel="closeComponent"></component>
+</template>
+
+<script lang="ts">
+import MtpTableScroll from '@/common/components/tableScroll/index.vue';
+import { BtnListType } from '@/common/components/btnList/interface';
+import { TradeMode } from '@/common/constants/enumCommon';
+import { enumOrderComponents } from '@/common/constants/enumOrderComponents';
+import { getBuyOrSellTypeName, getOrderStatusName } from '@/common/constants/enumsName';
+import { BtnList, defineAsyncComponent, defineComponent, queryTableList } from '@/common/export/commonTable';
+import { formatTime } from '@/common/methods';
+import { getRecordItemTab } from '@/common/setup/order/orderData';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { handleComposeOrderTable } from '@/common/setup/table/compose';
+import { ComposeOrderTableParam } from '@/common/setup/table/interface';
+import { queryTradeOrderDetail } from '@/services/go/ermcp/order';
+import { QueryTradeOrderDetailRsp } from '@/services/go/ermcp/order/interface';
+import { WrPerformancePlan } from '@/services/go/wrtrade/interface';
+import Bus from '@/utils/eventBus/index';
+
+export default defineComponent({
+  name: enumOrderComponents.commodity_contract_commission,
+  components: {
+    MtpTableScroll,
+    BtnList,
+    swap_commodity_contract_commission_cancel_order: defineAsyncComponent(() => import('./components/cancel/index.vue')),
+  },
+  setup() {
+    // 表格列表数据
+    const { loading, tableList, queryTable } = queryTableList<QueryTradeOrderDetailRsp>();
+    // 获取列表数据
+    const queryTableAction = () => {
+      queryTable(queryTradeOrderDetail, { tradeMode: TradeMode.DiaoQi.toString() });
+    };
+    // 表格通用逻辑
+    const param: ComposeOrderTableParam = {
+      queryFn: queryTableAction,
+      tableName: 'table_pcweb_spot_trade_bottom_commodity_contract_commission',
+      recordList: getRecordItemTab(),
+    };
+    function filterBtnList(list: BtnListType[], record: QueryTradeOrderDetailRsp) {
+      //委托状态 - 1:委托请求 2:待冻结 3:委托成功 4:委托失败 5:配对成功 6:已撤 7:已成 8:成交失败 9:委托拒绝 1number;
+      const arr = [3, 7];
+      if (!arr.includes(record.orderstatus)) {
+        return list.filter((e) => e.code !== 'swap_commodity_contract_commission_cancel_order');
+      } else {
+        return list;
+      }
+    }
+    // 挂牌
+    Bus.$on('spotTrade', () => {
+      queryTableAction();
+    });
+    return {
+      ...handleComposeOrderTable<WrPerformancePlan>(param),
+      loading,
+      tableList,
+      formatTime,
+      expandIcon,
+      getBuyOrSellTypeName,
+      getOrderStatusName,
+      filterBtnList,
+    };
+  },
+});
+</script>
+
+<style lang="less">
+</style>;

+ 101 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_make_deal/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <!-- 商品订单 - 成交 -->
+  <mtp-table-scroll>
+    <template #default="{ scroll }">
+      <a-table :columns="columns" class="srcollYTable" :scroll="scroll" :pagination="false" :loading="loading" :expandedRowKeys="expandedRowKeys" :customRow="Rowclick" :expandIcon="expandIcon" :expandIconAsCell="false" rowKey="key" :data-source="tableList">
+        <!-- 额外的展开行 -->
+        <template v-if="btnList.length" #expandedRowRender="{ record }">
+          <BtnList :btnList="btnList" :record="record" class="btn-list-sticky" @click="openComponent" />
+        </template>
+        <!-- 类型 -->
+        <template #buyorsell="{ text }">
+          <span>{{ getBuyOrSellTypeName(text) }}</span>
+        </template>
+        <!-- 成交类型 -->
+        <template #buildtype="{ text }">
+          <span>{{ getChannelBuildName(text) }}</span>
+        </template>
+        <template #tradeprice="{ text, record }">
+          <span>{{ handleType(record, text) }}</span>
+        </template>
+        <template #matchaccountid="{ text, record }">
+          <span>{{ handleType(record, text) }}</span>
+        </template>
+        <!-- 状态 -->
+        <template #orderstatus="{ record }">
+          <a>{{ getOrderStatusName(record.orderstatus) }}</a>
+        </template>
+        <template #tradetime="{ text }">
+          <a>{{ formatTime(text) }}</a>
+        </template>
+      </a-table>
+    </template>
+  </mtp-table-scroll>
+  <component :is="componentId" v-if="componentId" :selectedRow="selectedRow" @cancel="closeComponent"></component>
+</template>
+
+<script lang="ts">
+import MtpTableScroll from '@/common/components/tableScroll/index.vue';
+import { TradeMode } from '@/common/constants/enumCommon';
+import { enumOrderComponents } from '@/common/constants/enumOrderComponents';
+import { getBuildTypeName, getBuyOrSellTypeName, getOrderStatusName, getChannelBuildName } from '@/common/constants/enumsName';
+import { BtnList, defineComponent, queryTableList } from '@/common/export/commonTable';
+import { formatTime } from '@/common/methods';
+import { getRecordItemTab } from '@/common/setup/order/orderData';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { handleComposeOrderTable } from '@/common/setup/table/compose';
+import { ComposeOrderTableParam } from '@/common/setup/table/interface';
+import { handleNoneValue } from '@/common/setup/table/tableQuote';
+import { queryTradeDetail } from '@/services/go/ermcp/order';
+import { QueryTradeDetailRsp } from '@/services/go/ermcp/order/interface';
+import Bus from '@/utils/eventBus/index';
+
+export default defineComponent({
+  name: enumOrderComponents.commodity_contract_make_deal,
+  components: {
+    MtpTableScroll,
+    BtnList,
+  },
+  setup() {
+    // 表格列表数据
+    const { loading, tableList, queryTable } = queryTableList<QueryTradeDetailRsp>();
+    // 获取列表数据
+    const queryTableAction = () => {
+      queryTable(queryTradeDetail, { tradeMode: TradeMode.DiaoQi.toString() });
+    };
+    // 表格通用逻辑
+    const param: ComposeOrderTableParam = {
+      queryFn: queryTableAction,
+      tableName: 'table_pcweb_spot_trade_bottom_commodity_contract_make_deal',
+      recordList: getRecordItemTab(),
+    };
+    // fix: #2063
+    function handleType(record: QueryTradeDetailRsp, value: string | number) {
+      let result: number | string = '--';
+      if (value) {
+        result = record.tradetype === 22 ? '--' : value;
+      }
+      return result;
+    }
+    Bus.$on('spotTrade', () => {
+      queryTableAction();
+    });
+    return {
+      ...handleComposeOrderTable<QueryTradeDetailRsp>(param),
+      loading,
+      tableList,
+      formatTime,
+      expandIcon,
+      getBuildTypeName,
+      getOrderStatusName,
+      getBuyOrSellTypeName,
+      handleNoneValue,
+      handleType,
+      getChannelBuildName,
+    };
+  },
+});
+</script>
+
+<style lang="less">
+</style>;

+ 19 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/setup.ts

@@ -0,0 +1,19 @@
+import { BuyOrSell } from "@/common/constants/enumCommon";
+import { getQuoteDayInfoByCodeFindPrice } from "@/services/bus/goods";
+import { QueryTradeHolderDetailRsp } from "@/services/go/order/interface";
+
+// 计算盈亏
+// 浮动盈亏	持仓单:
+// 收益权=(最新价-持仓价)*持仓数量*合约单位*方向(买[1]:卖[-1])(*汇率)
+// 所有权=(最新价*持仓数量*合约单位(*汇率) - 持仓金额)
+export function useProfit(item: QueryTradeHolderDetailRsp, goodcode: string) {
+    // 最新价
+    const lastPrice = getQuoteDayInfoByCodeFindPrice(goodcode);
+    if (lastPrice && lastPrice !== '--') {
+        const { holderprice, holderqty, agreeunit, decimalplace, buyorsell } = item
+        const temp = buyorsell === BuyOrSell.buy ? 1 : -1
+        return ((+lastPrice - holderprice) * holderqty * agreeunit * temp).toFixed(decimalplace)
+    } else {
+        return lastPrice
+    }
+}

+ 334 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/index.vue

@@ -0,0 +1,334 @@
+<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" :model="formState" :rules="rules">
+        <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>
+
+            <div class="lineBar">
+              <div class="line1">
+                <div class="name">{{ selectedRow.tradeid }}</div>
+                <div class="date">{{ formatTime(selectedRow.expiredate, 'd') }}</div>
+              </div>
+              <div class="line2">
+                <div class="left">{{ selectedRow.buyorsell === BuyOrSell.buy ? '买入' : '卖出' }}</div>
+                <div class="middle">
+                  <div>{{ selectedRow.holderqty }}</div>
+                  <div>{{ selectedRow.holderprice }}</div>
+                  <div>{{ selectedRow.holderamount }}</div>
+                </div>
+                <div class="right red">{{ useProfit(selectedRow, goodscode) }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="fixedBtns">
+          <a-row :gutter="24">
+            <a-col :span="24" class="mt12">
+              <a-form-item label="协议价" name="price" class="inputIconBox mb10 not-copy">
+                <a-input-number class="commonInput not-copy" v-model:value="formState.price" style="width: 200px" :min="0" />
+                <MinusOutlined @click="decreasePrice" />
+                <PlusOutlined @click="increasePirce" />
+              </a-form-item>
+            </a-col>
+            <a-col :span="24">
+              <a-form-item label="平仓金额" class="mb10 not-copy">
+                <span class="white">{{ getMoney() }}</span>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-form-item class="btnCenter mt10">
+            <a-button class="listedBtn" :loading="loading" :disabled="loading" @click="submit">提交</a-button>
+            <a-button class="ml10 cancelBtn" @click="cancel">取消</a-button>
+          </a-form-item>
+        </div>
+      </a-form>
+    </div>
+  </Drawer>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import UploadImg from '@/common/components/uploadImg/index.vue';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { formatTime } from '@/common/methods';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { validateAction } from '@/common/setup/form';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTradeHolderDetailRsp } from '@/services/go/order/interface';
+import { QueryQuoteGoodsListRsp } from '@/services/go/Tjmd/interface';
+import { tradeHoldTransferApply } from '@/services/proto/warehousetrade';
+import { TradeHoldTransferApplyReq } from '@/services/proto/warehousetrade/interface';
+import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue';
+import Long from 'long';
+import { defineComponent, PropType, ref } from 'vue';
+import { findGoodsCode } from '../../setup';
+import { useProfit } from '../setup';
+import { FormState } from './interface';
+import { handleForm, usePrice } from './setup';
+
+export default defineComponent({
+  name: 'swap_commodity_contract_summary_deal_closed',
+  components: { Drawer, UploadImg, PlusOutlined, MinusOutlined },
+  emits: ['cancel', 'update'],
+  props: {
+    selectedRow: {
+      type: Object as PropType<QueryTradeHolderDetailRsp>,
+      default: {},
+    },
+    swapList: {
+      type: Array as PropType<QueryQuoteGoodsListRsp[]>,
+      default: [],
+    },
+  },
+  setup(props, context) {
+    const { visible, cancel } = _closeModal(context);
+    const { rules, formState, formRef } = handleForm();
+    const goodscode = findGoodsCode(props.selectedRow.goodsid, props.selectedRow.goodscode, props.swapList);
+    const loading = ref<boolean>(false);
+
+    // 平仓金额
+    function getMoney() {
+      let result = '--';
+      if (formState.price) {
+        const { holderqty, agreeunit, decimalplace } = props.selectedRow;
+        result = (+formState.price * holderqty * agreeunit).toFixed(decimalplace);
+      }
+      return result;
+    }
+
+    const toFixed0 = (value: number) => +value.toFixed(0);
+
+    function submit() {
+      validateAction<FormState>(formRef, formState).then((res) => {
+        const param: TradeHoldTransferApplyReq = {
+          TradeID: Long.fromString(props.selectedRow.tradeid),
+          BuyorSell: props.selectedRow.buyorsell,
+          TransferPrice: res.price,
+          ApplySrc: 2,
+          ApplicantID: geLoginID_number()!,
+          Remark: '',
+        };
+        requestResultLoadingAndInfo(tradeHoldTransferApply, param, loading, ['协议平仓成功', '协议平仓失败:']).then(() => {
+          cancel(true);
+        });
+      });
+    }
+    return {
+      visible,
+      cancel,
+      submit,
+      loading,
+      toFixed0,
+      rules,
+      formState,
+      formRef,
+      ...usePrice(formState),
+      BuyOrSell,
+      formatTime,
+      useProfit,
+      goodscode,
+      getMoney,
+    };
+  },
+});
+</script>
+
+<style lang="less" scoped>
+.c_c_s_s {
+    background: @m-black40;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    .formBar {
+        padding: 0;
+        height: calc(100% - 170px);
+        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: 12px;
+                    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;
+                    }
+                    .date {
+                        flex: 1;
+                        text-align: right;
+                        font-size: 14px;
+                        color: @m-grey1;
+                    }
+                }
+                .line2 {
+                    width: 100%;
+                    user-select: none;
+                    padding: 12px 0 14px 0;
+                    display: inline-flex;
+                    .left {
+                        width: 25%;
+                        color: @m-white6;
+                        font-size: 14px;
+                        white-space: nowrap;
+                        text-overflow: ellipsis;
+                        overflow: hidden;
+                        line-height: 34px;
+                        // }
+                    }
+                    .middle {
+                        width: 50%;
+                        display: inline-flex;
+                        justify-content: space-between;
+                        padding: 0 10px;
+                        font-size: 16px;
+                        color: @m-white6;
+                        line-height: 34px;
+                        > div {
+                            white-space: nowrap;
+                        }
+                    }
+                    .right {
+                        width: 25%;
+                        font-size: 16px;
+                        text-align: right;
+                        line-height: 34px;
+                        white-space: nowrap;
+                    }
+                }
+            }
+        }
+    }
+    .fixedBtns {
+        padding-top: 0;
+        left: 0;
+        right: 0;
+        padding-left: 20px;
+        padding-right: 20px;
+    }
+    .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;
+        }
+    }
+    .inputIconBox {
+        .ant-form-item-children {
+            .anticon-plus {
+                right: 156px;
+            }
+        }
+    }
+}
+</style>;
+
+function queryTradeHolderDetail(queryTradeHolderDetail: any, param: { applytype: number; }) {
+  throw new Error('Function not implemented.');
+}

+ 10 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/interface.ts

@@ -0,0 +1,10 @@
+import { QueryTradeHolderDetailRsp } from "@/services/go/order/interface";
+
+export interface FormState {
+    price: number,
+}
+
+
+export interface BargainList extends QueryTradeHolderDetailRsp {
+    checked: boolean
+}

+ 35 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_deal_closed/setup.ts

@@ -0,0 +1,35 @@
+import { validateCommon } from "@/common/setup/validate";
+import { RuleObject } from "ant-design-vue/lib/form/interface";
+import { reactive, ref, UnwrapRef } from "vue";
+import { FormState } from "./interface";
+
+export function handleForm() {
+    const formRef = ref();
+    const v_num = async (rule: RuleObject, value: number) => {
+        return validateCommon(value, '请输入协议价');
+    };
+    const formState: UnwrapRef<FormState> = reactive({
+        price: 0,
+    })
+    const rules = {
+        price: [
+            { require: true, message: '请输入协议价', trigger: 'blur', type: 'number', validator: v_num },
+        ],
+    }
+    return { rules, formState, formRef }
+}
+
+export function usePrice(formState: UnwrapRef<FormState>) {
+    function increasePirce() {
+        formState.price++
+    }
+    function decreasePrice() {
+        if (formState.price) {
+            formState.price--
+        }
+    }
+    return { increasePirce, decreasePrice }
+}
+
+
+

+ 339 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/index.vue

@@ -0,0 +1,339 @@
+<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" :model="formState" :rules="rules">
+        <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>
+            <div class="lineBar">
+              <div class="line1">
+                <div class="name">
+                  {{ selectedRow.tradeid }}
+                  <template v-if="selectedRow.holderdays">
+                    <span class="red">{{ selectedRow.holderdays }}</span>天后可平
+                  </template>
+                </div>
+                <div class="date">{{ formatTime(selectedRow.expiredate, 'd') }}</div>
+              </div>
+              <div class="line2">
+                <div class="left">{{ selectedRow.buyorsell === BuyOrSell.buy ? '买入' : '卖出' }}</div>
+                <div class="middle">
+                  <div>{{ selectedRow.holderqty }}</div>
+                  <div>{{ selectedRow.holderprice }}</div>
+                  <div>{{ selectedRow.holderamount }}</div>
+                </div>
+                <div :class="['right', +useProfit(selectedRow, goodscode) > 0 ? 'up-quote-color' : 'down-quote-color']">{{ useProfit(selectedRow, goodscode) }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="fixedBtns">
+          <a-row :gutter="24">
+            <a-col :span="24" class="mt12">
+              <a-form-item label="估算价" class="inputIconBox mb10 not-copy">
+                <!-- 估算价取标的商品行情的最新价 -->
+                <span class="white">{{ getQuoteDayInfoByCodeFindPrice(goodscode) }}</span>
+              </a-form-item>
+            </a-col>
+            <a-col :span="24">
+              <a-form-item label="估算金额" class="mb10 not-copy">
+                <span class="white">{{ getMoney() }}</span>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-form-item class="btnCenter mt10">
+            <a-button class="listedBtn" :loading="loading" :disabled="loading" @click="submit">提交</a-button>
+            <a-button class="ml10 cancelBtn" @click="cancel">取消</a-button>
+          </a-form-item>
+        </div>
+      </a-form>
+    </div>
+  </Drawer>
+</template>
+
+<script lang="ts">
+import Drawer from '@/common/components/drawer/index.vue';
+import UploadImg from '@/common/components/uploadImg/index.vue';
+import { BuyOrSell } from '@/common/constants/enumCommon';
+import { ModalEnum } from '@/common/constants/modalNameEnum';
+import { formatTime } from '@/common/methods';
+import { requestResultLoadingAndInfo } from '@/common/methods/request/resultInfo';
+import { validateAction } from '@/common/setup/form';
+import { _closeModal } from '@/common/setup/modal/modal';
+import { getSelectedAccountId } from '@/services/bus/account';
+import { getQuoteDayInfoByCodeFindPrice } from '@/services/bus/goods';
+import { geLoginID_number } from '@/services/bus/login';
+import { QueryTradeHolderDetailRsp } from '@/services/go/order/interface';
+import { QueryQuoteGoodsListRsp } from '@/services/go/Tjmd/interface';
+import { holderClose } from '@/services/proto/warehousetrade';
+import { HolderCloseReq } from '@/services/proto/warehousetrade/interface';
+import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue';
+import Long from 'long';
+import { defineComponent, PropType, ref } from 'vue';
+import { findGoodsCode } from '../../setup';
+import { useProfit } from '../setup';
+import { FormState } from './interface';
+import { handleForm, usePrice } from './setup';
+
+export default defineComponent({
+  name: ModalEnum.commodity_contract_summary_settlement,
+  components: { Drawer, UploadImg, PlusOutlined, MinusOutlined },
+  emits: ['cancel', 'update'],
+  props: {
+    selectedRow: {
+      type: Object as PropType<QueryTradeHolderDetailRsp>,
+      default: {},
+    },
+    swapList: {
+      type: Array as PropType<QueryQuoteGoodsListRsp[]>,
+      default: [],
+    },
+  },
+  setup(props, context) {
+    const goodscode = findGoodsCode(props.selectedRow.goodsid, props.selectedRow.goodscode, props.swapList);
+
+    const { visible, cancel } = _closeModal(context);
+    const { rules, formState, formRef } = handleForm();
+    const loading = ref<boolean>(false);
+    // 估算金额=估算价*平仓数量*合约单位。
+    function getMoney() {
+      let result = '--';
+      const lastPrice = getQuoteDayInfoByCodeFindPrice(goodscode);
+      if (lastPrice && lastPrice !== '--') {
+        const { holderqty, agreeunit, decimalplace } = props.selectedRow;
+        result = (+lastPrice * holderqty * agreeunit).toFixed(decimalplace);
+      }
+      return result;
+    }
+
+    const toFixed0 = (value: number) => +value.toFixed(0);
+
+    function submit() {
+      validateAction<FormState>(formRef, formState).then((res) => {
+        const param: HolderCloseReq = {
+          TradeID: Long.fromString(props.selectedRow.tradeid),
+          LoginID: geLoginID_number()!, // uint64 登陆账号
+          AccountID: getSelectedAccountId(), // uint64 交易账号
+          GoodsID: props.selectedRow.goodsid,
+          MarketID: props.selectedRow.marketid, // uint32 市场ID
+          BuyOrSell: props.selectedRow.buyorsell,
+          OperatorID: geLoginID_number()!, // uint64 操作员账号ID
+        };
+        requestResultLoadingAndInfo(holderClose, param, loading, ['平仓成功', '平仓失败:']).then(() => {
+          cancel(true);
+        });
+      });
+    }
+    return {
+      visible,
+      cancel,
+      submit,
+      loading,
+      toFixed0,
+      rules,
+      formState,
+      formRef,
+      ...usePrice(formState),
+      BuyOrSell,
+      formatTime,
+      useProfit,
+      goodscode,
+      getQuoteDayInfoByCodeFindPrice,
+      getMoney,
+    };
+  },
+});
+</script>
+
+<style lang="less" scoped>
+.c_c_s_s {
+    background: @m-black40;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    .formBar {
+        padding: 0;
+        height: calc(100% - 170px);
+        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: 12px;
+                    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;
+                    }
+                    .date {
+                        flex: 1;
+                        text-align: right;
+                        font-size: 14px;
+                        color: @m-grey1;
+                    }
+                }
+                .line2 {
+                    width: 100%;
+                    user-select: none;
+                    padding: 12px 0 14px 0;
+                    display: inline-flex;
+                    .left {
+                        width: 25%;
+                        color: @m-white6;
+                        font-size: 14px;
+                        white-space: nowrap;
+                        text-overflow: ellipsis;
+                        overflow: hidden;
+                        line-height: 34px;
+                        // }
+                    }
+                    .middle {
+                        width: 50%;
+                        display: inline-flex;
+                        justify-content: space-between;
+                        padding: 0 10px;
+                        font-size: 16px;
+                        color: @m-white6;
+                        line-height: 34px;
+                        > div {
+                            white-space: nowrap;
+                        }
+                    }
+                    .right {
+                        width: 25%;
+                        font-size: 16px;
+                        text-align: right;
+                        line-height: 34px;
+                        white-space: nowrap;
+                    }
+                }
+            }
+        }
+    }
+    .fixedBtns {
+        padding-top: 0;
+        left: 0;
+        right: 0;
+        padding-left: 20px;
+        padding-right: 20px;
+    }
+    .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;
+        }
+    }
+    .inputIconBox {
+        .ant-form-item-children {
+            .anticon-plus {
+                right: 156px;
+            }
+        }
+    }
+}
+</style>;

+ 10 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/interface.ts

@@ -0,0 +1,10 @@
+import { QueryTradeHolderDetailRsp } from "@/services/go/order/interface";
+
+export interface FormState {
+    price: number,
+}
+
+
+export interface BargainList extends QueryTradeHolderDetailRsp {
+    checked: boolean
+}

+ 32 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/components/swap_commodity_contract_summary_order_closed/setup.ts

@@ -0,0 +1,32 @@
+import { validateCommon } from "@/common/setup/validate";
+import { RuleObject } from "ant-design-vue/lib/form/interface";
+import { reactive, ref, UnwrapRef } from "vue";
+import { FormState } from "./interface";
+
+export function handleForm() {
+    const formRef = ref();
+    const v_num = async (rule: RuleObject, value: number) => {
+        return validateCommon(value, '请输入协议价');
+    };
+    const formState: UnwrapRef<FormState> = reactive({
+        price: 0,
+    })
+    const rules = {
+        price: [
+            { require: true, message: '请输入协议价', trigger: 'blur', type: 'number', validator: v_num },
+        ],
+    }
+    return { rules, formState, formRef }
+}
+
+export function usePrice(formState: UnwrapRef<FormState>) {
+    function increasePirce() {
+        formState.price++
+    }
+    function decreasePrice() {
+        if (formState.price) {
+            formState.price--
+        }
+    }
+    return { increasePirce, decreasePrice }
+}

+ 161 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <!-- 商品订单 - 合约汇总 -->
+  <mtp-table-scroll>
+    <template #default="{ scroll }">
+      <a-table :columns="getTableColums()" class="srcollYTableExpendBgColor srcollYTable" :scroll="scroll" :pagination="false" :loading="loading" :expandedRowKeys="expandedRowKeys" :customRow="Rowclick" :expandIcon="expandIcon" :expandIconAsCell="false" rowKey="key" :data-source="positionList">
+        <!-- 额外的展开行 -->
+        <template #expandedRowRender="{ record }">
+          <a-table :columns="getDetailColums()" class="expandBottomTable" :pagination="false" :loading="detailLoading" :expandedRowKeys="expandedRowKeys" :expandIcon="expandIcon" :expandIconAsCell="false" rowKey="key" :data-source="getTradeHolderDetail(record)">
+            <template #operate="sub">
+              <BtnList :btnList="handleBtnList(record, btnList)" :record="sub.record" class="btn-list-sticky" @click="openComponent" />
+            </template>
+            <!-- 持仓盈亏 -->
+            <template #profitloss="{ record }">
+              <span :class="[+getDetailProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) > 0 ? 'up-quote-color' : +getDetailProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) < 0 ? 'down-quote-color' : '']">{{ getDetailProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) }}</span>
+            </template>
+            <!-- 市值 -->
+            <template #marketamount="{ record }">
+              <span>{{ getDetailMarketAmount(record) }}</span>
+            </template>
+            <template #expiredate="{ text }">
+              <span>{{ handleNoneValue(text) }}</span>
+            </template>
+          </a-table>
+        </template>
+        <template #createtime="{ record }">
+          <a>{{ formatTime(record.createtime) }}</a>
+        </template>
+        <!-- 现价 -->
+        <template #lastprice="{ record }">
+          <a>{{ getLastprice(record) }}</a>
+        </template>
+        <!-- 均价 -->
+        <template #averageprice="{ text }">
+          <a>{{ handleNoneValue(text) }}</a>
+        </template>
+        <!-- 持仓盈亏 -->
+        <template #profitloss="{ record }">
+          <span :class="[+useProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) > 0 ? 'up-quote-color' : +useProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) < 0 ? 'down-quote-color' : '']">{{ record.averageprice ? useProfitloss(record, findGoodsCode(record.goodsid, record.goodscode, swapList)) : '--' }}</span>
+        </template>
+        <template #buyorsell="{ record }">
+          <span>{{ getBuyOrSellName(record.buyorsell) }}</span>
+        </template>
+        <!-- <template #marketamount="{ record, text }">
+        <span>{{ isDiaoQi(record) ? '--' : text }}</span>
+      </template>-->
+      </a-table>
+    </template>
+  </mtp-table-scroll>
+  <component :is="componentId" v-if="componentId" :selectedRow="selectedRow" :tableList="positionList" :swapList="swapList" @cancel="clsoeAction"></component>
+</template>
+
+<script lang="ts">
+import MtpTableScroll from '@/common/components/tableScroll/index.vue';
+import { BtnListType } from '@/common/components/btnList/interface';
+import { TradeMode } from '@/common/constants/enumCommon';
+import { enumOrderComponents } from '@/common/constants/enumOrderComponents';
+import { getBuyOrSellName } from '@/common/constants/enumsName';
+import { BtnList, defineAsyncComponent, defineComponent, queryTableList } from '@/common/export/commonTable';
+import { formatTime } from '@/common/methods';
+import { handleDeliveryRelation } from '@/common/setup/deliveryRelation';
+import { getRecordItemTab } from '@/common/setup/order/orderData';
+import { expandIcon } from '@/common/setup/table/clolumn';
+import { handleComposeOrderTable } from '@/common/setup/table/compose';
+import { ComposeOrderTableParam } from '@/common/setup/table/interface';
+import { handleNoneValue, handleQuotePriceColor } from '@/common/setup/table/tableQuote';
+import { getQuoteDayInfoByCodeFindPrice } from '@/services/bus/goods';
+import { useHolderprice } from '@/services/bus/holdPosition';
+import { QueryTradePositionRsp } from '@/services/go/ermcp/order/interface';
+import Bus from '@/utils/eventBus/index';
+import { isInvestment } from '@/views/market/market-spot/spot_trade_order_transaction/spot_trade_order_transaction_swap/components/setup';
+import { useHazardRates } from '@/views/order/funding_information/components/funding_information_funding_summary/setup'
+import { findGoodsCode, getTableColums, useDetail } from './setup';
+
+
+export default defineComponent({
+  name: enumOrderComponents.commodity_contract_summary,
+  components: {
+    MtpTableScroll,
+    BtnList,
+    swap_commodity_contract_summary_deal_closed: defineAsyncComponent(() => import('./components/swap_commodity_contract_summary_deal_closed/index.vue')), // 协议平仓
+    swap_commodity_contract_summary_order_closed: defineAsyncComponent(() => import('./components/swap_commodity_contract_summary_order_closed/index.vue')), // 平仓
+  },
+  setup() {
+    const { positionList, swapList, getHoldsList, getSwapList, getTradeHolderDetail, useProfitloss } = useHazardRates();
+    // 表格列表数据
+    const { loading } = queryTableList<QueryTradePositionRsp>();
+    // 交割商品
+    handleDeliveryRelation();
+    getSwapList();
+
+    // 获取列表数据
+    const queryTableAction = () => getHoldsList(loading, TradeMode.DiaoQi.toString());
+
+    // 明细 逻辑
+    const { detailLoading, getDetailColums, getDetailProfitloss, getDetailMarketAmount } = useDetail();
+    // 表格通用逻辑
+    const param: ComposeOrderTableParam = {
+      queryFn: queryTableAction,
+      tableName: 'table_pcweb_spot_trade_bottom_commodity_contract_summary',
+      recordList: getRecordItemTab(),
+    };
+
+    // 现价
+    function getLastprice(record: QueryTradePositionRsp) {
+      let result: number | string = '--';
+      const goodscode = findGoodsCode(record.goodsid, record.goodscode, swapList.value);
+      if (goodscode) {
+        result = getQuoteDayInfoByCodeFindPrice(goodscode);
+      }
+      return result;
+    }
+
+    function handleBtnList(record: QueryTradePositionRsp, btnList: BtnListType[]) {
+      // 贸易圈
+      // 只有机构 才有平仓
+      const diaoqi = isInvestment() ? ['swap_commodity_contract_summary_deal_closed', 'swap_commodity_contract_summary_order_closed'] : ['swap_commodity_contract_summary_deal_closed'];
+      return btnList.filter((e) => diaoqi.includes(e.code));
+    }
+    const {
+      contextMenu, openContext, closeContext, // 右键
+      columns, registerColumn, updateColumn,  // 表头
+      expandedRowKeys, selectedRow, Rowclick, // 表格折腾面板数据与单击、双击事件
+      componentId, closeComponent, openComponent,  // 控制异步组件
+      btnList, // 表格按钮
+    } = handleComposeOrderTable<QueryTradePositionRsp>(param)
+    function clsoeAction(value: boolean) {
+      closeComponent(value)
+    }
+    Bus.$on('spotTrade', () => {
+      queryTableAction()
+    });
+    return {
+      contextMenu, openContext, closeContext, // 右键
+      columns, registerColumn, updateColumn,  // 表头
+      expandedRowKeys, selectedRow, Rowclick, // 表格折腾面板数据与单击、双击事件
+      componentId, closeComponent, openComponent,  // 控制异步组件
+      btnList, // 表格按钮
+      loading,
+      positionList,
+      formatTime,
+      expandIcon,
+      getLastprice,
+      useProfitloss,
+      useHolderprice,
+      handleBtnList,
+      getTableColums,
+      getBuyOrSellName,
+      swapList,
+      handleNoneValue,
+      detailLoading,
+      getDetailColums,
+      getTradeHolderDetail,
+      findGoodsCode,
+      getDetailProfitloss, getDetailMarketAmount, handleQuotePriceColor, clsoeAction
+    };
+  },
+});
+</script>
+
+<style lang="less">
+</style>;

+ 128 - 0
src/views/order/swap_the_order/components/swap_commodity_contract_summary/setup.ts

@@ -0,0 +1,128 @@
+// 获取最新价
+
+import { BuyOrSell, TradeMode } from "@/common/constants/enumCommon";
+import { queryResultLoadingAndInfo } from "@/common/methods/request/resultInfo";
+import { queryTableList } from "@/common/setup/table";
+import { useSetColumns } from "@/hooks/table/columns";
+import { ItemColumns } from "@/hooks/table/interface";
+import { findGoodsTradeModeById, getQuoteDayInfoByCodeFindPrice } from "@/services/bus/goods";
+import { getMarketIdsByTradeMode } from "@/services/bus/market";
+import { getUserAccountType, getUserId } from "@/services/bus/user";
+import { QueryTradePositionRsp } from "@/services/go/ermcp/order/interface";
+import { queryTradeHolderDetail } from "@/services/go/order";
+import { QueryTradeHolderDetailReq, QueryTradeHolderDetailRsp } from "@/services/go/order/interface";
+import { queryQuoteGoodsList } from "@/services/go/Tjmd";
+import { QueryQuoteGoodsListReq, QueryQuoteGoodsListRsp } from "@/services/go/Tjmd/interface";
+import { ref } from "vue";
+
+export const useIsDiaoQi = (goodsid: number) => {
+    return findGoodsTradeModeById(goodsid) === TradeMode.DiaoQi
+}
+
+
+// 商品掉期取参考行情最新价,挂牌点选取自己行情的最新价
+export function findGoodsCode(goodsid: number, goodscode: string, swapList: QueryQuoteGoodsListRsp[]) {
+    const result = useIsDiaoQi(goodsid) ? swapList.find((el) => el.goodsid === goodsid)?.refgoodscode : goodscode;
+    return result ? result : ''
+}
+
+export function getSwapList() {
+    const { loading, queryTable } = queryTableList<QueryQuoteGoodsListRsp>();
+    // 组装 参数
+    const marketids = getMarketIdsByTradeMode(TradeMode.DiaoQi)
+    const param: QueryQuoteGoodsListReq = {
+        usertype: getUserAccountType(),
+    }
+    if (marketids) {
+        param.marketids = marketids
+    }
+    return queryTable(queryQuoteGoodsList, param)
+}
+
+export function getTableColums() {
+    const list: ItemColumns[] = [
+        { key: 'goodsname', title: '订单合约' },
+        { key: 'buyorsell', title: '方向' },
+        { key: 'curpositionqty', title: '持有数量' },
+        { key: 'enableqty', title: '可用数量' },
+        { key: 'frozenqty', title: '冻结数量' },
+        { key: 'averageprice', title: '均价' },
+        { key: 'lastprice', title: '现价' },
+        { key: 'curholderamount', title: '持仓金额' },
+        // { key: 'marketamount', title: '市值' },
+        { key: 'profitloss', title: '浮动盈亏' },
+    ]
+    return useSetColumns(list)
+}
+
+// 明细
+export const useDetail = () => {
+    // 详情列表数据
+    const detailTableList = ref<QueryTradeHolderDetailRsp[]>([])
+    // 详情 loading
+    const detailLoading = ref<boolean>(false)
+    // 获取明细
+    function getTradeHolderDetail({ accountid, trademode, marketid, goodsid, buyorsell }: QueryTradePositionRsp) {
+        const param: QueryTradeHolderDetailReq = {
+            userid: getUserId(),
+            accids: accountid.toString(),
+            trademodes: trademode.toString(),
+            marketids: marketid.toString(),
+            goodsid,
+            buyorsell,
+        }
+        queryResultLoadingAndInfo(queryTradeHolderDetail, detailLoading, param).then(res => {
+            detailTableList.value = res
+        })
+    }
+
+    // 表头
+    function getDetailColums() {
+        const list: ItemColumns[] = [
+            { key: 'tradetime', title: '建仓时间', width: 140 },
+            { key: 'expiredate', title: '到期日' },
+            { key: 'openqty', title: '建仓数量' },
+            { key: 'holderqty', title: '可用数量' },
+            { key: 'freezeqty', title: '冻结数量' },
+            { key: 'openprice', title: '建仓价' },
+            { key: 'tradeid', title: '持仓单号', width: 160 },
+            { key: 'holderamount', title: '建仓金额' },
+            // { key: 'marketamount', title: '市值' },
+            { key: 'profitloss', title: '浮动盈亏' },
+            { key: 'operate', title: '操作', width: 160 },
+        ]
+        return useSetColumns(list)
+    }
+
+    // 计算 明细列表里 具体一条数据的 市值
+    // 市值(所有权) = 数量 * 现价 * 合约单位
+    function getDetailMarketAmount(record: QueryTradeHolderDetailRsp) {
+        // 最新价
+        const lastPrice = getQuoteDayInfoByCodeFindPrice(record.goodscode);
+        if (lastPrice !== '--') {
+            const { decimalplace, agreeunit, holderqty } = record;
+            return (+lastPrice * holderqty * agreeunit).toFixed(decimalplace);
+        } else {
+            return lastPrice
+        }
+    }
+    // 计算 明细列表里 具体一条数据的 浮动盈亏
+    // 持仓盈亏
+    // 浮动盈亏	持仓单:
+    // 收益权=(最新价-持仓价)*持仓数量*合约单位*方向(买[1]:卖[-1])(*汇率)
+    // 所有权=(最新价*持仓数量*合约单位(*汇率) - 持仓金额)
+    function getDetailProfitloss(record: QueryTradeHolderDetailRsp, goodscode: string) {
+        // 最新价
+        const lastPrice = getQuoteDayInfoByCodeFindPrice(goodscode);
+        if (lastPrice !== '--') {
+            const { holderprice, decimalplace, agreeunit, holderqty, buyorsell } = record;
+            const temp = buyorsell === BuyOrSell.buy ? 1 : -1
+            const result = ((+lastPrice - holderprice) * holderqty * agreeunit * temp).toFixed(decimalplace);
+            return result === '-0' ? '0' : result
+        } else {
+            return lastPrice;
+        }
+    }
+
+    return { getTradeHolderDetail, detailLoading, getDetailColums, detailTableList, getDetailProfitloss, getDetailMarketAmount }
+}

+ 45 - 0
src/views/order/swap_the_order/index.vue

@@ -0,0 +1,45 @@
+<!-- 无用组件,待废弃 -->
+<template>
+  <!-- 掉期订单 -->
+  <section class="spot_warran">
+    <component :is="componentId" v-if="componentId"></component>
+    <thirdMenu :list="tabList" @selectMenu="changeTab" :value="'title'">
+      <!-- 议价单 -->
+      <div class="goods-apply" v-if="componentId === BARGIN">
+        <a-radio-group class="conditionCommonRadioGroup" v-model:value="bargainValue">
+          <a-radio @focus="changeBargain(ApplyType.my)" :value="ApplyType.my">我的申请</a-radio>
+          <a-radio @focus="changeBargain(ApplyType.counterpart)" :value="ApplyType.counterpart">对方申请</a-radio>
+        </a-radio-group>
+      </div>
+    </thirdMenu>
+  </section>
+</template>
+
+<script lang="ts">
+import { defineAsyncComponent, defineComponent, ref } from 'vue';
+import { enumOrderComponents } from '@/common/constants/enumOrderComponents';
+import thirdMenu from '@/common/components/thirdMenu/index.vue';
+import { handleOrderDetailList } from '@/common/setup/order/orderData';
+import Bus from '@/utils/eventBus/index';
+import { ApplyType } from '@/common/constants/enumCommon';
+
+const BARGIN = 'swap_commodity_contract_bargain';
+
+export default defineComponent({
+  components: {
+    thirdMenu,
+    swap_commodity_contract_summary: defineAsyncComponent(() => import('./components/swap_commodity_contract_summary/index.vue')), // 合约汇总
+    swap_commodity_contract_commission: defineAsyncComponent(() => import('./components/swap_commodity_contract_commission/index.vue')), // 委托
+    swap_commodity_contract_make_deal: defineAsyncComponent(() => import('./components/swap_commodity_contract_make_deal/index.vue')), // 成交
+    [BARGIN]: defineAsyncComponent(() => import('./components/swap_commodity_contract_bargain/index.vue')), // 议价单
+  },
+  setup() {
+    // 切换 我的
+    function changeBargain(value: ApplyType) {
+      Bus.$emit('bargain', value);
+    }
+    const bargainValue = ref<ApplyType>(ApplyType.my);
+    return { ...handleOrderDetailList('swap_the_order'), changeBargain, BARGIN, ApplyType, bargainValue };
+  },
+});
+</script>