瀏覽代碼

1.修改cta机器管理页面
2.添加cta机器余额处理
3.添加cta机器详情页面
4.修改机器人管理页面组件名错误

DESKTOP-NE65RNK\Citrus_limon 7 月之前
父節點
當前提交
e39fe31fe0

+ 24 - 0
src/api/index.ts

@@ -232,6 +232,30 @@ export const refresh_cta_robot_balance = (params: any, callback: any) => {
     if (data) callback && callback(data);
   });
 };
+// 机器人管理-CTA机器复位本金
+export const restoration_cta_robot_balance = (params: any, callback: any) => {
+  return http.request("/cta/transaction_config/restoration", "post", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+// 机器人管理-CTA机器详情
+export const get_cta_robot_detail = (params: any, callback: any) => {
+  return http.request("/cta/transaction_config/detail", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+// 机器人管理-CTA机器订单列表
+export const get_cta_robot_order_list = (params: any, callback: any) => {
+  return http.request("/cta/statistics/order/getPage", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+// 机器人管理-CTA机器利润
+export const get_cta_robot_profit = (params: any, callback: any) => {
+  return http.request("/cta/statistics/profitLossAndTradeVolume", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
 
 // 策略管理
 // 策略管理-策略列表

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

@@ -94,6 +94,9 @@ body,
       background-color: var(--color-theme);
     }
   }
+  .card-subtitle{
+    font-size: 12px;
+  }
   .layui-card-header-extra {
     float: none;
     height: auto;

+ 7 - 1
src/router/routes.ts

@@ -212,7 +212,7 @@ const routes: Array<RouteRecordRaw> = [
     path: "/bot/as/detail/:id",
     name: "BotAsDetail",
     component: () => import("@/views/bot/as/detail.vue"),
-    meta: { title: "AS机器人详情", keepAlive: true },
+    meta: { title: "AS机器人详情", keepAlive: false },
   },
   {
     path: "/bot/arbitrage/detail/:id",
@@ -220,6 +220,12 @@ const routes: Array<RouteRecordRaw> = [
     component: () => import("@/views/bot/arbitrage/detail.vue"),
     meta: { title: "套利机器人详情", keepAlive: false },
   },
+  {
+    path: "/bot/cta/detail/:id",
+    name: "BotCtaDetail",
+    component: () => import("@/views/bot/cta/detail.vue"),
+    meta: { title: "CTA机器人详情", keepAlive: false },
+  }
 ];
 
 export default routes;

+ 7 - 0
src/utils/index.ts

@@ -1,4 +1,5 @@
 import { md5 } from "js-md5";
+import dayjs from "dayjs";
 
 export const generateAvatar = (text: string, backgroundColor?: string, textColor?: string) => {
   const canvas = document.createElement("canvas");
@@ -42,3 +43,9 @@ export const unitConverts = (value: number) => {
   if (value >= 1000) return `${(value / 1000).toFixed(2)}K`;
   return `${value}`;
 };
+
+
+export const formatDate = (value: number) => {
+  return dayjs(value).format("YYYY-MM-DD HH:mm:ss");
+};
+

+ 2 - 1
src/views/bot/arbitrage/detail.vue

@@ -59,7 +59,7 @@
   </div>
   <LogText ref="logtextRef" />
 </template>
-<script lang="ts" setup name="BotManageDetail">
+<script lang="ts" setup name="BotArbitrageDetail">
 import { ref, reactive, onMounted, onUnmounted, shallowRef } from "vue";
 import { useRoute } from "vue-router";
 import * as echarts from "echarts";
@@ -247,6 +247,7 @@ onUnmounted(() => {
   height: 1200px;
 }
 .robot-info-header {
+  min-width: 1352px;
   background-color: white;
   padding: 16px 24px;
   margin-bottom: 20px;

+ 1 - 1
src/views/bot/arbitrage/index.vue

@@ -52,7 +52,7 @@
   </lay-card>
 </template>
 
-<script lang="ts" setup name="BotManage">
+<script lang="ts" setup name="BotArbitrage">
 import { ref, reactive, onBeforeUnmount } from "vue";
 import { get_arbitrage_robot_list } from "@/api";
 import { timeConverts } from "@/utils";

+ 2 - 1
src/views/bot/as/detail.vue

@@ -61,7 +61,7 @@
   </div>
   <LogText ref="logtextRef" />
 </template>
-<script lang="ts" setup name="BotManageDetail">
+<script lang="ts" setup name="BotAsDetail">
 import { ref, reactive, onMounted, onUnmounted, shallowRef } from "vue";
 import { useRoute } from "vue-router";
 import * as echarts from "echarts";
@@ -315,6 +315,7 @@ onUnmounted(() => {
   height: 1200px;
 }
 .robot-info-header {
+  min-width: 1352px;
   background-color: white;
   padding: 16px 24px;
   margin-bottom: 20px;

+ 1 - 1
src/views/bot/as/index.vue

@@ -168,7 +168,7 @@
   <Automate ref="automateRef" />
 </template>
 
-<script lang="ts" setup name="BotManage">
+<script lang="ts" setup name="BotAs">
 import { ref, reactive, getCurrentInstance, onActivated, onDeactivated } from "vue";
 import BatchUpdate from "./components/BatchUpdate.vue";
 import Update from "./components/Update.vue";

+ 40 - 0
src/views/bot/cta/components/InfoLayer.vue

@@ -0,0 +1,40 @@
+<template>
+  <lay-layer :title="modelConfig.title" v-model="modelConfig.visible" area="auto">
+    <div class="width-1000 custom-layer" style="padding: 20px">
+      <div class="content">
+        {{ modelParams.text }}
+      </div>
+    </div>
+  </lay-layer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from "vue";
+
+interface ModelConfig {
+  title: string;
+  visible: boolean;
+  isUpdate: boolean;
+  loading: boolean;
+}
+interface ModelParams {
+  text?: string;
+}
+
+let modelParams = ref<ModelParams>({});
+let modelConfig: ModelConfig = reactive({ title: "", visible: false, isUpdate: false, loading: false });
+
+const show = (params?: any) => {
+  modelConfig.visible = true;
+  modelConfig.title = "数据详情";
+  modelParams.value = { text: params };
+};
+
+defineExpose({ show });
+</script>
+<style lang="scss" scoped>
+.content {
+  word-wrap: break-word;
+  padding: 10px;
+}
+</style>

+ 3 - 3
src/views/bot/cta/components/Update.vue

@@ -13,13 +13,13 @@
               <lay-input v-model="modelParams.symbol" placeholder="交易币对" />
             </lay-form-item>
           </lay-col>
-          <!-- <lay-col md="12" sm="12" xs="24">
+          <lay-col md="12" sm="12" xs="24">
             <lay-form-item label="服务器" prop="serverId">
               <lay-select v-model="modelParams.serverId" :show-search="true">
                 <lay-select-option v-for="item in serverList" :value="item.id" :label="item.value" placeholder="选择服务器" />
               </lay-select>
             </lay-form-item>
-          </lay-col> -->
+          </lay-col>
           <lay-col md="12" sm="12" xs="24">
             <lay-form-item label="交易所" prop="exchange">
               <lay-select v-model="modelParams.exchange" :show-search="true">
@@ -71,7 +71,7 @@ interface ModelParams {
   symbol?: string;
   fundRatio?: number;
   exchange?: string;
-  // serverId?: number;
+  serverId?: number;
   accountId?: number;
   stopLoss?: number;
 }

+ 201 - 129
src/views/bot/cta/detail.vue

@@ -4,149 +4,205 @@
       <lay-space>
         <span class="robot-name">{{ robotDetail.name }}</span>
         <lay-tag size="sm">
-          <span class="robot-status" v-if="robotDetail.status == 'RUNNING'">
+          <span class="robot-status" v-if="robotDetail.status">
             <lay-badge type="dot" theme="blue" ripple />
             <span>{{ ROBOT_STATUS[robotDetail.status] }}</span>
           </span>
-          <span class="robot-status" v-else-if="robotDetail.status == 'ERROR'">
-            <lay-badge type="dot" ripple />
-            <span>{{ ROBOT_STATUS[robotDetail.status] }}</span>
-          </span>
-          <span class="robot-status" v-else>
-            <lay-badge type="dot" theme="orange" ripple />
+          <span class="robot-status" v-else-if="!robotDetail.status">
+            <lay-badge type="dot" />
             <span>{{ ROBOT_STATUS[robotDetail.status] }}</span>
           </span>
         </lay-tag>
       </lay-space>
     </div>
 
-    <lay-card v-show="apiList?.includes('/remaining/list')" class="custom-card">
-      <template v-slot:title>
-        <span class="card-title">净值图</span>
-      </template>
-      <template v-slot:body>
-        <div class="profit-chart" ref="balanceChartRef"></div>
-      </template>
-    </lay-card>
-
     <lay-card class="custom-card">
       <template v-slot:title>
-        <span class="card-title">内部数据</span>
-      </template>
-      <template v-slot:extra>
-        <lay-button class="card-button" @click="handleReloadIframe()">{{ robotRunDataIsShow ? "刷新" : "获取" }} </lay-button>
-        <lay-button class="card-button" @click="handleOtherOpen()">站外打开</lay-button>
+        <span class="card-title">收益图</span>
+        <span class="card-subtitle">(近3天)</span>
       </template>
       <template v-slot:body>
-        <div :class="{ 'card-body-wp': true, 'height-1200': robotRunDataIsShow }">
-          <iframe v-if="robotRunDataIsShow" :class="{ chart: true, 'height-1200': robotRunDataIsShow }" :src="robotRunData" frameborder="0"></iframe>
-          <div v-else>内部数据,数据可能较大,请勿频繁获取、刷新!</div>
-        </div>
+        <div class="profit-chart" ref="profitChartRef"></div>
       </template>
     </lay-card>
-
-    <lay-card v-if="apiList?.includes('/robot/getRobotLog')" class="custom-card">
+    <lay-card class="custom-card">
       <template v-slot:title>
-        <span class="card-title">运行日志</span>
+        <span class="card-title">订单列表</span>
       </template>
 
       <template v-slot:body>
-        <lay-table :columns="columns" size="sm" resize :data-source="logsList">
+        <lay-table :page="ordersPage" :columns="orderColumns" size="sm" resize :data-source="ordersList" :loading="pageConfig.ordersLoading" @change="handleCurrentChange">
           <template v-slot:text="{ row }">
-            <span class="ellipsis-2" @click="showLog(row.text)">{{ row.text }}</span>
+            {{ row.text }}
+          </template>
+          <template v-slot:symbol="{ row }">
+            {{ JSON.parse(row.resJson).symbol.split(":")[0] }}
+          </template>
+          <template v-slot:price="{ row }">
+            {{ JSON.parse(row.resJson).price }}
+          </template>
+          <template v-slot:average="{ row }">
+            {{ JSON.parse(row.resJson).average }}
+          </template>
+          <template v-slot:side="{ row }">
+            {{ JSON.parse(row.resJson).side }}
+          </template>
+          <template v-slot:sideType="{ row }">
+            {{ JSON.parse(row.resJson).reduceOnly ? "平仓" : "开仓" }}
+          </template>
+          <template v-slot:amount="{ row }">
+            {{ JSON.parse(row.resJson).amount }}
+          </template>
+          <template v-slot:timestamp="{ row }">
+            {{ formatDate(JSON.parse(row.resJson).timestamp) }}
+          </template>
+          <template v-slot:resJson="{ row }">
+            <span @click="showInfoLayer(row.resJson)">{{ row.resJson }}</span>
           </template>
         </lay-table>
       </template>
     </lay-card>
   </div>
-  <LogText ref="logtextRef" />
+  <InfoLayer ref="infoLayerRef" />
 </template>
-<script lang="ts" setup name="BotManageDetail">
+<script lang="ts" setup name="BotCtaDetail">
 import { ref, reactive, onMounted, onUnmounted, shallowRef } from "vue";
 import { useRoute } from "vue-router";
+import { formatDate } from "@/utils/index";
 import * as echarts from "echarts";
-import LogText from "./components/LogText.vue";
-import { get_robot_detail, get_robot_logs, get_remaining_detail } from "@/api";
+import Decimal from "decimal.js";
+import dayjs from "dayjs";
+import InfoLayer from "./components/InfoLayer.vue";
+import { get_cta_robot_detail, get_cta_robot_order_list, get_cta_robot_profit } from "@/api";
 
 const ROBOT_STATUS: any = reactive({
-  STOPPED: "已停止",
-  STOP_PENDING: "停止中",
-  RUNNING: "运行中",
-  START_PENDING: "启动中",
-  RESTART_PENDING: "重启中",
-  DOWNLOADING: "下载中",
-  ERROR: "错误",
+  0: "已停止",
+  1: "运行中",
 });
 
-const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
+// const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
 
-const balanceChartRef = ref();
-const logtextRef = ref();
+const profitChartRef = ref();
+const infoLayerRef = ref();
 
 const route = useRoute();
 
 interface PageConfig {
-  predictorLoading: boolean;
-  robotLoading: boolean;
-  balanceLoading: boolean;
-  logsLoading: boolean;
+  detailLoading: boolean;
+  ordersLoading: boolean;
+  profitLoading: boolean;
 }
-interface Logs {
+interface Order {
   time?: string;
   text?: string;
 }
 
 let pageConfig: PageConfig = reactive({
-  predictorLoading: false,
-  robotLoading: false,
-  balanceLoading: false,
-  logsLoading: false,
+  detailLoading: true,
+  ordersLoading: true,
+  profitLoading: true,
 });
 
-const columns = ref([
-  { title: "时间", key: "time", width: 150 },
-  { title: "日志", key: "text", customSlot: "text" },
+interface OrderItem {
+  pageNum?: Number;
+  pageSize?: Number;
+  name?: String;
+  symbol?: String;
+  robotState?: String;
+}
+const ordersParams: OrderItem = reactive({ pageNum: 1, pageSize: 50 });
+
+interface OrderPage {
+  current: number;
+  limit: number;
+  total: number;
+}
+const ordersPage: OrderPage = reactive({ current: 1, limit: 50, total: 0, limits: [20, 50, 100, 200, 500] });
+
+const orderColumns = ref([
+  { title: "订单号", key: "id", width: 150 },
+  { title: "币对", key: "symbol", customSlot: "symbol", align: "center" },
+  { title: "价格", key: "price", customSlot: "price", align: "center" },
+  { title: "成交均价", key: "average", customSlot: "average", align: "center" },
+  { title: "方向", key: "side", customSlot: "side", align: "center" },
+  { title: "类型", key: "sideType", customSlot: "sideType", align: "center" },
+  { title: "数量", key: "amount", customSlot: "amount", align: "center" },
+  { title: "订单时间", key: "timestamp", customSlot: "timestamp", align: "center" },
+  { title: "源数据", key: "resJson", customSlot: "resJson", ellipsisTooltip: true, align: "center" },
 ]);
 
-let logsList = ref<Array<Logs>>();
+let ordersList = ref<Array<Order>>();
 let robotDetail = ref<any>({});
-let balanceList = ref([]);
-let balanceChart = shallowRef();
+let profitList = ref([]);
+let profitChart = shallowRef();
 let predictorChart = shallowRef();
 let timer = ref();
-let robotRunData = ref();
-let robotRunDataIsShow = ref(false);
 
 // 获取机器人详情
-const getRobotDetail = () => {
+const getCtaRobotDetail = () => {
   const params = { id: route.params.id };
-  pageConfig.robotLoading = true;
-  get_robot_detail(params, (data: any) => {
-    pageConfig.robotLoading = false;
+  pageConfig.detailLoading = true;
+  get_cta_robot_detail(params, (data: any) => {
+    pageConfig.detailLoading = false;
     if (data.code == 200) {
       robotDetail.value = data.data;
       document.title = data.data.name;
-      getBalanceInfo(data.data.accId);
-      robotRunData.value = `https://4lapi.skyfffire.com/downloadDataFile?url=http://${robotDetail.value.serverIp}:3000/downloadDataFile?id=${robotDetail.value.id}`;
+      getCtaRobotOrderList();
+      getProfitInfo(data.data.id);
+    }
+  });
+};
+
+const getCtaRobotOrderList = () => {
+  const params = { ...ordersParams, tId: route.params.id };
+  pageConfig.ordersLoading = true;
+  get_cta_robot_order_list(params, (data: any) => {
+    pageConfig.ordersLoading = false;
+    if (data.code == 200) {
+      ordersList.value = data.data.list;
+      ordersPage.total = data.data.total;
     }
   });
 };
 
-const getBalanceInfo = (id: number) => {
-  const params = { id: id };
-  pageConfig.balanceLoading = true;
-  get_remaining_detail(params, (data: any) => {
-    pageConfig.balanceLoading = false;
+// 分页设置
+const handleCurrentChange = (val: any) => {
+  ordersParams.pageNum = val.current;
+  ordersParams.pageSize = val.limit;
+  getCtaRobotOrderList();
+};
+const getProfitInfo = (id: number) => {
+  const params = { tId: id, startTime: +dayjs().subtract(72, "hour"), endTime: +dayjs() };
+  pageConfig.profitLoading = true;
+  get_cta_robot_profit(params, (data: any) => {
+    pageConfig.profitLoading = false;
     if (data.code == 200) {
-      balanceList.value = data.data;
+      profitList.value = data.data;
 
-      const xData = data.data.map((item: any) => item.creationTime);
-      const sData = data.data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
-      const yMinData = Math.min(sData.map((item: any) => item[1]));
+      let balance = new Decimal(0);
+      const sData = data.data.map((item: any) => {
+        balance = new Decimal(item.profitLoss).add(balance);
+        return [
+          formatDate(item.timestamp),
+          balance.toString(),
+          item.symbol.split(":")[0],
+          item.openSide,
+          item.openPrice,
+          item.openSize,
+          item.openTradeVolume,
+          item.closedSide,
+          item.closedPrice,
+          item.closedSize,
+          item.closedTradeVolume,
+          item.profitLoss,
+        ];
+      });
+      const xData = sData.map((item: any) => item[0]);
+      const yMinData = Math.min(...sData.map((item: any) => item[1]));
 
-      !balanceChart.value
-        ? initBalanceChart(data.data)
-        : balanceChart.value.setOption({
+      !profitChart.value
+        ? initProfitChart(data.data)
+        : profitChart.value.setOption({
             xAxis: {
               type: "category",
               boundaryGap: false,
@@ -156,7 +212,7 @@ const getBalanceInfo = (id: number) => {
               type: "value",
               boundaryGap: [0, "100%"],
               min: yMinData,
-              interval: 1,
+              splitNumber: 5,
             },
             series: {
               name: "Balance",
@@ -173,43 +229,60 @@ const getBalanceInfo = (id: number) => {
 };
 
 // 请求机器人日志
-const getLogsInfo = () => {
-  const params = { id: route.params.id, n: 500 };
-  pageConfig.logsLoading = true;
-  get_robot_logs(params, (data: any) => {
-    pageConfig.logsLoading = false;
-    if (data.code == 200) {
-      logsList.value = handlePageInfo(data.data);
-    }
-  });
-};
-getLogsInfo();
+// const getLogsInfo = () => {
+//   const params = { id: route.params.id, n: 500 };
+//   pageConfig.logsLoading = true;
+//   get_robot_logs(params, (data: any) => {
+//     pageConfig.logsLoading = false;
+//     if (data.code == 200) {
+//       logsList.value = handlePageInfo(data.data);
+//     }
+//   });
+// };
+// getLogsInfo();
 
-const showLog = (data: any) => {
-  logtextRef.value.show(data);
-};
+// const handlePageInfo = (data: any) => {
+//   let infoList = data;
+//   let result = infoList.map((item: string) => {
+//     return { time: item.slice(0, 18), text: item.slice(19).trim() };
+//   });
+//   return result;
+// };
 
-const handlePageInfo = (data: any) => {
-  let infoList = data;
-  let result = infoList.map((item: string) => {
-    return { time: item.slice(0, 18), text: item.slice(19).trim() };
-  });
-  return result;
+const showInfoLayer = (data: any) => {
+  infoLayerRef.value.show(data);
 };
 
-const initBalanceChart = (data: any) => {
-  if (balanceChart.value != null && !balanceChart.value.isDisposed()) echarts.dispose(balanceChart.value);
+const initProfitChart = (data: any) => {
+  if (profitChart.value != null && !profitChart.value.isDisposed()) echarts.dispose(profitChart.value);
 
-  balanceChart.value = echarts.init(balanceChartRef.value);
+  profitChart.value = echarts.init(profitChartRef.value);
 
-  window.removeEventListener("resize", () => balanceChart.value.resize());
-  window.addEventListener("resize", () => balanceChart.value.resize());
+  window.removeEventListener("resize", () => profitChart.value.resize());
+  window.addEventListener("resize", () => profitChart.value.resize());
 
-  const xData = data.map((item: any) => item.creationTime);
-  const sData = data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
-  const yMinData = Math.min(sData);
+  let balance = new Decimal(0);
+  const sData = data.map((item: any) => {
+    balance = new Decimal(item.profitLoss).add(balance);
+    return [
+      formatDate(item.timestamp),
+      balance.toString(),
+      item.symbol.split(":")[0],
+      item.openSide,
+      item.openPrice,
+      item.openSize,
+      item.openTradeVolume,
+      item.closedSide,
+      item.closedPrice,
+      item.closedSize,
+      item.closedTradeVolume,
+      item.profitLoss,
+    ];
+  });
+  const xData = sData.map((item: any) => item[0]);
+  const yMinData = Math.min(...sData.map((item: any) => item[1]));
 
-  const balanceChartOption = {
+  const profitChartOption = {
     tooltip: {
       trigger: "axis",
       axisPointer: {
@@ -217,7 +290,16 @@ const initBalanceChart = (data: any) => {
       },
       formatter: (params: any) => {
         let info = params[0];
-        return `${info.marker}${info.seriesName}<br/>时间:${info.value[0]} <br/>余额:${info.value[1]}<br/>收益:${info.value[2]}<br/>币对:${info.value[3]}<br/>开仓:${info.value[4]}<br/>平仓:${info.value[5]}`;
+        return `${info.marker}${info.seriesName}<br/>
+        时间:${info.value[0]} <br/>
+        币对:${info.value[2]}<br/>
+        总体收益:${info.value[1]}<br/>
+        单笔收益:${info.value[11]}<br/>
+        开仓方向:${info.value[3]}<br/>
+        开仓价格:${info.value[4]}&nbsp;&nbsp;&nbsp;&nbsp;开仓数量:${info.value[5]}&nbsp;&nbsp;&nbsp;&nbsp;开仓价值:${info.value[6]}<br/>
+        平仓方向:${info.value[7]}<br/>
+        平仓价格:${info.value[8]}&nbsp;&nbsp;&nbsp;&nbsp;平仓数量:${info.value[9]}&nbsp;&nbsp;&nbsp;&nbsp;平仓价值:${info.value[10]}<br/>
+        `;
       },
     },
     dataZoom: [
@@ -240,7 +322,7 @@ const initBalanceChart = (data: any) => {
       type: "value",
       boundaryGap: [0, "100%"],
       min: yMinData,
-      interval: 1,
+      splitNumber: 5,
     },
     series: {
       name: "Balance",
@@ -249,33 +331,22 @@ const initBalanceChart = (data: any) => {
       data: sData,
     },
   };
-  balanceChart.value.setOption(balanceChartOption);
+  profitChart.value.setOption(profitChartOption);
 };
 
 timer.value = setInterval(() => {
-  getBalanceInfo(robotDetail.value.accId);
-  getLogsInfo();
-}, 5000);
-
-getLogsInfo();
+  getProfitInfo(robotDetail.value.id);
+  // getLogsInfo();
+}, 10000);
 
-const handleReloadIframe = () => {
-  robotRunDataIsShow.value = true;
-  robotRunData.value = ``;
-  setTimeout(() => {
-    robotRunData.value = `https://4lapi.skyfffire.com/downloadDataFile?url=http://${robotDetail.value.serverIp}:3000/downloadDataFile?id=${robotDetail.value.id}`; // 重新赋值
-  }, 0);
-};
-const handleOtherOpen = () => {
-  window.open(`https://4lapi.skyfffire.com/downloadDataFile?url=http://${robotDetail.value.serverIp}:3000/downloadDataFile?id=${robotDetail.value.id}`, "_blank");
-};
+// getLogsInfo();
 
 onMounted(() => {
-  getRobotDetail();
+  getCtaRobotDetail();
 });
 
 onUnmounted(() => {
-  window.removeEventListener("resize", () => balanceChart.value.resize());
+  window.removeEventListener("resize", () => profitChart.value.resize());
   clearInterval(timer.value);
   predictorChart.value.dispose();
 });
@@ -315,6 +386,7 @@ onUnmounted(() => {
   height: 1200px;
 }
 .robot-info-header {
+  min-width: 1352px;
   background-color: white;
   padding: 16px 24px;
   margin-bottom: 20px;

+ 29 - 16
src/views/bot/cta/index.vue

@@ -32,15 +32,14 @@
           <lay-space>
             <!-- <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'green'" size="xs" @click="handleStatus(selectedKeys, 'RUN')">开机</lay-button> -->
             <!-- <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'red'" size="xs" @click="handleStatus(selectedKeys, 'STOP')">停机</lay-button> -->
-            <!-- <lay-button v-if="apiList?.includes('/robot/resetCapital')" :border="'green'" size="xs" @click="handleResetCapital(selectedKeys)">复位本金</lay-button> -->
+            <lay-button :border="'green'" size="xs" @click="handleRrestoration(selectedKeys)">复位余额</lay-button>
           </lay-space>
         </div>
       </div>
       <div>
         <lay-table :page="tablePage" :columns="columns" resize id="id" :data-source="dataSource" v-model:selected-keys="selectedKeys" :loading="pageConfig.loading" @change="handleCurrentChange">
           <template v-slot:name="{ row }">
-            <span v-if="apiList?.includes('/robot/findById')" class="normal-color" @click="jumpDetail(row)">{{ row.name }}</span>
-            <span v-else>{{ row.name }}</span>
+            <span class="normal-color" @click="jumpDetail(row)">{{ row.name }}</span>
           </template>
           <template v-slot:earningRate="{ row }">
             <span :class="{ 'primary-color': row.nowAmount - row.startAmount > 0, 'danger-color': row.nowAmount - row.startAmount < 0 }">
@@ -72,32 +71,32 @@
               <TableButton :text="row.status ? '关机' : '开机'" :type="row.status ? 'danger' : 'primary'" @click="handleStatus(row)" />
               <TableButton text="编辑" @click="handleUpdate(row)" />
               <TableButton text="更新余额" @click="refreshBalance(row)" />
-              <TableButton v-if="row.status" type="danger" text="删除" @click="handleDelete(row)" />
+              <TableButton v-if="!row.status" type="danger" text="删除" @click="handleDelete(row)" />
             </lay-space>
           </template>
         </lay-table>
       </div>
-      <!-- <div class="custom-operator-wp padding-top-10">
-        <div class="custom-group collect-wp" v-html="collectInfo" />
+      <div class="custom-operator-wp padding-top-10">
+        <!-- <div class="custom-group collect-wp" v-html="collectInfo" /> -->
         <div class="custom-group">
           <lay-space>
-            <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'green'" size="xs" @click="handleStatus(selectedKeys, 'RUN')">开机</lay-button>
-            <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'red'" size="xs" @click="handleStatus(selectedKeys, 'STOP')">停机</lay-button>
-            <lay-button v-if="apiList?.includes('/robot/resetCapital')" :border="'green'" size="xs" @click="handleResetCapital(selectedKeys)">复位本金</lay-button>
+            <!-- <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'green'" size="xs" @click="handleStatus(selectedKeys, 'RUN')">开机</lay-button> -->
+            <!-- <lay-button v-if="apiList?.includes('/robot/submitStatus')" :border="'red'" size="xs" @click="handleStatus(selectedKeys, 'STOP')">停机</lay-button> -->
+            <lay-button :border="'green'" size="xs" @click="handleRrestoration(selectedKeys)">复位余额</lay-button>
           </lay-space>
         </div>
-      </div> -->
+      </div>
     </template>
   </lay-card>
   <Update ref="updateRef" />
 </template>
 
-<script lang="ts" setup name="BotManage">
+<script lang="ts" setup name="BotCta">
 import { ref, reactive, getCurrentInstance, onActivated, onDeactivated } from "vue";
 import Update from "./components/Update.vue";
 import TableButton from "@/components/TableButton.vue";
 import { timeConverts } from "@/utils/index";
-import { get_cta_robot_list, delete_cta_robot, set_cta_robot_status, refresh_cta_robot_balance } from "@/api";
+import { get_cta_robot_list, delete_cta_robot, set_cta_robot_status, refresh_cta_robot_balance, restoration_cta_robot_balance } from "@/api";
 
 const ROBOT_STATUS: any = reactive({
   0: "已停止",
@@ -107,7 +106,7 @@ const ROBOT_STATUS: any = reactive({
 const { proxy }: any = getCurrentInstance();
 const updateRef = ref();
 
-const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
+// const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
 
 interface PageConfig {
   loading: boolean;
@@ -137,12 +136,12 @@ const tablePage: TablePage = reactive({ current: 1, limit: 50, total: 0, limits:
 const columns = ref([
   { title: "选项", width: "44px", type: "checkbox" },
   { title: "ID", width: "50px", key: "id" },
-  { title: "名称", key: "name", ellipsisTooltip: true },
+  { title: "名称", key: "name", customSlot: "name", ellipsisTooltip: true },
   { title: "账户", key: "accountName", ellipsisTooltip: true },
   { title: "币对", key: "symbol", align: "center", ellipsisTooltip: true },
   { title: "初始余额", width: "100px", key: "startAmount", align: "center" },
   { title: "当前余额", width: "100px", key: "nowAmount", align: "center" },
-  { title: "收益", width: "70px", key: "earningRate", customSlot: "earningRate", align: "center" },
+  { title: "收益", width: "80px", key: "earningRate", customSlot: "earningRate", align: "center" },
   { title: "配置信息", width: "200px", key: "configs", customSlot: "configs" },
   { title: "状态", width: "90px", key: "status", customSlot: "status", align: "center" },
   { title: "IP", width: "120px", key: "serverName", ellipsisTooltip: true },
@@ -188,7 +187,7 @@ const getPageInfo = (isSearch?: boolean, isRefresh?: boolean) => {
 getPageInfo();
 
 const jumpDetail = (info: any) => {
-  window.open(`/bot/as/detail/${info.id}`);
+  window.open(`/bot/cta/detail/${info.id}`);
 };
 
 // const handleShowInfo = (info: any) => {
@@ -220,6 +219,20 @@ const handleUpdate = async (value?: any) => {
   if (result) getPageInfo();
 };
 
+const handleRrestoration = async (value?: any) => {
+  let result = await proxy.$waitingConfirm("是否确认复位机器人余额?");
+  if (!result) return;
+  let params = value;
+  pageConfig.loading = true;
+  await restoration_cta_robot_balance(params, (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      proxy.$message(`更新成功!`);
+      getPageInfo();
+    }
+  });
+};
+
 // 更新余额
 const refreshBalance = async (value?: any) => {
   let result = await proxy.$waitingConfirm("是否确认更新该机器人余额?");

+ 7 - 4
src/views/bot/manage/detail.vue

@@ -127,7 +127,9 @@ const getBalanceInfo = (id: number) => {
 
       const xData = data.data.map((item: any) => item.creationTime);
       const sData = data.data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
-      const yMinData = Math.min(sData.map((item: any) => item[1]));
+      
+      console.log(sData)
+      const yMinData = Math.min(...sData.map((item: any) => item[1]));
 
       !balanceChart.value
         ? initBalanceChart(data.data)
@@ -141,7 +143,7 @@ const getBalanceInfo = (id: number) => {
               type: "value",
               boundaryGap: [0, "100%"],
               min: yMinData,
-              interval: 1,
+              splitNumber: 5,
             },
             series: {
               name: "Balance",
@@ -192,7 +194,7 @@ const initBalanceChart = (data: any) => {
 
   const xData = data.map((item: any) => item.creationTime);
   const sData = data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
-  const yMinData = Math.min(sData);
+  const yMinData = Math.min(...sData.map((item: any) => item[1]));
 
   const balanceChartOption = {
     tooltip: {
@@ -225,7 +227,7 @@ const initBalanceChart = (data: any) => {
       type: "value",
       boundaryGap: [0, "100%"],
       min: yMinData,
-      interval: 1,
+      splitNumber: 5,
     },
     series: {
       name: "Balance",
@@ -275,6 +277,7 @@ onUnmounted(() => {
   height: 1200px;
 }
 .robot-info-header {
+  min-width: 1352px;
   background-color: white;
   padding: 16px 24px;
   margin-bottom: 20px;