|
|
@@ -0,0 +1,274 @@
|
|
|
+<template>
|
|
|
+ <lay-card class="custom-card">
|
|
|
+ <template v-slot:title>
|
|
|
+ <span class="card-title">机器人管理</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:extra>
|
|
|
+ <lay-button class="card-button" v-if="apiList?.includes('/userServer/save')" @click="handleCopyRobot(selectedKeys)">复制机器人</lay-button>
|
|
|
+ <lay-button class="card-button" v-if="apiList?.includes('/userServer/save')" @click="handleUpdate(0)">添加</lay-button>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-slot:body>
|
|
|
+ <div class="custom-form-layout">
|
|
|
+ <lay-form class="form-wp" :model="pageParams" mode="inline">
|
|
|
+ <lay-form-item label="名称" prop="name">
|
|
|
+ <lay-input v-model="pageParams.name" />
|
|
|
+ </lay-form-item>
|
|
|
+ <div class="form-button-wp">
|
|
|
+ <lay-button @click="getPageInfo(true)">搜索</lay-button>
|
|
|
+ </div>
|
|
|
+ </lay-form>
|
|
|
+ </div>
|
|
|
+ <div class="custom-operator-wp">
|
|
|
+ <lay-space>
|
|
|
+ <div v-html="collectInfo" class="collect-wp" />
|
|
|
+ <div>
|
|
|
+ <lay-button :border="'green'" size="xs" @click="handleStatus(selectedKeys, 'RUN')">开机</lay-button>
|
|
|
+ <lay-button :border="'green'" size="xs" @click="handleStatus(selectedKeys, 'RESTART')">重启</lay-button>
|
|
|
+ <lay-button :border="'red'" size="xs" @click="handleStatus(selectedKeys, 'STOP')">停机</lay-button>
|
|
|
+ <lay-button :border="'green'" size="xs" @click="handleResetCapital(selectedKeys)">复位本金</lay-button>
|
|
|
+ </div>
|
|
|
+ </lay-space>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <lay-table
|
|
|
+ :page="tablePage"
|
|
|
+ :columns="columns"
|
|
|
+ size="sm"
|
|
|
+ resize
|
|
|
+ id="id"
|
|
|
+ :data-source="dataSource"
|
|
|
+ v-model:selected-keys="selectedKeys"
|
|
|
+ :loading="pageConfig.loading"
|
|
|
+ @change="handleCurrentChange"
|
|
|
+ >
|
|
|
+ <template v-slot:earningRate="{ row }">
|
|
|
+ <span :class="{ 'primary-color': row.earningRate > 0, 'danger-color': row.earningRate < 0 }">{{ row.earningRate }}%</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:status="{ row }">
|
|
|
+ <lay-space v-if="row.status == 'RUNNING'">
|
|
|
+ <lay-badge type="dot" theme="blue" ripple />
|
|
|
+ <span>{{ ROBOT_STATUS[row.status] }}</span>
|
|
|
+ </lay-space>
|
|
|
+ <lay-space v-else-if="row.status == 'ERROR'">
|
|
|
+ <lay-badge type="dot" ripple />
|
|
|
+ <span>{{ ROBOT_STATUS[row.status] }}</span>
|
|
|
+ </lay-space>
|
|
|
+ <lay-space v-else>
|
|
|
+ <lay-badge type="dot" theme="orange" ripple />
|
|
|
+ <span>{{ ROBOT_STATUS[row.status] }}</span>
|
|
|
+ </lay-space>
|
|
|
+ </template>
|
|
|
+ <template v-slot:ip="{ row }">
|
|
|
+ {{ `${row.serverIp}:${row.processNum}` }}
|
|
|
+ </template>
|
|
|
+ <template v-slot:lastReportTime="{ row }">
|
|
|
+ <span :class="{ 'danger-color': timeConverts(row.lastReportTime).indexOf('秒') == -1 }">{{ row.lastReportTime ? timeConverts(row.lastReportTime) : "未通讯" }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:updateTime="{ row }">
|
|
|
+ <span>{{ timeConverts(row.updateTime) }}</span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:operator="{ row }">
|
|
|
+ <lay-space>
|
|
|
+ <TableButton v-if="apiList?.includes('/userServer/testConnect') && ['STOPPED', 'STOP_PENDING', 'ERROR'].includes(row.status)" text="开机" @click="handleStatus([row.id], 'RUN')" />
|
|
|
+ <TableButton
|
|
|
+ v-if="apiList?.includes('/userServer/testConnect') && ['RUNNING', 'START_PENDING', 'RESTART_PENDING'].includes(row.status)"
|
|
|
+ text="停机"
|
|
|
+ @click="handleStatus([row.id], 'STOP')"
|
|
|
+ />
|
|
|
+ <TableButton v-if="apiList?.includes('/userServer/delete')" text="编辑" @click="handleUpdate(row)" />
|
|
|
+ <TableButton
|
|
|
+ v-if="apiList?.includes('/userServer/update') && ['RUNNING', 'START_PENDING', 'RESTART_PENDING'].includes(row.status)"
|
|
|
+ text="重启"
|
|
|
+ @click="handleStatus([row.id], 'RESTART')"
|
|
|
+ />
|
|
|
+ <TableButton v-if="apiList?.includes('/userServer/update') && ['STOPPED', 'STOP_PENDING', 'ERROR'].includes(row.status)" text="删除" @click="handleDelete(row)" />
|
|
|
+ </lay-space>
|
|
|
+ </template>
|
|
|
+ </lay-table>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </lay-card>
|
|
|
+ <Update ref="updateRef" />
|
|
|
+ <Copy ref="copyRef" />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup name="BotManage">
|
|
|
+import { ref, reactive, getCurrentInstance, onBeforeUnmount } from "vue";
|
|
|
+import Update from "./components/Update.vue";
|
|
|
+import Copy from "./components/Copy.vue";
|
|
|
+import TableButton from "@/components/TableButton.vue";
|
|
|
+import { timeConverts } from "@/utils/index";
|
|
|
+import { get_robot_list, delete_robot, set_robot_status, set_robot_reset_capital } from "@/api";
|
|
|
+
|
|
|
+const ROBOT_STATUS: any = reactive({
|
|
|
+ STOPPED: "已停止",
|
|
|
+ STOP_PENDING: "停止中",
|
|
|
+ RUNNING: "运行中",
|
|
|
+ START_PENDING: "启动中",
|
|
|
+ RESTART_PENDING: "重启中",
|
|
|
+ DOWNLOADING: "下载中",
|
|
|
+ ERROR: "错误",
|
|
|
+});
|
|
|
+
|
|
|
+const { proxy }: any = getCurrentInstance();
|
|
|
+const updateRef = ref();
|
|
|
+const copyRef = ref();
|
|
|
+
|
|
|
+const apiList = ref(window.sessionStorage.getItem("_4L_API_LIST"));
|
|
|
+
|
|
|
+interface PageConfig {
|
|
|
+ loading: boolean;
|
|
|
+}
|
|
|
+
|
|
|
+let pageConfig: PageConfig = reactive({
|
|
|
+ loading: false,
|
|
|
+});
|
|
|
+
|
|
|
+interface FormItem {
|
|
|
+ pageNum?: Number;
|
|
|
+ pageSize?: Number;
|
|
|
+ name?: String;
|
|
|
+}
|
|
|
+const pageParams: FormItem = reactive({ pageNum: 1, pageSize: 10 });
|
|
|
+
|
|
|
+interface TablePage {
|
|
|
+ current: number;
|
|
|
+ limit: number;
|
|
|
+ total: number;
|
|
|
+}
|
|
|
+const tablePage: TablePage = reactive({ current: 1, limit: 10, total: 0 });
|
|
|
+const columns = ref([
|
|
|
+ { title: "选项", width: "44px", type: "checkbox" },
|
|
|
+ { title: "ID", key: "id" },
|
|
|
+ { title: "名称", key: "name" },
|
|
|
+ { title: "起始", key: "startAmount", align: "center" },
|
|
|
+ { title: "收益", key: "earningRate", customSlot: "earningRate", align: "center" },
|
|
|
+ { title: "状态", key: "status", customSlot: "status", align: "center" },
|
|
|
+ { title: "参数", key: "configs", ellipsisTooltip: true },
|
|
|
+ { title: "IP:编号", key: "ip", customSlot: "ip" },
|
|
|
+ { title: "通讯", key: "lastReportTime", customSlot: "lastReportTime", align: "center" },
|
|
|
+ { title: "修改", key: "updateTime", customSlot: "updateTime", align: "center" },
|
|
|
+ {
|
|
|
+ title: "操作",
|
|
|
+ customSlot: "operator",
|
|
|
+ key: "operator",
|
|
|
+ ignoreExport: true,
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+let dataSource = ref([]);
|
|
|
+let selectedKeys = ref([]);
|
|
|
+let collectInfo = ref(`[0/0] 利润:<span class="primary-color">0(0%)</span> 初始:<span class="primary-color">0</span> 现有:<span class="primary-color">0</span>`);
|
|
|
+// 请求机器人列表
|
|
|
+const getPageInfo = (isSearch?: boolean) => {
|
|
|
+ if (isSearch) pageParams.pageNum = 1;
|
|
|
+ pageConfig.loading = true;
|
|
|
+ get_robot_list(pageParams, (data: any) => {
|
|
|
+ pageConfig.loading = false;
|
|
|
+ if (data.code == 200) {
|
|
|
+ dataSource.value = data.data.list;
|
|
|
+ tablePage.total = data.data.total;
|
|
|
+ handleShowInfo(data.data);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+getPageInfo();
|
|
|
+let refreshInterval = setInterval(() => {
|
|
|
+ get_robot_list(pageParams, (data: any) => {
|
|
|
+ if (data.code == 200) {
|
|
|
+ dataSource.value = data.data.list;
|
|
|
+ tablePage.total = data.data.total;
|
|
|
+ handleShowInfo(data.data);
|
|
|
+ }
|
|
|
+ });
|
|
|
+}, 2000);
|
|
|
+
|
|
|
+const handleShowInfo = (info: any) => {
|
|
|
+ document.title = `[${info.runNum || 0}/${info.total || 0}] 利润:${info.income || 0}(${info.incomeRate || 0}%)
|
|
|
+ 初始:${info.startAmount || 0} 现有:${info.nowAmount || 0}`;
|
|
|
+ collectInfo.value = `[${info.runNum || 0}/${info.total || 0}] 利润:<span class="primary-color">${info.income || 0}(${info.incomeRate || 0}%)</span>
|
|
|
+ 初始:<span class="primary-color">${info.startAmount || 0}</span> 现有:<span class="primary-color">${info.nowAmount || 0}</span>`;
|
|
|
+};
|
|
|
+
|
|
|
+const handleCopyRobot = async (ids: any) => {
|
|
|
+ if (ids.length > 1 || ids.length == 0) return proxy.$message(`请勾选1个要复制的机器!`, 7);
|
|
|
+ const result = await copyRef.value.show(ids[0]);
|
|
|
+ if (result) getPageInfo();
|
|
|
+};
|
|
|
+
|
|
|
+const handleResetCapital = async (ids: any) => {
|
|
|
+ let result = await proxy.$waitingConfirm("是否确认要复位机器本金?");
|
|
|
+ if (!result) return;
|
|
|
+ if (ids.length == 0) return proxy.$message(`请先选择要复位本金机器!`, 7);
|
|
|
+ const params = ids;
|
|
|
+ set_robot_reset_capital(params, (data: any) => {
|
|
|
+ if (data.code == 200) {
|
|
|
+ proxy.$message(`执行成功!`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleStatus = (ids: any, status: String) => {
|
|
|
+ if (ids.length == 0) return proxy.$message(`请先选择要执行命令机器!`, 7);
|
|
|
+ const params = { robotIds: ids, status };
|
|
|
+ set_robot_status(params, (data: any) => {
|
|
|
+ if (data.code == 200) {
|
|
|
+ proxy.$message(`执行成功!`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleUpdate = async (value?: any) => {
|
|
|
+ const result = await updateRef.value.show(value);
|
|
|
+ if (result) getPageInfo();
|
|
|
+};
|
|
|
+
|
|
|
+// 删除机器人
|
|
|
+const handleDelete = async (value: any) => {
|
|
|
+ let result = await proxy.$waitingConfirm("是否确认删除该机器人?");
|
|
|
+ if (!result) return;
|
|
|
+ let params = [value.id];
|
|
|
+ pageConfig.loading = true;
|
|
|
+ delete_robot(params, (data: any) => {
|
|
|
+ pageConfig.loading = false;
|
|
|
+ if (data.code == 200) {
|
|
|
+ proxy.$message(`删除成功!`);
|
|
|
+ getPageInfo();
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+// 分页设置
|
|
|
+const handleCurrentChange = (val: any) => {
|
|
|
+ pageParams.pageNum = val.current;
|
|
|
+ getPageInfo();
|
|
|
+};
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ document.title = '两江资本—无敌中控';
|
|
|
+ clearInterval(refreshInterval);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.custom-operator-wp {
|
|
|
+ .collect-wp {
|
|
|
+ line-height: 24px;
|
|
|
+ padding: 0 4px;
|
|
|
+ border: 1px solid var(--normal-color);
|
|
|
+ color: var(--normal-color);
|
|
|
+ :deep(.primary-color) {
|
|
|
+ color: var(--primary-color);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.custom-form-layout {
|
|
|
+ font-size: 12px !important;
|
|
|
+}
|
|
|
+.primary-color {
|
|
|
+ color: var(--primary-color);
|
|
|
+}
|
|
|
+.danger-color {
|
|
|
+ color: var(--danger-color);
|
|
|
+}
|
|
|
+</style>
|