Handy_Cao 1 год назад
Родитель
Сommit
76047ba65b

+ 82 - 0
public/config/columns.json

@@ -221,6 +221,88 @@
         ]
     },
     {
+        "tableKey": "pricing-order",
+        "columns": [
+            {
+                "field": "goodsname",
+                "label": "商品代码/名称"
+            },
+            {
+                "field": "buyorsell",
+                "label": "方向"
+            },
+            {
+                "field": "orderqty",
+                "label": "委托数量"
+            },
+            {
+                "field": "orderprice",
+                "label": "委托价格"
+            },
+            {
+                "field": "tradeqty",
+                "label": "成交数量"
+            },
+            {
+                "field": "orderstatus",
+                "label": "委托状态"
+            },
+            {
+                "field": "ordertime",
+                "label": "委托时间"
+            },
+            {
+                "field": "orderid",
+                "label": "委托单号"
+            }
+        ]
+    },
+    {
+        "tableKey": "pricing-trade",
+        "columns": [
+            {
+                "field": "goodsname",
+                "label": "商品代码/名称"
+            },
+            {
+                "field": "buildtype",
+                "label": "类型"
+            },
+            {
+                "field": "buyorsell",
+                "label": "方向"
+            },
+            {
+                "field": "tradeprice",
+                "label": "成交价格"
+            },
+            {
+                "field": "tradeqty",
+                "label": "成交数量"
+            },
+            {
+                "field": "tradeamount",
+                "label": "成交金额"
+            },
+            {
+                "field": "closepl",
+                "label": "平仓损益"
+            },
+            {
+                "field": "charge",
+                "label": "手续费"
+            },
+            {
+                "field": "tradetime",
+                "label": "成交时间"
+            },
+            {
+                "field": "tradeid",
+                "label": "成交单号"
+            }
+        ]
+    },
+    {
         "tableKey": "swap-order",
         "columns": [
             {

+ 82 - 2
public/config/router.json

@@ -156,6 +156,36 @@
             {
                 "authType": 2,
                 "sort": 4,
+                "title": "挂牌点价",
+                "code": "bottom_pricing",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "持仓汇总",
+                        "code": "bottom_pricing_position",
+                        "component": "views/footer/pricing/position/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "委托",
+                        "code": "bottom_pricing_order",
+                        "component": "views/footer/pricing/order/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
+                        "title": "成交",
+                        "code": "bottom_pricing_trade",
+                        "component": "views/footer/pricing/trade/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 2,
+                "sort": 5,
                 "title": "掉期市场",
                 "code": "bottom_swap",
                 "component": "views/footer/index.vue",
@@ -185,7 +215,7 @@
             },
             {
                 "authType": 2,
-                "sort": 5,
+                "sort": 6,
                 "title": "履约信息",
                 "code": "bottom_performance",
                 "component": "views/footer/index.vue",
@@ -231,7 +261,7 @@
             },
             {
                 "authType": 2,
-                "sort": 6,
+                "sort": 8,
                 "title": "资金信息",
                 "code": "bottom_capital",
                 "component": "views/footer/index.vue",
@@ -393,6 +423,31 @@
                     {
                         "authType": 1,
                         "sort": 4,
+                        "title": "挂牌点价",
+                        "code": "query_order_pricing",
+                        "url": "pricing",
+                        "urlType": 1,
+                        "component": "views/query/order/pricing/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_order_pricing_list",
+                                "component": "views/query/order/pricing/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_order_pricing_history",
+                                "component": "views/query/order/pricing/history/index.vue"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 1,
+                        "sort": 5,
                         "title": "掉期市场",
                         "code": "query_order_swap",
                         "url": "swap",
@@ -504,6 +559,31 @@
                     {
                         "authType": 1,
                         "sort": 4,
+                        "title": "挂牌点价",
+                        "code": "query_trade_pricing",
+                        "url": "pricing",
+                        "urlType": 1,
+                        "component": "views/query/trade/pricing/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_trade_pricing_list",
+                                "component": "views/query/trade/pricing/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_trade_pricing_history",
+                                "component": "views/query/trade/pricing/history/index.vue"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 1,
+                        "sort": 5,
                         "title": "掉期市场",
                         "code": "query_trade_swap",
                         "url": "swap",

+ 2 - 0
src/packages/pc/components/layouts/footer/index.vue

@@ -44,6 +44,7 @@
                 </template>
                 <component :is="GoodsListing" v-if="globalStore.showGoodsListing" />
                 <component :is="TransferListing" v-if="globalStore.showTransferListing" />
+                <component :is="PricingListing" v-if="globalStore.showPricingListing" />
             </app-auth-component>
         </div>
     </div>
@@ -56,6 +57,7 @@ import AppAuthComponent from '@pc/components/modules/auth-component/index.vue'
 
 const GoodsListing = defineAsyncComponent(() => import('@pc/views/market/trade/goods/list/listing/index.vue')) // 订单挂牌
 const TransferListing = defineAsyncComponent(() => import('@pc/views/market/trade/presell/transfer/listing/index.vue')) // 转让挂牌
+const PricingListing = defineAsyncComponent(() => import('@pc/views/market/trade/pricing/list/listing/index.vue')) // 挂牌点价
 
 const emit = defineEmits(['tabChange'])
 const globalStore = useGlobalStore()

+ 1 - 1
src/packages/pc/components/modules/goods-detail/index.vue

@@ -20,7 +20,7 @@
                             </span>
                         </template>
                         <slot name="headerRight"></slot>
-                        <template v-if="![50, 99].includes(quote?.trademode ?? 0)">
+                        <template v-if="![50, 99, 10].includes(quote?.trademode ?? 0)">
                             <el-button type="primary" @click="active = false" v-if="active">买卖大厅</el-button>
                             <el-button type="primary" @click="active = true" v-else>图表</el-button>
                         </template>

+ 48 - 0
src/packages/pc/views/footer/pricing/order/cancel/index.vue

@@ -0,0 +1,48 @@
+<!-- 挂牌点价-挂单-撤销 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认要撤销吗?</div>
+        <template #footer>
+            <el-button type="info" @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onCancelSumit()">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { useCancelOrder } from '@/business/trade'
+import { handleRequestBigNumber } from '@/filters'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.TradeOrderDetailRsp>,
+        required: true
+    }
+})
+
+const { cancelSubmit, formData, loading } = useCancelOrder()
+
+const show = ref(true)
+const refresh = ref(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onCancelSumit = () => {
+    /// 市场ID
+    formData.Header = { MarketID: props.selectedRow.marketid, GoodsID: props.selectedRow.goodsid }
+    formData.OldOrderId = handleRequestBigNumber(props.selectedRow.orderid)
+    /// 提交
+    cancelSubmit().then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+    })
+}
+</script>

+ 78 - 0
src/packages/pc/views/footer/pricing/order/index.vue

@@ -0,0 +1,78 @@
+<!-- 挂牌点价-委托 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey"
+        :expand-row-keys="expandKeys" @row-click="rowClick">
+        <!-- 商品代码/名称 -->
+        <template #wrtradetype="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+         <!-- 方向 -->
+         <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 类型 -->
+        <template #pricemode="{ value }">
+            {{ value === 2 ? '固定价' : '浮动价' }}
+        </template>
+        <!-- 委托状态 -->
+        <template #orderstatus="{ value }">
+            {{ getWRTradeOrderStatusName(value) }}
+        </template>
+        <!-- 委托时间 -->
+        <template #ordertime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+        <!-- 展开行 -->
+        <template #expand="{ row }">
+            <div class="buttonbar">
+                <el-button type="danger" v-if="[3, 7].includes(row.orderstatus)" size="small"
+                    @click="showComponent('cancel', row)">撤销</el-button>
+            </div>
+        </template>
+        <template #footer>
+            <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)"
+                @closed="closeComponent" v-if="componentId" />
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { formatDate } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { queryTradeOrderDetail } from '@/services/api/order'
+import { useComponent } from '@/hooks/component'
+import { getWRTradeOrderStatusName, getBuyOrSellName } from '@/constants/order'
+import { useComposeTable } from '@pc/components/base/table'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const componentMap = new Map<string, unknown>([
+    ['cancel', defineAsyncComponent(() => import('./cancel/index.vue'))],
+])
+
+const { getTableColumns } = useTableColumnsStore()
+const tableColumns = shallowRef<Model.TableColumn[]>([])
+
+const { loading, dataList, run } = useRequest(queryTradeOrderDetail, {
+    params: {
+        tradeMode: '10'
+    },
+})
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    run()
+})
+
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.TradeOrderDetailRsp>({ rowKey: 'orderid' })
+const selectedRow = shallowRef<Model.TradeOrderDetailRsp>()
+
+const showComponent = (componentName: string, row: Model.TradeOrderDetailRsp) => {
+    selectedRow.value = row
+    openComponent(componentName)
+}
+
+getTableColumns('swap-order').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 137 - 0
src/packages/pc/views/footer/pricing/position/close/index.vue

@@ -0,0 +1,137 @@
+<!-- 掉期市场-持仓汇总-平仓 -->
+<template>
+    <app-drawer :title="`${position.goodscode}/${position.goodsname}`" v-model:show="show" :width="1100" :loading="loading"
+        :refresh="refresh">
+        <app-table :data="computedList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey"
+            :expand-row-keys="expandKeys" @row-click="rowClick">
+            <!-- 方向 -->
+            <template #buyorsell="{ value }">
+                {{ getBuyOrSellName(value) }}
+            </template>
+            <!-- 持仓金额 -->
+            <template #holderamount="{ value }">
+                {{ formatDecimal(value) }}
+            </template>
+            <!-- 可用数量 -->
+            <template #enableqty="{ row }">
+                {{ row.holderqty - row.freezeqty }}
+            </template>
+            <!-- 到期日 -->
+            <template #expiredate="{ value }">
+                {{ formatDate(value, 'YYYY/MM/DD') }}
+            </template>
+            <!-- 平仓盈亏 -->
+            <template #closepl="{ row }">
+                <span :class="handlePriceColor(row.closepl)">{{ formatDecimal(row.closepl, quote?.decimalplace) }}</span>
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <div class="buttonbar" v-if="useStore.userType === 5 && [1, 3].includes(quote?.goodstradetype ?? 0)">
+                    <el-button type="danger" size="small" @click="onCloseSubmit(row)">平仓</el-button>
+                </div>
+                <span v-else>--</span>
+            </template>
+        </app-table>
+        <template #footer>
+            <el-button type="info" @click="show = false">取消</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, ref, PropType, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useComposeTable } from '@pc/components/base/table'
+import { useRequest } from '@/hooks/request'
+import { useHolderClose } from '@/business/trade'
+import { queryTradeHolderDetail } from '@/services/api/order'
+import { formatDate, formatDecimal, handlePriceColor, handleRequestBigNumber, round } from '@/filters'
+import { getBuyOrSellName } from '@/constants/order'
+import { ETradeMode } from '@/constants/client'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import { useFuturesStore, useUserStore } from '@/stores'
+import { BuyOrSell } from '@/constants/order'
+
+const props = defineProps({
+    position: {
+        type: Object as PropType<Model.TradePositionRsp>,
+        required: true,
+    }
+})
+
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.TradeHolderDetailRsp>({ rowKey: 'tradeid' })
+
+const { holderCloseSubmit, formData } = useHolderClose()
+const show = ref(true)
+const refresh = ref(false)
+const useStore = useUserStore()
+const futuresStore = useFuturesStore()
+
+const refQuote = futuresStore.getGoodsQuote(props.position.refgoodscode)
+const quote = futuresStore.getGoodsQuote(props.position.goodscode)
+
+const { dataList, loading, run } = useRequest(queryTradeHolderDetail, {
+    params: {
+        /// 交易模式, 格式 1,2,3
+        trademodes: ETradeMode.TRADEMODE_TJMD.toString(),
+        /// marketid
+        marketids: props.position.marketid.toString(),
+        /// 商品id
+        goodsid: props.position.goodsid,
+        /// 买卖方向 0-买 1-卖
+        buyorsell: props.position.buyorsell
+    }
+})
+
+const computedList = computed(() => dataList.value.map((item) => {
+    const last = refQuote.value?.last || quote.value?.last || 0 // 有 refgoodscode 的优先取 refgoodscode 行情
+    const presettle = quote.value?.presettle || 0
+    const price = last || presettle // 没有最新价取昨结价
+
+    // 计算市值 = 现价 * 数量 * 合约单位
+    const marketValue = price ? price * item.holderqty * item.agreeunit : 0
+    const roundedMarketValue = round(marketValue, quote.value?.decimalplace)
+    // 计算浮动盈亏
+    const closepl = price ? (roundedMarketValue - item.holderamount) * (item.buyorsell === BuyOrSell.Buy ? 1 : -1) : 0
+
+    return {
+        ...item,
+        closepl
+    }
+}))
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'tradeid', label: '单号' },
+    { field: 'buyorsell', label: '方向' },
+    { field: 'holderqty', label: '持有量' },
+    { field: 'freezeqty', label: '冻结量' },
+    { field: 'enableqty', label: '可用量' },
+    { field: 'holderprice', label: '订单价格' },
+    { field: 'holderamount', label: '订单金额' },
+    { field: 'closepl', label: '参考损益' },
+    { field: 'expiredate', label: '到期日' },
+    { field: 'operate', label: '操作', fixed: 'right', width: 100 }
+])
+
+const onCloseSubmit = (row: Model.TradeHolderDetailRsp) => {
+    ElMessageBox.confirm(
+        '是否立即平仓?',
+        '提示'
+    ).then(() => {
+        const { marketid, goodsid, buyorsell, tradeid } = row
+        formData.Header = { MarketID: marketid, GoodsID: goodsid }
+        formData.GoodsID = goodsid
+        formData.BuyOrSell = buyorsell
+        formData.MarketID = marketid
+        formData.TradeID = handleRequestBigNumber(tradeid)
+
+        holderCloseSubmit().then(() => {
+            ElMessage.success('提交成功')
+            run()
+        }).catch((err) => {
+            ElMessage.error('提交失败:' + err)
+        })
+    })
+}
+</script>

+ 76 - 0
src/packages/pc/views/footer/pricing/position/index.vue

@@ -0,0 +1,76 @@
+<!-- 挂牌点价-持仓汇总 -->
+<template>
+    <app-table :data="positionList" v-model:columns="tableColumns" :loading="positionStore.loading" :row-key="rowKey"
+        :expand-row-keys="expandKeys" @row-click="rowClick">
+        <!-- 商品代码/名称 -->
+        <template #wrtradetype="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 方向 -->
+        <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 最新价 -->
+        <template #lastprice="{ row }">
+            <span :class="row.lastColor">
+                {{ handleNumberValue(row.lastprice) }}
+            </span>
+        </template>
+        <!-- 持仓均价 -->
+        <template #averageprice="{ value }">
+            {{ handleNumberValue(formatDecimal(value)) }}
+        </template>
+        <!-- 浮动盈亏-->
+        <template #closepl="{ row }">
+            <span :class="row.closeplColor">{{ formatDecimal(row.closepl, row.decimalplace) }}</span>
+        </template>
+        <!-- 展开行 -->
+        <template #expand="{ row }">
+            <div class="buttonbar">
+                <el-button type="danger" size="small" @click="showComponent('close', row)">明细</el-button>
+            </div>
+        </template>
+        <!-- <template #footer>
+            <component ref="componentRef" v-bind="{ position: selectedRow }" :is="componentMap.get(componentId)"
+                @closed="closeComponent" v-if="componentId" />
+        </template> -->
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, computed } from 'vue'
+import { formatDecimal, handleNumberValue } from '@/filters'
+// import { useComponent } from '@/hooks/component'
+import { getBuyOrSellName } from '@/constants/order'
+import { useComposeTable } from '@pc/components/base/table'
+import { usePositionStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+
+// const componentMap = new Map<string, unknown>([
+//     ['close', defineAsyncComponent(() => import('./close/index.vue'))],
+// ])
+
+const positionStore = usePositionStore()
+// const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.TradePositionRsp>({ rowKey: 'pkid' })
+const selectedRow = shallowRef<Model.TradePositionRsp>()
+
+const positionList = computed(() => positionStore.getPositionListByTradeMode(10))
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'goodsname', label: '商品代码/名称' },
+    { field: 'buyorsell', label: '方向' },
+    { field: 'curpositionqty', label: '持有量' },
+    { field: 'lastprice', label: '现价' },
+    { field: 'averageprice', label: '订单价格' },
+    { field: 'frozenqty', label: '冻结量' },
+    { field: 'curholderamount', label: '订单总额' },
+    { field: 'enableqty', label: '可用量' },
+    { field: 'closepl', label: '参考损益' }
+])
+
+const showComponent = (componentName: string, row: Model.TradePositionRsp) => {
+    selectedRow.value = row
+    // openComponent(componentName)
+}
+</script>

+ 44 - 0
src/packages/pc/views/footer/pricing/trade/index.vue

@@ -0,0 +1,44 @@
+<!-- 挂牌点价-成交 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <!-- 类型 -->
+        <template #buildtype="{ value }">
+            {{ getBuildTypeName(value) }}
+        </template>
+         <!-- 方向 -->
+         <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 商品合约 -->
+        <template #goodsname="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 时间 -->
+        <template #tradetime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { formatDate } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { queryTradeDetail } from '@/services/api/order'
+import { getBuildTypeName, getBuyOrSellName } from '@/constants/order'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const { getTableColumns } = useTableColumnsStore()
+const tableColumns = shallowRef<Model.TableColumn[]>([])
+
+const { loading, dataList } = useRequest(queryTradeDetail, {
+    params: {
+        tradeMode: '10'
+    },
+})
+
+getTableColumns('pricing-trade').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 1 - 0
src/packages/pc/views/market/trade/index.vue

@@ -23,6 +23,7 @@ const componentMap = new Map<string, unknown>([
     ['tradeModel_17', defineAsyncComponent(() => import('./spot/index.vue'))], // 现货挂牌
     ['tradeModel_46', defineAsyncComponent(() => import('./swap/index.vue'))], // 掉期市场
     ['tradeModel_99', defineAsyncComponent(() => import('./market/index.vue'))], // 参考行情
+    ['tradeModel_10', defineAsyncComponent(() => import('./pricing/index.vue'))], // 挂牌点价
 ])
 
 const futuresStore = useFuturesStore()

+ 132 - 0
src/packages/pc/views/market/trade/pricing/index.vue

@@ -0,0 +1,132 @@
+<!-- 交易市场 - 掉期市场 -->
+<template>
+    <app-table :data="tableList" v-model:columns="tableColumns" @row-click="onRowClick" showIndex>
+        <!-- 当前价 -->
+        <template #last="{ row }">
+            <span :class="row.lastColor">{{ row.last }}</span>
+        </template>
+        <!-- 涨跌 -->
+        <template #rise="{ row }">
+            <span :class="row.lastColor">{{ row.rise }}</span>
+        </template>
+        <!-- 幅度 -->
+        <template #change="{ row }">
+            <span :class="row.lastColor">{{ row.change }}</span>
+        </template>
+        <!-- 今开 -->
+        <template #opened="{ row }">
+            <span :class="row.openedColor">{{ row.opened }}</span>
+        </template>
+        <!-- 最低 -->
+        <template #lowest="{ row }">
+            <span :class="row.lowestColor">{{ row.lowest }}</span>
+        </template>
+        <!-- 最高 -->
+        <template #highest="{ row }">
+            <span :class="row.highestColor">{{ row.highest }}</span>
+        </template>
+        <!-- 买价 -->
+        <template #ask="{ row }">
+            <span :class="row.askColor">{{ row.ask }}</span>
+        </template>
+        <!-- 卖价 -->
+        <template #bid="{ row }">
+            <span :class="row.bidColor">{{ row.bid }}</span>
+        </template>
+        <template #footer>
+            <component ref="componentRef" v-bind="{ goodsId: futuresStore.selectedGoodsId }"
+                :is="componentMap.get(componentId)" @closed="closeComponent" v-if="componentId" />
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onMounted, onUnmounted, defineAsyncComponent, computed } from 'vue'
+import { useComponent } from '@/hooks/component'
+import { parsePercent, handleNumberValue, formatDecimal } from '@/filters'
+import { useFuturesStore, useUserStore, useGlobalStore } from '@/stores'
+import { useRequest } from '@/hooks/request'
+import { queryQuoteGoodsList } from '@/services/api/swap'
+import quoteSocket from '@/services/websocket/quote'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const subscribe = quoteSocket.createSubscribe()
+const futuresStore = useFuturesStore()
+const userStore = useUserStore()
+const globalStore = useGlobalStore()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => true, false)
+
+const componentMap = new Map<string, unknown>([
+    ['detail', defineAsyncComponent(() => import('@pc/components/modules/goods-detail/index.vue'))], // 详情
+])
+
+const { dataList, run } = useRequest(queryQuoteGoodsList, {
+    manual: true,
+    params: {
+        usertype: userStore.userType ?? 0,
+        marketids: '10101'
+    },
+    onSuccess: (res) => {
+        const goodsCodes = res.data.map((e) => e.goodscode)
+        subscribe.start(...goodsCodes)
+    }
+})
+
+const tableList = computed(() => {
+    return dataList.value.map((item ) => {
+        const quote = futuresStore.getGoodsQuote(item.goodscode)
+        const { lastColor, openedColor, lowestColor, highestColor, last = 0, presettle = 0, rise = 0, change, amplitude, highest = 0, lowest = 0, opened = 0, ask = 0, bid = 0, bidColor, askColor, decimalplace } = quote.value ?? {}
+        return {
+            ...item,
+            lastColor,
+            openedColor,
+            lowestColor,
+            highestColor,
+            last: handleNumberValue(formatDecimal(last, decimalplace)),
+            rise: handleNumberValue(formatDecimal(rise, decimalplace)),
+            change: parsePercent(change),
+            opened: handleNumberValue(formatDecimal(opened, decimalplace)),
+            presettle: handleNumberValue(formatDecimal(presettle, decimalplace)),
+            lowest: handleNumberValue(formatDecimal(lowest, decimalplace)),
+            highest: handleNumberValue(formatDecimal(highest, decimalplace)),
+            amplitude: parsePercent(amplitude),
+            ask: handleNumberValue(formatDecimal(ask, decimalplace)),
+            bid: handleNumberValue(formatDecimal(bid, decimalplace)),
+            bidColor,
+            askColor
+        }
+    })
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'goodsname', label: '商品/标的' },
+    { field: 'last', label: '当前价' },
+    { field: 'ask', label: '买价' },
+    { field: 'bid', label: '卖价' },
+    { field: 'rise', label: '涨跌' },
+    { field: 'change', label: '幅度' },
+    { field: 'opened', label: '今开' },
+    { field: 'presettle', label: '昨结' },
+    { field: 'lowest', label: '最低' },
+    { field: 'highest', label: '最高' },
+    { field: 'amplitude', label: '振幅' },
+])
+
+const onRowClick = (row: Model.GoodsQuote) => {
+    futuresStore.selectedGoodsId = row.goodsid
+    openComponent('detail')
+}
+
+futuresStore.onDataCompleted(() => run())
+
+onMounted(() => {
+    globalStore.showPricingListing = true
+})
+
+onUnmounted(() => {
+    globalStore.showPricingListing = false
+})
+
+onUnmounted(() => subscribe.stop())
+</script>

+ 48 - 0
src/packages/pc/views/market/trade/pricing/list/listing/index.less

@@ -0,0 +1,48 @@
+.pricing-listing {
+    display: flex;
+    height: 100%;
+    background-color: #14181B;
+
+    &__forex {
+        width: 200px;
+        padding: 5px 10px;
+        border-left: 1px solid #363f45;
+
+        .app-quote-forex {
+            height: 100%;
+
+            li {
+                cursor: pointer;
+                padding: 5px;
+            }
+        }
+    }
+
+    &__form {
+        width: 300px;
+        padding: 10px;
+        border-left: 1px solid #363f45;
+
+        .el-form {
+            padding: 0;
+        }
+
+        .header-title {
+            text-align: center;
+            margin-bottom: 10px;
+        }
+
+        .row-price {
+            display: flex;
+            align-items: center;
+            font-size: 12px;
+            line-height: normal;
+        }
+
+        .footer-btnbar {
+            .el-button {
+                flex: 1;
+            }
+        }
+    }
+}

+ 367 - 0
src/packages/pc/views/market/trade/pricing/list/listing/index.vue

@@ -0,0 +1,367 @@
+<template>
+    <div class="pricing-listing">
+        <div class="pricing-listing__forex" v-if="selectedGoods">
+            <Forex v-bind="{ goodsCode: selectedGoods.goodscode }" @price-click="onPriceClick" />
+        </div>
+        <div class="pricing-listing__form">
+            <h4 class="header-title">挂牌点价</h4>
+            <el-form ref="formRef" class="el-form--vertical" label-width="60px" :show-message="false" :model="formData"
+                :rules="formRules">
+                <el-form-item prop="GoodsID" label="商品">
+                    <el-select effect="dark" placeholder="请选择" v-model="selectedGoodsId" filterable>
+                        <el-option :label="item.goodsname" :value="item.goodsid" v-for="(item, index) in marketGoodsList"
+                            :key="index" />
+                    </el-select>
+                </el-form-item>
+                <el-form-item prop="BuyOrSell" label="方向">
+                    <el-radio-group v-model="formData.BuyOrSell">
+                        <el-radio v-for="(item, index) in getBuyOrSellList()" :key="index" :label="item.value">
+                            {{ item.label }}
+                        </el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item prop="PriceMode" label="方式">
+                    <el-radio-group v-model="formData.PriceMode">
+                        <el-radio v-for="(item, index) in getPricemode2List()" :key="index" :label="item.value">
+                            {{ item.label }}
+                        </el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item prop="OrderPrice" label="价格" v-if="formData.PriceMode === PriceMode.Market">
+                    <div class="el-form-item--col">
+                        <span>{{ marketPrice.toFixed(decimalplace) }}</span>
+                        <div v-if="selectedGoods">
+                            <div class="row-price g-price-up">
+                                <Icon icon="Top" />
+                                <span>{{ selectedGoods.limitup.toFixed(decimalplace) }}</span>
+                            </div>
+                            <div class="row-price g-price-down">
+                                <Icon icon="Bottom" />
+                                <span>{{ selectedGoods.limitdown.toFixed(decimalplace) }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </el-form-item>
+                <el-form-item prop="MarketMaxSub" label="点差" v-if="formData.PriceMode === PriceMode.Market">
+                    <el-input-number ref="priceRef" placeholder="请输入" :min="0" :max="9999999999" v-model="formData.MarketMaxSub" 
+                    @keyup.enter="submitFocus" integer />
+                </el-form-item>
+                <el-form-item prop="OrderPrice" label="价格" v-if="formData.PriceMode === PriceMode.Limit">
+                    <el-input-number ref="priceRef" placeholder="请输入" :max="9999999999" :min="0" v-model="formData.OrderPrice" 
+                     :auto-fixed="false" :decimal-length="decimalplace" :step="decimalvalue" @keyup.enter="submitFocus" />
+                </el-form-item>
+                <el-form-item prop="OrderQty" label="数量">
+                    <div class="g-qty-group">
+                        <el-input-number ref="qtyRef" placeholder="请输入" :min="0" :max="9999999999" :precision="0" :step="qtyStep || 1"
+                            v-model="formData.OrderQty" @keyup.enter="submitFocus" />
+                        <el-radio-group size="small" v-model="qtyStep" :validate-event="false" @change="onRadioChange">
+                            <el-radio v-for="(value, index) in qtyStepList" :key="index" :label="value" border />
+                        </el-radio-group>
+                        <template
+                            v-if="(formData.BuyOrSell === BuyOrSell.Buy || selectedGoods?.tradeproperty !== 2) && settingStore.getSettingValue('showOrderEnableQty')">
+                            <div
+                                style="display: flex;flex-direction: column;line-height: normal;font-size: 12px;color: #7a8a94;">
+                                <span>预估可订立量:{{ total.enableQty }}</span>
+                                <span>预扣保证金:{{ total.deposit.toFixed(2) }}</span>
+                                <span>可用资金:{{ accountStore.currentAccount.avaiableMoney?.toFixed(2) }}</span>
+                            </div>
+                        </template>
+                    </div>
+                </el-form-item>
+                <el-form-item class="footer-btnbar">
+                    <template v-if="formData.BuyOrSell === BuyOrSell.Buy">
+                        <el-button ref="submitRef" type="danger" :disabled="!selectedGoodsId || !formData.OrderQty"
+                            @click="onBeforeSubmit(BuildType.Open)"
+                            v-if="!selectedGoods?.iscannotbuy">订立</el-button>
+                        <el-button type="primary"
+                            :disabled="!formData.OrderQty || !sellQty || (formData.OrderQty > sellQty)"
+                            @click="onBeforeSubmit(BuildType.Close)" v-if="!isTrademode16">
+                            <span>转让</span>
+                            <span v-if="sellQty">(≤{{ sellQty }})</span>
+                        </el-button>
+                    </template>
+                    <template v-if="formData.BuyOrSell === BuyOrSell.Sell">
+                        <el-button ref="submitRef" type="success" :disabled="!selectedGoodsId || !formData.OrderQty"
+                            @click="onBeforeSubmit(BuildType.Open)"
+                            v-if="!isTrademode16 && !selectedGoods?.iscannotsell">订立</el-button>
+                        <el-button type="primary" :disabled="!formData.OrderQty || !buyQty || (formData.OrderQty > buyQty)"
+                            @click="onBeforeSubmit(BuildType.Close)">
+                            <span>转让</span>
+                            <span v-if="buyQty">(≤{{ buyQty }})</span>
+                        </el-button>
+                    </template>
+                </el-form-item>
+            </el-form> 
+        </div>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, computed, watch, onMounted } from 'vue'
+import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
+import { BuyOrSell, getBuyOrSellList, getPricemode2List, PriceMode, BuildType } from '@/constants/order'
+import { useOrder } from '@/business/trade'
+import { useFuturesStore, useSettingStore, useAccountStore, usePositionStore } from '@/stores'
+import Forex from '@pc/components/modules/quote/forex/index.vue'
+import Icon from '@pc/components/base/icon/index.vue'
+
+const accountStore = useAccountStore()
+const settingStore = useSettingStore()
+const futuresStore = useFuturesStore()
+
+const { selectedGoodsId, selectedGoods, marketGoodsList } = futuresStore.$toRefs()
+const { formData, formSubmit, loading } = useOrder()
+const positionStore = usePositionStore()
+const formRef = shallowRef<FormInstance>()
+const qtyStepList = [1, 10, 100] // 数量步长列表
+const qtyStep = shallowRef(qtyStepList[0]) // 数量步长
+
+const priceRef = shallowRef()
+const qtyRef = shallowRef()
+const submitRef = shallowRef()
+
+const marketPrice = computed(() => {
+    const { ask = 0, bid = 0 } = selectedGoods.value ?? {}
+    return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+})
+
+const isTrademode16 = computed(() => selectedGoods.value?.trademode === 16)
+
+const total = computed(() => {
+    const { avaiableMoney = 0 } = accountStore.currentAccount
+    const { marketmarginalgorithm = 0, marketmarginvalue = 0, agreeunit = 0 } = selectedGoods.value ?? {}
+
+    const result = {
+        enableQty: 0,
+        deposit: 0
+    }
+
+    const fixed = agreeunit * marketmarginvalue
+    const ratio = fixed * (formData.OrderPrice ?? 0)
+
+    if (fixed && ratio) {
+        if (marketmarginalgorithm === 1) {
+            const qty = Math.trunc(avaiableMoney / ratio)
+            result.deposit = (formData.OrderQty ?? 0) * ratio
+            result.enableQty = qty > 0 ? qty : 0
+        }
+        if (marketmarginalgorithm === 2) {
+            const qty = Math.trunc(avaiableMoney / fixed)
+            result.deposit = (formData.OrderQty ?? 0) * fixed
+            result.enableQty = qty > 0 ? qty : 0
+        }
+    }
+    return result
+})
+
+const position = shallowRef<Model.TradePositionRsp[]>([]) // 持仓汇总
+
+// 买方向持仓数量
+const buyQty = computed(() => positionStore.getOrderQty(BuyOrSell.Buy, selectedGoodsId.value))
+
+// 卖方向持仓数量
+const sellQty = computed(() => positionStore.getOrderQty(BuyOrSell.Sell, selectedGoodsId.value))
+
+// 价格类型
+const orderPriceType = computed(() => settingStore.getSettingValue('orderPriceType'))
+
+// 买卖方向
+const orderBuyOrSell = computed(() => settingStore.getSettingValue('orderBuyOrSell'))
+
+// 是否禁用价格输入
+const isDisabled = computed(() => [3, 4].includes(orderPriceType.value))
+
+const { decimalplace = 0.0, decimalvalue = 0.0 } = selectedGoods.value ?? { }
+
+const formRules: FormRules = {
+    OrderPrice: [{
+        required: true,
+        type: 'number',
+        validator: (rule, value, callback) => {
+            if (value) {
+                callback()
+            } else {
+                callback(new Error('请输入价格'))
+            }
+        }
+    }],
+    MarketMaxSub: [{
+        required: true,
+        type: 'number',
+        validator: (rule, value, callback) => {
+            if (value) {
+                callback()
+            } else {
+                callback(new Error('请输入允许成交范围'))
+            }
+        }
+    }],
+    OrderQty: [{
+        required: true,
+        validator: (rule, value, callback) => {
+            if (value) {
+                callback()
+            } else {
+                callback(new Error('请输入数量'))
+            }
+        }
+    }],
+    SlPrice: [{
+        required: true,
+        type: 'number',
+        validator: (rule, value, callback) => {
+            if (value) {
+                callback()
+            } else {
+                callback(new Error('请输入止损价'))
+            }
+        }
+    }],
+    SpPrice: [{
+        required: true,
+        type: 'number',
+        validator: (rule, value, callback) => {
+            if (value) {
+                callback()
+            } else {
+                callback(new Error('请输入止盈价'))
+            }
+        }
+    }],
+}
+
+const onPriceClick = (buyorsell: BuyOrSell, value: number) => {
+    formData.BuyOrSell = buyorsell === BuyOrSell.Sell ? BuyOrSell.Buy : BuyOrSell.Sell
+    if (isDisabled.value) {
+        qtyInputFocus()
+    } else {
+        formData.OrderPrice = value
+        priceInputFocus()
+    }
+}
+
+// 价格输入框获取焦点
+const priceInputFocus = () => {
+    priceRef.value.focus()
+}
+
+// 数量输入框获取焦点
+const qtyInputFocus = () => {
+    qtyRef.value.focus()
+}
+
+// 提交按钮获取焦点
+const submitFocus = () => {
+    submitRef.value.ref.focus()
+}
+
+const onRadioChange = (value: number) => {
+    formData.OrderQty = value
+    qtyInputFocus()
+}
+
+const onBeforeSubmit = (buildType: BuildType) => {
+    if (!loading.value) {
+        formRef.value?.validate((valid) => {
+            if (valid) {
+                formData.BuildType = buildType
+                if (buildType === BuildType.Close) {
+                    const { ask = 0, bid = 0 } = selectedGoods.value ?? {}
+                    formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
+
+                    const datas = position.value.filter(item => formData.BuyOrSell === BuyOrSell.Buy ? item.buyorsell === BuyOrSell.Sell : item.buyorsell === BuyOrSell.Buy) // 反方向持仓
+                    if (datas.length > 0) {
+                        formData.OrderQty = datas[0].enableqty
+                    }
+                }
+
+                if (settingStore.getSettingValue('showOrderDialog')) {
+                    ElMessageBox.confirm(
+                            '是否立即挂牌?',
+                            '提示'
+                        ).then(() => onSubmit())
+                } else {
+                    onSubmit()
+                }
+            }
+        })
+    }
+}
+
+// 提交挂牌
+const onSubmit = () => {
+    const { marketid = 0, goodsid = 0 } = selectedGoods.value ?? {}
+    /// 获取对应的市场ID
+    formData.MarketID = marketid
+    formData.GoodsID = goodsid
+    if (formData.PriceMode === PriceMode.Market) { formData.OrderPrice = marketPrice.value }
+
+    formSubmit().then(() => {
+        if (settingStore.getSettingValue('orderQtyIsEmpty')) {
+            formData.OrderQty = undefined
+            qtyStep.value = 0
+        }
+        if (settingStore.getSettingValue('showOrderSuccessMessage')) {
+            ElMessage.success('挂牌成功')
+        }
+    }).catch((err) => {
+        if (settingStore.getSettingValue('showOrderFailMessage')) {
+            ElMessage.error('挂牌失败:' + err)
+        }
+    }).finally(() => {
+        const focusType = settingStore.getSettingValue('orderFocusType')
+        if (focusType === 2 || isDisabled.value) {
+            qtyInputFocus()
+        } else {
+            priceInputFocus()
+        }
+    })
+}
+
+const getOrderPrice = () => {
+    const { last, bid, ask, presettle = 0 } = selectedGoods.value ?? {}
+    const price = last || presettle
+    // 1=现价,2=对手价,3=实时价,4=实时对手价
+    switch (orderPriceType.value) {
+        case 1:
+        case 3:
+            return price
+        case 2:
+        case 4:
+            if (formData.BuyOrSell === BuyOrSell.Buy) {
+                return ask || price
+            } else {
+                return bid || price
+            }
+        default:
+            return 0
+    }
+}
+
+watch([selectedGoodsId, orderPriceType], () => {
+    formData.OrderPrice = getOrderPrice()
+})
+
+watch(orderBuyOrSell, (val) => {
+    formData.BuyOrSell = val
+})
+
+watch([() => formData.BuyOrSell, () => selectedGoods.value?.last, () => selectedGoods.value?.bid, () => selectedGoods.value?.ask], () => {
+    if (isDisabled.value) {
+        formData.OrderPrice = getOrderPrice()
+    }
+})
+
+onMounted(() => {
+    formData.OrderPrice = getOrderPrice()
+    formData.OrderQty = qtyStep.value
+    formData.BuyOrSell = orderBuyOrSell.value
+    formData.PriceMode = PriceMode.Market
+    formData.BuildType = BuildType.Open
+    formData.MarketMaxSub = 100.0
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 110 - 0
src/packages/pc/views/query/order/pricing/history/index.vue

@@ -0,0 +1,110 @@
+<!-- 委托记录-挂牌点价-历史记录 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <template #headerLeft>
+            <app-filter :options="filterOptons">
+                <template #before>
+                    <el-date-picker effect="dark" :editable="false" :clearable="false" placeholder="请选择"
+                        value-format="YYYY-MM-DD" v-model="dateValue" />
+                </template>
+            </app-filter>
+        </template>
+        <!-- 方向 -->
+        <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 类型 -->
+        <template #pricemode="{ value }">
+            {{ value === 2 ? '固定价' : '浮动价' }}
+        </template>
+        <!-- 商品代码/名称 -->
+        <template #goodsname="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 委托状态 -->
+        <template #orderstatus="{ value }">
+            {{ getWRTradeOrderStatusName(value) }}
+        </template>
+        <!-- 委托时间 -->
+        <template #ordertime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+        <template #append v-if="pageIndex < pageCount">
+            <el-button size="small" plain @click="loadMore">加载更多</el-button>
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+import { formatDate } from '@/filters'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryHisTradeOrderDetail } from '@/services/api/order'
+import { getBuyOrSellName, getWRTradeOrderStatusName, getWRTradeOrderStatusList } from '@/constants/order'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+
+const { getTableColumns } = useTableColumnsStore()
+const { filterOptons, getQueryParams } = useDataFilter<Model.HisTradeOrderDetailReq>()
+const currentDate = new Date()
+const tableColumns = ref<Model.TableColumn[]>([])
+const dataList = ref<Model.HisTradeOrderDetailRsp[]>([])
+const dateValue = ref(formatDate(currentDate.toISOString(), 'YYYY-MM-DD'))
+
+const { loading, run, pageIndex, pageCount } = useRequest(queryHisTradeOrderDetail, {
+    manual: true,
+    params: {
+        pagesize: 30,
+        pageflag: 1,
+        tradeMode: '10',
+        orderStatus: '3',
+        startDate: dateValue.value,
+        endDate: dateValue.value
+    },
+    onSuccess: (res) => {
+        if (pageIndex.value === 1) {
+            dataList.value = []
+        }
+        dataList.value.push(...res.data)
+    }
+})
+
+filterOptons.selectList = [
+    {
+        key: 'orderStatus',
+        selectedValue: 3,
+        options: getWRTradeOrderStatusList().filter(e => { return [1, 2, 3, 4, 6, 7, 8, 9, 10, 11].includes(e.value) }),
+        locked: true,
+    }
+]
+
+filterOptons.buttonList = [
+    {
+        lable: '查询',
+        className: 'el-button--info',
+        onClick: () => {
+            pageIndex.value = 1
+            onSearch()
+        }
+    }
+]
+
+const loadMore = () => {
+    pageIndex.value++
+    onSearch()
+}
+
+const onSearch = () => {
+    getQueryParams((qs) => {
+        qs.startDate = dateValue.value
+        qs.endDate = dateValue.value
+        run(qs)
+    })
+}
+
+getTableColumns('pricing-order').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 8 - 0
src/packages/pc/views/query/order/pricing/index.vue

@@ -0,0 +1,8 @@
+<!-- 委托记录-挂牌点价 -->
+<template>
+    <app-auth-component direction="bottom" />
+</template>
+
+<script lang="ts" setup>
+import AppAuthComponent from '@pc/components/modules/auth-component/index.vue'
+</script>

+ 48 - 0
src/packages/pc/views/query/order/pricing/list/index.vue

@@ -0,0 +1,48 @@
+<!-- 委托记录-挂牌点价-当前记录 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <!-- 方向 -->
+        <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 类型 -->
+        <template #pricemode="{ value }">
+            {{ value === 2 ? '固定价' : '浮动价' }}
+        </template>
+        <!-- 商品代码/名称 -->
+        <template #goodsname="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 委托状态 -->
+        <template #orderstatus="{ value }">
+            {{ getWRTradeOrderStatusName(value) }}
+        </template>
+        <!-- 委托时间 -->
+        <template #ordertime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { formatDate } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { queryTradeOrderDetail } from '@/services/api/order'
+import { getBuyOrSellName, getWRTradeOrderStatusName } from '@/constants/order'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const { getTableColumns } = useTableColumnsStore()
+const tableColumns = shallowRef<Model.TableColumn[]>([])
+
+const { loading, dataList } = useRequest(queryTradeOrderDetail, {
+    params: {
+        tradeMode: '10'
+    },
+})
+
+getTableColumns('pricing-order').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 110 - 0
src/packages/pc/views/query/trade/pricing/history/index.vue

@@ -0,0 +1,110 @@
+<!-- 成交记录-挂牌点价-历史记录 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <template #headerLeft>
+            <app-filter :options="filterOptons">
+                <template #before>
+                    <el-date-picker effect="dark" :editable="false" :clearable="false" placeholder="请选择"
+                        value-format="YYYY-MM-DD" v-model="dateValue" />
+                </template>
+            </app-filter>
+        </template>
+        <!-- 类型 -->
+        <template #buildtype="{ value }">
+            {{ getBuildTypeName(value) }}
+        </template>
+        <!-- 方向 -->
+        <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+        <!-- 成交对手 -->
+        <template #matchaccountid="{ value }">
+            {{ tmMatchAccountID(value) }}
+        </template>
+        <!-- 商品合约 -->
+        <template #goodsname="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 时间 -->
+        <template #tradetime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+        <template #append v-if="pageIndex < pageCount">
+            <el-button size="small" plain @click="loadMore">加载更多</el-button>
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+import { formatDate, tmMatchAccountID } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { useDataFilter } from '@/hooks/datatable'
+import { queryHisTradeDetail, } from '@/services/api/order'
+import { getBuildTypeName, getBuyOrSellName, getBuildTypeList } from '@/constants/order'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+
+const { getTableColumns } = useTableColumnsStore()
+const { filterOptons, getQueryParams } = useDataFilter<Model.HisTradeDetailReq>()
+const currentDate = new Date()
+const tableColumns = ref<Model.TableColumn[]>([])
+const dataList = ref<Model.HisTradeDetailRsp[]>([])
+const dateValue = ref(formatDate(currentDate.toISOString(), 'YYYY-MM-DD'))
+
+const { loading, run, pageIndex, pageCount } = useRequest(queryHisTradeDetail, {
+    manual: true,
+    params: {
+        pagesize: 30,
+        pageflag: 1,
+        tradeMode: ' 10',
+        buildType: 1,
+        startDate: dateValue.value,
+        endDate: dateValue.value
+    },
+    onSuccess: (res) => {
+        if (pageIndex.value === 1) {
+            dataList.value = []
+        }
+        dataList.value.push(...res.data)
+    }
+})
+
+filterOptons.selectList = [
+    {
+        key: 'buildType',
+        selectedValue: 1,
+        options: getBuildTypeList(),
+        locked: true,
+    }
+]
+
+filterOptons.buttonList = [
+    {
+        lable: '查询',
+        className: 'el-button--info',
+        onClick: () => {
+            pageIndex.value = 1
+            onSearch()
+        }
+    }
+]
+
+const loadMore = () => {
+    pageIndex.value++
+    onSearch()
+}
+
+const onSearch = () => {
+    getQueryParams((qs) => {
+        qs.startDate = dateValue.value
+        qs.endDate = dateValue.value
+        run(qs)
+    })
+}
+
+getTableColumns('pricing-trade').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 8 - 0
src/packages/pc/views/query/trade/pricing/index.vue

@@ -0,0 +1,8 @@
+<!-- 成交记录-挂牌点价 -->
+<template>
+    <app-auth-component direction="bottom" />
+</template>
+
+<script lang="ts" setup>
+import AppAuthComponent from '@pc/components/modules/auth-component/index.vue'
+</script>

+ 48 - 0
src/packages/pc/views/query/trade/pricing/list/index.vue

@@ -0,0 +1,48 @@
+<!-- 成交记录- 挂牌点价-当前记录 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <!-- 类型 -->
+        <template #buildtype="{ value }">
+            {{ getBuildTypeName(value) }}
+        </template>
+         <!-- 方向 -->
+         <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+         <!-- 成交对手 -->
+         <template #matchaccountid="{ value }">
+            {{ tmMatchAccountID(value) }}
+        </template>
+        <!-- 商品合约 -->
+        <template #goodsname="{ row }">
+            {{ row.goodscode }}/{{ row.goodsname }}
+        </template>
+        <!-- 成交时间 -->
+        <template #tradetime="{ value }">
+            {{ formatDate(value) }}
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { formatDate, tmMatchAccountID } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { queryTradeDetail } from '@/services/api/order'
+import { getBuildTypeName, getBuyOrSellName } from '@/constants/order'
+import { useTableColumnsStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const { getTableColumns } = useTableColumnsStore()
+const tableColumns = shallowRef<Model.TableColumn[]>([])
+
+const { loading, dataList } = useRequest(queryTradeDetail, {
+    params: {
+        tradeMode: '10'
+    },
+})
+
+getTableColumns('pricing-trade').then((res) => {
+    tableColumns.value = res
+})
+</script>

+ 1 - 0
src/stores/modules/global.ts

@@ -26,6 +26,7 @@ export const useGlobalStore = defineStore(() => {
     const state = reactive({
         dateDiff: 0, // 服务器和本地的时间差(毫秒数)
         showGoodsListing: false, // 是否显示订单交易挂牌
+        showPricingListing: false, // 是否显示挂牌点价交易
         showTransferListing: false, // 是否显示定金转让挂牌
         clientWidth: 0, // 客户端宽度
         isMobile: false, // 是否移动设备