|
|
@@ -0,0 +1,261 @@
|
|
|
+<template>
|
|
|
+ <div class="container-wp">
|
|
|
+ <div class="robot-info-header">
|
|
|
+ <lay-space>
|
|
|
+ <span class="robot-name">{{ robotDetail.alias }}</span>
|
|
|
+ <lay-tag size="sm">
|
|
|
+ <span class="robot-status" v-if="robotDetail.status == '1'">
|
|
|
+ <lay-badge type="dot" theme="blue" ripple />
|
|
|
+ <span>运行中</span>
|
|
|
+ </span>
|
|
|
+ <span class="robot-status" v-else>
|
|
|
+ <lay-badge type="dot" theme="orange" ripple />
|
|
|
+ <span>已停止</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 v-if="apiList?.includes('/robot/getRobotLog')" class="custom-card">
|
|
|
+ <template v-slot:title>
|
|
|
+ <span class="card-title">持仓信息</span>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-slot:body>
|
|
|
+ <lay-table :columns="columns" size="sm" resize :data-source="positionList">
|
|
|
+ <template v-slot:spotBase="{ row }">
|
|
|
+ <span>{{ `${row.spot_base}/${row.spot_quote}` }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:swapBase="{ row }">
|
|
|
+ <span>{{ `${row.swap_base}/${row.swap_quote}` }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:openBaseDelta="{ row }">
|
|
|
+ <span>{{ row.config.config_payload.open_base_delta }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:closeDelta="{ row }">
|
|
|
+ <span>{{ row.config.config_payload.close_delta }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:openIncDelta="{ row }">
|
|
|
+ <span>{{ row.config.config_payload.open_inc_delta }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:openMaxValue="{ row }">
|
|
|
+ <span>{{ row.config.config_payload.open_max_value }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:positionMaxValue="{ row }">
|
|
|
+ <span>{{ row.config.config_payload.position_max_value }}</span>
|
|
|
+ </template>
|
|
|
+ </lay-table>
|
|
|
+ </template>
|
|
|
+ </lay-card>
|
|
|
+ </div>
|
|
|
+ <LogText ref="logtextRef" />
|
|
|
+</template>
|
|
|
+<script lang="ts" setup name="BotManageDetail">
|
|
|
+import { ref, reactive, onMounted, onUnmounted, shallowRef } from "vue";
|
|
|
+import { useRoute } from "vue-router";
|
|
|
+import * as echarts from "echarts";
|
|
|
+import { get_arbitrage_robot_detail, get_arbitrage_robot_detail_balance } from "@/api";
|
|
|
+
|
|
|
+const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
|
|
|
+
|
|
|
+const balanceChartRef = ref();
|
|
|
+const logtextRef = ref();
|
|
|
+
|
|
|
+const route = useRoute();
|
|
|
+
|
|
|
+interface PageConfig {
|
|
|
+ loading: boolean;
|
|
|
+}
|
|
|
+interface Logs {
|
|
|
+ time?: string;
|
|
|
+ text?: string;
|
|
|
+}
|
|
|
+
|
|
|
+let pageConfig: PageConfig = reactive({
|
|
|
+ loading: false,
|
|
|
+});
|
|
|
+
|
|
|
+const columns = ref([
|
|
|
+ { title: "现货交易对", key: "spot_base", customSlot: "spotBase", align: "center" },
|
|
|
+ { title: "合约交易对", key: "swap_base", customSlot: "swapBase", align: "center" },
|
|
|
+ { title: "现货数量", key: "spot_base_amount", align: "center" },
|
|
|
+ { title: "合约数量", key: "swap_base_amount", align: "center" },
|
|
|
+ { title: "开", key: "open_base_delta", customSlot: "openBaseDelta", align: "center" },
|
|
|
+ { title: "平", key: "close_delta", customSlot: "closeDelta", align: "center" },
|
|
|
+ { title: "阶梯", key: "open_inc_delta", customSlot: "openIncDelta", align: "center" },
|
|
|
+ { title: "阶梯容量", key: "open_max_value", customSlot: "openMaxValue", align: "center" },
|
|
|
+ { title: "最大持仓", key: "position_max_value", customSlot: "positionMaxValue", align: "center" },
|
|
|
+]);
|
|
|
+let positionList = ref<Array<Logs>>();
|
|
|
+let robotDetail = ref<any>({});
|
|
|
+let balanceList = ref([]);
|
|
|
+let balanceChart = shallowRef();
|
|
|
+// let timer = ref();
|
|
|
+
|
|
|
+// 获取机器人详情
|
|
|
+const getRobotDetail = () => {
|
|
|
+ const params = { id: route.params.id };
|
|
|
+ pageConfig.loading = true;
|
|
|
+ get_arbitrage_robot_detail(params, (data: any) => {
|
|
|
+ pageConfig.loading = false;
|
|
|
+ if (data.code == 200) {
|
|
|
+ robotDetail.value = data.data;
|
|
|
+ document.title = data.data.alias;
|
|
|
+ positionList.value = data.data.position;
|
|
|
+ getBalanceInfo(data.data.bot_id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+const getBalanceInfo = (id: number) => {
|
|
|
+ const params = { botId: id, startTime: +new Date() - 7 * 24 * 60 * 60 * 1000, endTime: +new Date() };
|
|
|
+ pageConfig.loading = true;
|
|
|
+ get_arbitrage_robot_detail_balance(params, (data: any) => {
|
|
|
+ pageConfig.loading = false;
|
|
|
+ if (data.code == 200) {
|
|
|
+ balanceList.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]));
|
|
|
+
|
|
|
+ !balanceChart.value
|
|
|
+ ? initBalanceChart(data.data)
|
|
|
+ : balanceChart.value.setOption({
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ boundaryGap: false,
|
|
|
+ data: xData,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ boundaryGap: [0, "100%"],
|
|
|
+ min: yMinData,
|
|
|
+ interval: 1,
|
|
|
+ },
|
|
|
+ series: {
|
|
|
+ name: "Balance",
|
|
|
+ type: "line",
|
|
|
+ areaStyle: {},
|
|
|
+ lineStyle: {
|
|
|
+ width: 1,
|
|
|
+ },
|
|
|
+ data: sData,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const initBalanceChart = (data: any) => {
|
|
|
+ if (balanceChart.value != null && !balanceChart.value.isDisposed()) echarts.dispose(balanceChart.value);
|
|
|
+
|
|
|
+ balanceChart.value = echarts.init(balanceChartRef.value);
|
|
|
+
|
|
|
+ window.removeEventListener("resize", () => balanceChart.value.resize());
|
|
|
+ window.addEventListener("resize", () => balanceChart.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);
|
|
|
+
|
|
|
+ const balanceChartOption = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ axisPointer: {
|
|
|
+ type: "cross",
|
|
|
+ },
|
|
|
+ formatter: (params: any) => {
|
|
|
+ let info = params[0];
|
|
|
+ return `${info.marker}${info.seriesName}<br/>时间:${info.value[0]} <br/>余额:${info.value[1]}`;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ dataZoom: [
|
|
|
+ {
|
|
|
+ start: 0,
|
|
|
+ end: 100,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: "inside",
|
|
|
+ start: 0,
|
|
|
+ end: 100,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ boundaryGap: false,
|
|
|
+ data: xData,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ boundaryGap: [0, "100%"],
|
|
|
+ min: yMinData,
|
|
|
+ interval: 1,
|
|
|
+ },
|
|
|
+ series: {
|
|
|
+ name: "Balance",
|
|
|
+ type: "line",
|
|
|
+ areaStyle: {},
|
|
|
+ data: sData,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ balanceChart.value.setOption(balanceChartOption);
|
|
|
+};
|
|
|
+
|
|
|
+// timer.value = setInterval(() => {
|
|
|
+// getBalanceInfo(robotDetail.value.bot_id);
|
|
|
+// }, 5000);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getRobotDetail();
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ // window.removeEventListener("resize", () => balanceChart.value.resize());
|
|
|
+ // clearInterval(timer.value);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.ellipsis-2 {
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+ overflow: hidden;
|
|
|
+ line-break: anywhere;
|
|
|
+ -webkit-line-clamp: 2; /* 控制显示的行数 */
|
|
|
+}
|
|
|
+.container-wp {
|
|
|
+ min-height: 100%;
|
|
|
+ padding: 20px 40px;
|
|
|
+ background-color: rgb(244, 246, 247);
|
|
|
+}
|
|
|
+.profit-chart {
|
|
|
+ height: 300px;
|
|
|
+}
|
|
|
+.predictor-chart {
|
|
|
+ height: 1200px;
|
|
|
+}
|
|
|
+.robot-info-header {
|
|
|
+ background-color: white;
|
|
|
+ padding: 16px 24px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ .robot-name {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .robot-status {
|
|
|
+ span {
|
|
|
+ font-size: 12px;
|
|
|
+ padding-left: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|