li.shaoyi 1 year ago
parent
commit
9201e0a9ed

+ 2 - 2
app/package.json

@@ -1,6 +1,6 @@
 {
-  "name": "trading",
-  "version": "1.0.1",
+  "name": "trading-beta",
+  "version": "1.0.31",
   "main": "main.js",
   "dependencies": {
     "electron-updater": "^6.1.4",

+ 2 - 2
oem/qxst/config/appconfig.json

@@ -1,8 +1,8 @@
 {
   "appId": "com.muchinfo.qxst",
   "appName": "贵州茶交数字化中心",
-  "version": "1.0.29",
-  "versionCode": "100029",
+  "version": "1.0.31",
+  "versionCode": "100031",
   "apiUrl": "http://192.168.31.204:8080/cfg?key=test_204",
   "tradeChannel": "ws",
   "modules": [

+ 3 - 3
oem/thj/config/appconfig.json

@@ -1,9 +1,9 @@
 {
   "appId": "com.muchinfo.thj",
   "appName": "铁合金掌上行",
-  "version": "1.2.21",
-  "versionCode": "12210",
-  "apiUrl": "http://101.133.236.116:8280/cfg?key=mtp_20",
+  "version": "1.0.2",
+  "versionCode": "100002",
+  "apiUrl": "http://192.168.31.167:8080/cfg?key=test_167",
   "tradeChannel": "ws",
   "modules": [
     "register",

+ 1 - 1
src/packages/gcszt/router/index.ts

@@ -115,7 +115,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/gstj/router/index.ts

@@ -250,7 +250,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/gzcj/router/index.ts

@@ -231,7 +231,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/mobile/components/modules/hqchart/candlestick/index.less

@@ -2,7 +2,7 @@
     flex: 1;
     display: flex;
     flex-direction: column;
-    height: 400px;
+    height: 360px;
     overflow: hidden;
     padding:0 10px;
 

+ 6 - 2
src/packages/mobile/components/modules/hqchart/candlestick/index.vue

@@ -29,6 +29,10 @@ const props = defineProps({
     cycleType: {
         type: Number,
         required: true
+    },
+    isShowTitle: {
+        type: Boolean,
+        default: true
     }
 })
 
@@ -108,7 +112,7 @@ const chartOption = {
     Border: {
         Left: 0,
         Right: 0,
-        Top: 36,
+        Top: props.isShowTitle ? 36 : 10,
         Bottom: 25,
         AutoLeft: { Blank: 15, MinWidth: 30 },
         AutoRight: { Blank: 15, MinWidth: 30 },
@@ -130,7 +134,7 @@ const chartOption = {
     {
         IsShowName: false, // 不显示股票名称
         IsShowSettingInfo: false, // 不显示周期/复权
-        IsShow: true // 是否显示标题
+        IsShow: props.isShowTitle // 是否显示标题
     },
     Frame: [
         {

+ 5 - 1
src/packages/mobile/components/modules/hqchart/timeline/index.less

@@ -2,9 +2,13 @@
     flex: 1;
     display: flex;
     flex-direction: column;
-    height: 400px;
+    height: 320px;
     overflow: hidden;
 
+    &.trademode99 {
+        height: 260px;
+    }
+
     .app-hqchart {
         flex: 1;
     }

+ 16 - 5
src/packages/mobile/components/modules/hqchart/timeline/index.vue

@@ -1,11 +1,11 @@
 <template>
-    <div class="app-timeline">
+    <div :class="classNames">
         <HQChart @ready="onReady" />
     </div>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue'
+import { shallowRef, computed } from 'vue'
 import { Chart } from 'hqchart'
 import { timerInterceptor } from '@/utils/timer'
 import { handleNumberValue, changeUnit } from '@/filters'
@@ -30,6 +30,17 @@ const { quoteWatch, getGoodsQuote } = useFuturesStore()
 const goods = getGoodsQuote(props.goodsCode)
 const chartInstance = shallowRef() // 图表实例
 
+// 是否掉期模式
+const isTradeMode99 = computed(() => goods.value?.trademode === 99)
+
+const classNames = computed(() => {
+    const result = ['app-timeline']
+    if (isTradeMode99.value) {
+        result.push('trademode99')
+    }
+    return result
+})
+
 // 自定义品种小数位
 // https://blog.csdn.net/jones2000/article/details/106592730/
 Chart.MARKET_SUFFIX_NAME.GetCustomDecimal = () => goods.value?.decimalplace ?? 2
@@ -67,7 +78,7 @@ const chartOption = {
     Frame: [
         {
             IsShowRightText: !!goods.value?.presettle // 是否显示Y轴右侧刻度
-        }
+        },
     ],
     OnCreatedCallback: (chart: MinuteChartContainer) => {
         const paint = chart.TitlePaint[0]
@@ -82,7 +93,7 @@ const chartOption = {
                     { Text: '价:' + handleNumberValue(Close.toFixed(decimalplace)), Color: paint.GetColor(Open, YClose || Open) },
                     { Text: '幅:' + Increase.toFixed(2) + '%', Color: paint.GetColor(Increase, 0) }
                 ]
-                if (goods.value?.trademode !== 99) {
+                if (!isTradeMode99.value) {
                     AryText.push(
                         { Text: '量:' + changeUnit(Vol), Color: paint.VolColor },
                         { Text: '额:' + changeUnit(Amount), Color: paint.AmountColor }
@@ -99,7 +110,7 @@ const chartOption = {
 const onReady = (chart: unknown) => {
     chartInstance.value = chart
     getTSDataAsync.then(() => {
-        if (goods.value?.trademode === 99) {
+        if (isTradeMode99.value) {
             chartOption.Frame.push({
                 Height: 0 // 第2个成交量图高度设置0隐藏掉
             })

+ 1 - 1
src/packages/nhgj/router/index.ts

@@ -236,7 +236,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/qdhs/router/index.ts

@@ -126,7 +126,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/qxst/router/index.ts

@@ -104,7 +104,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 1
src/packages/tc/router/index.ts

@@ -231,7 +231,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 18 - 0
src/packages/thj/components/hqchart/index.less

@@ -0,0 +1,18 @@
+.app-quote-chart {
+    background-color: #fff;
+    margin-top: 10px;
+
+    &__header {
+        display: flex;
+        align-items: center;
+        border-bottom: 1px solid #eee;
+
+        .van-tabs {
+            flex: 1;
+
+            &__nav {
+                background-color: transparent;
+            }
+        }
+    }
+}

+ 55 - 0
src/packages/thj/components/hqchart/index.vue

@@ -0,0 +1,55 @@
+<template>
+    <div class="app-quote-chart">
+        <div class="app-quote-chart__header">
+            <Tabs v-model:active="tabIndex" :before-change="onTabChange">
+                <Tab title="日线" />
+                <Tab title="周线" />
+                <Tab title="月线" />
+            </Tabs>
+        </div>
+        <KLine v-bind="{ isShowTitle: false, symbol, goodsCode, cycleType }" />
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { Tab, Tabs } from 'vant'
+import { ChartCycleType } from '@/constants/chart'
+import KLine from '@mobile/components/modules/hqchart/candlestick/index.vue'
+
+defineProps({
+    goodsCode: {
+        type: String,
+        required: true
+    }
+})
+
+const symbol = '000000.et' // https://blog.csdn.net/jones2000/article/details/104457569
+const tabIndex = shallowRef(0) // 当前选中的标签
+const cycleType = shallowRef(ChartCycleType.Day) // 图表周期类型
+
+// 切换图表
+const onTabChange = (index: number) => {
+    switch (index) {
+        case 0: {
+            cycleType.value = ChartCycleType.Day
+            return true
+        }
+        case 1: {
+            cycleType.value = ChartCycleType.Week
+            return true
+        }
+        case 2: {
+            cycleType.value = ChartCycleType.Month
+            return true
+        }
+        default: {
+            return true
+        }
+    }
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 20 - 0
src/packages/thj/components/quote/index.less

@@ -0,0 +1,20 @@
+.app-quote-price {
+    display: flex;
+    justify-content: center;
+    align-items: baseline;
+    color: #333;
+    background-color: #fff;
+    padding: 10px 0;
+
+    .block-left {
+        font-size: 36px;
+    }
+
+    .block-right {
+        font-size: 16px;
+
+        span {
+            margin-left: 10px;
+        }
+    }
+}

+ 39 - 0
src/packages/thj/components/quote/index.vue

@@ -0,0 +1,39 @@
+<template>
+    <div class="app-quote-price">
+        <template v-if="quote">
+            <div class="block-left">
+                <span :class="quote.lastColor">{{ handleNumberValue(quote.last.toFixed(quote.decimalplace))
+                    }}</span>
+            </div>
+            <div class="block-right">
+                <span :class="quote.lastColor">{{ quote.rise.toFixed(quote.decimalplace) }}</span>
+                <span :class="quote.lastColor">{{ parsePercent(quote.change) }}</span>
+            </div>
+        </template>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted } from 'vue'
+import { parsePercent, handleNumberValue } from '@/filters'
+import { useFuturesStore } from '@/stores'
+import quoteSocket from '@/services/websocket/quote'
+
+const props = defineProps({
+    goodsCode: {
+        type: String,
+        required: true
+    }
+})
+
+const futuresStore = useFuturesStore()
+const subscribe = quoteSocket.createSubscribe()
+const quote = futuresStore.getGoodsQuote(props.goodsCode)
+
+onMounted(() => subscribe.start(props.goodsCode))
+onUnmounted(() => subscribe.stop())
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 51 - 3
src/packages/thj/router/index.ts

@@ -34,6 +34,7 @@ const routes: Array<RouteRecordRaw> = [
         name: 'home',
         component: () => import('@mobile/views/home/Index.vue'),
         children: [
+          ...homeRoutes,
           {
             path: '',
             name: 'home-index',
@@ -47,7 +48,16 @@ const routes: Array<RouteRecordRaw> = [
             name: 'home-mine',
             component: () => import('../views/mine/Index.vue'),
           },
-          ...homeRoutes
+          {
+            path: 'swap',
+            name: 'home-swap',
+            component: () => import('../views/swap/list/index.vue'),
+          },
+          {
+            path: 'market',
+            name: 'home-market',
+            component: () => import('../views/market/list/index.vue'),
+          }
         ]
       }
     ]
@@ -120,7 +130,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },
@@ -289,7 +299,45 @@ const routes: Array<RouteRecordRaw> = [
       }
     ]
   },
-  ...pageRoutes
+  ...pageRoutes,
+  {
+    path: '/swap',
+    component: Page,
+    children: [
+      {
+        path: 'list',
+        name: 'swap-list',
+        component: () => import('../views/swap/list/index.vue'),
+        props: {
+          showBackButton: true
+        }
+      },
+      {
+        path: 'detail',
+        name: 'swap-detail',
+        component: () => import('../views/swap/detail/index.vue'),
+      }
+    ]
+  },
+  {
+      path: '/market',
+      component: Page,
+      children: [
+          {
+              path: 'list',
+              name: 'market-list',
+              component: () => import('../views/market/list/index.vue'),
+              props: {
+                  showBackButton: true
+              }
+          },
+          {
+              path: 'detail',
+              name: 'market-detail',
+              component: () => import('../views/market/detail/index.vue'),
+          }
+      ]
+  }
 ]
 
 const router = animateRouter.create({

+ 1 - 3
src/packages/thj/views/home/main/index.less

@@ -99,9 +99,7 @@
                 padding: 6px 0;
 
                 &.is-active {
-                    &::before {
-                        background-color: transparent
-                    }
+                    background-color: #f9f9f9;
 
                     &.g-price-up {
                         background-color: #fff3f3;

+ 22 - 0
src/packages/thj/views/market/detail/index.vue

@@ -0,0 +1,22 @@
+<template>
+    <app-view class="market-detail">
+        <template #header>
+            <app-navbar :title="futuresStore.getGoodsName(goodsCode) ?? '商品详情'" />
+        </template>
+        <component :is="Price" v-bind="{ goodsCode }" />
+        <component :is="Chart" v-bind="{ goodsCode }" />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { defineAsyncComponent } from 'vue'
+import { useNavigation } from '@mobile/router/navigation'
+import { useFuturesStore } from '@/stores'
+
+const Price = defineAsyncComponent(() => import('../../../components/quote/index.vue'))
+const Chart = defineAsyncComponent(() => import('../../../components/hqchart/index.vue'))
+
+const { getQueryString } = useNavigation()
+const goodsCode = getQueryString('goodscode') ?? ''
+const futuresStore = useFuturesStore()
+</script>

+ 79 - 0
src/packages/thj/views/market/list/index.vue

@@ -0,0 +1,79 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar :title="titleName" :show-back-button="showBackButton" />
+        </template>
+        <app-table :columns="columns" :data-list="dataList" @row-click="rowClick">
+            <!-- 商品/代码 -->
+
+            <template #goodsname="{ row }">
+                <span>{{ row.goodsname }}</span>
+                <span class="text-small">{{ row.goodscode }}</span>
+            </template>
+            <!-- 最新价 -->
+
+            <template #last="{ row }">
+                <span :class="row.lastColor">{{ handleNumberValue(formatDecimal(row.last, row.decimalplace)) }}</span>
+            </template>
+            <!-- 涨跌 -->
+
+            <template #rise="{ row }">
+                <span :class="row.lastColor">{{ handleNumberValue(formatDecimal(row.rise, row.decimalplace)) }}</span>
+            </template>
+            <!-- 幅度 -->
+
+            <template #change="{ row }">
+                <span :class="row.lastColor">{{ parsePercent(row.change) }}</span>
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { onActivated, onUnmounted, computed, PropType } from 'vue'
+import { parsePercent, handleNumberValue, formatDecimal } from '@/filters'
+import { useNavigation } from '@mobile/router/navigation'
+import { useFuturesStore } from '@/stores'
+import quoteSocket from '@/services/websocket/quote'
+import AppTable from '@mobile/components/base/list/index.vue'
+
+const props = defineProps({
+    showBackButton: {
+        type: Boolean,
+        default: false
+    },
+    marketSection: {
+        type: Object as PropType<Model.Marketsectionconfignew>
+    }
+})
+
+const { router, getQueryString } = useNavigation()
+const futuresStore = useFuturesStore()
+
+const title = getQueryString('title')
+const titleName = computed(() => title ? decodeURIComponent(title) : props.marketSection?.displayname ?? '参考行情')
+
+const dataList = computed(() => futuresStore.quotationList.filter((e) => e.marketid === 99201))
+
+const goodsCodes = dataList.value.map((e) => e.goodscode.toUpperCase())
+const subscribe = quoteSocket.createSubscribe()
+
+const columns: Model.TableColumn[] = [
+    { prop: 'goodsname', label: '商品/代码', fixed: 'left', width: 120 },
+    { prop: 'last', label: '最新价' },
+    { prop: 'rise', label: '涨跌' },
+    { prop: 'change', label: '幅度' },
+]
+
+const rowClick = (row: Model.GoodsQuote) => {
+    router.push({
+        name: 'market-detail',
+        query: {
+            goodscode: row.goodscode
+        }
+    })
+}
+
+onActivated(() => subscribe.start(...goodsCodes))
+onUnmounted(() => subscribe.stop())
+</script>

+ 171 - 0
src/packages/thj/views/swap/detail/index.vue

@@ -0,0 +1,171 @@
+<template>
+    <app-view class="swap-detail">
+        <template #header>
+            <app-navbar :title="item.goodscode + '/' + item.goodsname">
+                <template #right>
+                    <div class="button-more" v-if="userStore.userType != 5" @click="onListing">
+                        <span>挂牌</span>
+                    </div>
+                </template>
+            </app-navbar>
+        </template>
+        <component :is="Price" v-bind="{ goodsCode }" />
+        <component :is="Chart" v-bind="{ goodsCode }" />
+        <Tabs v-model:active="tabIndex" @click="onRefresh" style="margin-top: 10px;">
+            <Tab title="买货大厅" :name="BuyOrSell.Buy" />
+            <Tab title="卖货大厅" :name="BuyOrSell.Sell" />
+        </Tabs>
+        <div class="trade-section sell" v-if="dataList.length">
+            <app-list :columns="columns" :data-list="dataList">
+                <template #orderprice="{ row }">
+                    <span :class="quote?.lastColor">{{ row.pricemode === 3 ? estimateprice(row) : row.orderprice
+                    }}</span>
+                </template>
+                <template #username="{ row }">
+                    <span>{{ row.userid }}/{{ row.username }}</span>
+                </template>
+                <template #operate="{ row }">
+                    <Button size="small" type="primary" :disabled="isDisable(row)" @click="onDelisting(row)">
+                        {{ getDelistingButtonTitles(tabIndex, row) }}
+                    </Button>
+                </template>
+            </app-list>
+        </div>
+        <Empty description="暂无数据" v-else />
+        <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedRow, tabIndex, item }"
+            @closed="closeComponent" v-if="componentId" />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent, computed } from 'vue'
+import { Tab, Tabs, Button, showToast, Empty } from 'vant'
+import { useRequest } from '@/hooks/request'
+import { useNavigation } from '@mobile/router/navigation'
+import { useComponent } from '@/hooks/component'
+import { BuyOrSell } from '@/constants/order'
+import { queryTjmdTradeOrderDetail, queryMdUserSwapProtocol } from '@/services/api/swap'
+import { useFuturesStore } from '@/stores'
+import { useLoginStore, useUserStore } from '@/stores'
+import AppList from '@mobile/components/base/list/index.vue'
+import { getUserId } from '@/services/methods/user'
+import { formatDecimal } from '@/filters'
+import { onActivated } from 'vue'
+
+const Price = defineAsyncComponent(() => import('../../../components/quote/index.vue'))
+const Chart = defineAsyncComponent(() => import('../../../components/hqchart/index.vue'))
+
+const componentMap = new Map<string, unknown>([
+    ['delisting', defineAsyncComponent(() => import('@mobile/views/swap/detail/components/delisting/Index.vue'))],
+    ['listing', defineAsyncComponent(() => import('@mobile/views/swap/detail/components/listing/Index.vue'))],
+])
+
+const loginStore = useLoginStore()
+const { getGlobalUrlParams, router } = useNavigation()
+const item: Model.QuoteGoodsListRsp = getGlobalUrlParams()
+const tabIndex = shallowRef(0)
+const selectedRow = shallowRef<Model.TjmdTradeOrderDetailRsp>()
+const futuresStore = useFuturesStore()
+const quote = futuresStore.getGoodsQuote(item.refgoodsid)
+const goodsCode = computed(() => quote.value?.goodscode ?? '')
+const userStore = useUserStore()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => onRefresh())
+
+/// 查询用户掉期协议签署表
+const { dataList: protocolList, run: runMdUserSwapProtocol } = useRequest(queryMdUserSwapProtocol, {
+    manual: true,
+    params: {
+        userId: getUserId()
+    }
+})
+
+/// 估算价格
+const estimateprice = (row: Model.TjmdTradeOrderDetailRsp) => {
+    const { last = 0, presettle = 0 } = quote.value ?? {}
+    const value = row.marketmaxsub + (last || presettle)
+    return formatDecimal(value, item.decimalplace)
+}
+
+const isDisable = (row: Model.TjmdTradeOrderDetailRsp) => {
+    return row.userid === getUserId() || (status(row) === 2 || status(row) === 3)
+}
+
+const status = (row: Model.TjmdTradeOrderDetailRsp) => {
+    return protocolList.value.find((e) => e.areauserid === row.userid)?.protocolstatus ?? 1
+}
+
+const { dataList, run } = useRequest(queryTjmdTradeOrderDetail, {
+    params: {
+        goodsid: item.goodsid,
+        buyorsell: tabIndex.value
+    }
+})
+
+const getDelistingButtonTitles = (tab: number, row: Model.TjmdTradeOrderDetailRsp) => {
+    /// 如果是机构自己的单 不能签署
+    if (row.userid === getUserId()) {
+        return '摘牌'
+    }
+    switch (status(row)) {
+        case 1:
+            return '签署'
+        case 2:
+            return '待审核'
+        case 3:
+            return '待审核'
+        default:
+            return '摘牌'
+    }
+}
+
+/// 每隔 30 秒去刷新请求数据信息
+setTimeout(() => {
+    // 获取买卖大厅数据
+    run()
+}, 30 * 1000)
+
+const onRefresh = () => {
+    run({
+        buyorsell: tabIndex.value,
+    })
+}
+
+const columns: Model.TableColumn[] = [
+    { prop: 'orderprice', label: '价格' },
+    { prop: 'orderqty', label: '数量' },
+    { prop: 'username', label: '挂牌方' },
+    { prop: 'operate', label: '摘牌' },
+]
+
+const onDelisting = (row: Model.TjmdTradeOrderDetailRsp) => {
+    selectedRow.value = row
+    /// 不能与自己成交
+    if (row.userid === loginStore.userId) {
+        showToast('不能与自己成交')
+        return
+    }
+    switch (status(row)) {
+        case 4: /// 已签署
+            openComponent('delisting')
+            break;
+        case 1:  /// 未签署
+            /// 传对应的机构 ID
+            /// 进行下一步
+            router.push({ name: 'account-protocol', query: { memberUserId: row.userid.toString() } })
+            break;
+        default: /// 其他状态
+            break;
+    }
+}
+
+const onListing = () => {
+    openComponent('listing')
+}
+
+onActivated(() => {
+    /// 查询
+    runMdUserSwapProtocol()
+})
+
+</script>

+ 193 - 0
src/packages/thj/views/swap/list/index.vue

@@ -0,0 +1,193 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar :title="titleName" :show-back-button="showBackButton" />
+        </template>
+        <app-table :columns="columns" :data-list="tableList" @row-click="rowClick">
+            <!-- 商品/代码 -->
+
+            <template #goodsname="{ row }">
+                <span>{{ row.goodsname }}</span>
+                <span class="text-small">{{ row.goodscode }}</span>
+            </template>
+            <!-- 当前价 -->
+
+            <template #last="{ row }">
+                <span :class="row.lastColor">{{ handleNumberValue(formatDecimal(row.last, row.decimalplace)) }}</span>
+            </template>
+            <!-- 涨跌 -->
+
+            <template #rise="{ row }">
+                <span :class="row.lastColor">{{ handleNumberValue(formatDecimal(row.rise, row.decimalplace)) }}</span>
+            </template>
+            <!-- 幅度 -->
+
+            <template #change="{ row }">
+                <span :class="row.lastColor">{{ parsePercent(row.change) }}</span>
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { computed, onUnmounted, onActivated, PropType } from 'vue'
+import { parsePercent, handleNumberValue, formatDecimal } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { useNavigation } from '@mobile/router/navigation'
+import { queryQuoteGoodsList, queryMdUserSwapProtocol } from '@/services/api/swap'
+import { requestInitMdUserSwapProtocol } from '@/services/api/account'
+import { useFuturesStore, useUserStore } from '@/stores'
+import { showToast } from 'vant'
+import { getMemberUserId, getUserId } from '@/services/methods/user'
+import { shallowRef } from 'vue'
+import quoteSocket from '@/services/websocket/quote'
+import AppTable from '@mobile/components/base/list/index.vue'
+
+const props = defineProps({
+    showBackButton: {
+        type: Boolean,
+        default: false
+    },
+    marketSection: {
+        type: Object as PropType<Model.Marketsectionconfignew>
+    }
+})
+
+const { router, getQueryString, setGlobalUrlParams } = useNavigation()
+const futuresStore = useFuturesStore()
+const userStore = useUserStore()
+const subscribe = quoteSocket.createSubscribe()
+const canProtocolSign = shallowRef(false)
+const title = getQueryString('title')
+const titleName = computed(() => title ? decodeURIComponent(title) : props.marketSection?.displayname ?? '掉期贸易')
+
+const { dataList, run } = useRequest(queryQuoteGoodsList, {
+    manual: true,
+    params: {
+        usertype: userStore.userType ?? 0,
+        marketids: userStore.getMarketId('TRADEMODE_TJMD').toString()
+    },
+    onSuccess: (res) => {
+        const goodsCodes = res.data.map((e) => e.refgoodscode)
+        subscribe.start(...goodsCodes)
+    }
+})
+
+const tableList = computed(() => {
+    return dataList.value.map(({ refgoodsid, refgoodscode, goodsid, goodscode, goodsname, refgoodsname, decimalplace }) => {
+        const quote = futuresStore.getGoodsQuote(refgoodsid)
+
+        const getValue = <K extends keyof Model.GoodsQuote>(key: K, defaultValue?: Model.GoodsQuote[K]) => {
+            const item = quote.value
+            return item ? item[key] : defaultValue
+        }
+
+        return Object.defineProperties({}, {
+            goodsid: {
+                get: () => goodsid,
+                enumerable: true
+            },
+            refgoodscode: {
+                get: () => refgoodscode,
+                enumerable: true
+            },
+            refgoodsid: {
+                get: () => refgoodsid,
+                enumerable: true
+            },
+            goodscode: {
+                get: () => goodscode,
+                enumerable: true
+            },
+            goodsname: {
+                get: () => goodsname,
+                enumerable: true
+            },
+            refgoodsname: {
+                get: () => refgoodsname,
+                enumerable: true
+            },
+            decimalplace: {
+                get: () => decimalplace,
+                enumerable: true
+            },
+            lastColor: {
+                get: () => getValue('lastColor'),
+                enumerable: true
+            },
+            last: {
+                get: () => getValue('last'),
+                enumerable: true
+            },
+            rise: {
+                get: () => getValue('rise'),
+                enumerable: true
+            },
+            change: {
+                get: () => getValue('change'),
+                enumerable: true
+            },
+        })
+    })
+})
+
+const columns: Model.TableColumn[] = [
+    { prop: 'goodsname', label: '商品/代码', fixed: 'left', width: 120 },
+    { prop: 'last', label: '当前价' },
+    { prop: 'rise', label: '涨跌' },
+    { prop: 'change', label: '幅度' }
+]
+
+const rowClick = (row: Model.QuoteGoodsListRsp) => {
+    /// 这里要去判断是否已经实名认证
+    if (userStore.hasAuth) {
+        if (userStore.userInfo.usertype != 2 && !canProtocolSign.value) {
+            showToast('请先通过“我的”-“协议签署”功能菜单签署相应的合同!')
+        } else {
+            setGlobalUrlParams(row)
+            router.push({ name: 'swap-detail' })
+        }
+    } else {
+        showToast('未实名认证,请先去实名认证,如果已提交实名认证,请耐心等待审核通过!')
+    }
+}
+
+/// 创建电子签合同
+const { run: initMdUserSwapProtocol } = useRequest(requestInitMdUserSwapProtocol, {
+    manual: true,
+    params: {
+        userId: getUserId(),
+        memberUserId: getMemberUserId()
+    },
+    onSuccess: () => {
+        /// 可以交易
+        canProtocolSign.value = true
+        /// 重新请求
+        showToast('合同已提交签署请求,请耐心等待审核通过!')
+    }
+})
+
+onActivated(() => {
+    const goodsCodes = dataList.value.map((e) => e.refgoodscode)
+    if (goodsCodes.length) {
+        subscribe.start(...goodsCodes)
+    } else {
+        run()
+    }
+
+    queryMdUserSwapProtocol({
+        data: {
+            userId: getUserId()
+        }
+    }).then((res) => {
+        if (res.data.length === 0) {
+            canProtocolSign.value = true
+            initMdUserSwapProtocol()
+        } else {
+            canProtocolSign.value = res.data.some(e => e.protocolstatus === 4)
+        }
+    })
+})
+
+onUnmounted(() => subscribe.stop())
+</script>

+ 1 - 1
src/packages/tjmd/router/index.ts

@@ -120,7 +120,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },

+ 1 - 3
src/packages/tjmd/views/home/main/index.less

@@ -99,9 +99,7 @@
                 padding: 6px 0;
 
                 &.is-active {
-                    &::before {
-                        background-color: transparent
-                    }
+                    background-color: #f9f9f9;
 
                     &.g-price-up {
                         background-color: #fff3f3;

+ 1 - 1
src/packages/zrwyt/router/index.ts

@@ -104,7 +104,7 @@ const routes: Array<RouteRecordRaw> = [
       {
         path: '',
         name: 'report',
-        component: () => import('@mobile//views/report/index.vue'),
+        component: () => import('@mobile/views/report/index.vue'),
       }
     ]
   },