li.shaoyi 2 yıl önce
ebeveyn
işleme
1a141d77ea
34 değiştirilmiş dosya ile 428 ekleme ve 154 silme
  1. 19 19
      package-lock.json
  2. 2 2
      package.json
  3. 10 3
      public/config/router.json
  4. 1 1
      src/business/position/index.ts
  5. 3 2
      src/filters/index.ts
  6. 15 15
      src/hooks/echarts/candlestick/index.ts
  7. 2 2
      src/hooks/echarts/candlestick/options.ts
  8. 4 4
      src/hooks/echarts/timeline/index.ts
  9. 1 1
      src/packages/mobile/views/order/position/components/swap/close/Index.vue
  10. BIN
      src/packages/pc/assets/logo-horizontal.png
  11. 6 0
      src/packages/pc/assets/themes/global/global.less
  12. 26 12
      src/packages/pc/components/layouts/page/index.vue
  13. 1 3
      src/packages/pc/components/modules/listing/index.vue
  14. 4 2
      src/packages/pc/components/modules/quote/tik/index.vue
  15. 8 0
      src/packages/pc/main.ts
  16. 11 0
      src/packages/pc/views/footer/capital/summary/index.vue
  17. 2 5
      src/packages/pc/views/footer/goods/delivery/index.vue
  18. 44 0
      src/packages/pc/views/footer/goods/detail/index.vue
  19. 52 0
      src/packages/pc/views/footer/goods/order/clear/index.vue
  20. 33 18
      src/packages/pc/views/footer/goods/order/index.vue
  21. 9 5
      src/packages/pc/views/footer/goods/position/index.vue
  22. 13 0
      src/packages/pc/views/footer/goods/trade/index.less
  23. 45 6
      src/packages/pc/views/footer/goods/trade/index.vue
  24. 1 1
      src/packages/pc/views/query/capital/list/index.less
  25. 1 1
      src/packages/pc/views/query/capital/list/index.vue
  26. 9 11
      src/services/api/common/index.ts
  27. 20 23
      src/services/api/order/index.ts
  28. 1 0
      src/services/bus/types.ts
  29. 28 0
      src/services/methods/user.ts
  30. 1 1
      src/services/websocket/trade.ts
  31. 1 1
      src/stores/index.ts
  32. 47 10
      src/stores/modules/account.ts
  33. 6 6
      src/stores/modules/position.ts
  34. 2 0
      src/types/model/order.d.ts

+ 19 - 19
package-lock.json

@@ -15,7 +15,7 @@
         "core-js": "^3.8.3",
         "crypto-js": "^4.1.1",
         "default-passive-events": "^2.0.0",
-        "echarts": "^5.3.2",
+        "echarts": "^5.4.3",
         "element-plus": "^2.3.8",
         "html5-qrcode": "^2.2.5",
         "long": "^5.2.0",
@@ -6716,17 +6716,17 @@
       }
     },
     "node_modules/echarts": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz",
-      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "version": "5.4.3",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz",
+      "integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
       "dependencies": {
         "tslib": "2.3.0",
-        "zrender": "5.3.1"
+        "zrender": "5.4.4"
       }
     },
     "node_modules/echarts/node_modules/tslib": {
       "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
       "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
     },
     "node_modules/ee-first": {
@@ -13379,16 +13379,16 @@
       "dev": true
     },
     "node_modules/zrender": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz",
-      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "version": "5.4.4",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz",
+      "integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
       "dependencies": {
         "tslib": "2.3.0"
       }
     },
     "node_modules/zrender/node_modules/tslib": {
       "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
       "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
     }
   },
@@ -18253,17 +18253,17 @@
       "dev": true
     },
     "echarts": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz",
-      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "version": "5.4.3",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz",
+      "integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
       "requires": {
         "tslib": "2.3.0",
-        "zrender": "5.3.1"
+        "zrender": "5.4.4"
       },
       "dependencies": {
         "tslib": {
           "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
           "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
         }
       }
@@ -23306,16 +23306,16 @@
       }
     },
     "zrender": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz",
-      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "version": "5.4.4",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz",
+      "integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
       "requires": {
         "tslib": "2.3.0"
       },
       "dependencies": {
         "tslib": {
           "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
           "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
         }
       }

+ 2 - 2
package.json

@@ -23,7 +23,7 @@
     "core-js": "^3.8.3",
     "crypto-js": "^4.1.1",
     "default-passive-events": "^2.0.0",
-    "echarts": "^5.3.2",
+    "echarts": "^5.4.3",
     "element-plus": "^2.3.8",
     "html5-qrcode": "^2.2.5",
     "long": "^5.2.0",
@@ -64,4 +64,4 @@
     "vconsole": "^3.14.6",
     "worker-loader": "^3.0.8"
   }
-}
+}

+ 10 - 3
public/config/router.json

@@ -15,7 +15,7 @@
                     {
                         "authType": 2,
                         "sort": 1,
-                        "title": "合约汇总",
+                        "title": "持仓汇总",
                         "code": "bottom_goods_position",
                         "component": "views/footer/goods/position/index.vue",
                         "children": [
@@ -38,20 +38,27 @@
                     {
                         "authType": 2,
                         "sort": 2,
+                        "title": "持仓明细",
+                        "code": "bottom_goods_detail",
+                        "component": "views/footer/goods/detail/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
                         "title": "委托",
                         "code": "bottom_goods_order",
                         "component": "views/footer/goods/order/index.vue"
                     },
                     {
                         "authType": 2,
-                        "sort": 3,
+                        "sort": 4,
                         "title": "成交",
                         "code": "bottom_goods_trade",
                         "component": "views/footer/goods/trade/index.vue"
                     },
                     {
                         "authType": 2,
-                        "sort": 4,
+                        "sort": 5,
                         "title": "交收",
                         "code": "bottom_goods_delivery",
                         "component": "views/footer/goods/delivery/index.vue"

+ 1 - 1
src/business/position/index.ts

@@ -12,7 +12,7 @@ export const usePosition = (tradeMode = 0) => {
     const store = usePositionStore()
     const subscribe = quoteSocket.createSubscribe()
 
-    const positionList = computed(() => store.orderPositionComputedList.filter((e) => tradeMode ? e.trademode === tradeMode : true))
+    const positionList = computed(() => store.positionComputedList.filter((e) => tradeMode ? e.trademode === tradeMode : true))
 
     // 获取持仓数量
     const getOrderQty = (buyOrSell: BuyOrSell, code?: string | number) => {

+ 3 - 2
src/filters/index.ts

@@ -79,7 +79,7 @@ export function getImageSrc(text?: string) {
 /**
  * 处理价格颜色的显示
  */
-export function handlePriceColor(curValue: number, preValue: number) {
+export function handlePriceColor(curValue: number, preValue = 0) {
     if (!curValue || curValue === preValue) {
         return ''
     } else if (curValue > preValue) {
@@ -146,7 +146,8 @@ export function formatDecimal(value: number | string, decimal = 2, round = true)
         return Math.trunc(val).toString()
     } else {
         if (round) {
-            return val.toFixed(decimal)
+            const res = val.toFixed(decimal)
+            return res === '-0.00' ? '0.00' : res // 计算精度丢失,临时处理,只适合两位小数
         }
         let num = val.toString()
         const index = num.indexOf('.')

+ 15 - 15
src/hooks/echarts/candlestick/index.ts

@@ -135,15 +135,15 @@ export function useCandlestickChart(goodscode: string) {
     /**
      * 更新图表数据
      */
-    const updateChart = () => {
-        const { last, lasttime } = quote.value;
+    const updateChart = (quote: Partial<Model.QuoteDayRsp>) => {
+        const { last, lasttime } = quote
         if (last && lasttime) {
-            const { candlestick, macd, vol, kdj, cci } = dataset;
-            const lastIndex = candlestick.source.length - 1; // 历史数据最后索引位置
-            const cycleMilliseconds = getCycleMilliseconds();
+            const { candlestick, macd, vol, kdj, cci } = dataset
+            const lastIndex = candlestick.source.length - 1 // 历史数据最后索引位置
+            const cycleMilliseconds = getCycleMilliseconds()
 
-            const oldTime = lastIndex === -1 ? moment(lasttime) : moment(candlestick.source[lastIndex].date); // 历史行情最后时间
-            const diffTime = moment(lasttime).valueOf() - oldTime.valueOf(); // 计算时间差
+            const oldTime = lastIndex === -1 ? moment(lasttime) : moment(candlestick.source[lastIndex].date) // 历史行情最后时间
+            const diffTime = moment(lasttime).valueOf() - oldTime.valueOf() // 计算时间差
 
             // if (diffTime > cycleMilliseconds * 2) {
             //     // 时间间隔超过两个周期,重新请求历史数据,待优化
@@ -211,27 +211,27 @@ export function useCandlestickChart(goodscode: string) {
                 })
             } else {
                 // 更新列表中最后一条记录的数据
-                const record = candlestick.source[lastIndex];
+                const record = candlestick.source[lastIndex]
                 if (record.lowest > last) {
-                    record.lowest = last; // 更新最低价
+                    record.lowest = last // 更新最低价
                 }
                 if (record.highest < last) {
-                    record.highest = last; // 更新最高价
+                    record.highest = last // 更新最高价
                 }
-                record.close = last; // 更新收盘价
+                record.close = last // 更新收盘价
             }
 
             // 计算各项指标
-            calcIndicator(lastIndex === -1 ? 0 : lastIndex);
-            updateOptions();
+            calcIndicator(lastIndex === -1 ? 0 : lastIndex)
+            updateOptions()
             // }
         }
     }
 
     // 监听行情推送
-    watch(() => quote.value, () => {
+    watch(() => quote.value, (val) => {
         if (!loading.value && !isEmpty.value) {
-            updateChart();
+            updateChart(val)
         }
     })
 

+ 2 - 2
src/hooks/echarts/candlestick/options.ts

@@ -348,7 +348,7 @@ export function useOptions(dataset: EchartsDataset) {
     }
 
     // 动态更新数据
-    const updateOptions = () => {
+    const updateOptions = timerInterceptor.setThrottle(() => {
         const { candlestick, macd, vol, kdj, cci } = dataset;
 
         options.candlestick = {
@@ -388,7 +388,7 @@ export function useOptions(dataset: EchartsDataset) {
                 source: cci.source,
             },
         }
-    }
+    }, 50)
 
     // 监听主题变化
     watch(appTheme, () => {

+ 4 - 4
src/hooks/echarts/timeline/index.ts

@@ -54,8 +54,8 @@ export function useTimelineChart(goodscode: string) {
     /**
      * 更新图表数据
      */
-    const updateChart = () => {
-        const { last, lasttime } = quote.value
+    const updateChart = (quote: Partial<Model.QuoteDayRsp>) => {
+        const { last, lasttime } = quote
         if (last && lasttime) {
             const { close, ma5 } = dataset.timeline.source
             const lastIndex = close.length - 1 // 历史数据最后索引位置
@@ -99,9 +99,9 @@ export function useTimelineChart(goodscode: string) {
     }
 
     // 监听行情推送
-    watch(() => quote.value, () => {
+    watch(() => quote.value, (val) => {
         if (!loading.value && !isEmpty.value) {
-            updateChart()
+            updateChart(val)
         }
     })
 

+ 1 - 1
src/packages/mobile/views/order/position/components/swap/close/Index.vue

@@ -62,7 +62,7 @@
 <script lang="ts" setup>
 import { shallowRef, PropType, computed, onMounted } from 'vue'
 import { useRequest } from '@/hooks/request'
-import { queryTradeHolderDetail } from '@/services/api/order';
+import { queryTradeHolderDetail } from '@/services/api/order'
 import { ETradeMode } from '@/constants/client';
 import { Button } from 'vant'
 import { getBuyOrSellName } from '@/constants/order'

BIN
src/packages/pc/assets/logo-horizontal.png


+ 6 - 0
src/packages/pc/assets/themes/global/global.less

@@ -27,6 +27,12 @@
     color: #0baf1f;
 }
 
+.g-text-message {
+    font-size: 16px;
+    text-align: center;
+    padding: 15px 0;
+}
+
 .el-form {
     &-item:last-child {
         margin-bottom: 0;

+ 26 - 12
src/packages/pc/components/layouts/page/index.vue

@@ -33,23 +33,25 @@
       <div class="statusbar-left">
       </div>
       <div class="statusbar-right">
-        {{ serverTime?.format('HH:mm:ss') }}
+        <!-- <span>{{ serverTime?.format('MM/DD') }}</span> -->
+        <span>{{ serverTime?.format('HH:mm:ss') }}</span>
       </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, onUnmounted } from 'vue'
 import { RouteRecordNormalized, RouteRecordName } from 'vue-router'
 import { timerTask } from '@/utils/timer'
 import { getServerTime } from '@/services/api/common'
 import { useGlobalStore } from '@/stores'
+import eventBus from '@/services/bus'
+import moment, { Moment } from 'moment'
 import AppHeader from '../header/index.vue'
 import AppFooter from '../footer/index.vue'
 import AppNavbar from '../navbar/index.vue'
 import AppSidebar from '../sidebar/index.vue'
-import moment, { Moment } from 'moment'
 
 const globalStore = useGlobalStore()
 const isCollapse = ref(globalStore.isMobile)
@@ -63,24 +65,36 @@ const handleComponent = (component: Record<'type', { name: RouteRecordName | und
   return component
 }
 
-// 刷新服务器时间
-const refreshServerTime = () => {
+// 校验服务器时间
+const checkServerTime = () => {
   getServerTime().then((res) => {
     serverTime.value = moment.parseZone(res.data)
-    const timer = timerTask.setInterval(() => {
-      serverTime.value = moment(serverTime.value).add(1000, 'ms')
-    }, 1000)
     // 每5分钟同步一次服务器时间
     timerTask.setTimeout(() => {
-      timer.clear()
-      refreshServerTime()
-    }, 5 * 60 * 1000)
+      checkServerTime()
+    }, 5 * 60 * 1000, 'getServerTime')
   })
 }
 
+// 接收窗口页面状态通知
+const documentVisibilityStateNotify = eventBus.$on('DocumentVisibilityStateNotify', (state) => {
+  if (state === 'visible') {
+    checkServerTime()
+  }
+})
+
 onMounted(() => {
   serverTime.value = moment(new Date())
-  refreshServerTime()
+  timerTask.setInterval(() => {
+    serverTime.value = moment(serverTime.value).add(1000, 'ms')
+  }, 1000, 'refreshTime')
+  checkServerTime()
+})
+
+onUnmounted(() => {
+  timerTask.clearInterval('refreshTime')
+  timerTask.clearTimeout('getServerTime')
+  documentVisibilityStateNotify.cancel()
 })
 </script>
 

+ 1 - 3
src/packages/pc/components/modules/listing/index.vue

@@ -175,12 +175,10 @@ const onSubmit = (buildType: number) => {
     })
 }
 
-watch(() => goodsStore.goodsId, () => {
+watch(quote, () => {
     const { last = 0, presettle = 0 } = quote.value ?? {}
     formData.OrderPrice = last || presettle
     formData.OrderQty = qtyStep.value
-}, {
-    immediate: true
 })
 </script>
 

+ 4 - 2
src/packages/pc/components/modules/quote/tik/index.vue

@@ -8,7 +8,9 @@
             <ul>
                 <li v-for="(item, index) in dataList" :key="index">
                     <span>{{ formatDate(item.TS, 'HH:mm:ss') }}</span>
-                    <span :class="handlePriceColor(item.PE, quoteDay.presettle)">{{ handleNumberValue(item.PE) }}</span>
+                    <span :class="handlePriceColor(item.PE, quoteDay.presettle)">
+                        {{ handleNumberValue(formatDecimal(item.PE, quoteDay.decimalplace)) }}
+                    </span>
                     <span>{{ handleNumberValue(item.Vol) }}</span>
                 </li>
             </ul>
@@ -18,7 +20,7 @@
 
 <script lang="ts" setup>
 import { ref, watch } from 'vue'
-import { formatDate, handleNumberValue, handlePriceColor } from '@/filters'
+import { formatDate, handleNumberValue, handlePriceColor, formatDecimal } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { queryHistoryTikDatas, queryMarketRun } from '@/services/api/market'
 import { useFuturesStore } from '@/stores'

+ 8 - 0
src/packages/pc/main.ts

@@ -10,6 +10,7 @@ import 'element-plus/dist/index.css'
 import './assets/themes/style.less' // 主题样式
 import { timerInterceptor } from '@/utils/timer'
 import { useGlobalStore } from '@/stores'
+import eventBus from '@/services/bus'
 
 const app = createApp(App)
 app.use(router)
@@ -29,6 +30,13 @@ document.addEventListener('DOMContentLoaded', () => {
     window.addEventListener('resize', timerInterceptor.setDebounce(() => screenAdapter()))
 }, false)
 
+// 监听窗口页面变化
+document.addEventListener('visibilitychange', () => {
+    const state = document.visibilityState
+    // 窗口页面状态通知
+    eventBus.$emit('DocumentVisibilityStateNotify', state)
+})
+
 // 注册全局图标
 for (const [key, value] of Object.entries(ElementIcons)) {
     app.component(key, value)

+ 11 - 0
src/packages/pc/views/footer/capital/summary/index.vue

@@ -2,6 +2,14 @@
 <template>
     <app-table :data="accountStore.accountComputedList" v-model:columns="tableColumns" :row-key="rowKey"
         :expand-row-keys="expandKeys" @row-click="rowClick">
+        <!-- 净值 -->
+        <template #netvalue="{ value }">
+            {{ formatDecimal(value) }}
+        </template>
+        <!-- 浮动盈亏 -->
+        <template #profitLoss="{ value }">
+            <span :class="handlePriceColor(value)">{{ formatDecimal(value) }}</span>
+        </template>
         <!-- 状态 -->
         <template #tradestatus="{ value }">
             {{ getTradeStatusName(value) }}
@@ -22,6 +30,7 @@
 
 <script lang="ts" setup>
 import { shallowRef, defineAsyncComponent, onMounted } from 'vue'
+import { formatDecimal, handlePriceColor } from '@/filters'
 import { useAccountStore } from '@/stores'
 import { useComponent } from '@/hooks/component'
 import { useComposeTable } from '@pc/components/base/table'
@@ -46,9 +55,11 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { prop: 'accountid', label: '资金账号', width: 160 },
     { prop: 'balance', label: '期初余额', decimal: 2 },
     { prop: 'currentbalance', label: '期末余额', decimal: 2 },
+    { prop: 'netvalue', label: '净值' },
     { prop: 'avaiableMoney', label: '可用资金', decimal: 2 },
     { prop: 'usedmargin', label: '占用资金', decimal: 2 },
     { prop: 'freezeMargin', label: '冻结资金', decimal: 2 },
+    { prop: 'profitLoss', label: '浮动盈亏' },
     { prop: 'inamount', label: '今日入金', decimal: 2 },
     { prop: 'outamount', label: '今日出金', decimal: 2 },
     { prop: 'closepl', label: '今日损益', decimal: 2 },

+ 2 - 5
src/packages/pc/views/footer/goods/delivery/index.vue

@@ -1,6 +1,6 @@
 <!-- 商品订单-交收 -->
 <template>
-    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey" :expand-row-keys="expandKeys"  @row-click="rowClick">
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
         <!-- 申请时间 -->
         <template #reqtime="{ value }">
             {{ formatDate(value) }}
@@ -11,14 +11,11 @@
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
 import { useRequest } from '@/hooks/request'
-import { useComposeTable } from '@pc/components/base/table'
 import { queryMineTradeGoodsDeliveryOfflines } from '@/services/api/transfer'
 import AppTable from '@pc/components/base/table/index.vue'
 import { formatDate } from '@/filters'
 
-const { loading, dataList } = useRequest(queryMineTradeGoodsDeliveryOfflines, {})
-
-const { rowKey, expandKeys, rowClick } = useComposeTable<Model.MineTradeGoodsDeliveryOfflinesRsp>({ rowKey: 'deliveryorderid' })
+const { loading, dataList } = useRequest(queryMineTradeGoodsDeliveryOfflines)
 
 const tableColumns = shallowRef<Model.TableColumn[]>([
     { prop: 'goodsnamedisplay', label: '订单合约' },

+ 44 - 0
src/packages/pc/views/footer/goods/detail/index.vue

@@ -0,0 +1,44 @@
+<!-- 商品订单-持仓明细 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey"
+        :expand-row-keys="expandKeys" @row-click="rowClick">
+        <!-- 方向 -->
+        <template #buyorsell="{ value }">
+            {{ getBuyOrSellName(value) }}
+        </template>
+    </app-table>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onUnmounted } from 'vue'
+import { getBuyOrSellName } from '@/constants/order'
+import { useRequest } from '@/hooks/request'
+import { useComposeTable } from '@pc/components/base/table'
+import { queryTradeHolderDetail } from '@/services/api/order'
+import AppTable from '@pc/components/base/table/index.vue'
+import eventBus from '@/services/bus'
+
+const { loading, dataList, run } = useRequest(queryTradeHolderDetail, {
+    params: {
+        trademodes: '50'
+    }
+})
+
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.TradeHolderDetailRsp>({ rowKey: 'tradeid' })
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { prop: 'tradeid', label: '成交单号' },
+    { prop: 'marketname', label: '市场' },
+    { prop: 'goodsname', label: '商品' },
+    { prop: 'buyorsell', label: '方向' },
+    { prop: 'holderqty', label: '持仓数量' },
+    { prop: 'holderprice', label: '持仓价格' },
+    { prop: 'holderamount', label: '持仓金额' },
+    { prop: 'tradedate', label: '交易时间' },
+])
+
+// 接收头寸变化通知通知
+const posChangedNtf = eventBus.$on('PosChangedNtf', () => run())
+
+onUnmounted(() => posChangedNtf.cancel())
+</script>

+ 52 - 0
src/packages/pc/views/footer/goods/order/clear/index.vue

@@ -0,0 +1,52 @@
+<!-- 商品订单-委托-一键全撤 -->
+<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 } from 'vue'
+import { ElMessage } from 'element-plus'
+import { queryTradeOrderDetail } from '@/services/api/order'
+import { useCancelOrder } from '@/business/trade'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const { cancelSubmit, formData } = useCancelOrder()
+const loading = ref(false)
+const show = ref(true)
+const refresh = ref(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onCancelSumit = () => {
+    loading.value = true
+    queryTradeOrderDetail({
+        data: {
+            tradeMode: '50',
+            orderStatus: '3,7,12'
+        }
+    }).then((res) => {
+        for (let i = 0; i < res.data.length; i++) {
+            const { orderid, marketid, goodsid } = res.data[i]
+            ///  参数信息
+            formData.Header = { MarketID: marketid, GoodsID: goodsid }
+            formData.OldOrderId = orderid
+            /// 提交
+            cancelSubmit()
+        }
+        loading.value = false
+        onCancel(true)
+    }).catch((err) => {
+        loading.value = false
+        ElMessage.error('提交失败:' + err)
+    })
+}
+</script>

+ 33 - 18
src/packages/pc/views/footer/goods/order/index.vue

@@ -2,6 +2,9 @@
 <template>
     <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey"
         :expand-row-keys="expandKeys" @row-click="rowClick">
+        <template #headerRight>
+            <el-button type="danger" size="small" @click="showComponent('clear')" v-if="dataList.length">一键全撤</el-button>
+        </template>
         <!-- 类型' -->
         <template #buyorsell="{ value }">
             {{ getBuyOrSellName(value) }}
@@ -17,14 +20,10 @@
         <!-- 展开行 -->
         <template #expand="{ row }">
             <div class="buttonbar">
-                <el-button type="danger" v-if="[3, 7, 12].includes(row.orderstatus)" size="small"
-                    @click="showComponent('cancel', row)">撤销</el-button>
+                <el-button type="danger" size="small" @click="showComponent('cancel', row)">撤销</el-button>
             </div>
         </template>
         <template #footer>
-            <div v-if="false">
-                <el-button type="danger" size="small">一键撤单</el-button>
-            </div>
             <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)"
                 @closed="closeComponent" v-if="componentId" />
         </template>
@@ -32,7 +31,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, defineAsyncComponent, onUnmounted } from 'vue'
+import { ref, defineAsyncComponent, onUnmounted } from 'vue'
 import { useRequest } from '@/hooks/request'
 import { getBuyOrSellName, getOrderStatusName } from '@/constants/order'
 import { queryTradeOrderDetail } from '@/services/api/order'
@@ -43,24 +42,27 @@ import { useComposeTable } from '@pc/components/base/table'
 import eventBus from '@/services/bus'
 
 const componentMap = new Map<string, unknown>([
-    ['cancel', defineAsyncComponent(() => import('./cancel/index.vue'))],
+    ['cancel', defineAsyncComponent(() => import('./cancel/index.vue'))], // 撤单
+    ['clear', defineAsyncComponent(() => import('./clear/index.vue'))], // 一键全撤
 ])
 
-const { loading, dataList, run } = useRequest(queryTradeOrderDetail, {
+const dataList = ref<Model.TradeOrderDetailRsp[]>([])
+
+const { loading, run, runAsync } = useRequest(queryTradeOrderDetail, {
     params: {
         tradeMode: '50',
         orderStatus: '3,7,12',
     },
+    onSuccess: (res) => {
+        dataList.value = res.data
+    }
 })
 
-const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
-    run()
-})
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
 
-const { rowKey, expandKeys, rowClick } = useComposeTable<Model.TradeOrderDetailRsp>({ rowKey: 'orderid' })
-const selectedRow = shallowRef<Model.TradeOrderDetailRsp>()
+const { rowKey, expandKeys, selectedRow, rowClick } = useComposeTable<Model.TradeOrderDetailRsp>({ rowKey: 'orderid' })
 
-const tableColumns = shallowRef<Model.TableColumn[]>([
+const tableColumns = ref<Model.TableColumn[]>([
     { prop: 'goodsname', label: '订单合约' },
     { prop: 'buyorsell', label: '类型' },
     { prop: 'orderprice', label: '委托价' },
@@ -71,15 +73,28 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { prop: 'orderstatus', label: '状态' }
 ])
 
-const showComponent = (componentName: string, row: Model.TradeOrderDetailRsp) => {
+const showComponent = (componentName: string, row?: Model.TradeOrderDetailRsp) => {
     selectedRow.value = row
     openComponent(componentName)
 }
 
-// 接收持仓变化通知、委托回应通知
-const subNotify = eventBus.$on(['PosChangedNtf', 'OrderRsp'], () => {
+// 接收成交通知
+const posChangedNtf = eventBus.$on('OrderDealedNtf', () => {
     run()
 })
 
-onUnmounted(() => subNotify.cancel())
+// 接收委托回应通知
+const orderRspNotify = eventBus.$on(['OrderRsp',], () => {
+    const [firstItem] = dataList.value
+    runAsync({
+        incOrderID: firstItem?.orderid
+    }).then((res) => {
+        dataList.value.unshift(...res.data)
+    })
+})
+
+onUnmounted(() => {
+    posChangedNtf.cancel()
+    orderRspNotify.cancel()
+})
 </script>

+ 9 - 5
src/packages/pc/views/footer/goods/position/index.vue

@@ -1,19 +1,23 @@
-<!-- 商品订单-合约汇总 -->
+<!-- 商品订单-持仓汇总 -->
 <template>
     <app-table :data="positionList" v-model:columns="tableColumns" :loading="loading" @row-click="showComponent">
         <!-- 挂牌类型 -->
         <template #buyorsell="{ value }">
             {{ getBuyOrSellName(value) }}
         </template>
+        <!-- 均价-->
+        <template #averageprice="{ row }">
+            <span>{{ formatDecimal(row.averageprice, row.decimalplace) }}</span>
+        </template>
         <!-- 最新价 -->
         <template #lastprice="{ row }">
             <span :class="row.lastColor">
-                {{ handleNumberValue(row.last) }}
+                {{ handleNumberValue(formatDecimal(row.last, row.decimalplace)) }}
             </span>
         </template>
         <!-- 浮动盈亏-->
         <template #closepl="{ row }">
-            <span :class="row.closeplColor">{{ row.closepl?.toFixed(2) }}</span>
+            <span :class="row.closeplColor">{{ formatDecimal(row.closepl) }}</span>
         </template>
         <!-- 操作 -->
         <template #operate="{ row }">
@@ -32,7 +36,7 @@ import { getBuyOrSellName } from '@/constants/order'
 import { useComponent } from '@/hooks/component'
 import { usePosition } from '@/business/position'
 import AppTable from '@pc/components/base/table/index.vue'
-import { handleNumberValue } from '@/filters'
+import { handleNumberValue, formatDecimal } from '@/filters'
 
 const componentMap = new Map<string, unknown>([
     ['delivery', defineAsyncComponent(() => import('./components/delivery/index.vue'))],
@@ -52,7 +56,7 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { prop: 'averageprice', label: '均价' },
     { prop: 'lastprice', label: '现价' },
     { prop: 'curholderamount', label: '持仓金额' },
-    { prop: 'usedmargin', label: '占用保证金' },
+    // { prop: 'usedmargin', label: '占用保证金' },
     { prop: 'closepl', label: '浮动盈亏' },
     { prop: 'operate', label: '操作', fixed: 'right', width: 80 },
 ])

+ 13 - 0
src/packages/pc/views/footer/goods/trade/index.less

@@ -0,0 +1,13 @@
+.goods-trade {
+    &-total {
+        display: flex;
+        color: #fff;
+        font-size: .12px;
+
+        li {
+            &:not(:first-child) {
+                padding-left: 5px;
+            }
+        }
+    }
+}

+ 45 - 6
src/packages/pc/views/footer/goods/trade/index.vue

@@ -1,6 +1,22 @@
 <!-- 商品订单 - 成交 -->
 <template>
-    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+    <app-table class="goods-trade" :data="dataList" v-model:columns="tableColumns" :loading="loading">
+        <template #headerRight>
+            <ul class="goods-trade-total">
+                <li>
+                    <span>数量:</span>
+                    <span>{{ qtyTotal }}</span>
+                </li>
+                <li>
+                    <span>手续费:</span>
+                    <span>{{ feeTotal.toFixed(2) }}</span>
+                </li>
+                <li>
+                    <span>盈亏:</span>
+                    <span>{{ plTotal.toFixed(2) }}</span>
+                </li>
+            </ul>
+        </template>
         <!-- 类型' -->
         <template #buyorsell="{ value }">
             {{ getBuyOrSellName(value) }}
@@ -17,7 +33,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, onUnmounted } from 'vue'
+import { ref, onUnmounted, computed } from 'vue'
 import { useRequest } from '@/hooks/request'
 import { getBuyOrSellName, getBuildTypeName } from '@/constants/order'
 import { queryTradeDetail } from '@/services/api/order'
@@ -25,13 +41,18 @@ import AppTable from '@pc/components/base/table/index.vue'
 import { formatDate } from '@/filters'
 import eventBus from '@/services/bus'
 
-const { loading, dataList, run } = useRequest(queryTradeDetail, {
+const dataList = ref<Model.TradeDetailRsp[]>([])
+
+const { loading, runAsync } = useRequest(queryTradeDetail, {
     params: {
         tradeMode: '50'
     },
+    onSuccess: (res) => {
+        dataList.value = res.data
+    }
 })
 
-const tableColumns = shallowRef<Model.TableColumn[]>([
+const tableColumns = ref<Model.TableColumn[]>([
     { prop: 'goodsname', label: '订单合约' },
     { prop: 'buyorsell', label: '方向' },
     { prop: 'buildtype', label: '成交类型' },
@@ -44,10 +65,28 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { prop: 'tradetime', label: '成交时间' }
 ])
 
+// 数量汇总
+const qtyTotal = computed(() => dataList.value.reduce((pre, cur) => pre += cur.tradeqty, 0))
+
+// 手续费汇总
+const feeTotal = computed(() => dataList.value.reduce((pre, cur) => pre += cur.charge, 0))
+
+// 盈亏汇总
+const plTotal = computed(() => dataList.value.reduce((pre, cur) => pre += cur.closepl, 0))
+
 // 接收成交通知
 const orderDealedNtf = eventBus.$on('OrderDealedNtf', () => {
-    run()
+    const [firstItem] = dataList.value
+    runAsync({
+        incTradeID: firstItem?.tradeid
+    }).then((res) => {
+        dataList.value.unshift(...res.data)
+    })
 })
 
 onUnmounted(() => orderDealedNtf.cancel())
-</script>
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 1 - 1
src/packages/pc/views/query/capital/list/index.less

@@ -1,5 +1,5 @@
 .query-capital {
-    &__total {
+    &-total {
         display: flex;
         color: #fff;
 

+ 1 - 1
src/packages/pc/views/query/capital/list/index.vue

@@ -2,7 +2,7 @@
 <template>
     <app-table class="query-capital" :data="dataList" v-model:columns="tableColumns" :loading="loading">
         <template #headerRight>
-            <ul class="query-capital__total">
+            <ul class="query-capital-total">
                 <li>
                     <span>手续费汇总:</span>
                     <span>{{ feeTotal.toFixed(2) }}</span>

+ 9 - 11
src/services/api/common/index.ts

@@ -1,9 +1,7 @@
-import { useLoginStore } from '@/stores'
+import { getUserId, getLoginId } from '@/services/methods/user'
+import { RequestConfig } from '@/services/http/types'
 import service from '@/services'
 import http from '@/services/http'
-import { RequestConfig } from '@/services/http/types'
-
-const loginStore = useLoginStore()
 
 /**
  * 获取应用配置信息
@@ -126,7 +124,7 @@ export function signin(config: RequestConfig<{ userid: number }> = {}) {
         method: 'post',
         url: '/Ferroalloy/Signin',
         data: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -149,7 +147,7 @@ export function queryUserLevelInfo(config: RequestConfig<Model.UserLevelInfoReq>
     return http.commonRequest<Model.UserLevelInfoRsp>({
         url: '/Ferroalloy/QueryUserLevelInfo',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -182,7 +180,7 @@ export function queryTHJProfits(config: RequestConfig<Model.THJProfitsReq> = {})
     return http.commonRequest<Model.THJProfitsRsp[]>({
         url: '/Ferroalloy/QueryTHJProfits',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -195,7 +193,7 @@ export function queryMyDeposit(config: RequestConfig<Model.MyDepositReq> = {}) {
     return http.commonRequest<Model.MyDepositRsp[]>({
         url: '/Ferroalloy/QueryMyDeposit',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -208,7 +206,7 @@ export function queryTHJinvesotrdeposit(config: RequestConfig<Model.THJinvesotrd
     return http.commonRequest<Model.THJinvesotrdepositRsp[]>({
         url: '/Ferroalloy/QueryTHJinvesotrdeposit',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -231,7 +229,7 @@ export function queryNotice(config: RequestConfig<Model.NoticeReq> = {}) {
     return http.commonRequest<Model.NoticeRsp[]>({
         url: '/Common/QueryNotice',
         params: {
-            loginID: loginStore.loginId,
+            loginID: getLoginId(),
             ...config.data
         },
     })
@@ -245,7 +243,7 @@ export function postNoticeReaded(config: RequestConfig<Model.NoticeReadedReq> =
         method: 'post',
         url: '/Common/NoticeReaded',
         data: {
-            loginID: loginStore.loginId,
+            loginID: getLoginId(),
             ...config.data
         },
     })

+ 20 - 23
src/services/api/order/index.ts

@@ -1,9 +1,6 @@
-import { useLoginStore, useAccountStore } from '@/stores'
-import http from '@/services/http'
+import { getUserId, getAccountId } from '@/services/methods/user'
 import { RequestConfig } from '@/services/http/types'
-
-const loginStore = useLoginStore()
-const accountStore = useAccountStore()
+import http from '@/services/http'
 
 /**
  * 查询仓单成交明细
@@ -12,7 +9,7 @@ export function queryWrTradeDetail(config: RequestConfig<Model.WrTradeDetailReq>
     return http.commonRequest<Model.WrTradeDetailRsp[]>({
         url: '/WrTrade2/QueryWrTradeDetail',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -25,7 +22,7 @@ export function queryWrOrderDetail(config: RequestConfig<Model.WrOrderDetailReq>
     return http.commonRequest<Model.WrOrderDetailRsp[]>({
         url: '/WrTrade2/QueryWrOrderDetail',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -38,7 +35,7 @@ export function queryTHJPurchaseTradeDetail(config: RequestConfig<Model.THJPurch
     return http.commonRequest<Model.THJPurchaseTradeDetailRsp[]>({
         url: '/Ferroalloy/QueryTHJPurchaseTradeDetail',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -51,7 +48,7 @@ export function queryHoldLB(config: RequestConfig<Model.HoldLBReq> = {}) {
     return http.commonRequest<Model.HoldLBRsp[]>({
         url: '/WrTrade2/QueryHoldLB',
         params: {
-            accountid: accountStore.currentAccountId,
+            accountid: getAccountId(),
             ...config.data
         },
     })
@@ -64,7 +61,7 @@ export function queryWrOutInApply(config: RequestConfig<Model.WrOutInApplyReq> =
     return http.commonRequest<Model.WrOutInApplyRsp[]>({
         url: '/WrTrade2/QueryWrOutInApply',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -77,7 +74,7 @@ export function queryTHJPromotionIncome(config: RequestConfig<Model.THJPromotion
     return http.commonRequest<Model.THJPromotionIncomeRsp[]>({
         url: '/Ferroalloy/QueryTHJPromotionIncome',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -90,7 +87,7 @@ export function queryTHJPromotionIncomeDetail(config: RequestConfig<Model.THJPro
     return http.commonRequest<Model.THJPromotionIncomeDetailRsp[]>({
         url: '/Ferroalloy/QueryTHJPromotionIncomeDetail',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -103,7 +100,7 @@ export function queryTHJPurchaseTransferOrder(config: RequestConfig<Model.THJPur
     return http.commonRequest<Model.THJPurchaseTransferOrderRsp[]>({
         url: '/Ferroalloy/QueryTHJPurchaseTransferOrder',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -126,7 +123,7 @@ export function queryHisTradeDetail(config: RequestConfig<Model.HisTradeDetailRe
     return http.commonRequest<Model.HisTradeDetailRsp[]>({
         url: '/Order/QueryHisTradeDetail',
         params: {
-            accountID: accountStore.currentAccountId,
+            accountID: getAccountId(),
             ...config.data
         },
     })
@@ -139,7 +136,7 @@ export function queryHisTradeOrderDetail(config: RequestConfig<Model.HisTradeOrd
     return http.commonRequest<Model.HisTradeOrderDetailRsp[]>({
         url: '/Order/QueryHisTradeOrderDetail',
         params: {
-            accountID: accountStore.currentAccountId,
+            accountID: getAccountId(),
             ...config.data
         },
     })
@@ -152,7 +149,7 @@ export function queryTradeDetail(config: RequestConfig<Model.TradeDetailReq> = {
     return http.commonRequest<Model.TradeDetailRsp[]>({
         url: '/Order/QueryTradeDetail',
         params: {
-            accountID: accountStore.currentAccountId,
+            accountID: getAccountId(),
             ...config.data
         },
     })
@@ -165,8 +162,8 @@ export function queryTradeHolderDetail(config: RequestConfig<Model.TradeHolderDe
     return http.commonRequest<Model.TradeHolderDetailRsp[]>({
         url: '/Order/QueryTradeHolderDetail',
         params: {
-            userid: loginStore.userId,
-            accids: accountStore.currentAccountId.toString(),
+            userid: getUserId(),
+            accids: getAccountId().toString(),
             ...config.data
         },
     })
@@ -179,7 +176,7 @@ export function queryTradeOrderDetail(config: RequestConfig<Model.TradeOrderDeta
     return http.commonRequest<Model.TradeOrderDetailRsp[]>({
         url: '/Order/QueryTradeOrderDetail',
         params: {
-            accountID: accountStore.currentAccountId,
+            accountID: getAccountId(),
             ...config.data
         },
     })
@@ -192,7 +189,7 @@ export function queryTradePosition(config: RequestConfig<Model.TradePositionReq>
     return http.commonRequest<Model.TradePositionRsp[]>({
         url: '/Order/QueryTradePosition',
         params: {
-            accountID: accountStore.currentAccountId,
+            accountID: getAccountId(),
             ...config.data
         },
     })
@@ -207,7 +204,7 @@ export function querySBYJMyOrders(config: RequestConfig<Model.SBYJMyOrderReq> =
     return http.commonRequest<Model.SBYJMyOrderRsp[]>({
         url: '/sbyj/GetMyOrders',
         params: {
-            userId: loginStore.userId,
+            userId: getUserId(),
             ...config.data
         },
     })
@@ -220,7 +217,7 @@ export function queryMyTradeGoodsDeliveryOfflines(config: RequestConfig<Model.My
     return http.commonRequest<Model.MyTradeGoodsDeliveryOfflineRsp[]>({
         url: '/sbyj/QueryMyTradegoodsdeliveryoffline',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })
@@ -233,7 +230,7 @@ export function queryMyDeliveryofflinedetails(config: RequestConfig<Model.MyDeli
     return http.commonRequest<Model.MyDeliveryofflinedetailRsp[]>({
         url: '/sbyj/QueryMyDeliveryofflinedetail',
         params: {
-            userid: loginStore.userId,
+            userid: getUserId(),
             ...config.data
         },
     })

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

@@ -2,6 +2,7 @@
  * 事件码
  */
 export enum EventCode {
+    DocumentVisibilityStateNotify, // 窗口页面状态通知
     QuotePushNotify, // 行情推送通知
     QuoteServerReconnectNotify, // 行情服务重连成功通知
     LoginNotify, // 用户登入通知

+ 28 - 0
src/services/methods/user.ts

@@ -0,0 +1,28 @@
+import { useLoginStore, useAccountStore } from '@/stores'
+
+/**
+ * 获取登录ID
+ * @returns 
+ */
+export function getLoginId() {
+    const store = useLoginStore()
+    return store.loginId
+}
+
+/**
+ * 获取用户ID
+ * @returns 
+ */
+export function getUserId() {
+    const store = useLoginStore()
+    return store.userId
+}
+
+/**
+ * 获取账号ID
+ * @returns 
+ */
+export function getAccountId() {
+    const store = useAccountStore()
+    return store.currentAccountId
+}

+ 1 - 1
src/services/websocket/trade.ts

@@ -15,7 +15,7 @@ export default new (class {
     constructor() {
         this.socket.onPush = (p) => {
             const { funCode } = p
-            const delay = 1000 // 延迟推送消息,防止短时间内重复请求
+            const delay = 500 // 延迟推送消息,防止短时间内重复请求
 
             switch (funCode) {
                 case FunCode.LogoutRsp: {

+ 1 - 1
src/stores/index.ts

@@ -1,3 +1,4 @@
+export { useEnumStore } from './modules/enum'
 export { useLoginStore } from './modules/login'
 export { useUserStore } from './modules/user'
 export { useGlobalStore } from './modules/global'
@@ -5,7 +6,6 @@ export { useMenuStore } from './modules/menu'
 export { useAccountStore } from './modules/account'
 export { useFuturesStore } from './modules/futures'
 //export { i18n, useLanguageStore } from './modules/language'
-export { useEnumStore } from './modules/enum'
 export { useErrorInfoStore } from './modules/errorInfo'
 export { useNoticeStore } from './modules/notice'
 export { useGoodsStore } from './modules/goods'

+ 47 - 10
src/stores/modules/account.ts

@@ -2,6 +2,8 @@ import { toRefs, computed, reactive } from 'vue'
 import { queryTaAccounts } from '@/services/api/account'
 import { defineStore } from '../store'
 import { useLoginStore } from './login'
+import { useUserStore } from './user'
+import { usePositionStore } from './position'
 import eventBus from '@/services/bus'
 
 /**
@@ -10,6 +12,8 @@ import eventBus from '@/services/bus'
  */
 export const useAccountStore = defineStore(() => {
     const loginStore = useLoginStore()
+    const userStore = useUserStore()
+    const positionStore = usePositionStore()
 
     const state = reactive({
         loading: false,
@@ -22,18 +26,57 @@ export const useAccountStore = defineStore(() => {
         const result: (Model.TaAccountsRsp & {
             freezeMargin: number; // 冻结资金
             avaiableMoney: number; // 可用资金
+            netvalue: number; // 净值
+            profitLoss: number; // 浮动盈亏
         })[] = []
 
         state.accountList.forEach((item) => {
-            // 计算冻结资金
-            const freezeMargin = item.freezecharge + item.freezemargin + item.otherfreezemargin + item.outamountfreeze
+            // 账号持仓列表
+            const positionList = positionStore.positionComputedList.filter((e) => e.accountid === item.accountid)
+
+            // 计算浮动盈亏
+            const profitLoss = positionList.reduce((pre, cur) => cur.tradeproperty === 1 ? pre += cur.closepl : pre, 0)
+
+            // 计算市值
+            const marketValue = positionList.reduce((pre, cur) => {
+                if (cur.tradeproperty === 2 && cur.last) {
+                    // 计算所有权 = 数量 * 现价 * 合约单位
+                    pre += cur.last * cur.curpositionqty * cur.agreeunit
+                }
+                return pre
+            }, 0)
+
+            // 计算权益/净值
+            // 根据系统参数“307 账户净值是否减冻结资金 - 0:不减 1:减“
+            // 0.净值=期末余额+市值+浮动盈亏(收益权)
+            // 1.净值=期末余额+市值+浮动盈亏(收益权)-其他冻结-出金冻结
+            const param037 = userStore.getSystemParamValue('037')
+            const free = param037 === '1' ? item.otherfreezemargin + item.outamountfreeze : 0 // 冻结资金
+            const netvalue = item.currentbalance + profitLoss + marketValue - free
+
+            // 计算冻结资金 = 冻结+其它冻结+手续费冻结+出金冻结
+            const freezeMargin = item.freezemargin + item.otherfreezemargin + item.freezecharge + item.outamountfreeze
+
             // 计算可用资金
-            const avaiableMoney = item.currentbalance - item.usedmargin - freezeMargin
+            let avaiableMoney = 0
+
+            // *系统参数”113“(当日浮动盈利是否可用) 0:不可用 1:可用
+            const param113 = userStore.getSystemParamValue('113')
+
+            if (profitLoss < 0 || param113 === '1') {
+                // 账户总浮动盈亏为负:= 期末余额+总浮动盈亏-占用-冻结资金
+                avaiableMoney = item.currentbalance + profitLoss - item.usedmargin - freezeMargin
+            } else {
+                // 账户总浮动盈亏为正 且 113 = 0 :=期末余额-占用-冻结资金
+                avaiableMoney = item.currentbalance - item.usedmargin - freezeMargin
+            }
 
             result.push({
                 ...item,
                 freezeMargin,
-                avaiableMoney
+                avaiableMoney,
+                netvalue,
+                profitLoss,
             })
         })
 
@@ -68,11 +111,6 @@ export const useAccountStore = defineStore(() => {
         }
     }
 
-    /** 获取资金账户持仓列表 */
-    const getAccountPositionList = () => {
-        throw '获取资金账户持仓列表'
-    }
-
     // 接收资金变动通知
     const moneyChangedNotify = eventBus.$on('MoneyChangedNotify', () => getAccountList())
 
@@ -82,6 +120,5 @@ export const useAccountStore = defineStore(() => {
         currentAccount,
         moneyChangedNotify,
         getAccountList,
-        getAccountPositionList,
     }
 })

+ 6 - 6
src/stores/modules/position.ts

@@ -13,7 +13,7 @@ export const usePositionStore = defineStore(() => {
     const futuresStore = useFuturesStore()
     const state = reactive({
         loading: false,
-        orderPositionList: <Model.TradePositionRsp[]>[], // 持仓汇总列表
+        positionList: <Model.TradePositionRsp[]>[], // 持仓汇总列表
     })
 
     // 获取持仓汇总列表
@@ -21,14 +21,14 @@ export const usePositionStore = defineStore(() => {
         try {
             state.loading = true
             const res = await queryTradePosition()
-            state.orderPositionList = res.data
+            state.positionList = res.data
         } finally {
             state.loading = false
         }
     }
 
     // 持仓汇总计算列表
-    const orderPositionComputedList = computed(() => {
+    const positionComputedList = computed(() => {
         const result: (Model.TradePositionRsp & {
             last: number; // 最新价
             lastColor: string; // 最新价颜色
@@ -36,7 +36,7 @@ export const usePositionStore = defineStore(() => {
             closeplColor: string; // 浮动盈亏颜色
         })[] = []
 
-        state.orderPositionList.forEach((item) => {
+        state.positionList.forEach((item) => {
             const quote = futuresStore.getGoodsQuote(item.goodscode)
             const { last = 0, lastColor = '' } = quote.value ?? {}
 
@@ -55,13 +55,13 @@ export const usePositionStore = defineStore(() => {
         return result
     })
 
-    // 接收持仓变化通知
+    // 接收头寸变化通知
     const posChangedNtf = eventBus.$on('PosChangedNtf', () => getTradePosition())
 
     return {
         ...toRefs(state),
         getTradePosition,
-        orderPositionComputedList,
+        positionComputedList,
         posChangedNtf,
     }
 })

+ 2 - 0
src/types/model/order.d.ts

@@ -815,6 +815,7 @@ declare namespace Model {
         orderStatus?: string
         /// 委托单号
         orderID?: number
+        incOrderID?: string; // 增量委托单号
     }
 
     /*  查询我的订单/掉期委托 响应*/
@@ -1324,6 +1325,7 @@ declare namespace Model {
         tradeType?: string
         /// 商品ID
         goodsID?: number
+        incTradeID?: string; // 增量成交单号,用于增量查询
     }
 
     /* 查询我的订单/订单成交 回应 */