Browse Source

添加热点币监控
添加热点信息

DESKTOP-NE65RNK\Citrus_limon 9 months ago
parent
commit
a63ee4f62b

+ 1 - 1
.env.development

@@ -1 +1 @@
-VITE_API_BASE_URL = "http://kline.skyfffire.com:82/priceCollect"
+VITE_API_BASE_URL = "http://cc.skyfffire.com:80"

+ 1 - 1
.env.production

@@ -1 +1 @@
-VITE_API_BASE_URL = "http://kline.skyfffire.com:82/priceCollect"
+VITE_API_BASE_URL = "http://cc.skyfffire.com:80"

+ 16 - 4
src/api/index.ts

@@ -1,24 +1,36 @@
 import http from "@/utils/request";
 
 export const get_exchange = (params: any, callback: any) => {
-  return http.request("/api/getExchange", "get", params).then((data) => {
+  return http.request("/priceCollect/api/getExchange", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
 };
 export const get_coin = (params: any, callback: any) => {
-  return http.request("/api/getCoin", "get", params).then((data) => {
+  return http.request("/priceCollect/api/getCoin", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
 };
 
 export const get_depth = (params: any, callback: any) => {
-  return http.request("/api/getPrices", "get", params).then((data) => {
+  return http.request("/priceCollect/api/getPrices", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
 };
 
 export const get_incremental_depth = (params: any, callback: any) => {
-  return http.request("/api/getAddPrices", "get", params).then((data) => {
+  return http.request("/priceCollect/api/getAddPrices", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+
+export const get_hot_list = (params: any, callback: any) => {
+  return http.request("/hotCollect/api/getHot", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+
+export const get_hotMonitoring_list = (params: any, callback: any) => {
+  return http.request("/hotCollect/api/getHotMonitoring", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
 };

+ 3 - 0
src/assets/css/index.scss

@@ -5,6 +5,9 @@
   --button-warm-color: #ffb800;
   --button-danger-color: #ff5722;
   --button-checked-color: #16b777;
+  --color-primary: rgb(28, 175, 131);
+  --color-danger: #ff5722;
+  --color-normal: #1e9fff;
 }
 
 * {

+ 36 - 0
src/components/PageLayout/Header.vue

@@ -0,0 +1,36 @@
+<template>
+  <div class="header-wp">
+    <div class="header-left-wp">
+      <div class="title">两江资本</div>
+      <div class="sub-title">无敌中控</div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+
+</script>
+<style lang="scss" scoped>
+.header-wp {
+  box-sizing: border-box;
+  height: 100%;
+  width: 100%;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+  display: flex;
+  .header-left-wp {
+    box-sizing: border-box;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+    text-align: center;
+    width: 256px;
+    border-right: 1px solid rgba(0, 0, 0, 0.1);
+    .title {
+      font-size: 18px;
+      font-weight: bold;
+    }
+    .sub-title {
+      font-weight: bold;
+    }
+  }
+}
+</style>

+ 117 - 0
src/components/PageLayout/Layout.vue

@@ -0,0 +1,117 @@
+<template>
+  <lay-layout class="layout-wp">
+    <lay-header :class="{ 'layout-header': true, 'layout-header-min': menuCollapse }">
+      <Header />
+    </lay-header>
+    <lay-layout>
+      <lay-side :class="{ 'layout-side': true, 'layout-side-min': menuCollapse }">
+        <Side :list="menuList" @collapse="handleCollapse" />
+      </lay-side>
+      <lay-body class="layout-body">
+        <div class="layout-main">
+          <div class="layout-content">
+            <router-view v-slot="{ Component, route }">
+              <keep-alive>
+                <component :is="Component" :key="route.name" />
+              </keep-alive>
+            </router-view>
+          </div>
+        </div>
+      </lay-body>
+    </lay-layout>
+  </lay-layout>
+</template>
+
+<script lang="ts" setup>
+import { ref } from "vue";
+import Header from "./Header.vue";
+import Side from "./Side.vue";
+
+interface MenuList {
+  icon?: string;
+  id?: number;
+  name?: string;
+  parentId?: number;
+  path?: string;
+  type?: number;
+  childMenu: Array<MenuList>;
+}
+
+const menuCollapse = ref<boolean>(JSON.parse(window.sessionStorage.getItem("_4L_MENU_COLLAPSE") || "false"));
+
+const menuList = ref<Array<MenuList>>([
+  {
+    icon: "",
+    id: 1,
+    name: "热点币信息",
+    parentId: 0,
+    path: "/hot",
+    type: 1,
+    childMenu: [],
+  },
+  {
+    icon: "",
+    id: 2,
+    name: "热点币监控",
+    parentId: 0,
+    path: "/hot_monitoring",
+    type: 1,
+    childMenu: [],
+  },
+  {
+    icon: "",
+    id: 3,
+    name: "深度信息",
+    parentId: 0,
+    path: "/depth",
+    type: 1,
+    childMenu: [],
+  },
+]);
+const handleCollapse = (value: boolean) => {
+  menuCollapse.value = value;
+};
+</script>
+<style lang="scss" scoped>
+.layout-wp {
+  min-width: 765px;
+  height: 100%;
+  :deep(.layout-header) {
+    height: 64px;
+  }
+
+  :deep(.layout-side) {
+    overflow: initial;
+    flex: 0 0 256px !important;
+    width: 256px !important;
+  }
+  :deep(.layout-header-min) {
+    .header-wp {
+      .header-left-wp {
+        flex: 0 0 64px !important;
+        width: 64px !important;
+        .title,
+        .sub-title {
+          display: none;
+        }
+      }
+    }
+  }
+  :deep(.layout-side-min) {
+    flex: 0 0 64px !important;
+    width: 64px !important;
+  }
+  .layout-body {
+    background-color: rgb(244, 246, 247);
+    .layout-main {
+      padding: 20px;
+      min-height: calc(100% - 51px);
+      box-sizing: border-box;
+      .layout-content {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}
+</style>

+ 161 - 0
src/components/PageLayout/Side.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="side-wp">
+    <div class="menu_switch_wp" @click="handeCwitchCollapse()">
+      <lay-icon size="12px" :type="collapse ? 'layui-icon-right' : 'layui-icon-left'" />
+    </div>
+    <lay-menu class="menu-wp" :selected-key="selectedKey" theme="light" v-model:openKeys="openKeys" :collapse="collapse" :tree="true">
+      <template v-for="item in list">
+        <lay-menu-item :id="item.path" v-if="item.childMenu.length == 0" @click="jumpPage(item)">
+          <template #icon>
+            <lay-icon :type="item.icon" />
+          </template>
+          <template #title>
+            {{ item.name }}
+          </template>
+        </lay-menu-item>
+        <lay-sub-menu :id="item.path" v-else>
+          <template #icon>
+            <lay-icon :type="item.icon" />
+          </template>
+          <template #title>
+            {{ item.name }}
+          </template>
+          <lay-menu-item :id="items.path" v-for="items in item.childMenu" @click="jumpPage(items)">
+            <span class="child-menu">{{ items.name }}</span>
+          </lay-menu-item>
+        </lay-sub-menu>
+      </template>
+    </lay-menu>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, watchEffect } from "vue";
+import { useRouter, useRoute } from "vue-router";
+
+const emit = defineEmits(["collapse", "open"]);
+
+const router = useRouter();
+const route = useRoute();
+
+interface MenuList {
+  icon?: string;
+  id?: number;
+  name?: string;
+  parentId?: number;
+  path?: string;
+  type?: number;
+  childMenu: Array<MenuList>;
+}
+
+const openKeys = ref<Array<string>>([]);
+const selectedKey = ref();
+const collapse = ref<boolean>(JSON.parse(window.sessionStorage.getItem("_4L_MENU_COLLAPSE") || "false"));
+
+const prpos = defineProps({
+  list: Array<MenuList>,
+  keepAliveList: Array<any>,
+});
+
+watchEffect(() => {
+  selectedKey.value = route.fullPath;
+  openKeys.value = [`/${route.fullPath.split("/")[1]}`];
+});
+
+const handeCwitchCollapse = () => {
+  collapse.value = !collapse.value;
+  window.sessionStorage.setItem("_4L_MENU_COLLAPSE", JSON.stringify(collapse.value));
+  emit("collapse", collapse.value);
+};
+
+const setSelectedKey = () => {
+  const defaultMenu = JSON.parse(window.sessionStorage.getItem("_4L_MENU_PATH") || "{}");
+  const selectedMenu = JSON.parse(window.sessionStorage.getItem("_4L_S_MENU_PATH") || "{}");
+  if (Object.keys(selectedMenu).length > 0) {
+    selectedKey.value = selectedMenu.path;
+    openKeys.value = [`/${selectedMenu.path.split("/")[1]}`];
+    jumpPage(selectedMenu);
+  } else if (Object.keys(defaultMenu).length > 0) {
+    selectedKey.value = defaultMenu.path;
+    openKeys.value = [`/${defaultMenu.path.split("/")[1]}`];
+    jumpPage(defaultMenu);
+  }
+};
+
+const jumpPage = (menu: any) => {
+  router.push({ path: menu.path, query: menu.query });
+  setTimeout(() => {
+    if (route.meta.keepAlive && !prpos.keepAliveList!.includes(route.name)) {
+      emit("open", route.name);
+    }
+  }, 100);
+};
+
+setSelectedKey();
+
+defineExpose({ collapse });
+</script>
+<style lang="scss" scoped>
+.side-wp {
+  position: relative;
+  box-sizing: border-box;
+  height: 100%;
+  width: 100%;
+  border-right: 1px solid rgba(0, 0, 0, 0.1);
+  .menu_switch_wp {
+    position: absolute;
+    right: -12px;
+    top: 40px;
+    width: 24px;
+    height: 24px;
+    font-size: 0;
+    line-height: 24px;
+    background: #ffffff;
+    color: rgba(51, 51, 51, 0.25);
+    text-align: center;
+    border-radius: 50%;
+    z-index: 2;
+    box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.05), 0 1px 4px -1px rgba(25, 15, 15, 0.07), 0 0 1px 0 rgba(0, 0, 0, 0.08);
+    &:hover {
+      color: rgba(51, 51, 51, 1);
+    }
+  }
+  .menu-wp {
+    box-sizing: border-box;
+    padding: 0;
+    width: auto;
+  }
+  :deep(.layui-nav-tree) {
+    .layui-this {
+      position: relative;
+      a {
+        background-color: rgb(232, 252, 247) !important;
+        border-right: 2px solid var(--color-theme) !important;
+        &::after {
+          content: "";
+          position: absolute;
+          width: 8px;
+          height: 8px;
+          z-index: 1;
+          transform: rotate(45deg) translateY(-50%);
+          transform-origin: center;
+          border-top: 1px solid var(--color-theme) !important;
+          border-right: 1px solid var(--color-theme) !important;
+          right: 20px;
+          top: 50%;
+        }
+        span,
+        i {
+          color: var(--color-theme) !important;
+        }
+      }
+    }
+    .layui-nav-child {
+      padding: 0;
+    }
+  }
+  .child-menu {
+    padding-left: 14px;
+  }
+}
+</style>

+ 34 - 0
src/components/TableButton.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="table-button" :class="props.type">{{ props.text }}</div>
+</template>
+<script lang="ts" setup>
+
+const props = defineProps({
+  type: {
+    type: String,
+    default: "primary",
+  },
+  text: {
+    type: String,
+    default: "按钮",
+  },
+});
+</script>
+<style lang="scss" scoped>
+.table-button{
+    cursor: pointer;
+    display: inline-block;
+}
+.primary {
+  color: var(--button-primary-color);
+}
+.normal {
+  color: var(--button-normal-color);
+}
+.warm {
+  color: var(--button-warm-color);
+}
+.danger {
+  color: var(--button-danger-color);
+}
+</style>

+ 24 - 5
src/router/routes.ts

@@ -3,13 +3,32 @@ import { RouteRecordRaw } from "vue-router";
 const routes: Array<RouteRecordRaw> = [
   {
     path: "/",
-    redirect: "/depth",
+    redirect: "/hot",
   },
   {
-    path: "/depth",
-    name: "Depth",
-    component: () => import("@/views/depth/index.vue"),
-    meta: { title: "深度信息" },
+    path: "/",
+    name: "Layout",
+    component: () => import("@/components/PageLayout/Layout.vue"),
+    children: [
+      {
+        path: "/depth",
+        name: "Depth",
+        component: () => import("@/views/depth/index.vue"),
+        meta: { title: "深度信息", keepAlive: true },
+      },
+      {
+        path: "/hot",
+        name: "Hot",
+        component: () => import("@/views/hot/index.vue"),
+        meta: { title: "热点币信息", keepAlive: true },
+      },
+      {
+        path: "/hot_monitoring",
+        name: "HotMonitoring",
+        component: () => import("@/views/hot_monitoring/index.vue"),
+        meta: { title: "热点币监控", keepAlive: true },
+      },
+    ],
   },
   {
     path: "/404",

+ 1 - 1
src/utils/request.ts

@@ -55,7 +55,7 @@ class HttpRequest {
       headers: {
         Accept: "application/json",
         "Content-Type": "application/json;charset=UTF-8",
-        auth: "43626546liangjiang",
+        auth: "4L",
       },
       timeout: 50000,
       baseURL: BASEURL,

+ 33 - 31
src/views/depth/index.vue

@@ -1,40 +1,42 @@
 <template>
-  <lay-loading :loading="pageLoading">
-    <div class="page_wp">
-      <div class="content_wp">
-        <div class="content_top_wp">
-          <div class="exchange_wp">
-            <div :class="{ exchange_item: true, selected: selectedExchangeList.includes(item) }" v-for="item in exchangeList" @click="handleExchange(item)">
-              {{ item }}
+  <lay-card>
+    <lay-loading :loading="pageLoading">
+      <div class="page_wp">
+        <div class="content_wp">
+          <div class="content_top_wp">
+            <div class="exchange_wp">
+              <div :class="{ exchange_item: true, selected: selectedExchangeList.includes(item) }" v-for="item in exchangeList" @click="handleExchange(item)">
+                {{ item }}
+              </div>
+            </div>
+            <div class="symbol_wp">
+              <div class="symbol_label">币对:</div>
+              <lay-select v-model="selectedSymbol" :show-search="true" @change="handleSelectedSymbol">
+                <lay-select-option v-for="item in symbolList" :keyword="item.toLocaleLowerCase()" :value="item" :label="item" />
+              </lay-select>
             </div>
           </div>
-          <div class="symbol_wp">
-            <div class="symbol_label">币对:</div>
-            <lay-select v-model="selectedSymbol" :show-search="true" @change="handleSelectedSymbol">
-              <lay-select-option v-for="item in symbolList" :keyword="item.toLocaleLowerCase()" :value="item" :label="item" />
-            </lay-select>
+          <div class="operator_wp" v-show="false">
+            <lay-space>
+              <div class="item_wp">
+                <div class="label">自动刷新</div>
+                <lay-switch v-model="isUpdate" />
+              </div>
+            </lay-space>
+          </div>
+          <div class="content_bottom_wp">
+            <lay-loading :loading="chartLoading">
+              <div class="chart_wp">
+                <div id="chart"></div>
+              </div>
+            </lay-loading>
           </div>
-        </div>
-        <div class="operator_wp" v-show="false">
-          <lay-space>
-            <div class="item_wp">
-              <div class="label">自动刷新</div>
-              <lay-switch v-model="isUpdate" />
-            </div>
-          </lay-space>
-        </div>
-        <div class="content_bottom_wp">
-          <lay-loading :loading="chartLoading">
-            <div class="chart_wp">
-              <div id="chart"></div>
-            </div>
-          </lay-loading>
         </div>
       </div>
-    </div>
-  </lay-loading>
+    </lay-loading>
+  </lay-card>
 </template>
-<script lang="ts" setup>
+<script lang="ts" setup name="Depth">
 import { ref, shallowRef, reactive, watch, onUnmounted } from "vue";
 import { init, getInstanceByDom } from "echarts";
 import dayjs from "dayjs";
@@ -76,7 +78,7 @@ watch(isUpdate, (value) => {
 
 // 获取交易所
 const getExchange = () => {
-  const ISUPDATE = JSON.parse(window.sessionStorage.getItem("_4L_K_V_ISUPDATE") || "true");
+  const ISUPDATE = JSON.parse(window.sessionStorage.getItem("_4L_K_V_ISUPDATE") || "false");
   isUpdate.value = ISUPDATE;
   pageLoading.value = true;
   get_exchange({}, (data: any) => {

+ 140 - 0
src/views/hot/index.vue

@@ -0,0 +1,140 @@
+<template>
+  <lay-card class="custom-card">
+    <template v-slot:title>
+      <span class="card-title">热点币信息</span>
+    </template>
+    <template v-slot:body>
+      <lay-tab type="brief" v-model="selectedTab" @change="handleTabChange">
+        <lay-tab-item :title="item.value" :id="item.key" v-for="item in tabList">
+          <div v-if="item.key == selectedTab" class="custom-form-layout">
+            <lay-form class="form-wp" :model="pageParams" mode="inline">
+              <lay-form-item label="排序方式" prop="sort">
+                <lay-select v-model="pageParams.sort" placeholder="请选择" @change="handleSortChange">
+                  <lay-select-option value="volume" label="交易量排序" />
+                  <lay-select-option value="diefu" label="涨幅排序" />
+                </lay-select>
+              </lay-form-item>
+            </lay-form>
+          </div>
+          <div v-if="item.key == selectedTab">
+            <lay-table :page="tablePage" :columns="columns" resize :data-source="dataSource" :loading="pageConfig.loading" @change="handleCurrentChange">
+              <template v-slot:diefu="{ row }">
+                <span :class="{ primary: row.diefu > 0, danger: row.diefu < 0 }">{{ row.diefuStr }}</span>
+              </template>
+            </lay-table>
+          </div>
+        </lay-tab-item>
+      </lay-tab>
+    </template>
+  </lay-card>
+</template>
+
+<script lang="ts" setup name="Hot">
+import { ref, reactive } from "vue";
+import { get_hot_list } from "@/api";
+
+interface PageConfig {
+  loading: boolean;
+}
+
+let pageConfig: PageConfig = reactive({
+  loading: false,
+});
+
+interface FormItem {
+  pageNum?: Number;
+  pageSize?: Number;
+  exchange?: String;
+  sort?: String;
+}
+const pageParams: FormItem = reactive({ pageNum: 1, pageSize: 10, exchange: "gate", sort: "volume" });
+
+interface TablePage {
+  current: number;
+  limit: number;
+  total: number;
+}
+const tablePage: TablePage = reactive({ current: 1, limit: 10, total: 0 });
+const columns = ref([
+  { title: "币对", key: "symbol" },
+  { title: "涨幅", key: "diefuStr", customSlot: "diefu" },
+  { title: "交易量", key: "volumeStr" },
+]);
+let dataSource = ref([]);
+
+const tabList = [
+  {
+    key: "gate",
+    value: "Gate",
+  },
+  {
+    key: "binance",
+    value: "Binance",
+  },
+];
+let selectedTab = ref(tabList[0].key);
+
+const handleTabChange = (tab: any) => {
+  switch (tab) {
+    case "gate":
+      pageParams.exchange = "gate";
+      getPageInfo(true);
+      break;
+    case "binance":
+      pageParams.exchange = "binance";
+      getPageInfo(true);
+      break;
+    default:
+      pageParams.exchange = "gate";
+      getPageInfo(true);
+      break;
+  }
+};
+const handleSortChange = () => {
+  getPageInfo();
+};
+
+// 请求热点列表
+const getPageInfo = (isSearch?: boolean) => {
+  if (isSearch) pageParams.pageNum = 1;
+  pageConfig.loading = true;
+  get_hot_list(pageParams, (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      dataSource.value = data.data.list;
+      tablePage.total = data.data.total;
+    }
+  });
+};
+getPageInfo();
+
+// 删除热点信息
+// const handleDelete = async (value: any) => {
+//   let result = await proxy.$waitingConfirm("是否确认删除该ApiKey?");
+//   if (!result) return;
+//   let params = [value.userProofId];
+//   pageConfig.loading = true;
+//   delete_apikey(params, (data: any) => {
+//     pageConfig.loading = false;
+//     if (data.code == 200) {
+//       proxy.$message(`删除成功!`);
+//       getPageInfo();
+//     }
+//   });
+// };
+
+// 分页设置
+const handleCurrentChange = (val: any) => {
+  pageParams.pageNum = val.current;
+  getPageInfo();
+};
+</script>
+
+<style lang="scss" scoped>
+.primary {
+  color: var(--color-primary);
+}
+.danger {
+  color: var(--color-danger);
+}
+</style>

+ 114 - 0
src/views/hot_monitoring/index.vue

@@ -0,0 +1,114 @@
+<template>
+  <lay-card class="custom-card">
+    <template v-slot:title>
+      <span class="card-title">热点币监控</span>
+    </template>
+    <template v-slot:body>
+      <div>
+        <lay-table :page="tablePage" :columns="columns" resize :data-source="dataSource" :loading="pageConfig.loading" @change="handleCurrentChange">
+          <template v-slot:content="{ row }">
+            <span :class="{ primary: row.diefu > 0, danger: row.diefu < 0 }">{{ row.diefu > 0 ? `▲上涨${row.diefu}%` : row.diefu < 0 ? `▼下跌${row.diefu}%` : `${row.diefu}%` }}</span>
+          </template>
+          <template v-slot:transaction="{ row }">
+            <span>
+              <lay-space>
+                <span>
+                  <span v-for="(item, index) in row.exchange.split('|')">
+                    <a class="normal" :href="handleHref(row, item)" target="_blank">
+                      {{ item }}
+                    </a>
+                    <lay-line direction="vertical" v-if="index != row.exchange.split('|').length - 1" />
+                  </span>
+                </span>
+                <span>--></span>
+                <span>{{ handleUnit(row.volume) }}</span>
+              </lay-space>
+            </span>
+          </template>
+        </lay-table>
+      </div>
+    </template>
+  </lay-card>
+</template>
+<script lang="ts" setup name="HotMonitoring">
+import { ref, reactive } from "vue";
+import { get_hotMonitoring_list } from "@/api";
+
+interface PageConfig {
+  loading: boolean;
+}
+
+let pageConfig: PageConfig = reactive({
+  loading: false,
+});
+
+interface FormItem {
+  pageNum?: Number;
+  pageSize?: Number;
+  exchange?: String;
+  sort?: String;
+}
+const pageParams: FormItem = reactive({ pageNum: 1, pageSize: 15 });
+
+interface TablePage {
+  current: number;
+  limit: number;
+  total: number;
+}
+const tablePage: TablePage = reactive({ current: 1, limit: 15, total: 0 });
+const columns = ref([
+  { title: "币种", key: "symbol" },
+  { title: "内容", key: "content", customSlot: "content" },
+  { title: "成交", key: "transaction", customSlot: "transaction" },
+  { title: "创建时间", key: "timeStr" },
+]);
+let dataSource = ref([]);
+// 请求热点列表
+const getPageInfo = (isSearch?: boolean) => {
+  if (isSearch) pageParams.pageNum = 1;
+  pageConfig.loading = true;
+  get_hotMonitoring_list(pageParams, (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      dataSource.value = data.data.list;
+      tablePage.total = data.data.total;
+    }
+  });
+};
+getPageInfo();
+
+const handleUnit = (value: string) => {
+  const volume = parseInt(value);
+  if (volume / 100000000 >= 1) return `${(volume / 100000000).toFixed(2)}亿`;
+  if (volume / 10000 >= 1) return `${(volume / 10000).toFixed(2)}万`;
+};
+
+const handleHref = (row: any, exchange: string) => {
+  switch (exchange) {
+    case "binance":
+      return `https://www.binance.com/zh-CN/futures/${row.symbol}`;
+    case "gate":
+      return `https://www.gate.io/zh/futures/USDT/${row.symbol.replace("USDT", "")}_USDT`;
+    default:
+      return `https://www.binance.com/zh-CN/futures/${row.symbol}`;
+  }
+};
+
+// 分页设置
+const handleCurrentChange = (val: any) => {
+  pageParams.pageNum = val.current;
+  getPageInfo();
+};
+</script>
+
+<style lang="scss" scoped>
+.primary {
+  color: var(--color-primary);
+}
+.danger {
+  color: var(--color-danger);
+}
+.normal {
+  color: var(--color-normal);
+}
+</style>