summaryrefslogtreecommitdiff
path: root/src/views/rangeNodeManage
diff options
context:
space:
mode:
authorll <[email protected]>2024-07-11 20:41:37 +0800
committerll <[email protected]>2024-07-11 20:41:37 +0800
commitbafa736c04845e103d7e3747a8152b410d1628fb (patch)
tree032d00938963b7cb21ff5c57e4f08723b521ae41 /src/views/rangeNodeManage
parentac8bc7f895baa346cdb498e1b8be41ce66130afd (diff)
Initial commitHEADmain
Diffstat (limited to 'src/views/rangeNodeManage')
-rw-r--r--src/views/rangeNodeManage/detail/console/index.vue220
-rw-r--r--src/views/rangeNodeManage/detail/console/module/ControlConsole.vue389
-rw-r--r--src/views/rangeNodeManage/detail/console/module/ControlConsole2.vue306
-rw-r--r--src/views/rangeNodeManage/detail/console/module/ControlConsole4.vue349
-rw-r--r--src/views/rangeNodeManage/detail/console/module/DirNameForm.vue95
-rw-r--r--src/views/rangeNodeManage/detail/console/module/FileManage.vue538
-rw-r--r--src/views/rangeNodeManage/detail/detail/index.vue107
-rw-r--r--src/views/rangeNodeManage/detail/detail/module/DetailInfo.vue82
-rw-r--r--src/views/rangeNodeManage/detail/detail/module/ResourceMonitor.vue199
-rw-r--r--src/views/rangeNodeManage/detail/detail/module/cpuMock.js91
-rw-r--r--src/views/rangeNodeManage/detail/detail/module/memoryMock.js91
-rw-r--r--src/views/rangeNodeManage/detail/file/index.vue304
-rw-r--r--src/views/rangeNodeManage/detail/file/mock.js26
-rw-r--r--src/views/rangeNodeManage/detail/file/module/Header.vue74
-rw-r--r--src/views/rangeNodeManage/detail/index.vue80
-rw-r--r--src/views/rangeNodeManage/detail/log/index.vue227
-rw-r--r--src/views/rangeNodeManage/detail/log/mock.js12
-rw-r--r--src/views/rangeNodeManage/detail/log/module/Header.vue122
-rw-r--r--src/views/rangeNodeManage/detail/mock.js38
-rw-r--r--src/views/rangeNodeManage/index.vue146
-rw-r--r--src/views/rangeNodeManage/nodeList/components/DirNameForm.vue95
-rw-r--r--src/views/rangeNodeManage/nodeList/components/DownloadFileManager.vue536
-rw-r--r--src/views/rangeNodeManage/nodeList/components/MainNode.vue98
-rw-r--r--src/views/rangeNodeManage/nodeList/components/OperateNode.vue98
-rw-r--r--src/views/rangeNodeManage/nodeList/components/UploadFileManager.vue520
-rw-r--r--src/views/rangeNodeManage/nodeList/index.vue445
-rw-r--r--src/views/rangeNodeManage/nodeList/mock.js38
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/RuleList.vue207
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/TaskList.vue391
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/index.vue110
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/DownloadPack.vue223
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/RuleForm.vue164
-rw-r--r--src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/TaskForm.vue522
-rw-r--r--src/views/rangeNodeManage/nodeList/module/Console.vue521
-rw-r--r--src/views/rangeNodeManage/nodeList/module/Download.vue274
-rw-r--r--src/views/rangeNodeManage/nodeList/module/Header.vue146
-rw-r--r--src/views/rangeNodeManage/nodeList/module/Upload.vue285
-rw-r--r--src/views/rangeNodeManage/topologyMap/index.vue30
-rw-r--r--src/views/rangeNodeManage/worldMap/Map.vue217
-rw-r--r--src/views/rangeNodeManage/worldMap/index.vue68
-rw-r--r--src/views/rangeNodeManage/worldMap/mock.js113
41 files changed, 0 insertions, 8597 deletions
diff --git a/src/views/rangeNodeManage/detail/console/index.vue b/src/views/rangeNodeManage/detail/console/index.vue
deleted file mode 100644
index 7ab20ca..0000000
--- a/src/views/rangeNodeManage/detail/console/index.vue
+++ /dev/null
@@ -1,220 +0,0 @@
-<template>
-<div :class="['tabs', {'is--maximize': isFullscreen}]">
- <el-tabs
- v-model="activeName"
- @tab-click="handleClick"
- >
- <el-tab-pane label="控制台" name="first">
- <ControlConsole ref="controlConsole"></ControlConsole>
- </el-tab-pane>
- <el-tab-pane label="文件管理" name="second">
- <FileManage :is-fullscreen="isFullscreen"></FileManage>
- </el-tab-pane>
- </el-tabs>
- <el-button class="console-btn" v-if="activeName === 'first'" :loading="consoleLoading" type="primary" @click="openConsoleTab">打开控制台</el-button>
- <span class="icon-span" slot="label">
- <i v-if="closeIcon" class="el-icon-close icon-zoom" @click="backNodeList"></i>
- <svg-icon v-else class="icon-zoom" :icon-class="fullscreenIcon" @click="zoomEvent"></svg-icon>
- </span>
-</div>
-</template>
-
-<script>
-import ControlConsole from './module/ControlConsole'
-import FileManage from './module/FileManage'
-export default {
- components: { ControlConsole, FileManage },
- data() {
- return {
- activeName: 'first',
- nodeId: '',
- // consoleUrl: '',
- fullscreenIcon: 'fullscreen',
- isFullscreen: false,
- closeIcon: false,
- consoleLoading: false
- };
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- // this.init()
- },
- immediate: true
- }
- },
- mounted() {
- this.closeIcon = this.$route.params.closeIcon
- },
- methods: {
- backNodeList() {
- this.$router.push({ name: 'rangeNodeManage' })
- },
- handleClick(tab, event) {
- console.log(tab, event);
- },
- openConsoleTab() {
- // 获取webshell地址,用浏览器打开
- const reqParams = { node_id: this.nodeId }
- this.consoleLoading = true
- this.$axios.get(this.$http.api.getWebshell, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const consoleUrl = 'http://' + window.g.baseURL + '/' + res?.result
- window.open(consoleUrl, '_blank')
- // var newWindow = window.open(consoleUrl , '_blank');
- // // 等待新页面加载完成
- // newWindow.onload = function() {
- // console.log('1111111111111111')
- // // 选择用户名输入框
- // var usernameInput = newWindow.document.querySelector('input[name="username"]');
- // // 选择密码输入框
- // var passwordInput = newWindow.document.querySelector('input[name="password"]');
- // // 选择登录按钮
- // var loginButton = newWindow.document.querySelector('button[type="submit"]');
- // console.log(usernameInput, 'usernameInput====')
-
- // // 如果输入框存在,则自动输入用户名和密码
- // if (usernameInput && passwordInput && loginButton) {
- // usernameInput.value = 'admin';
- // passwordInput.value = 'Bjhit@2020';
-
- // // 触发登录按钮的点击事件
- // loginButton.click();
- // }
- // };
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.consoleLoading = false
- })
- },
- zoomEvent() {
- if (this.activeName === 'first') {
-
- this.isFullscreen = !this.isFullscreen
- this.fullscreenIcon = this.isFullscreen ? 'narrow' : 'fullscreen'
- // this.$refs.controlConsole.resize()
- } else {
- this.isFullscreen = !this.isFullscreen
- this.fullscreenIcon = this.isFullscreen ? 'narrow' : 'fullscreen'
- }
- },
- findNthOccurrence(str, char, n) {
- let index = str.indexOf(char)
- while (--n > 0 && index !== -1) {
- index = str.indexOf(char, index + 1)
- }
- return index
- }
- }
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.is--maximize {
- position: fixed !important;
- top: 9%;
- left: 10%;
- width: 90% !important;
- height: 91% !important;
- padding: 0.5em 1em;
- // background-color: #17234e;
- background: url(../../../../img/background/bgMain.svg);
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-position: center; /* 居中显示 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- z-index: 1000;
-}
-// ::v-deep #tab-zoom {
-// border: none;
-// background-color: #1b202e !important;
-// position: absolute;
-// top: 1px;
-// right: 0;
-// font-weight: 500;
-// font-size: 15px;
-// color: #fff !important;
-// }
-.tabs {
- width: 100%;
- height: calc(100% - 15px);
- text-align: center;
- position: relative;
- padding: 0 0;
- // display: flex;
- // .detail-title {
- // position:absolute;
- // margin: 10px;
- // }
-}
-::v-deep .el-tabs{
- color: #000;
- left: 0px;
- top: 0px;
- padding: 0 0;
- width: 100%;
- height: 100%;
- position: relative;
- .el-tabs__header {
- margin: 15px 30px;
- }
- .el-tabs__content {
- width: 100%;
- height: calc(100% - 50px);
- .el-tab-pane {
- width: 100%;
- height: 100%;
- }
- }
-}
-/* 去除灰色横条 */
-::v-deep .el-tabs__nav-wrap::after {
- position: static !important;
-}
-/* 设置滑块颜色 */
-::v-deep .el-tabs__active-bar{
- background-color: #0E3D8A !important;
-}
-/* 设置滑块停止位置 */
-::v-deep .el-tabs__active-bar.is-top{
- height: 37px;
- width: 104px ! important;
- border-radius: 17px;
- top: 0px !important;
- left: -18px !important;
- position: absolute !important;
- z-index: 1;
-}
-/* 设置当前选中样式 */
-::v-deep .el-tabs__item.is-active{
- color:#02DDEA !important;
- z-index: 2;
-}
-/* 设置未被选中样式 */
-::v-deep .el-tabs__item{
- padding: 0 20px !important;
- width: 104px;
- box-sizing: border-box;
- display: inline-block;
- position: relative !important;
- color:#02DDEA !important;
- z-index: 2;
-}
-.console-btn {
- position: absolute;
- top: 5px;
- right: 100px;
-}
-.icon-span {
- position: absolute;
- top: 10px;
- right: 30px;
- .icon-zoom {
- font-size: 30px;
- color: #02DDEA;
- margin: 0 15px;
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/console/module/ControlConsole.vue b/src/views/rangeNodeManage/detail/console/module/ControlConsole.vue
deleted file mode 100644
index 3971e08..0000000
--- a/src/views/rangeNodeManage/detail/console/module/ControlConsole.vue
+++ /dev/null
@@ -1,389 +0,0 @@
-<template>
- <div
- style="height: 100%;
- background: #002833;"
- >
- <div class="indexContainer" id="terminal" ref="terminal" v-resize="onResize"></div>
- </div>
-</template>
-
-<script>
- // 引入xterm,请注意这里和3.x版本的引入路径不一样
- import { Terminal } from "xterm";
- import "xterm/css/xterm.css";
- import "xterm/lib/xterm.js";
- import { FitAddon } from "xterm-addon-fit";
-
- import resize from 'vue-resize-directive';
-
- export default {
- name: "Shell",
- directives: { resize },
- data() {
- return {
- nodeId: '',
- showOrder: "", // 保存服务端返回的命令
- inputList: [],
- shellWs: "",
- term: "", // 保存terminal实例
- rows: 40,
- cols: 100,
- urlParam: {
- Tag: 'tag',
- name: 'name',
- pod: 'pod'
- },
- commandPrefix: 'target'
- };
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- },
- immediate: true
- }
- },
- created() {
- this.getWebsocketUrl()
- },
-
- mounted() {
- let _this = this;
- localStorage.setItem('commands', '')
- // 获取容器宽高/字号大小,定义行数和列数
- this.rows = document.querySelector(".indexContainer").offsetHeight / 16 - 6;
- this.cols = document.querySelector(".indexContainer").offsetWidth / 14;
-
- let term = new Terminal({
- rendererType: "canvas", //渲染类型
- rows: parseInt(_this.rows), //行数
- cols: parseInt(_this.cols), // 不指定行数,自动回车后光标从下一行开始
- convertEol: true, //启用时,光标将设置为下一行的开头
- fontSize: 16, //字体大小
- // scrollback: 50, //终端中的回滚量
- disableStdin: false, //是否应禁用输入。
- cursorStyle: "underline", //光标样式
- cursorBlink: true, //光标闪烁
- // theme: {
- // foreground: "#7e9192", //字体
- // background: "#002833", //背景色
- // cursor: "help", //设置光标
- // lineHeight: 16
- // }
- theme: {
- foreground: "yellow", //字体
- background: "#060101", //背景色
- cursor: "help", //设置光标
- lineHeight: 16
- }
- });
-
- // 创建terminal实例
- term.open(this.$refs["terminal"]);
-
- // 换行并输入起始符“$”
- term.prompt = () => {
- term.write("\r\n$ ");
- };
- term.prompt();
-
- // // canvas背景全屏
- var fitAddon = new FitAddon();
- term.loadAddon(fitAddon);
- fitAddon.fit();
-
- window.addEventListener("resize", resizeScreen);
- // document.querySelector(".indexContainer").addEventListener('resize', resizeScreen)
-
- // 内容全屏显示
- function resizeScreen() {
- // 不传size
- try {
- fitAddon.fit();
- // 窗口大小改变时触发xterm的resize方法,向后端发送行列数,格式由后端决定
- // 这里不使用size默认参数,因为改变窗口大小只会改变size中的列数而不能改变行数,所以这里不使用size.clos,而直接使用获取我们根据窗口大小计算出来的行列数
- term.onResize(() => {
- _this.onSend({ Op: "resize", Cols: term.cols, Rows: term.rows });
- });
- } catch (e) {
- console.log("e", e.message);
- }
- }
-
- function runFakeTerminal(_this) {
- if (term._initialized) {
- return;
- }
-
- term._initialized = true;
-
- term.prompt = () => {
- term.write("\r\n ");
- };
-
- // term.writeln("Welcome to xterm.js");
- // term.writeln(
- // "This is a local terminal emulation, without a real terminal in the back-end."
- // );
- // term.writeln("Type some keys and commands to play around.");
-
- // term.writeln("root@target:/#");
- // term.prompt();
-
- // 监控键盘输入事件
- // / **
- // *添加事件监听器,用于按下键时的事件。事件值包含
- // *将在data事件以及DOM事件中发送的字符串
- // *触发了它。
- // * @返回一个IDisposable停止监听。
- // * /
- let last = 0;
-
- term.onKey(function(event) {
- // 可打印状态,即不是alt键ctrl等功能健时
- // console.log(event, '输入的key======')
- const printable = !event.domEvent.altKey && !event.domEvent.altGraphKey && !event.domEvent.ctrlKey && !event.domEvent.metaKey
-
- // !key.charCodeAt(0).altKey && !key.charCodeAt(0).altGraphKey && !key.charCodeAt(0).ctrlKey && !key.charCodeAt(0).metaKey;
-
- // 因服务端返回命令包含乱码,但使用write方法输出时并不显示,故将真实显示内容截取出来
- let show = ''
- if (_this.showOrder) {
- let index = _this.showOrder.indexOf("sh");
- show = _this.showOrder.substr(index, _this.showOrder.length - 1);
- }
-
- // 当输入回车时
- if (event.domEvent.keyCode === 13) {
- if (_this.order == "cls" || _this.order == "clear") {
- _this.order = "";
- return false;
- }
- //先将数据发送
- term.prompt();
- // 判断如果不是英文给出提醒
- let reg = /[a-zA-Z]/;
- // let order = {
- // Data: _this.order,
- // Op: "stdin"
- // };
- let order = _this.order
-
- if (!reg.test(_this.order)) {
- term.writeln("请输入有效指令~");
- } else {
- // 发送数据
- _this.inputList.push(_this.order);
- last = _this.inputList.length - 1;
- _this.onSend(order);
- // 清空输入内容变量
- }
- } else if (event.domEvent.keyCode === 8) {
- // 当输入退
- // 当前行字符长度如果等于后端返回字符就不进行删除
- if(_this.order.length > 0) {
- _this.order = _this.order.substr(0, _this.order.length - 1);
- term.write('\b \b')
- }
- // if (term._core.buffer.x > _this.showOrder.length) {
- // term.write("\b \b"); // 输出退格
- // }
-
- // // 将输入内容变量删除
-
- // if (_this.trim(_this.order) == _this.trim(_this.showOrder)) {
- // return false;
- // } else {
- // _this.order = _this.order.substr(0, _this.order.length - 1);
- // term.write('\b \b')
- // }
- } else if (event.domEvent.keyCode === 127) {
- if (term._core.buffer.x > (_this.showOrder.length + 2)) {
- term.write('\b \b')
- _this.order = _this.order.substr(0, _this.order.length - 1)
- }
- } else if (event.domEvent.keyCode === 38 || event.domEvent.keyCode === 40) {
- let len = _this.inputList.length;
- let code = event.domEvent.keyCode;
-
- if (code === 38 && last <= len && last >= 0) {
- // 直接取出字符串数组最后一个元素
- let inputVal = _this.inputList[last];
- term.write(inputVal);
- if (last > 0) {
- last--;
- }
- }
- if (code === 40 && last < len) {
- // last现在为当前元素
- if (last == len - 1) {
- return;
- }
- if (last < len - 1) {
- last++;
- }
-
- let inputVal = _this.inputList[last];
- term.write(inputVal);
- }
- } else if (event.domEvent.keyCode === 9) {
- // 如果按tab键前输入了之前后端返回字符串的第一个字符,就显示此命令
- if (_this.order !== "" && show.indexOf(_this.order) == 0) {
- term.write(_this.showOrder);
- }
- } else if (event.key == '\x16') {
- navigator.clipboard.readText().then(clipText => {
- term.write(clipText);
- })
- //ctrol+ c copy
- } else if (event.key == '\x03' && term.hasSelection()) {
- navigator.clipboard.writeText(term.getSelection())
- } else if (printable) {
- let key = event.key
- // // 当为可打印内容时
- // if (/[a-zA-Z]/.test(key)) {
- // key = key.toLowerCase();
- // }
- // 存入输入内容变量
- _this.order = _this.order + key;
- // 将变量写入终端内
- term.write(key);
- }
- });
-
- _this.term = term;
- }
- runFakeTerminal(_this);
- },
-
- methods: {
-
- /**
- * **wsShell 创建页面级别的websocket,加载页面数据
- * ws 接口:/xxx/xxx/xxx
- * 参数:无
- * ws参数:
- * @deployId 任务id
- * @tagString 当前节点
- * 返回:无
- * **/
- wsShell(url) {
- const _this = this;
- let tag = this.urlParam.Tag;
- let name= this.urlParam.name;
- let pod= this.urlParam.pod;
-
- // let query = `?tag=${tag}&name=${name}&pod=${pod}`;
- // let url = `xxxx/xxxx${query}`;// websocket连接接口
- // let url = 'ws://172.16.0.120:30598/ws/target-19-austria-80-110-35-0-24/target-19-relay-127-54b5df76f4-8958g/relay-127'
-
- this.shellWs = this.websoketLib.WS({
- url,
- isInit: true,
- openFn(e) {
- console.log('连接websocket成功===', e)
- // _this.term.resize({ rows: _this.rows, cols: 100 }); //终端窗口重新设置大小 并触发term.on("resize")
- },
- messageFn(e) {
- console.log("message", e);
- if (e) {
- // let data = JSON.parse(e.data);
- // if (data.Data == "\n" || data.Data == "\r\nexit\r\n") {
- // _this.$message("连接已关闭");
- // }
- // 打印后端返回数据
- // _this.term.write(data.Data);
-
- let backData = ''
- // 创建一个包含文本内容的Blob对象
- var blob = e.data;
- // 创建一个新的FileReader对象
- var reader = new FileReader();
- // 读取Blob并将其转换为字符串
- reader.onloadend = function () {
- backData = reader.result; // 获得转换后的字符串
- console.log(backData, '服务端websockt返回结果===='); // 输出结果到控制台
- let index = _this.order?.length;
- backData = backData.substring(index, backData.length);
- // 如果返回字符包含这些字符显示close提示
- if (backData == "\n" || backData == "\r\nexit\r\n") {
- alert("closed");
- }
- if (backData.trim() === 'Connected!') {
- _this.term.write(backData)
- _this.term.write(`root@${_this.commandPrefix}:/#`);
- } else {
- _this.term.write(backData)
- }
- _this.showOrder = backData;
- _this.order = "";
- };
-
- // 开始读取Blob
- reader.readAsText(blob);
- }
- },
- errorFn(e) {
- //出现错误关闭当前ws,并且提示
- console.log("error", e);
- _this.$message.error({
- message: "ws 请求失败,请刷新重试~",
- duration: 5000
- });
- }
- });
- },
-
- onSend(data) {
- // data = this.websoketLib.isObject(data) ? JSON.stringify(data) : data;
- // data = this.websoketLib.isArray(data) ? data.toString() : data;
- // data = data.replace(/\\\\/, "\\");
- this.shellWs.onSend(data);
- },
-
- //删除左右两端的空格
- trim(str) {
- return str.replace(/(^\s*)|(\s*$)/g, "");
- },
- // 获取websocket地址
- getWebsocketUrl() {
- const reqParams = { node_id: this.nodeId }
- this.$axios.get(this.$http.api.getWebsocketUrl, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const wsUrl = 'ws://' + window.g.baseURL + res.result
- this.wsShell(wsUrl)
- this.commandPrefix = res.result.split('/')[3]
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 全屏时重新设置控制台行高
- onResize() {
- this.rows = document.querySelector(".indexContainer").offsetHeight / 16 - 6;
- this.cols = document.querySelector(".indexContainer").offsetWidth / 14;
- this.term.resize(parseInt(this.rows), parseInt(this.cols))
- // canvas背景全屏
- var fitAddon = new FitAddon();
- this.term.loadAddon(fitAddon);
- try {
- fitAddon.fit();
- // 窗口大小改变时触发xterm的resize方法,向后端发送行列数,格式由后端决定
- // 这里不使用size默认参数,因为改变窗口大小只会改变size中的列数而不能改变行数,所以这里不使用size.clos,而直接使用获取我们根据窗口大小计算出来的行列数
- term.onResize(() => {
- this.onSend({ Op: "resize", Cols: term.cols, Rows: term.rows });
- });
- } catch (e) {
- console.log("e", e.message);
- }
- },
- }
- };
-</script>
-<style lang="less" scoped>
-.indexContainer {
- height: calc(100% - 0px);
-}
-</style>
- \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/console/module/ControlConsole2.vue b/src/views/rangeNodeManage/detail/console/module/ControlConsole2.vue
deleted file mode 100644
index a1851c9..0000000
--- a/src/views/rangeNodeManage/detail/console/module/ControlConsole2.vue
+++ /dev/null
@@ -1,306 +0,0 @@
-<template>
- <!-- <div class="content"> -->
- <!-- <div id="xterm" class="xterm"/> -->
- <div id="log" style="margin:10px auto;">
- <div class="console" id="terminal"></div>
- </div>
- <!-- </div> -->
-</template>
-
-<script>
-import "xterm/css/xterm.css";
-import { Terminal } from "xterm";
-import { FitAddon } from "xterm-addon-fit";
-import { AttachAddon } from "xterm-addon-attach";
-export default {
- name: "Xterm",
- props: {
- // socketURI: {
- // type: String,
- // default: ''
- // },
- },
- data() {
- return {
- term: null, //terminal 黑窗口容器
- socket: null,
- rows: 32,
- cols: 20,
- SetOut: false,
- isKey: false,
- prefix: "[root@serverip ~]# "//前缀
- // inputText: "",//输入内容,每次回车后进行ws通信然后清空此数据
- };
- },
- watch: {},
- mounted() {
- this.initSocket()
- },
- beforeDestroy() {
- this.socket.close()
- // this.term.dispose()
- },
- methods: {
- //初始化黑窗口
- async initTerm() {
- const term = new Terminal({
- rendererType: "canvas", //渲染类型
- rows: this.rows, //行数
- // cols: this.cols,// 设置之后会输入多行之后覆盖现象
- convertEol: true, //启用时,光标将设置为下一行的开头
- // scrollback: 10,//终端中的回滚量
- fontSize: 14, //字体大小
- disableStdin: false, //是否应禁用输入。
- cursorStyle: "block", //光标样式
- // cursorBlink: true, //光标闪烁
- scrollback: 30,
- tabStopWidth: 4,
- theme: {
- foreground: "yellow", //字体
- background: "#060101", //背景色
- cursor: "help" //设置光标
- }
- });
-
- const attachAddon = new AttachAddon(this.socket);
- const fitAddon = new FitAddon();
- term.loadAddon(attachAddon);
- term.loadAddon(fitAddon);
- //开启Xterm终端
- term.open(document.getElementById("terminal"));
-
- term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
- term.focus();
- this.term = term;
- // if (term._initialized) {
- // return
- // }
- // term._initialized = true
- // term.prompt = () => {
- // term.write('\r\n$ ')
- // }
-
- // term.writeln('Welcome to xterm.js')
- // term.writeln('This is a local terminal emulation, Type some keys and commands to play around')
- // term.writeln('')
- // term.prompt()
-
- // // xterm.4.x 输入
- // term.onKey(e => {
- // const ev = e.domEvent
- // const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
- // if (ev.keyCode === 13) {
- // term.prompt()
- // } else if (ev.keyCode === 8) {
- // // Do not delete the prompt
- // if (term._core.buffer.x > 2) {
- // term.write('\b \b')
- // }
- // } else if (printable) {
- // term.write(e.key);
- // this.socket.send(e.key);
- // }
- // })
- // this.term = term
- },
- // //事件
- // termKeyCode() {
- // const TERMINAL_INPUT_KEY = {
- // BACK: 8, // 退格删除键
- // ENTER: 13, // 回车键
- // UP: 38, // 方向盘上键
- // DOWN: 40, // 方向盘键
- // LEFT: 37, // 方向盘左键
- // RIGHT: 39, // 方向盘右键
- // };
- // const { eqpCode, server } = this.selectObj;
- // let inputText = "";
- // let currentIndex = 0;
- // let inputTextList = [];
- // this.term.onKey((e) => {
- // const { key, domEvent } = e;
- // const { keyCode, altKey, altGraphKey, ctrlKey, metaKey } = domEvent;
-
- // const printAble = !(altKey || altGraphKey || ctrlKey || metaKey); // 禁止相关按键
- // const totalOffsetLength = inputText.length + this.prefix.length; // 总偏移量
- // const currentOffsetLength = this.term._core.buffer.x; // 当前x偏移量
-
- // switch (keyCode) {
- // //删除
- // case TERMINAL_INPUT_KEY.BACK:
- // if (currentOffsetLength > this.prefix.length) {
- // const cursorOffSetLength = this.getCursorOffsetLength(totalOffsetLength - currentOffsetLength, "\x1b[D"); // 保留原来光标位置
-
- // this.term._core.buffer.x = currentOffsetLength - 1;
- // this.term.write("\x1b[?K" + inputText.slice(currentOffsetLength - this.prefix.length));
- // this.term.write(cursorOffSetLength);
- // inputText = `${inputText.slice(0, currentOffsetLength - this.prefix.length - 1)}${inputText.slice(
- // currentOffsetLength - this.prefix.length
- // )}`;
- // }
- // break;
- // //回车
- // case TERMINAL_INPUT_KEY.ENTER: {
- // this.term.write("\r\n");
- // console.log("inputText", inputText);
- // //ws 通信参数
- // let wsParams = { EqpCode: eqpCode, Action: "terminal", Data: inputText };
- // this.$emit("websocketSend", wsParams, server);
-
- // if (!inputText.trim()) {
- // this.term.prompt();
- // return;
- // }
-
- // if (inputTextList.indexOf(inputText) === -1) {
- // inputTextList.push(inputText);
- // currentIndex = inputTextList.length;
- // }
-
- // this.term.prompt();
- // inputText = "";
- // break;
- // }
-
- // case TERMINAL_INPUT_KEY.UP: {
- // if (!inputTextList[currentIndex - 1]) break;
-
- // const offsetLength = this.getCursorOffsetLength(inputText.length, "\x1b[D");
-
- // inputText = inputTextList[currentIndex - 1];
- // this.term.write(offsetLength + "\x1b[?K");
- // this.term.write(inputTextList[currentIndex - 1]);
- // this.term._core.buffer.x = totalOffsetLength;
- // currentIndex--;
-
- // break;
- // }
- // case TERMINAL_INPUT_KEY.LEFT:
- // if (currentOffsetLength > this.prefix.length) {
- // this.term.write(key); // '\x1b[D'
- // }
- // break;
-
- // case TERMINAL_INPUT_KEY.RIGHT:
- // if (currentOffsetLength < totalOffsetLength) {
- // this.term.write(key); // '\x1b[C'
- // }
- // break;
- // default: {
- // // 在当前的坐标写上 key 和坐标后面的字符
- // // 移动停留在当前位置的光标
- // if (!printAble) break;
- // if (totalOffsetLength >= this.term.cols) break;
- // if (currentOffsetLength >= totalOffsetLength) {
- // this.term.write(key);
- // inputText += key;
- // break;
- // }
- // let cursorOffSetLength = this.getCursorOffsetLength(totalOffsetLength - currentOffsetLength, "\x1b[D");
- // this.term.write("\x1b[?K" + `${key}${inputText.slice(currentOffsetLength - this.prefix.length)}`);
- // this.term.write(cursorOffSetLength);
- // inputText = inputText.slice(0, currentOffsetLength) + key + inputText.slice(totalOffsetLength - currentOffsetLength);
- // break;
- // }
- // }
- // });
- // },
- // //限制和后端交互,只有输入回车键才显示结果
- // termPromt() {
- // this.term.prompt = () => {
- // this.term.write(this.prefix);
- // };
- // },
- //获取光标当前位置
- getCursorOffsetLength(offsetLength, subString) {
- let cursorOffsetLength = "";
- for (let offset = 0; offset < offsetLength; offset++) {
- cursorOffsetLength += subString;
- }
- return cursorOffsetLength;
- },
- //写入黑窗口
- wirteTerm(data) {
- console.log("写入黑窗口", data);
- this.term.writeln(data);
- this.term.prompt();
- },
- // //加载基础数据
- // pageLoad(data) {
- // this.selectObj = data;
- // this.drawerFlag = true;
- // this.$nextTick(() => {
- // this.initTerm();
- // });
- // },
- cancelClick() {
- this.drawerFlag = false;
- //关闭弹框
- this.term.dispose(document.getElementById("xterm"));
- },
- initSocket() {
- const wsurl = 'ws://172.16.0.120:30598/ws/target-19-austria-80-110-35-0-24/target-19-relay-127-54b5df76f4-8958g/relay-127'
- this.socket = new WebSocket(wsurl);
- this.socketOnClose();
- this.socketOnOpen();
- this.socketOnError();
- },
- socketOnOpen() {
- this.socket.onopen = () => {
- console.log('socket 连接成功')
- // 链接成功后
- this.initTerm()
- }
- // this.socket.onmessage = function(evt) {
- // // let str = new TextDecoder().decode(evt.data);
- // // console.log('onmessage=====', evt)
- // this.term.write(evt.data);
- // };
- // //返回
- // this.socket.onmessage = function(evt) {
- // // let str = new TextDecoder().decode(evt.data);
- // console.log('onmessage=====', evt)
- // this.term.write(evt.data);
- // };
- },
- socketOnClose() {
- this.socket.onclose = (e) => {
- console.log('socket 关闭:' + '错误码==' + e.code + ';错误原因==' + e.reason + ';wasClean==' + e.wasClean)
- }
- },
- socketOnError() {
- this.socket.onerror = () => {
- console.log('socket 连接失败')
- }
- }
- },
-};
-</script>
-
-<style lang='less' scoped="scoped">
-// .content {
-// ::v-deep .el-textarea__inner {
-// background-color: #1A2648;
-// }
-// }
-.xterm-screen{
- min-height: calc(100vh);
-}
-</style>
-<style scoped>
- h1, h2 {
- font-weight: normal;
-}
-ul {
- list-style-type: none;
- padding: 0;
-}
-li {
- display: inline-block;
- margin: 0 10px;
-}
-a {
- color: #42b983;
-}
-
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/console/module/ControlConsole4.vue b/src/views/rangeNodeManage/detail/console/module/ControlConsole4.vue
deleted file mode 100644
index 778bea4..0000000
--- a/src/views/rangeNodeManage/detail/console/module/ControlConsole4.vue
+++ /dev/null
@@ -1,349 +0,0 @@
-<template>
- <div
- style="height: 100%;
- background: #002833;"
- >
- <div class="indexContainer" id="terminal" ref="terminal"></div>
- </div>
- </template>
-
- <script>
- // 引入xterm,请注意这里和3.x版本的引入路径不一样
- import { Terminal } from "xterm";
- import "xterm/css/xterm.css";
- import "xterm/lib/xterm.js";
- import { FitAddon } from "xterm-addon-fit";
-
- export default {
- name: "Shell",
- data() {
- return {
- nodeId: '',
- shellWs: "",
- term: "", // 保存terminal实例
- rows: 40,
- cols: 100,
- urlParam: {
- Tag: 'tag',
- name: 'name',
- pod: 'pod'
- }
- };
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- },
- immediate: true
- }
- },
- created() {
- this.getWebsocketUrl()
- },
-
- mounted() {
- let _this = this;
- localStorage.setItem('commands', '')
- // 获取容器宽高/字号大小,定义行数和列数
- // this.rows = document.querySelector(".indexContainer").offsetHeight / 16 - 6;
- // this.cols = document.querySelector(".indexContainer").offsetWidth / 14;
-
- let term = new Terminal({
- rendererType: "canvas", //渲染类型
- // rows: parseInt(_this.rows), //行数
- // cols: parseInt(_this.cols), // 不指定行数,自动回车后光标从下一行开始
- convertEol: true, //启用时,光标将设置为下一行的开头
- // scrollback: 50, //终端中的回滚量
- disableStdin: false, //是否应禁用输入。
- cursorStyle: "underline", //光标样式
- cursorBlink: true, //光标闪烁
- theme: {
- foreground: "#7e9192", //字体
- background: "#002833", //背景色
- cursor: "help", //设置光标
- lineHeight: 16
- }
- });
-
- // 创建terminal实例
- term.open(this.$refs["terminal"]);
-
- // 换行并输入起始符“$”
- term.prompt = () => {
- term.write("\r\n$ ");
- };
- term.prompt();
-
- // // canvas背景全屏
- var fitAddon = new FitAddon();
- term.loadAddon(fitAddon);
- fitAddon.fit();
-
- window.addEventListener("resize", resizeScreen);
-
- // 内容全屏显示
- function resizeScreen() {
- // 不传size
-
- try {
- fitAddon.fit();
-
- // 窗口大小改变时触发xterm的resize方法,向后端发送行列数,格式由后端决定
- // 这里不使用size默认参数,因为改变窗口大小只会改变size中的列数而不能改变行数,所以这里不使用size.clos,而直接使用获取我们根据窗口大小计算出来的行列数
- term.onResize(() => {
- _this.onSend({ Op: "resize", Cols: term.cols, Rows: term.rows });
- });
- } catch (e) {
- console.log("e", e.message);
- }
- }
-
- // function runFakeTerminal(_this) {
- // if (term._initialized) {
- // return;
- // }
- // // 初始化
- // term._initialized = true;
-
- // term.writeln("Welcome to use Superman. ");
- // term.writeln(
- // `This is Web Terminal of pod\x1B[1;3;31m ${
- // _this.urlParam.podName
- // }\x1B[0m in namespace\x1B[1;3;31m ${_this.urlParam.namespace}\x1B[0m`
- // );
-
- // term.prompt();
-
- // // / **
- // // *添加事件监听器,用于按下键时的事件。事件值包含
- // // *将在data事件以及DOM事件中发送的字符串
- // // *触发了它。
- // // * @返回一个IDisposable停止监听。
- // // * /
- // // / ** 更新:xterm 4.x(新增)
- // // *为数据事件触发时添加事件侦听器。发生这种情况
- // // *用户输入或粘贴到终端时的示例。事件值
- // // *是`string`结果的结果,在典型的设置中,应该通过
- // // *到支持pty。
- // // * @返回一个IDisposable停止监听。
- // // * /
- // // 支持输入与粘贴方法
- // term.onData(function(key) {
- // let order = {
- // Data: key,
- // Op: "stdin"
- // };
- // _this.onSend(key);
- // // 为解决窗体resize方法才会向后端发送列数和行数,所以页面加载时也要触发此方法
- // _this.onSend({
- // Op: "resize",
- // Cols: parseInt(term.cols),
- // Rows: parseInt(term.rows)
- // });
- // });
-
- // _this.term = term;
- // }
- // runFakeTerminal(_this);
- function runFakeTerminal(_this) {
- if (term._initialized) {
- return;
- }
-
- term._initialized = true;
-
- term.prompt = () => {
- term.write("\r\n ");
- };
-
- term.writeln("Welcome to xterm.js");
- term.writeln(
- "This is a local terminal emulation, without a real terminal in the back-end."
- );
- term.writeln("Type some keys and commands to play around.");
- term.writeln("");
- term.prompt();
-
- // 监控键盘输入事件
- // / **
- // *添加事件监听器,用于按下键时的事件。事件值包含
- // *将在data事件以及DOM事件中发送的字符串
- // *触发了它。
- // * @返回一个IDisposable停止监听。
- // * /
- // 添加事件监听器,支持输入方法
- term.onData( function (key) {
- if (key.charCodeAt(0) == 13) { // 回车
- if(_this.command === 'clear') {
- term.clear()
- }
- if (_this.command.trim().length === 0) {
- term.prompt()
- } else {
- // 保存命令
- let commands = localStorage.getItem('commands') ? JSON.parse(localStorage.getItem('commands')) : []
- commands.push(_this.command)
- localStorage.setItem('commands', JSON.stringify(commands))
- localStorage.setItem('index', commands.length)
- // _this.sendData(0)
- _this.onSend(localStorage.getItem('commands'))
- }
- _this.command = ''
- } else if (key === '\u001b[A') { // 向上方向
- let commands = localStorage.getItem('commands') ? JSON.parse(localStorage.getItem('commands')) : []
- // console.log(commands)
- let index = localStorage.getItem('index') ? localStorage.getItem('index') : commands.length
- index = parseInt(index)
- if (commands.length && index < commands.length + 1 && index > 0) {
- // 删除现有命令
- for (let i = 0; i < _this.command.length; i++) {
- if (term._core.buffer.x > (_this.sshPrompt.length + 2)) {
- term.write('\b \b')
- }
- }
- _this.command = commands[index - 1]
- term.write(_this.command)
- localStorage.setItem('index', index - 1)
- }
- } else if (key === '\u001b[B') { // 向下方向
- let commands = localStorage.getItem('commands') ? JSON.parse(localStorage.getItem('commands')) : []
- let index = localStorage.getItem('index') ? localStorage.getItem('index') : commands.length
- index = parseInt(index)
- if (commands.length && index < commands.length - 1 && index > -1) {
- // 删除现有命令
- for (let i = 0; i < _this.command.length; i++) {
- if (term._core.buffer.x > (_this.sshPrompt.length + 2)) {
- term.write('\b \b')
- }
- }
- _this.command = commands[index + 1]
- term.write(_this.command)
- localStorage.setItem('index', index + 1)
- }
- } else if (key.charCodeAt(0) === 9) { // tab键
- let params = {
- consoleUUID: _this.activeMsf,
- cmd: _this.command
- }
- // tab补全
- _this.$apis.readTabsComplete(params).then((res) => {
- if (res.code === 200) {
- if (res.data.length) {
- for (let i = 0; i < _this.command.length; i++) {
- term.write('\b \b')
- }
- let data = res.data.join('\r\n')
- _this.command = res.data[res.data.length - 1]
- if (res.data.length > 1) {
- term.write('\r\n')
- term.write(data)
- term.prompt()
- term.write(res.data[res.data.length - 1])
- } else {
- term.write(_this.command)
- }
- }
- } else {
- _this.$message.error(res.message())
- }
- })
- } else if (key.charCodeAt(0) === 127) {
- if (term._core.buffer.x > (_this.sshPrompt.length + 2)) {
- term.write('\b \b')
- _this.command = _this.command.substr(0, _this.command.length - 1)
- }
- } else{
- _this.command += key
- term.write(key)
- }
- })
-
- _this.term = term;
-
- // 粘贴事件
- term.onData(function(data) {
- _this.order = data;
- term.write(data);
- });
- }
- runFakeTerminal(_this);
- },
-
- methods: {
-
- /**
- * **wsShell 创建页面级别的websocket,加载页面数据
- * ws 接口:/xxx/xxx/xxx
- * 参数:无
- * ws参数:
- * @deployId 任务id
- * @tagString 当前节点
- * 返回:无
- * **/
- wsShell(url) {
- const _this = this;
- let tag = this.urlParam.Tag;
- let name= this.urlParam.name;
- let pod= this.urlParam.pod;
-
- // let query = `?tag=${tag}&name=${name}&pod=${pod}`;
- // let url = `xxxx/xxxx${query}`;// websocket连接接口
- // let url = 'ws://172.16.0.120:30598/ws/target-19-austria-80-110-35-0-24/target-19-relay-127-54b5df76f4-8958g/relay-127'
-
- this.shellWs = this.websoketLib.WS({
- url,
- isInit: true,
- openFn(e) {
- console.log('连接websocket成功===', e)
- // _this.term.resize({ rows: _this.rows, cols: 100 }); //终端窗口重新设置大小 并触发term.on("resize")
- },
- messageFn(e) {
- console.log("message", e);
- if (e) {
- _this.term.write(e.data);
- // let data = JSON.parse(e.data);
- // if (data.Data == "\n" || data.Data == "\r\nexit\r\n") {
- // _this.$message("连接已关闭");
- // }
- // 打印后端返回数据
- // _this.term.write(data.Data);
- }
- },
- errorFn(e) {
- //出现错误关闭当前ws,并且提示
- console.log("error", e);
- _this.$message.error({
- message: "ws 请求失败,请刷新重试~",
- duration: 5000
- });
- }
- });
- },
-
- onSend(data) {
- // data = this.websoketLib.isObject(data) ? JSON.stringify(data) : data;
- // data = this.websoketLib.isArray(data) ? data.toString() : data;
- // data = data.replace(/\\\\/, "\\");
- this.shellWs.onSend(data);
- },
-
- //删除左右两端的空格
- trim(str) {
- return str.replace(/(^\s*)|(\s*$)/g, "");
- },
- // 获取websocket地址
- getWebsocketUrl() {
- const reqParams = { node_id: this.nodeId }
- this.$axios.get(this.$http.api.getWebsocketUrl, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.wsShell(res.result)
- }
- }).catch(err => {
- console.log(err)
- })
- }
- }
- };
- </script>
- \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/console/module/DirNameForm.vue b/src/views/rangeNodeManage/detail/console/module/DirNameForm.vue
deleted file mode 100644
index 55ac4ca..0000000
--- a/src/views/rangeNodeManage/detail/console/module/DirNameForm.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-<template>
-<div class="role-dialog" v-if="visible">
- <i class="el-icon-close" style="float: right; padding-right: 7%;padding-top: 2.8%" @click="close"></i>
- <div class="fbs">
- <span style="margin-right: 3%">文件名</span>
- <el-input
- size="mini"
- :value="value"
- placeholder="请输入内容"
- style="width: 50%"
- v-bind="$attrs"
- v-on="$listeners">
- </el-input>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="submit">确认</el-button>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-export default {
- name: 'RoleForm',
- props: {
- value: {
- typeof: String,
- require: true,
- default: ''
- }
- },
- data() {
- return {
- visible: false
- }
- },
- watch: {
- value: {
- handler(val) {
- this.$emit('input', val)
- }
- }
- },
- methods: {
- close() {
- // document.querySelector('.mask').style.display = 'none'
- this.visible = false
- },
- submit() {
- // document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.$emit('makeDirSubmit')
- }
- }
-
-}
-</script>
-
-<style lang="less" scoped>
-.role-dialog{
- z-index: 998;
- width: 300px;
- height: 120px;
- position: absolute; /* 绝对定位 */
- top: 100px; /* 向下偏移50% */
- left: 150px; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../../img/jbpzxybqr.png');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- .fbs{
- width: 100%;
- float: left;
- margin-top: 3%;
- text-align: center;
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-top: 5%;
- text-align: center;
- .glBut{
- width: 50px;
- height: 18px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/console/module/FileManage.vue b/src/views/rangeNodeManage/detail/console/module/FileManage.vue
deleted file mode 100644
index df28f48..0000000
--- a/src/views/rangeNodeManage/detail/console/module/FileManage.vue
+++ /dev/null
@@ -1,538 +0,0 @@
-<template>
-<div class="content">
- <el-tree
- ref="tree"
- class="tree-section"
- lazy
- node-key="id"
- :data="treeData"
- :props="defaultProps"
- :load="loadNode"
- @node-click="handleNodeClick"
- @node-contextmenu="openTreeMenu"
- v-dragresize="dragConfig"
- >
- </el-tree>
- <div class="tree-content">
- <div style="text-align:left; width: 100%; padding: 10px;border: 1px solid #BAD0F11A;">
- <span>
- {{ dirTitle }}
- </span>
- </div>
- <div style="clear:both;text-align:left; padding: 10px;border-bottom: 1px solid #BAD0F11A;">
- <img src="../../../../../img/icon/file-icon.svg" alt="" style="width: 18px; height: 18px;">
- {{ currentFileName }}
- </div>
- <ul style="clear:both;" class="tree-content-ul">
- <li v-for="fileItem in fileList" :key="fileItem.name" @contextmenu.prevent="openMenu(fileItem, $event)">
- <i class="el-icon-document file-info" style="font-size: 20px"></i>
- <span class="file-info">{{ fileItem.name }}</span>
- <span class="file-info">{{ fileItem.size }}</span>
- <span class="file-info">{{ fileItem.time }}</span>
- </li>
- </ul>
- <div class="empty-box" @contextmenu.prevent="openUploadMenu($event)"></div>
- </div>
- <ul
- v-show="visible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li>
- <li @click="download">下载</li>
- <li @click="del">删除</li>
- </ul>
- <ul
- v-show="uploadVisible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li>
- </ul>
- <div v-show="showTreeMenu" class="treeMenu">
- <div @click="makeDir">新建文件夹</div>
- <div @click="delDir">删除文件夹</div>
- </div>
- <DirNameForm
- ref="dirNameForm"
- v-model="dirName"
- @makeDirSubmit="makeDirSubmit">
- </DirNameForm>
-</div>
-</template>
-
-<script>
-import DirNameForm from './DirNameForm.vue'
-export default {
-components: { DirNameForm },
-props: ['isFullscreen'],
-data() {
- return{
- visible: false,
- uploadVisible: false,
- top: 0,
- left: 0,
- nodeId: '',
- dirTitle: '>',
- currentFileName: '',
- fileList: [],
- selectFile: {},
- selectNode: {path: '/'},
- rightClickNode: {},
- defaultProps: {
- children: 'children',
- label: 'name',
- },
- showTreeMenu: false, // 文件夹数据
- contextNode: {}, // 文件夹数据
- dirName: '', // 新建文件名
- treeData: []
- }
-},
-computed: {
- dragConfig() {
- return [
- {
- dragBorder: "right",
- setCssProperty: "width",
- },
- ];
- },
-},
-watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- // this.getCurrentDirFile('/')
- },
- immediate: true
- },
- visible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeMenu)
- } else {
- document.body.removeEventListener('click', this.closeMenu)
- }
- },
- uploadVisible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeUploadMenu)
- } else {
- document.body.removeEventListener('click', this.closeUploadMenu)
- }
- },
-},
-methods: {
- upload(e) {
- const params = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- file: e.target.files[0]
- }
- const submitForm = new FormData()
- for(const key in params) {
- submitForm.append(key, params[key])
- }
- this.$axios.postFormData(this.$http.api.uploadFile, submitForm).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '上传文件成功',
- type: 'success',
- duration: 2500
- })
- // this.$refs.tree.remove(item.id);
- // this.setCurrentHighlight(null);
- // console.log('选中了节点id===', this.selectNode.$treeNodeId)
- // 更新当前路径下的文件信息
- this.handleNodeClick(this.selectNode)
- this.setCurrentHighlight(this.selectNode.$treeNodeId);
- // this.init()
- }
- }).catch(err => {
- console.log(err)
- })
- },
- download() {
- // this.downLoading = true
- const reqParams = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- filename: this.selectFile.name
- }
- this.$axios.getFile(this.$http.api.downloadFile, reqParams).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载文件成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载文件失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- // this.downLoading = false
- })
- },
- del() {
- const params = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- filename: this.selectFile.name
- }
- this.$axios.delete(this.$http.api.delFile, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 更新当前路径下的文件信息
- this.handleNodeClick(this.selectNode)
- // console.log('选中了节点id===', this.selectNode.$treeNodeId)
- this.setCurrentHighlight(this.selectNode.$treeNodeId);
- // this.init()
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 设置当前选中高亮
- setCurrentHighlight (id) {
- this.$nextTick(() => {
- this.$refs.tree.setCurrentKey(id)
- })
- },
- openMenu(fileItem, e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 180 // fix 位置bug
- } else {
- this.top = e.clientY - 600 // fix 位置bug
- }
- this.uploadVisible = false
- this.visible = true
- this.selectFile = fileItem
- },
- closeMenu() {
- this.visible = false
- },
- openUploadMenu(e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 120 // fix 位置bug
- } else {
- this.top = e.clientY - 600 // fix 位置bug
- }
- this.visible = false
- this.uploadVisible = true
- },
- closeUploadMenu() {
- this.uploadVisible = false
- },
- // 获取当前路径下文件
- getCurrentDirFile(currentDir) {
- const reqParams = { node_id: this.nodeId, current_dir: currentDir }
- return this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const dirs = res?.result?.object?.dir || []
- this.fileList = res?.result?.object?.file || []
- // console.log('请求回来files===', files)
- const nodeData = dirs.map(dir => {
- return {
- name: dir.name,
- path: currentDir === '/' ? currentDir + dir.name : `${currentDir}/${dir.name}`,
- fileList: []
- }
- })
- // console.log('请求回来nodeData====', nodeData)
- return nodeData
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 点击加载子节点
- async loadNode(node, reslove) {
- // console.log('执行了loadNode', node)
- if (node.level == 0) {
- let nodeData = await this.getCurrentDirFile('/')
- // console.log('初始化数据===', nodeData)
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- } else {
- let nodeData = await this.getCurrentDirFile(node.data.path)
- // 判断是否为最底层节点 根据自己接口返回的数据判断即可
- nodeData.forEach(item => {
- item.hasChildren == false ? item.lastNode = ture : null
- });
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- }
- },
- handleNodeClick(node) {
- // this.fileList = []
- // console.log('选中了节点===', node)
- // console.log('选中了节点id===', node.$treeNodeId)
- this.selectNode = node
- this.dirTitle = node.path.split('/').join('>')
- this.currentFileName = node.name
- // this.fileList = node.fileList
- const reqParams = { node_id: this.nodeId, current_dir: node.path }
- this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.fileList = res?.result?.object?.file || []
- }
- }).catch(err => {
- console.log(err)
- })
- },
- openTreeMenu(event, data, node, target) {
- // console.log(event, data, node, target)
- this.showTreeMenu = true // 显示菜单
- this.contextNode = data // 存储数据
- // console.log(this.contextNode, 'contextNode')
- // console.log(node, 'rightClickNode=======')
- // console.log(target, 'target')
- this.rightClickNode = node
- document.querySelector('.treeMenu').setAttribute('style',`top:${event.clientY + 30}px;left:${event.clientX + 30}px;`)
- document.addEventListener('click', this.closeTreeMenu)
- document.addEventListener('contextmenu', this.closeTreeMenu)
- },
- closeTreeMenu() {
- this.showTreeMenu = false // 关闭菜单
- document.removeEventListener('click', this.closeTreeMenu)
- document.removeEventListener('contextmenu', this.closeTreeMenu)
- },
- // 当新建文件夹时,先填写名字
- openDirNameForm() {
- this.$refs.dirNameForm.visible = true
- },
- // 新建文件夹
- makeDir() {
- this.openDirNameForm()
- },
- // 新建文件夹接口提交
- makeDirSubmit() {
- const reqParams = { node_id: this.nodeId, current_dir: this.contextNode.path, new_dir_name: this.dirName }
- this.$axios.get(this.$http.api.makeDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '新建文件夹成功',
- type: 'success',
- duration: 2500
- })
- // 页面增加子节点
- let id = Math.ceil(Math.random() * 1000000)
- var addNode = {
- path: this.contextNode.path + '/' + this.dirName,
- name: this.dirName,
- fileList: []
- // id: id,
- // name: this.dirName,
- // data: {
- // path: this.contextNode.path,
- // name: this.dirName,
- // fileList: []
- // }
- }
- // console.log(addNode, 'addNode======')
- this.$refs.tree.append(addNode, this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 删除文件夹
- delDir() {
- const index = this.contextNode.path.lastIndexOf('/')
- const path = this.contextNode.path.substring(0, index);
- const params = {
- node_id : this.nodeId,
- current_dir: path,
- dir_name: this.contextNode.name
- }
- this.$axios.delete(this.$http.api.delDir, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 页面删除子节点
- this.$refs.tree.remove(this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- }
-}
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.content {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- color: #ffffff;
- .tree-section {
- width: 25%;
- height: 100%;
- // background-color: #1A2648;
- background: transparent;
- border: 1px solid #BAD0F11A;
- color: #06F7FF;
- overflow-y: auto;
- ::v-deep .el-tree-node__content:hover {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- ::v-deep .el-tree-node.is-current > .el-tree-node__content {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- }
- .tree-content {
- width: 75%;
- height: 100%;
- display: flex;
- flex-direction: column;
- .tree-content-ul {
- width: 100%;
- background-color: rgba(25, 33, 61, 0.4);
- overflow-y: auto;
- li {
- display: flex;
- flex-direction: row;
- justify-content: space-around;
- border-bottom: 1px solid #BAD0F11A;
- padding: 5px;
- .file-info {
- flex: 1 1 100px;
- }
- }
- }
- .empty-box {
- flex: 1;
- }
- }
-}
-.contextmenu {
- margin: 0;
- border-radius: 6px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- background: #0E3D8A;
- z-index: 3000;
- position: absolute;
- list-style-type: none;
- padding: 5px 0;
- font-size: 12px;
- font-weight: 400;
- color: #06F7FF;
- // box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- li {
- margin: 0;
- padding: 7px 30px;
- cursor: pointer;
- &:hover {
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- }
- }
- .file-input {
- display: none;
- }
- }
-
-.treeMenu {
- position: fixed;
- z-index: 99999;
- top: 50%;
- left: 50%;
- color: #06F7FF;
- background-color: #0E3D8A;
- overflow: hidden;
- border-radius: 5px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- div{
- padding: 7px 30px;
- box-sizing: border-box;
- //width: 50px;
- text-align: center;
- }
- div:hover{
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- cursor: pointer;
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/detail/index.vue b/src/views/rangeNodeManage/detail/detail/index.vue
deleted file mode 100644
index 0a254c1..0000000
--- a/src/views/rangeNodeManage/detail/detail/index.vue
+++ /dev/null
@@ -1,107 +0,0 @@
-<template>
-<div class="tabs">
- <i class="el-icon-back back-btn" @click="backNodeList"></i>
- <el-tabs v-model="activeName" @tab-click="handleClick">
- <el-tab-pane label="详细信息" name="second">
- <DetailInfo></DetailInfo>
- </el-tab-pane>
- <el-tab-pane label="资源监控" name="third">
- <ResourceMonitor v-if="activeName==='third'"></ResourceMonitor>
- </el-tab-pane>
- </el-tabs>
-</div>
-</template>
-
-<script>
-import DetailInfo from './module/DetailInfo'
-import ResourceMonitor from './module/ResourceMonitor'
-export default {
- components: { DetailInfo, ResourceMonitor },
- data() {
- return {
- activeName: 'second'
- };
- },
- methods: {
- handleClick(tab, event) {
- },
- backNodeList() {
- this.$router.push({ name: 'rangeNodeManage' })
- }
- }
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.tabs {
- width: 100%;
- height: 100%;
- text-align: center;
- position: relative;
- padding: 8px 0 0;
- display: flex;
- .detail-title {
- position:absolute;
- margin: 10px;
- }
- .back-btn {
- position: absolute;
- cursor: pointer;
- font-size: 30px;
- color: #02DDEA;
- margin: 5px;
- z-index: 10;
- }
-}
-::v-deep .el-tabs{
- color: #000;
- left: 0px;
- top: 0px;
- width: 100%;
- height: 100%;
- position: relative;
- .el-tabs__header {
- margin-left: 100px;
- }
- .el-tabs__content{
- height: calc(100% - 48px);
- // height: 100%;
- .el-tab-pane{
- height: 100%;
- }
- }
-}
-/* 去除灰色横条 */
-::v-deep .el-tabs__nav-wrap::after {
- position: static !important;
-}
-/* 设置滑块颜色 */
-::v-deep .el-tabs__active-bar{
- background-color: #0E3D8A !important;
-}
-/* 设置滑块停止位置 */
-::v-deep .el-tabs__active-bar.is-top{
- height: 37px;
- width: 104px ! important;
- border-radius: 17px;
- top: 0px !important;
- left: -18px !important;
- position: absolute !important;
- z-index: 1;
-}
-/* 设置当前选中样式 */
-::v-deep .el-tabs__item.is-active{
- color:#02DDEA !important;
- z-index: 2;
-}
-/* 设置未被选中样式 */
-::v-deep .el-tabs__item{
- padding: 0 20px !important;
- width: 104px;
- box-sizing: border-box;
- display: inline-block;
- position: relative !important;
- color:#02DDEA !important;
- z-index: 2;
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/detail/module/DetailInfo.vue b/src/views/rangeNodeManage/detail/detail/module/DetailInfo.vue
deleted file mode 100644
index cec66d8..0000000
--- a/src/views/rangeNodeManage/detail/detail/module/DetailInfo.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-<template>
- <div class="detail-info" v-loading="loading">
- <el-descriptions :column="2">
- <el-descriptions-item label="Tor版本">{{nodeDetail.owner_setting && nodeDetail.owner_setting.tor_version}}</el-descriptions-item>
- <el-descriptions-item label="状态">{{nodeDetail.status}}</el-descriptions-item>
- <el-descriptions-item label="角色">{{nodeDetail.owner_setting && nodeDetail.owner_setting.role}}</el-descriptions-item>
- <el-descriptions-item label="创建开始时间">{{formatTime(nodeDetail.create_time)}}</el-descriptions-item>
- <el-descriptions-item label="宽带">{{nodeDetail.owner_setting && nodeDetail.owner_setting.bandwidth + '&nbsp;M'}}</el-descriptions-item>
- <el-descriptions-item label="创建完成时间">{{formatTime(nodeDetail.complete_time)}}</el-descriptions-item>
- <el-descriptions-item label="内存">{{nodeDetail.owner_setting && nodeDetail.owner_setting.memory + '&nbsp;Mi'}}</el-descriptions-item>
- <el-descriptions-item label="ip">{{nodeDetail.ip}}</el-descriptions-item>
- <el-descriptions-item label="sockport">{{nodeDetail.owner_setting && nodeDetail.owner_setting.socks_port}}</el-descriptions-item>
- <el-descriptions-item label="pod名">{{nodeDetail.pod_name}}</el-descriptions-item>
- <el-descriptions-item label="网络">{{nodeDetail.owner_setting && nodeDetail.owner_setting.use_network.cidr}}</el-descriptions-item>
- <el-descriptions-item label="节点昵称">{{nodeDetail.nick_name}}</el-descriptions-item>
- <el-descriptions-item v-if="nodeDetail.owner_setting && nodeDetail.owner_setting.role==='onion'" label="onion">{{nodeDetail.onion}}</el-descriptions-item>
- </el-descriptions>
- </div>
- </template>
-
- <script>
- import { formatTime } from '../../../../../utils'
- export default {
- name: 'DetailInfo',
- data() {
- return {
- loading: false,
- nodeId: '',
- nodeDetail: {}
- }
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- this.init()
- },
- immediate: true
- }
- },
- methods: {
- formatTime,
- init() {
- // this.nodeDetail = getTargetsResponse?.result
- this.loading = true
- const reqParams = { node_id: this.nodeId }
- this.$axios.get(this.$http.api.getNodeDetail, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.nodeDetail = res?.result
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- }
- }
- }
- </script>
-
- <style lang='less' scoped="scoped">
- .detail-info {
- width: 100%;
- height: 100%;
- background-color: rgba(25, 33, 61, 0.4);
- border: 1px solid rgba(186, 208, 241, 0.1);
- border-radius: 8px;
- }
-.el-descriptions{
- ::v-deep .el-descriptions__body {
- background-color: transparent;
- .el-descriptions__table .el-descriptions-item__cell {
- font-size: 16px;
- font-weight: 500;
- line-height: 20px;
- padding-top: 20px;
- padding-left: 25px;
- color: rgba(255, 255, 255, 0.6);
- }
- }
-}
- </style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/detail/module/ResourceMonitor.vue b/src/views/rangeNodeManage/detail/detail/module/ResourceMonitor.vue
deleted file mode 100644
index 37ff85c..0000000
--- a/src/views/rangeNodeManage/detail/detail/module/ResourceMonitor.vue
+++ /dev/null
@@ -1,199 +0,0 @@
-<template>
- <div class="dresource-monitor">
- <div class="cpu">
- <div style="width:100%;height: 100%;" id="cpu"></div>
- </div>
- <div class="memory">
- <div style="width:100%;height: 100%;" id="memory"></div>
- </div>
- </div>
- </template>
-
- <script>
- import * as echarts from 'echarts';
- import dayjs from 'dayjs'
- import { getCpuResponse } from './cpuMock.js'
- import { getMemoryResponse } from './memoryMock.js'
- export default {
- data() {
- return {
- nodeId: '',
- cpuData: [],
- cpuDataX: [],
- cpuDataY: [],
- memoryData: [],
- memoryDataX: [],
- memoryDataY: []
- }
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- // this.init()
- },
- immediate: true
- }
- },
- created() {
- },
- mounted() {
- this.init()
- },
- methods: {
- init() {
- // this.cpuData = getCpuResponse.result
- // this.cpuData.forEach(item => {
- // this.cpuDataX.push(item[0])
- // this.cpuDataY.push(item[1])
- // })
- // this.memoryData = getMemoryResponse.result
- // this.memoryData.forEach(item => {
- // this.memoryDataX.push(item[0])
- // this.memoryDataY.push(item[1])
- // })
- // this.setCpuEcharts()
- // this.setMemoryEcharts()
-
- const reqParams = {
- node_id: this.nodeId,
- }
- this.$axios.get(this.$http.api.getCpu, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.cpuData = res?.result
- this.cpuData.forEach(item => {
- this.cpuDataX.push(dayjs(item[0]).format('HH:mm:ss'))
- this.cpuDataY.push(item[1])
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.setCpuEcharts()
- })
- this.$axios.get(this.$http.api.getMemory, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.memoryData = res?.result
- this.memoryData.forEach(item => {
- this.memoryDataX.push(dayjs(item[0]).format('HH:mm:ss'))
- this.memoryDataY.push(item[1])
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.setMemoryEcharts()
- })
- },
- setCpuEcharts() {
- var chartDom = document.getElementById('cpu');
- var myChart = echarts.init(chartDom);
- var option;
-
- option = {
- // color: ['rgba(61, 255, 220, 0.2)'],
- grid: {
- // top: '8%',
- height: '55%' // 设置折线图的高度为容器高度的百分之四十
- },
- xAxis: {
- type: 'category',
- data: this.cpuDataX,
- axisLabel: {
- color: '#ffffff'
- }
- },
- yAxis: {
- type: 'value',
- name: 'cpu (mcore)',
- nameTextStyle: {
- color: '#ffffff'
- },
- axisLine: {
- show: true // 将此处改为 true 则显示 Y 轴刻度线
- // symbol: ['none', 'arrow']
- },
- splitLine: {
- show: false
- },
- axisLabel: {
- color: '#ffffff'
- }
- },
- series: [
- {
- data: this.cpuDataY,
- type: 'line',
- smooth: true
- }
- ]
- }
- option && myChart.setOption(option)
- },
-
- setMemoryEcharts() {
- var chartDom = document.getElementById('memory');
- var myChart = echarts.init(chartDom);
- var option;
-
- option = {
- grid: {
- top: '18%',
- height: '55%' // 设置折线图的高度为容器高度的百分之四十
- },
- xAxis: {
- type: 'category',
- data: this.memoryDataX,
- axisLabel: {
- color: '#ffffff'
- }
- },
- yAxis: {
- type: 'value',
- name: '内存 (Mi)',
- nameTextStyle: {
- color: '#ffffff'
- },
- axisLine: {
- show: true // 将此处改为 true 则显示 Y 轴刻度线
- // symbol: ['none', 'arrow']
- },
- splitLine: {
- show: false
- },
- axisLabel: {
- color: '#ffffff'
- }
- },
- series: [
- {
- data: this.memoryDataY,
- type: 'line',
- smooth: true
- }
- ]
- }
- option && myChart.setOption(option)
- }
- }
-
- }
- </script>
-
-<style lang='less' scoped="scoped">
-.dresource-monitor {
- width: 100%;
- height: 100%;
- background-color: rgba(25, 33, 61, 0.4);
- border: 1px solid rgba(186, 208, 241, 0.1);
- border-radius: 8px;
-}
-.cpu {
- width: 100%;
- height: 50%;
-}
-.memory {
- width: 100%;
- height: 50%;
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/detail/module/cpuMock.js b/src/views/rangeNodeManage/detail/detail/module/cpuMock.js
deleted file mode 100644
index f7220e0..0000000
--- a/src/views/rangeNodeManage/detail/detail/module/cpuMock.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const getCpuResponse = {
- "code": 200,
- "message": "success",
- "result": [
- [
- "2024-01-06 09:33:14",
- 1.757
- ],
- [
- "2024-01-06 09:34:14",
- 1.694
- ],
- [
- "2024-01-06 09:35:14",
- 1.573
- ],
- [
- "2024-01-06 09:36:14",
- 0.877
- ],
- [
- "2024-01-06 09:37:14",
- 0.774
- ],
- [
- "2024-01-06 09:38:14",
- 0.855
- ],
- [
- "2024-01-06 09:39:14",
- 0.903
- ],
- [
- "2024-01-06 09:40:14",
- 0.929
- ],
- [
- "2024-01-06 09:41:14",
- 1.135
- ],
- [
- "2024-01-06 09:42:14",
- 1.154
- ],
- [
- "2024-01-06 09:43:14",
- 0.963
- ],
- [
- "2024-01-06 09:44:14",
- 1.195
- ],
- [
- "2024-01-06 09:45:14",
- 1.128
- ],
- [
- "2024-01-06 09:46:14",
- 1.294
- ],
- [
- "2024-01-06 09:47:14",
- 1.698
- ],
- [
- "2024-01-06 09:48:14",
- 1.136
- ],
- [
- "2024-01-06 09:49:14",
- 1.554
- ],
- [
- "2024-01-06 09:50:14",
- 1.721
- ],
- [
- "2024-01-06 09:51:14",
- 1.941
- ],
- [
- "2024-01-06 09:52:14",
- 1.594
- ],
- [
- "2024-01-06 09:53:14",
- 1.955
- ]
- ]
- }
- export { getCpuResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/detail/module/memoryMock.js b/src/views/rangeNodeManage/detail/detail/module/memoryMock.js
deleted file mode 100644
index 4197939..0000000
--- a/src/views/rangeNodeManage/detail/detail/module/memoryMock.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const getMemoryResponse = {
- "code": 200,
- "message": "success",
- "result": [
- [
- "2024-01-07 01:08:27",
- 42.371
- ],
- [
- "2024-01-07 01:09:27",
- 42.371
- ],
- [
- "2024-01-07 01:10:27",
- 42.371
- ],
- [
- "2024-01-07 01:11:27",
- 42.371
- ],
- [
- "2024-01-07 01:12:27",
- 42.371
- ],
- [
- "2024-01-07 01:13:27",
- 42.371
- ],
- [
- "2024-01-07 01:14:27",
- 42.371
- ],
- [
- "2024-01-07 01:15:27",
- 42.383
- ],
- [
- "2024-01-07 01:16:27",
- 42.383
- ],
- [
- "2024-01-07 01:17:27",
- 42.383
- ],
- [
- "2024-01-07 01:18:27",
- 42.383
- ],
- [
- "2024-01-07 01:19:27",
- 42.383
- ],
- [
- "2024-01-07 01:20:27",
- 42.383
- ],
- [
- "2024-01-07 01:21:27",
- 42.383
- ],
- [
- "2024-01-07 01:22:27",
- 42.383
- ],
- [
- "2024-01-07 01:23:27",
- 42.383
- ],
- [
- "2024-01-07 01:24:27",
- 42.383
- ],
- [
- "2024-01-07 01:25:27",
- 42.395
- ],
- [
- "2024-01-07 01:26:27",
- 42.402
- ],
- [
- "2024-01-07 01:27:27",
- 42.41
- ],
- [
- "2024-01-07 01:28:27",
- 42.422
- ]
- ]
- }
- export { getMemoryResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/file/index.vue b/src/views/rangeNodeManage/detail/file/index.vue
deleted file mode 100644
index d94fffc..0000000
--- a/src/views/rangeNodeManage/detail/file/index.vue
+++ /dev/null
@@ -1,304 +0,0 @@
-<template>
-<div class="range-config-manage" ref="appRef">
- <Header
- :down-loading="downLoading"
- :start-loading="startLoading"
- :stop-loading="stopLoading"
- @download="download"
- @start="start"
- @end="end"
- ></Header>
- <div class="list" >
- <el-table
- class="custom-table"
- ref="multipleTable"
- v-loading="loading"
- height="100%"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionChange"
- >
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="bucket_name"
- label="桶名称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="file_name"
- label="文件名"
- min-width="250"/>
- <el-table-column
- align="center"
- prop="size"
- label="文件大小"
- min-width="80"/>
- <el-table-column
- align="center"
- prop="last_modified"
- label="更新时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.last_modified | formatTime }}
- </template>
- </el-table-column>
- </el-table>
- </div>
- <!-- <el-pagination
- background
- :current-page="page"
- :page-sizes="[10, 20, 30, 40]"
- :page-size="10"
- :total="total"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- >
- </el-pagination> -->
-</div>
-</template>
-<script>
-import Header from './module/Header.vue'
-import { getTargetsResponse } from './mock.js'
-export default {
- name: "File",
- components:{ Header},
- data(){
- return{
- target_id: '',
- nodeId: '',
- tableData: [],
- selectFileNameList: [],
- selectTableData: [],
- loading: false,
- downLoading: false,
- startLoading: false,
- stopLoading: false
- }
- },
- mounted() {
-
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- this.init()
- },
- immediate: true
- },
- '$store.state.node.startTraffic': {
- handler(newVal, oldVal) {
- this.startLoading = newVal
- },
- immediate: true
- },
- '$store.state.node.endTraffic': {
- handler(newVal, oldVal) {
- this.stopLoading = newVal
- },
- immediate: true
- }
- },
- created() {
- },
- methods:{
- init() {
- // this.tableData = getTargetsResponse?.result
- const reqParams = { node_id: this.nodeId }
- this.loading = true
- this.$axios.get(this.$http.api.getNodeFile, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.tableData = res?.result
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- // 当选择其它角色时,弹窗填写角色窗
- openRoleForm() {
- this.$refs.roleForm.visible = true
- },
- // 下载
- download() {
- if (this.selectFileNameList.length <= 0) {
- this.$notify({
- title: '请勾选要下载的文件',
- type: 'warning',
- duration: 2500
- })
- return
- }
- const reqParams = {
- node_id: this.nodeId,
- object_file_name_list: JSON.stringify(this.selectFileNameList)
- }
- this.downLoading = true
- this.$axios.getFile(this.$http.api.downloadNodeFile, reqParams).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载文件成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载文件失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.downLoading = false
- })
- },
- // 开始
- start() {
- const reqParams = {
- node_id: this.nodeId,
- command: 'start'
- }
- // this.startLoading = true
- this.$store.commit('node/setStartTraffic', true)
- this.$axios.get(this.$http.api.flowStartStop, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '开始统计流量',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- this.$store.commit('node/setStartTraffic', false)
- }).finally(() => {
- // this.startLoading = false
- })
- },
- // 结束
- end() {
- const reqParams = {
- node_id: this.nodeId,
- command: 'stop'
- }
- // this.stopLoading = true
- this.$store.commit('node/setEndTraffic', true)
- this.$axios.get(this.$http.api.flowStartStop, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$store.commit('node/setStartTraffic', false)
- this.$notify({
- title: '结束统计流量',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- setTimeout(() => {
- // this.stopLoading = false
- this.$store.commit('node/setEndTraffic', false)
- this.init()
- }, 5 * 1000);
- })
- },
- // 处理选中的数据
- handleSelectionChange(selectData) {
- this.selectTableData = selectData
- this.selectFileNameList = selectData.map(item => {
- return item.file_name
- })
- },
- // // 修改每页数据条数
- // handleSizeChange(val) {
- // console.log(`每页 ${val} 条`)
- // this.page=1
- // this.size=val
- // this.query()
- // },
- // // 修改页数
- // handleCurrentChange(val) {
- // console.log(`当前页: ${val}`)
- // this.page=val
- // this.query()
- // }
- }
-}
-
-</script>
-
-<style lang='less' scoped="scoped">
-.el-pagination {
- padding: 15px 55px 0 0 !important;
-}
-.custom-table {
- width: 100%;
- height: 100%;
-}
-.range-config-manage{
- width: 100%;
- height: 100%;
- // display: flex;
- // flex-direction: column;
- // justify-content: flex-start;
- .list{
- width: 100%;
- height: 87%;
- background-color: rgba(25, 33, 61, 0.4);
- border: 1px solid rgba(186, 208, 241, 0.1);
- border-radius: 8px;
- // margin-left: 2.5%;
- // overflow-y: auto;
- // overflow-y: scroll;
- // overflow-x: hidden;
- // border: none;
- }
- .list::-webkit-scrollbar {
- width: 0px; /* 隐藏滚动条 */
- height: 0px;
- background-color: transparent; /* 让背景透明 */
-
- }
- /* 隐藏火狐浏览器滚动条 */
- @-moz-document url-prefix() {
- .trackSource {
- scrollbar-width: none;
- }
- }
- // 遮罩层
- .mask{
- position: fixed; /*将元素设置为固定定位*/
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: rgba(0,0,0,0.5); /*通过rgba函数来控制遮罩层的透明度*/
- display: none; /*将元素隐藏*/
- }
- }
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/file/mock.js b/src/views/rangeNodeManage/detail/file/mock.js
deleted file mode 100644
index c51e523..0000000
--- a/src/views/rangeNodeManage/detail/file/mock.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const getTargetsResponse = {
- "code": 200,
- "message": "success",
- "result": [
- {
- "bucket_name": "target-1-da-15",
- "file_name": "target_1_da_15_2023_07_31_23_58_04.pcap",
- "last_modified": "2023-07-31T15:58:40.158000+00:00",
- "size": "3.80KiB"
- },
- {
- "bucket_name": "target-1-da-15",
- "file_name": "target_1_da_15_2023_08_01_00_04_07.pcap",
- "last_modified": "2023-07-31T16:07:09.377000+00:00",
- "size": "21.7KiB"
- },
- {
- "bucket_name": "target-1-da-15",
- "file_name": "target_1_da_15_2023_08_01_00_13_41.pcap",
- "last_modified": "2023-07-31T16:16:08.605000+00:00",
- "size": "20.6KiB"
- }
- ]
-}
-
-export { getTargetsResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/file/module/Header.vue b/src/views/rangeNodeManage/detail/file/module/Header.vue
deleted file mode 100644
index 6dc6599..0000000
--- a/src/views/rangeNodeManage/detail/file/module/Header.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<template>
-<div class="head">
- <span class="title">节点流量采集文件</span>
- <el-button :loading="downLoading" type="primary" @click="download">下载</el-button>
- <el-button :loading="startLoading" type="primary" @click="start">开始</el-button>
- <el-button :loading="stopLoading" type="primary" @click="end">结束</el-button>
-</div>
-</template>
-
-<script>
-export default {
- name: 'Header',
- props: ['startLoading', 'stopLoading', 'downLoading'],
- data() {
- return {
- role: '',
- has_deployed: ''
- }
- },
- methods: {
- // 下载
- download() {
- this.$emit('download')
- },
- // 开始
- start() {
- this.$emit('start')
- },
- // 结束
- end() {
- this.$emit('end')
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.head{
- width: 100%;
- height: 12%;
- margin-top: 1%;
- text-align: right;
-
- /*background-color: #5daf34;*/
- .block{
- display: inline-block;
- margin-left: 2%;
-
- }
- .input{
- display: inline-block;
- height: 60%;
- width: 10%;
- margin-left: 0.5%;
- .el-input::placeholder {
- width: auto;
- }
- .icon-group {
- display: flex; /* 设置容器为 Flexbox 容器 */
- align-items: center; /* 垂直居中图片 */
- gap: 5px; /* 图片和文字之间的间距,可以根据需要进行调整 */
-
- }
- .icon-group img {
- transform: scale(1);
- margin-right: 15px;
- margin-top: 6px;
- }
- }
- .title {
- margin-right: 60%;
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/index.vue b/src/views/rangeNodeManage/detail/index.vue
deleted file mode 100644
index 3435d74..0000000
--- a/src/views/rangeNodeManage/detail/index.vue
+++ /dev/null
@@ -1,80 +0,0 @@
-<template>
- <div class="container">
- <div class="card-detail">
- <Detail></Detail>
- </div>
- <div class="card-file">
- <File></File>
- </div>
- <div class="card">
- <Log></Log>
- </div>
- <div class="card">
- <Console></Console>
- </div>
- </div>
-</template>
-
-<script>
-import Detail from './detail/index.vue'
-import File from './file/index.vue'
-import Log from './log/index.vue'
-import Console from './console/index.vue'
-import { getTargetsResponse } from './mock.js'
-export default {
- name: "NodeDetail",
- components: { Detail, File, Log, Console},
- data(){
- return{
- nodeId: '',
- nodeDetail: {}
- }
- },
- mounted() {
- },
- // watch: {
- // '$store.state.range.nodeId': {
- // handler(newVal, oldVal) {
- // this.nodeId = newVal
- // this.init()
- // },
- // immediate: true
- // }
- // },
- created() {
- },
- methods:{
- // init() {}
- }
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.container{
- width: 100%;
- height: 100%;
- display: flex;
- flex-wrap: wrap;
- flex-direction: row;
- justify-content: space-around;
- align-content: space-around;
- background-image:url('../../../img/background/backgroundFourCorner.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% auto; /* 宽度为100%,高度自适应保持宽高比 */
- .card{
- width: 48%;
- height: 46%;
- background-image:url('../../../img/backgroundFourCorner.png');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- }
- .card-detail{
- width: 48%;
- height: 46%;
- }
- .card-file{
- width: 48%;
- height: 46%;
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/log/index.vue b/src/views/rangeNodeManage/detail/log/index.vue
deleted file mode 100644
index b7a0638..0000000
--- a/src/views/rangeNodeManage/detail/log/index.vue
+++ /dev/null
@@ -1,227 +0,0 @@
-<template>
- <div :class="['range-config-manage', {'is--maximize': isFullscreen}]" ref="appRef">
- <Header
- :is-fullscreen="isFullscreen"
- :fullscreen-icon="fullscreenIcon"
- :down-loading="downLoading"
- :close-icon="closeIcon"
- @query="query"
- @download="download"
- @zoomEvent="zoomEvent"
- ></Header>
- <div class="list">
- <el-table
- class="custom-table"
- ref="multipleTable"
- v-loading="loading"
- height="100%"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- >
- <el-table-column
- align="center"
- prop="id"
- label="id"
- min-width="50"/>
- <el-table-column
- align="left"
- prop="content"
- label="日志内容"
- min-width="500"
- show-overflow-tooltip/>
- </el-table>
- </div>
- </div>
-</template>
-<script>
-import Header from './module/Header.vue'
-import { getTargetsResponse } from './mock.js'
-export default {
- name: "File",
- components:{ Header},
- data(){
- return{
- fullscreenIcon: 'fullscreen',
- isFullscreen: false,
- target_id: '',
- nodeId: '',
- downLoading: false,
- tableData: [],
- inverterMonTimer: null,
- loading: false,
- closeIcon: false
- }
- },
- mounted() {
- this.closeIcon = this.$route.params.closeIcon
- },
- watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- this.init()
- },
- immediate: true
- }
- },
- created() {
- this.inverterMonTimer = setInterval(() => {
- this.init()
- }, 5 * 1000)
- },
- beforeDestroy() {
- if (this.inverterMonTimer) {
- clearInterval(this.inverterMonTimer);
- this.inverterMonTimer = null;
- }
- },
-
- methods:{
- zoomEvent() {
- this.isFullscreen = !this.isFullscreen
- this.fullscreenIcon = this.isFullscreen ? 'narrow' : 'fullscreen'
- },
- init(params={}) {
- // const responseData = getTargetsResponse?.result
- // this.tableData = responseData.map((item, index) => {
- // return {
- // id: index,
- // content: item
- // }
- // })
- // TODO: 暂时注释接口
- const reqParams = {
- node_id: this.nodeId,
- ...params
- }
- this.loading = true
- this.$axios.get(this.$http.api.getLog, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const responseData = res?.result
- this.tableData = responseData.map((item, index) => {
- return {
- id: index,
- content: item
- }
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- query(params) {
- // 清除日志轮询器
- if (this.inverterMonTimer) {
- clearInterval(this.inverterMonTimer);
- this.inverterMonTimer = null;
- }
- // 立即查询一次
- this.init(params)
- // 开启新的日志轮询器
- this.inverterMonTimer = setInterval(() => {
- this.init(params)
- }, 5 * 1000)
- },
- // 下载
- download() {
- this.downLoading = true
- const reqParams = { node_id: this.nodeId }
- this.$axios.getFile(this.$http.api.downloadLog, reqParams).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载日志成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载日志失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.downLoading = false
- })
- },
- // // 修改每页数据条数
- // handleSizeChange(val) {
- // console.log(`每页 ${val} 条`)
- // this.page=1
- // this.size=val
- // this.query()
- // },
- // // 修改页数
- // handleCurrentChange(val) {
- // console.log(`当前页: ${val}`)
- // this.page=val
- // this.query()
- // }
- }
-}
-
-</script>
-
-<style lang='less' scoped="scoped">
-.is--maximize {
- position: fixed;
- top: 9%;
- left: 10%;
- width: 90% !important;
- height: 91% !important;
- padding: 0.5em 1em;
- // background-color: #17234e;
- background: url(../../../../img/background/bgMain.svg);
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-position: center; /* 居中显示 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- z-index: 1000;
-}
-.el-pagination {
- padding: 15px 55px 0 0 !important;
-}
-.custom-table {
- width: 100%;
- height: 100%;
- border-radius: 0px;
- background-color: transparent !important;
-}
-.range-config-manage{
- width: 100%;
- height: 100%;
- .list{
- width: 100%;
- height: calc(100% - 85px);
- }
- // 遮罩层
- .mask{
- position: fixed; /*将元素设置为固定定位*/
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: rgba(0,0,0,0.5); /*通过rgba函数来控制遮罩层的透明度*/
- display: none; /*将元素隐藏*/
- }
- }
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/log/mock.js b/src/views/rangeNodeManage/detail/log/mock.js
deleted file mode 100644
index 40b73cf..0000000
--- a/src/views/rangeNodeManage/detail/log/mock.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const getTargetsResponse ={
- "code": 200,
- "message": "success",
- "result": [
- "Jan 02 18:36:44.000 [notice] Tor 0.4.8.10 opening new log file.\n",
- "Jan 02 18:36:44.000 [info] Tor 0.4.8.10 opening new log file.\n",
- "Jan 02 18:36:44.000 [warn] Tor 0.4.8.10 opening new log file.\n",
- "Jan 02 18:36:44.000 [warn] Tor 0.4.8.10 opening new log file.\n",
- ]
- }
-
-export { getTargetsResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/log/module/Header.vue b/src/views/rangeNodeManage/detail/log/module/Header.vue
deleted file mode 100644
index bee079f..0000000
--- a/src/views/rangeNodeManage/detail/log/module/Header.vue
+++ /dev/null
@@ -1,122 +0,0 @@
-<template>
-<div class="head">
- <span class="title">日志流展示</span>
- <div class="role-select">
- <el-select v-model="level" clearable placeholder="全部" @change="query">
- <el-option
- v-for="item in levelDict"
- :key="item.value"
- :label="item.label"
- :value="item.value">
- </el-option>
- </el-select>
- </div>
- <el-button :loading="downLoading" class="role-select" type="primary" @click="download">下载</el-button>
- <span class="icon-span" slot="label">
- <i v-if="closeIcon" class="el-icon-close icon-zoom" @click="backNodeList"></i>
- <svg-icon v-else class="icon-zoom" :icon-class="fullscreenIcon" @click="zoomEvent"></svg-icon>
- </span>
-</div>
-</template>
-
-<script>
-export default {
- name: 'Header',
- props: {
- isFullscreen: {
- typeof: Boolean
- },
- fullscreenIcon: {
- typeof: String
- },
- downLoading: {
- typeof: Boolean
- },
- closeIcon: {
- typeof:Boolean
- }
- },
- data() {
- return {
- level: '',
- levelDict:[
- {label: 'info', value: 'info'},
- {label: 'notice', value: 'notice'},
- {label: 'warn', value: 'warn'}
- ],
- }
- },
- methods: {
- zoomEvent() {
- this.$emit('zoomEvent')
- // this.fullscreenIcon = this.isFullscreen ? 'el-icon-full-screen' : 'el-icon-rank'
- },
- // 查询
- query() {
- let params = {}
- if (this.level) {
- params.level = this.level
- }
- this.$emit('query', params)
- },
- // 下载
- download() {
- this.$emit('download')
- },
- backNodeList() {
- this.$router.push({ name: 'rangeNodeManage' })
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.head{
- width: 100%;
- height: 50px;
- margin-top: 20px;
- text-align: right;
-
- /*background-color: #5daf34;*/
- .block{
- display: inline-block;
- margin-left: 2%;
-
- }
- .input{
- display: inline-block;
- height: 60%;
- width: 10%;
- margin-left: 0.5%;
- .el-input::placeholder {
- width: auto;
- }
- .icon-group {
- display: flex; /* 设置容器为 Flexbox 容器 */
- align-items: center; /* 垂直居中图片 */
- gap: 5px; /* 图片和文字之间的间距,可以根据需要进行调整 */
-
- }
- .icon-group img {
- transform: scale(1);
- margin-right: 15px;
- margin-top: 6px;
- }
- }
- .title {
- margin-right: 45%;
- }
- ::v-deep .role-select{
- display: inline-block;
- margin-right: 15px;
- }
- .icon-span {
- padding: 12px 20px;
- .icon-zoom {
- font-size: 30px;
- color: #02DDEA;
- margin: 0 15px;
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/detail/mock.js b/src/views/rangeNodeManage/detail/mock.js
deleted file mode 100644
index 0566abd..0000000
--- a/src/views/rangeNodeManage/detail/mock.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const getTargetsResponse = {
- "code": 200,
- "message": "success",
- "result": {
- "setting_id": 70,
- "traffic_collect_task_id": null,
- "id": 90,
- "ip": "148.113.2.0",
- "pod_name": "target-11-relay-90-568f44566f-rvbl8",
- "nick_name": "relaykmuhkwkdjy",
- "status": "complete",
- "onion": null,
- "create_time": "2024-01-02T18:36:37",
- "complete_time": "2024-01-02T18:48:20",
- "role": null,
- "owner_setting": {
- "role": "relay",
- "image_id": 34,
- "replicas": "1",
- "bandwidth": 10,
- "memory": 100,
- "service": null,
- "tor_version": "4.8.9",
- "create_time": null,
- "update_time": null,
- "out_port": null,
- "socks_port": 19001,
- "control_port": 19002,
- "or_port": 7000,
- "dir_port": 9030,
- "use_network": {
- "cidr": "148.113.2.0/24"
- }
- }
- }
-}
-
-export { getTargetsResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/index.vue b/src/views/rangeNodeManage/index.vue
deleted file mode 100644
index 27f2086..0000000
--- a/src/views/rangeNodeManage/index.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<template>
- <div class="range-node-manage">
- <div class="container">
- <div class="header">
- <el-select class="range-select" v-model="target_id" placeholder="全部靶场" @change="changeRange">
- <el-option
- v-for="item in rangeDict"
- :key="item.value"
- :label="item.label"
- :value="item.value">
- </el-option>
- </el-select>
- </div>
- <div class="map-container">
- <WorldMap></WorldMap>
- <TopologyMap></TopologyMap>
- </div>
- <div class="list-container">
- <NodeList></NodeList>
- </div>
- </div>
- </div>
-</template>
-
-<script>
-import WorldMap from './worldMap'
-import TopologyMap from './topologyMap'
-import NodeList from './nodeList'
-export default {
- name: 'rangeNodeManage',
- components: {
- NodeList,
- WorldMap,
- TopologyMap
- },
- data() {
- return {
- target_id: '',
- rangeDict: []
- }
- },
- watch: {
- '$store.state.range.targetId': {
- handler(newVal, oldVal) {
- this.target_id = newVal
- },
- immediate: true
- }
- },
- created() {
- this.getRangeDict()
- },
- methods: {
- // 改变靶场
- changeRange() {
- this.$store.commit('range/setTargetId', this.target_id)
- },
- // 获取靶场列表字典
- getRangeDict() {
- const reqParams = {
- page: 1,
- size: 99,
- }
- this.$axios.get(this.$http.api.getTargets, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.rangeDict = res?.result?.items.map(item => {
- return {
- label: item.target_name,
- value: item.id
- }
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.rangeDict.unshift({label: '全部靶场', value: ''})
- })
- },
- }
-
-}
-</script>
-
-<style lang='less' scoped>
-.range-node-manage {
- width: 100%;
- height: 100%;
- position: relative;
- .container {
- width: 95%;
- height: 95%;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../img/backgroundFourCorner.png');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- padding: 1.5%;
- }
-}
-.header {
- height: 7%;
- width: 100%;
- text-align: left;
- .range-select {
- // position: absolute;
- // top: 12px;
- // right: 140px;
- ::v-deep .el-input {
- width: 60%;
- .el-input__inner {
- background-color: transparent !important;
- border-color: transparent;
- border-radius: 0;
- color: #FFFFFF;
- }
- /* select去除竖线 */
- .el-input__suffix::before {
- content: "";
- width: 0;
- height: 0;
- margin: 0;
- position: absolute;
- }
- /*select的上下箭头图标样式*/
- .el-select__caret {
- color: rgba(2, 221, 234, 0.9);
- }
- }
-}
-}
-.map-container{
- height: 43%;
- width: 100%;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-
-}
-.list-container{
- height: 50%;
- width: 100%;
-}
-
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/components/DirNameForm.vue b/src/views/rangeNodeManage/nodeList/components/DirNameForm.vue
deleted file mode 100644
index 7939629..0000000
--- a/src/views/rangeNodeManage/nodeList/components/DirNameForm.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-<template>
-<div class="role-dialog" v-if="visible">
- <i class="el-icon-close" style="float: right; padding-right: 7%;padding-top: 2.8%" @click="close"></i>
- <div class="fbs">
- <span style="margin-right: 3%">文件名</span>
- <el-input
- size="mini"
- :value="value"
- placeholder="请输入内容"
- style="width: 50%"
- v-bind="$attrs"
- v-on="$listeners">
- </el-input>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="submit">确认</el-button>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-export default {
- name: 'RoleForm',
- props: {
- value: {
- typeof: String,
- require: true,
- default: ''
- }
- },
- data() {
- return {
- visible: false
- }
- },
- watch: {
- value: {
- handler(val) {
- this.$emit('input', val)
- }
- }
- },
- methods: {
- close() {
- // document.querySelector('.mask').style.display = 'none'
- this.visible = false
- },
- submit() {
- // document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.$emit('makeDirSubmit')
- }
- }
-
-}
-</script>
-
-<style lang="less" scoped>
-.role-dialog{
- z-index: 998;
- width: 300px;
- height: 120px;
- position: absolute; /* 绝对定位 */
- top: 100px; /* 向下偏移50% */
- left: 150px; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../img/jbpzxybqr.png');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- .fbs{
- width: 100%;
- float: left;
- margin-top: 3%;
- text-align: center;
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-top: 5%;
- text-align: center;
- .glBut{
- width: 50px;
- height: 18px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/components/DownloadFileManager.vue b/src/views/rangeNodeManage/nodeList/components/DownloadFileManager.vue
deleted file mode 100644
index 9c77da3..0000000
--- a/src/views/rangeNodeManage/nodeList/components/DownloadFileManager.vue
+++ /dev/null
@@ -1,536 +0,0 @@
-<template>
-<div class="content">
- <el-tree
- ref="tree"
- class="tree-section"
- lazy
- node-key="id"
- :data="treeData"
- :props="defaultProps"
- :load="loadNode"
- @node-click="handleNodeClick"
- v-dragresize="dragConfig"
- >
- </el-tree>
- <div class="tree-content">
- <div style="text-align:left; width: 100%; padding: 10px;border: 1px solid #BAD0F11A;">
- <span>
- {{ dirTitle }}
- </span>
- </div>
- <div style="clear:both;text-align:left; padding: 10px;border-bottom: 1px solid #BAD0F11A;">
- <img src="../../../../img/icon/file-icon.svg" alt="" style="width: 18px; height: 18px;">
- {{ currentFileName }}
- </div>
- <ul style="clear:both;" class="tree-content-ul">
- <li v-for="fileItem in fileList" :key="fileItem.name">
- <el-radio v-model="filename" :label="fileItem.name" class="file-info">{{ '' }}</el-radio>
- <span class="file-info">{{ fileItem.name }}</span>
- <i class="el-icon-document file-info" style="font-size: 20px"></i>
- <span class="file-info">{{ fileItem.size }}</span>
- <span class="file-info">{{ fileItem.time }}</span>
- </li>
- </ul>
- <div class="empty-box"></div>
- </div>
- <!-- <ul
- v-show="visible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li>
- <li @click="download">下载</li>
- <li @click="del">删除</li>
- </ul> -->
- <!-- <ul
- v-show="uploadVisible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li>
- </ul> -->
- <!-- <div v-show="showTreeMenu" class="treeMenu">
- <div @click="makeDir">新建文件夹</div>
- <div @click="delDir">删除文件夹</div>
- </div> -->
- <DirNameForm
- ref="dirNameForm"
- v-model="dirName"
- @makeDirSubmit="makeDirSubmit">
- </DirNameForm>
-</div>
-</template>
-
-<script>
-import DirNameForm from './DirNameForm.vue'
-export default {
-components: { DirNameForm },
-props: ['isFullscreen'],
-data() {
- return{
- visible: false,
- uploadVisible: false,
- top: 0,
- left: 0,
- nodeId: '',
- dirTitle: '>',
- currentFileName: '',
- fileList: [],
- selectFile: {},
- selectNode: {path: '/'},
- rightClickNode: {},
- defaultProps: {
- children: 'children',
- label: 'name',
- },
- showTreeMenu: false, // 文件夹数据
- contextNode: {}, // 文件夹数据
- dirName: '', // 新建文件名
- treeData: [],
- filename: ''
- }
-},
-computed: {
- dragConfig() {
- return [
- {
- dragBorder: "right",
- setCssProperty: "width",
- },
- ];
- },
-},
-watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- // this.getCurrentDirFile('/')
- },
- immediate: true
- },
- visible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeMenu)
- } else {
- document.body.removeEventListener('click', this.closeMenu)
- }
- },
- uploadVisible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeUploadMenu)
- } else {
- document.body.removeEventListener('click', this.closeUploadMenu)
- }
- },
-},
-methods: {
- // upload(e) {
- // this.$emit('selectUploadFile', {path: this.selectNode.path, file: e.target.files[0]})
- // const params = {
- // node_id : this.nodeId,
- // current_dir: this.selectNode.path,
- // file: e.target.files[0]
- // }
- // const submitForm = new FormData()
- // for(const key in params) {
- // submitForm.append(key, params[key])
- // }
- // this.$axios.postFormData(this.$http.api.uploadFile, submitForm).then(res => {
- // if (res.code == 200 || res.code == "OK") {
- // this.$notify({
- // title: '上传文件成功',
- // type: 'success',
- // duration: 2500
- // })
- // // 更新当前路径下的文件信息
- // this.handleNodeClick(this.selectNode)
- // this.setCurrentHighlight(this.selectNode.$treeNodeId);
- // }
- // }).catch(err => {
- // console.log(err)
- // })
- // },
- // download() {
- // // this.downLoading = true
- // const reqParams = {
- // master_node_id : this.nodeId,
- // current_dir: this.selectNode.path,
- // filename: this.selectFile.name
- // }
- // this.$axios.getFile(this.$http.api.batchDownload, reqParams).then(res => {
- // if (res.status == 200 || res.statusText == "OK") {
- // const { data, headers } = res
- // const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- // //const blob = new Blob([JSON.stringify(data)], ...)
- // const blob = new Blob([data], {type: headers['content-type']})
- // let dom = document.createElement('a')
- // let url = window.URL.createObjectURL(blob)
- // dom.href = url
- // dom.download = decodeURI(fileName)
- // dom.style.display = 'none'
- // document.body.appendChild(dom)
- // dom.click()
- // dom.parentNode.removeChild(dom)
- // window.URL.revokeObjectURL(url)
- // this.$notify({
- // title: '下载文件成功',
- // type: 'success',
- // duration: 2500
- // })
- // } else {
- // this.$notify({
- // title: '下载文件失败',
- // type: 'success',
- // duration: 2500
- // })
- // }
- // }).catch(err => {
- // console.log(err)
- // }).finally(() => {
- // // this.downLoading = false
- // })
- // },
- del() {
- const params = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- filename: this.selectFile.name
- }
- this.$axios.delete(this.$http.api.delFile, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 更新当前路径下的文件信息
- this.handleNodeClick(this.selectNode)
- // console.log('选中了节点id===', this.selectNode.$treeNodeId)
- this.setCurrentHighlight(this.selectNode.$treeNodeId);
- // this.init()
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 设置当前选中高亮
- setCurrentHighlight (id) {
- this.$nextTick(() => {
- this.$refs.tree.setCurrentKey(id)
- })
- },
- openMenu(fileItem, e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 180 // fix 位置bug
- } else {
- this.top = e.clientY - 160 // fix 位置bug
- }
- this.uploadVisible = false
- this.visible = true
- this.selectFile = fileItem
- },
- closeMenu() {
- this.visible = false
- },
- openUploadMenu(e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 120 // fix 位置bug
- } else {
- this.top = e.clientY - 160 // fix 位置bug
- }
- this.visible = false
- this.uploadVisible = true
- },
- closeUploadMenu() {
- this.uploadVisible = false
- },
- // 获取当前路径下文件
- getCurrentDirFile(currentDir) {
- const reqParams = { node_id: this.nodeId, current_dir: currentDir }
- return this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const dirs = res?.result?.object?.dir || []
- this.fileList = res?.result?.object?.file || []
- // console.log('请求回来files===', files)
- const nodeData = dirs.map(dir => {
- return {
- name: dir.name,
- path: currentDir === '/' ? currentDir + dir.name : `${currentDir}/${dir.name}`,
- fileList: []
- }
- })
- // console.log('请求回来nodeData====', nodeData)
- return nodeData
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 点击加载子节点
- async loadNode(node, reslove) {
- // console.log('执行了loadNode', node)
- if (node.level == 0) {
- let nodeData = await this.getCurrentDirFile('/')
- // console.log('初始化数据===', nodeData)
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- } else {
- let nodeData = await this.getCurrentDirFile(node.data.path)
- // 判断是否为最底层节点 根据自己接口返回的数据判断即可
- nodeData.forEach(item => {
- item.hasChildren == false ? item.lastNode = ture : null
- });
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- }
- },
- handleNodeClick(node) {
- // this.fileList = []
- // console.log('选中了节点===', node)
- // console.log('选中了节点id===', node.$treeNodeId)
- this.selectNode = node
- this.dirTitle = node.path.split('/').join('>')
- this.currentFileName = node.name
- // this.fileList = node.fileList
- const reqParams = { node_id: this.nodeId, current_dir: node.path }
- this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.fileList = res?.result?.object?.file || []
- }
- }).catch(err => {
- console.log(err)
- })
- },
- openTreeMenu(event, data, node, target) {
- // console.log(event, data, node, target)
- this.showTreeMenu = true // 显示菜单
- this.contextNode = data // 存储数据
- // console.log(this.contextNode, 'contextNode')
- // console.log(node, 'rightClickNode=======')
- // console.log(target, 'target')
- this.rightClickNode = node
- document.querySelector('.treeMenu').setAttribute('style',`top:${event.clientY + 30}px;left:${event.clientX + 30}px;`)
- document.addEventListener('click', this.closeTreeMenu)
- document.addEventListener('contextmenu', this.closeTreeMenu)
- },
- closeTreeMenu() {
- this.showTreeMenu = false // 关闭菜单
- document.removeEventListener('click', this.closeTreeMenu)
- document.removeEventListener('contextmenu', this.closeTreeMenu)
- },
- // 当新建文件夹时,先填写名字
- openDirNameForm() {
- this.$refs.dirNameForm.visible = true
- },
- // 新建文件夹
- makeDir() {
- this.openDirNameForm()
- },
- // 新建文件夹接口提交
- makeDirSubmit() {
- const reqParams = { node_id: this.nodeId, current_dir: this.contextNode.path, new_dir_name: this.dirName }
- this.$axios.get(this.$http.api.makeDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '新建文件夹成功',
- type: 'success',
- duration: 2500
- })
- // 页面增加子节点
- let id = Math.ceil(Math.random() * 1000000)
- var addNode = {
- path: this.contextNode.path + '/' + this.dirName,
- name: this.dirName,
- fileList: []
- // id: id,
- // name: this.dirName,
- // data: {
- // path: this.contextNode.path,
- // name: this.dirName,
- // fileList: []
- // }
- }
- // console.log(addNode, 'addNode======')
- this.$refs.tree.append(addNode, this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 删除文件夹
- delDir() {
- const index = this.contextNode.path.lastIndexOf('/')
- const path = this.contextNode.path.substring(0, index);
- const params = {
- node_id : this.nodeId,
- current_dir: path,
- dir_name: this.contextNode.name
- }
- this.$axios.delete(this.$http.api.delDir, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 页面删除子节点
- this.$refs.tree.remove(this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- }
-}
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.content {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- color: #ffffff;
- .tree-section {
- width: 25%;
- height: 100%;
- // background-color: #1A2648;
- background: transparent;
- border: 1px solid #BAD0F11A;
- color: #06F7FF;
- overflow-y: auto;
- ::v-deep .el-tree-node__content:hover {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- ::v-deep .el-tree-node.is-current > .el-tree-node__content {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- }
- .tree-content {
- width: 75%;
- height: 100%;
- display: flex;
- flex-direction: column;
- .tree-content-ul {
- width: 100%;
- background-color: rgba(25, 33, 61, 0.4);
- overflow-y: auto;
- li {
- display: flex;
- flex-direction: row;
- justify-content: space-around;
- border-bottom: 1px solid #BAD0F11A;
- padding: 5px;
- .file-info {
- flex: 1 1 100px;
- }
- }
- }
- .empty-box {
- flex: 1;
- }
- }
-}
-.contextmenu {
- margin: 0;
- border-radius: 6px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- background: #0E3D8A;
- z-index: 3000;
- position: absolute;
- list-style-type: none;
- padding: 5px 0;
- font-size: 12px;
- font-weight: 400;
- color: #06F7FF;
- // box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- li {
- margin: 0;
- padding: 7px 30px;
- cursor: pointer;
- &:hover {
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- }
- }
- .file-input {
- display: none;
- }
- }
-
-.treeMenu {
- position: fixed;
- z-index: 99999;
- top: 50%;
- left: 50%;
- color: #06F7FF;
- background-color: #0E3D8A;
- overflow: hidden;
- border-radius: 5px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- div{
- padding: 7px 30px;
- box-sizing: border-box;
- //width: 50px;
- text-align: center;
- }
- div:hover{
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- cursor: pointer;
- }
-}
-</style>
diff --git a/src/views/rangeNodeManage/nodeList/components/MainNode.vue b/src/views/rangeNodeManage/nodeList/components/MainNode.vue
deleted file mode 100644
index 5219549..0000000
--- a/src/views/rangeNodeManage/nodeList/components/MainNode.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-<template>
-<el-table
- class="main-table styleTable"
- ref="mainTable"
- height="500px"
- style="width: 100%;"
- :data="nodeList"
- tooltip-effect="dark"
- highlight-current-row
->
- <el-table-column label="" width="80" align="center">
- <template slot-scope="scope">
- <el-radio v-model="master_node_id" :label="scope.row.id" @input="handleSelectionMain(scope.row)">{{ "" }}</el-radio>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <!-- <template slot-scope="scope">
- {{ scope.row.has_deployed ? '已部署' : '未部署' }}
- </template> -->
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatTime }}
- </template>
- </el-table-column>
-</el-table>
-</template>
-
-<script>
-export default {
- name: 'MainNode',
- props: {
- nodeList: {
- typeof: Array,
- require: true
- }
- },
- data() {
- return {
- master_node_id: ''
- }
- },
- methods: {
- // 选择主节点
- handleSelectionMain(row) {
- this.$emit('selectMainNode', row)
- },
- }
-}
-</script>
-
-<style lang="less" scoped>
-
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/components/OperateNode.vue b/src/views/rangeNodeManage/nodeList/components/OperateNode.vue
deleted file mode 100644
index 30e5881..0000000
--- a/src/views/rangeNodeManage/nodeList/components/OperateNode.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-<template>
-<el-table
- class="main-table styleTable"
- ref="operateTable"
- height="500px"
- style="width: 100%;"
- :data="nodeList"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionOperateNode"
->
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <!-- <template slot-scope="scope">
- {{ scope.row.has_deployed ? '已部署' : '未部署' }}
- </template> -->
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatTime }}
- </template>
- </el-table-column>
-</el-table>
-</template>
-
-<script>
-export default {
- name: 'OperateNode',
- props: {
- nodeList: {
- typeof: Array,
- require: true
- }
- },
- data() {
- return {
-
- }
- },
- methods: {
- // 选择被操作节点
- handleSelectionOperateNode(selectRows) {
- this.$emit('selectOperateNode', selectRows)
- },
- }
-}
-</script>
-
-<style lang="less" scoped>
-
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/components/UploadFileManager.vue b/src/views/rangeNodeManage/nodeList/components/UploadFileManager.vue
deleted file mode 100644
index d62dfdf..0000000
--- a/src/views/rangeNodeManage/nodeList/components/UploadFileManager.vue
+++ /dev/null
@@ -1,520 +0,0 @@
-<template>
-<div class="content">
- <el-tree
- ref="tree"
- class="tree-section"
- lazy
- node-key="id"
- :data="treeData"
- :props="defaultProps"
- :load="loadNode"
- @node-click="handleNodeClick"
- v-dragresize="dragConfig"
- >
- </el-tree>
- <div class="tree-content">
- <div style="text-align:left; width: 100%; padding: 10px;border: 1px solid #BAD0F11A;">
- <span>
- {{ dirTitle }}
- </span>
- </div>
- <div style="clear:both;text-align:left; padding: 10px;border-bottom: 1px solid #BAD0F11A;">
- <img src="../../../../img/icon/file-icon.svg" alt="" style="width: 18px; height: 18px;">
- {{ currentFileName }}
- </div>
- <ul style="clear:both;" class="tree-content-ul">
- <li v-for="fileItem in fileList" :key="fileItem.name">
- <i class="el-icon-document file-info" style="font-size: 20px"></i>
- <span class="file-info">{{ fileItem.name }}</span>
- <span class="file-info">{{ fileItem.size }}</span>
- <span class="file-info">{{ fileItem.time }}</span>
- </li>
- </ul>
- <!-- <div class="empty-box" @contextmenu.prevent="openUploadMenu($event)"></div> -->
- </div>
- <ul
- v-show="visible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <!-- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li> -->
- <!-- <li @click="download">下载</li>
- <li @click="del">删除</li> -->
- </ul>
- <!-- <ul
- v-show="uploadVisible"
- :style="{left:left+'px',top:top+'px'}"
- class="contextmenu"
- >
- <li>
- <label
- class="button"
- for="file-input"
- >
- <span>上传</span>
- <input
- type="file"
- class="file-input"
- id="file-input"
- @change="upload"
- />
- </label>
- </li>
- </ul> -->
- <!-- <div v-show="showTreeMenu" class="treeMenu">
- <div @click="makeDir">新建文件夹</div>
- <div @click="delDir">删除文件夹</div>
- </div> -->
- <DirNameForm
- ref="dirNameForm"
- v-model="dirName"
- @makeDirSubmit="makeDirSubmit">
- </DirNameForm>
-</div>
-</template>
-
-<script>
-import DirNameForm from './DirNameForm.vue'
-export default {
-components: { DirNameForm },
-props: ['isFullscreen'],
-data() {
- return{
- visible: false,
- uploadVisible: false,
- top: 0,
- left: 0,
- nodeId: '',
- dirTitle: '>',
- currentFileName: '',
- fileList: [],
- selectFile: {},
- selectNode: {path: '/'},
- rightClickNode: {},
- defaultProps: {
- children: 'children',
- label: 'name',
- },
- showTreeMenu: false, // 文件夹数据
- contextNode: {}, // 文件夹数据
- dirName: '', // 新建文件名
- treeData: []
- }
-},
-computed: {
- dragConfig() {
- return [
- {
- dragBorder: "right",
- setCssProperty: "width",
- },
- ];
- },
-},
-watch: {
- '$store.state.range.nodeId': {
- handler(newVal, oldVal) {
- this.nodeId = newVal
- // this.getCurrentDirFile('/')
- },
- immediate: true
- },
- visible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeMenu)
- } else {
- document.body.removeEventListener('click', this.closeMenu)
- }
- },
- uploadVisible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeUploadMenu)
- } else {
- document.body.removeEventListener('click', this.closeUploadMenu)
- }
- },
-},
-methods: {
- // upload(e) {
- // this.$emit('selectUploadFile', {path: this.selectNode.path, file: e.target.files[0]})
- // const params = {
- // node_id : this.nodeId,
- // current_dir: this.selectNode.path,
- // file: e.target.files[0]
- // }
- // },
- updateCurrentPath() {
- this.handleNodeClick(this.selectNode)
- this.setCurrentHighlight(this.selectNode.$treeNodeId);
- },
- download() {
- // this.downLoading = true
- const reqParams = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- filename: this.selectFile.name
- }
- this.$axios.getFile(this.$http.api.downloadFile, reqParams).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载文件成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载文件失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- // this.downLoading = false
- })
- },
- del() {
- const params = {
- node_id : this.nodeId,
- current_dir: this.selectNode.path,
- filename: this.selectFile.name
- }
- this.$axios.delete(this.$http.api.delFile, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 更新当前路径下的文件信息
- this.handleNodeClick(this.selectNode)
- // console.log('选中了节点id===', this.selectNode.$treeNodeId)
- this.setCurrentHighlight(this.selectNode.$treeNodeId);
- // this.init()
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 设置当前选中高亮
- setCurrentHighlight (id) {
- this.$nextTick(() => {
- this.$refs.tree.setCurrentKey(id)
- })
- },
- openMenu(fileItem, e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 180 // fix 位置bug
- } else {
- this.top = e.clientY - 160 // fix 位置bug
- }
- this.uploadVisible = false
- this.visible = true
- this.selectFile = fileItem
- },
- closeMenu() {
- this.visible = false
- },
- openUploadMenu(e) {
- const menuMinWidth = 105
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
- const offsetWidth = this.$el.offsetWidth // container width
- const maxLeft = offsetWidth - menuMinWidth // left boundary
- const left = e.clientX - offsetLeft + 60 // 15: margin right
-
- if (left > maxLeft) {
- this.left = maxLeft
- } else {
- this.left = left
- }
-
- if (this.isFullscreen) {
- this.top = e.clientY - 120 // fix 位置bug
- } else {
- this.top = e.clientY - 160 // fix 位置bug
- }
- this.visible = false
- this.uploadVisible = true
- },
- closeUploadMenu() {
- this.uploadVisible = false
- },
- // 获取当前路径下文件
- getCurrentDirFile(currentDir) {
- const reqParams = { node_id: this.nodeId, current_dir: currentDir }
- return this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- const dirs = res?.result?.object?.dir || []
- this.fileList = res?.result?.object?.file || []
- // console.log('请求回来files===', files)
- const nodeData = dirs.map(dir => {
- return {
- name: dir.name,
- path: currentDir === '/' ? currentDir + dir.name : `${currentDir}/${dir.name}`,
- fileList: []
- }
- })
- // console.log('请求回来nodeData====', nodeData)
- return nodeData
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 点击加载子节点
- async loadNode(node, reslove) {
- // console.log('执行了loadNode', node)
- if (node.level == 0) {
- let nodeData = await this.getCurrentDirFile('/')
- // console.log('初始化数据===', nodeData)
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- } else {
- let nodeData = await this.getCurrentDirFile(node.data.path)
- // 判断是否为最底层节点 根据自己接口返回的数据判断即可
- nodeData.forEach(item => {
- item.hasChildren == false ? item.lastNode = ture : null
- });
- // this.selectNode = nodeData.fileList
- return reslove(nodeData)
- }
- },
- handleNodeClick(node) {
- // this.fileList = []
- // console.log('选中了节点===', node)
- // console.log('选中了节点id===', node.$treeNodeId)
- this.selectNode = node
- this.dirTitle = node.path.split('/').join('>')
- this.currentFileName = node.name
- // this.fileList = node.fileList
- const reqParams = { node_id: this.nodeId, current_dir: node.path }
- this.$axios.get(this.$http.api.getCurrentDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.fileList = res?.result?.object?.file || []
- }
- }).catch(err => {
- console.log(err)
- })
- },
- openTreeMenu(event, data, node, target) {
- // console.log(event, data, node, target)
- this.showTreeMenu = true // 显示菜单
- this.contextNode = data // 存储数据
- // console.log(this.contextNode, 'contextNode')
- // console.log(node, 'rightClickNode=======')
- // console.log(target, 'target')
- this.rightClickNode = node
- document.querySelector('.treeMenu').setAttribute('style',`top:${event.clientY + 30}px;left:${event.clientX + 30}px;`)
- document.addEventListener('click', this.closeTreeMenu)
- document.addEventListener('contextmenu', this.closeTreeMenu)
- },
- closeTreeMenu() {
- this.showTreeMenu = false // 关闭菜单
- document.removeEventListener('click', this.closeTreeMenu)
- document.removeEventListener('contextmenu', this.closeTreeMenu)
- },
- // 当新建文件夹时,先填写名字
- openDirNameForm() {
- this.$refs.dirNameForm.visible = true
- },
- // 新建文件夹
- makeDir() {
- this.openDirNameForm()
- },
- // 新建文件夹接口提交
- makeDirSubmit() {
- const reqParams = { node_id: this.nodeId, current_dir: this.contextNode.path, new_dir_name: this.dirName }
- this.$axios.get(this.$http.api.makeDir, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '新建文件夹成功',
- type: 'success',
- duration: 2500
- })
- // 页面增加子节点
- let id = Math.ceil(Math.random() * 1000000)
- var addNode = {
- path: this.contextNode.path + '/' + this.dirName,
- name: this.dirName,
- fileList: []
- // id: id,
- // name: this.dirName,
- // data: {
- // path: this.contextNode.path,
- // name: this.dirName,
- // fileList: []
- // }
- }
- // console.log(addNode, 'addNode======')
- this.$refs.tree.append(addNode, this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 删除文件夹
- delDir() {
- const index = this.contextNode.path.lastIndexOf('/')
- const path = this.contextNode.path.substring(0, index);
- const params = {
- node_id : this.nodeId,
- current_dir: path,
- dir_name: this.contextNode.name
- }
- this.$axios.delete(this.$http.api.delDir, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除文件成功',
- type: 'success',
- duration: 2500
- })
- // 页面删除子节点
- this.$refs.tree.remove(this.rightClickNode)
- }
- }).catch(err => {
- console.log(err)
- })
- }
-}
-}
-</script>
-
-<style lang='less' scoped="scoped">
-.content {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- color: #ffffff;
- .tree-section {
- width: 25%;
- height: 100%;
- // background-color: #1A2648;
- background: transparent;
- border: 1px solid #BAD0F11A;
- color: #06F7FF;
- overflow-y: auto;
- ::v-deep .el-tree-node__content:hover {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- ::v-deep .el-tree-node.is-current > .el-tree-node__content {
- background-color: rgba(14, 61, 138, 0.3) !important;
- }
- }
- .tree-content {
- width: 75%;
- height: 100%;
- display: flex;
- flex-direction: column;
- .tree-content-ul {
- width: 100%;
- background-color: rgba(25, 33, 61, 0.4);
- overflow-y: auto;
- li {
- display: flex;
- flex-direction: row;
- justify-content: space-around;
- border-bottom: 1px solid #BAD0F11A;
- padding: 5px;
- .file-info {
- flex: 1 1 100px;
- }
- }
- }
- .empty-box {
- flex: 1;
- }
- }
-}
-.contextmenu {
- margin: 0;
- border-radius: 6px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- background: #0E3D8A;
- z-index: 3000;
- position: absolute;
- list-style-type: none;
- padding: 5px 0;
- font-size: 12px;
- font-weight: 400;
- color: #06F7FF;
- // box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- li {
- margin: 0;
- padding: 7px 30px;
- cursor: pointer;
- &:hover {
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- }
- }
- .file-input {
- display: none;
- }
- }
-
-.treeMenu {
- position: fixed;
- z-index: 99999;
- top: 50%;
- left: 50%;
- color: #06F7FF;
- background-color: #0E3D8A;
- overflow: hidden;
- border-radius: 5px;
- border: 0.5px solid rgba(6, 247, 255, 0.20);
- box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.10), 0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 3px 14px 2px rgba(0, 0, 0, 0.05);
- div{
- padding: 7px 30px;
- box-sizing: border-box;
- //width: 50px;
- text-align: center;
- }
- div:hover{
- border-radius: 3px;
- background: rgba(6, 247, 255, 0.10);
- cursor: pointer;
- }
-}
-</style>
diff --git a/src/views/rangeNodeManage/nodeList/index.vue b/src/views/rangeNodeManage/nodeList/index.vue
deleted file mode 100644
index 7a0e2fd..0000000
--- a/src/views/rangeNodeManage/nodeList/index.vue
+++ /dev/null
@@ -1,445 +0,0 @@
-<template>
-<div class="range-config-manage" ref="appRef">
- <Header
- :range-dict="rangeDict"
- @query="query"
- @batchConsole="batchConsole"
- @batchDownload="batchDownload"
- @batchUpload="batchUpload"
- @batchCollectTraffic="batchCollectTraffic"
- ></Header>
- <div class="list" >
- <el-table
- class="custom-table"
- ref="multipleTable"
- v-loading="loading"
- element-loading-text="加载中..."
- height="100%"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- >
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- <span style="padding-left: 5px;">{{ roleDict[scope.row.role] || scope.row.role }}</span>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <template slot-scope="scope">
- <div class="deploy-status">
- <svg-icon :icon-class="getStatus(scope.row.status).class"></svg-icon>
- <span :class="getStatus(scope.row.status).class">{{ getStatus(scope.row.status).label }}</span>
- </div>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="collecting"
- label="正在采集流量"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.collecting ? '是' : '否' }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="150"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="150"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- label="操作"
- min-width="200"
- >
- <template slot-scope="scope">
- <el-button type="text" size="medium" :disabled="scope.row.status==='pending' || !roleDict[scope.row.role]" @click="console(scope.row)">控制台</el-button>
- <el-button type="text" size="medium" :disabled="!roleDict[scope.row.role]" @click="log(scope.row)">日志</el-button>
- <el-button type="text" size="medium" :disabled="!roleDict[scope.row.role]" @click="detail(scope.row)">详情</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <el-pagination
- background
- :current-page="page"
- :page-sizes="[10, 20, 30, 40]"
- :page-size="10"
- :total="total"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- >
- </el-pagination>
- <div class="mask"></div>
- <Console
- ref="batchConsole"
- :target_id="target_id"
- @refresh="init">
- </Console>
- <Download
- ref="batchDownload"
- :target_id="target_id"
- @refresh="init">
- </Download>
- <Upload
- ref="batchUpload"
- :target_id="target_id"
- @refresh="init">
- </Upload>
- <CollectTraffic
- ref="batchCollectTraffic"
- :target_id="target_id"
- @refresh="init">
- </CollectTraffic>
-</div>
-</template>
-<script>
-import Header from './module/Header.vue'
-import Console from './module/Console.vue'
-import Download from './module/Download.vue'
-import Upload from './module/Upload.vue'
-import CollectTraffic from './module/CollectTraffic'
-
-export default {
- name: "RangeConfigManage",
- components:{ Header, Console, Download, Upload, CollectTraffic },
-
- data(){
- return{
- page: 1,
- size: 10,
- total: 0,
- target_id: '',
- tableData: [],
- selectConfigIds: [],
- rangeDict: [],
- loading: false,
- pendingTimer: null,
- roleDict:{
- da: '权威目录节点',
- client: '客户端节点',
- guard: '入口节点',
- relay: '路由节点',
- exit: '出口节点',
- onion: '洋葱服务节点',
- }
- }
- },
- mounted() {
-
- },
- watch: {
- '$store.state.range.targetId': {
- handler(newVal, oldVal) {
- this.target_id = newVal
- this.init()
- },
- immediate: true
- }
- },
- created() {},
- beforeDestroy() {
- if (this.pendingTimer) {
- clearInterval(this.pendingTimer)
- this.pendingTimer = null
- }
-},
- methods:{
- init(params={}) {
- // this.tableData = getTargetsResponse?.result?.items
- // this.total = getTargetsResponse?.result?.total
-
- // const checkedData = JSON.parse(JSON.stringify(this.selectTableData))
- const reqParams = {
- page: this.page,
- size: this.size,
- ...params
- }
- if (this.target_id && this.target_id !== '') {
- reqParams.target_id = this.target_id
- }
- this.loading = true
- this.$axios.get(this.$http.api.getNodeList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.tableData = res?.result?.items
- this.total = res?.result?.total
- // this.$nextTick(()=>{
- // checkedData.forEach((item) => {
- // this.$refs?.multipleTable?.toggleRowSelection(this.tableData.find(val => val.id === item.id), true)
- // })
- // })
- let index = this.tableData?.findIndex(item => {
- return item.status === 'pending'
- })
- if (index !== -1) {
- if (!this.pendingTimer) {
- this.pendingTimer = setInterval(() => {
- this.init()
- }, 10 * 1000)
- }
- }
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- query(params) {
- this.init(params)
- },
- // 批量控制台
- batchConsole() {
- document.querySelector('.mask').style.display = 'block'
- this.$refs.batchConsole.visible = true
- },
- // 批量下载文件
- batchDownload() {
- this.$refs.batchDownload.getNodeList()
- document.querySelector('.mask').style.display = 'block'
- this.$refs.batchDownload.visible = true
- },
- // 批量上传
- batchUpload() {
- // this.$store.commit('range/setNodeId', '')
- this.$refs.batchUpload.getNodeList()
- document.querySelector('.mask').style.display = 'block'
- this.$refs.batchUpload.visible = true
- },
- // 批量运行流水线
- batchCollectTraffic() {
- this.$refs.batchCollectTraffic.getNodeList()
- document.querySelector('.mask').style.display = 'block'
- this.$refs.batchCollectTraffic.visible = true
- },
- // 控制台
- console(row) {
- this.$store.commit('range/setNodeId', row.id)
- this.$router.push({
- name: 'console',
- params: {
- closeIcon : true
- }
- })
- },
- // 日志
- log(row) {
- this.$store.commit('range/setNodeId', row.id)
- this.$router.push({
- name: 'log',
- params: {
- closeIcon : true
- }
- })
- },
- // 详情
- detail(row) {
- this.$store.commit('range/setNodeId', row.id)
- //保存是否正在采集流量
- this.$store.commit('node/setStartTraffic', row.collecting)
- //保存是否正在结束采集流量
- this.$store.commit('node/setEndTraffic', row.analysing)
- this.$router.push({ name: 'nodeDetail'})
- },
- getStatus(status) {
- let statusInfo = {
- label: '',
- class: ''
- }
- switch (status) {
- case 'true':
- case 'pending':
- statusInfo.label = '正在部署'
- statusInfo.class = 'deployNormal'
- break;
- case 'false':
- statusInfo.label = '部署失败'
- statusInfo.class = 'deployFail'
- break;
- case 'complete':
- statusInfo.label = '部署完成'
- statusInfo.class = 'deploySuccess'
- break;
- default:
- break;
- }
- return statusInfo
- },
- // 获取靶场列表字典
- getRangeDict() {
- const reqParams = {
- page: 1,
- size: 99,
- }
- this.$axios.get(this.$http.api.getTargets, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.rangeDict = res?.result?.items.map(item => {
- return {
- label: item.target_name,
- value: item.id
- }
- })
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // // 处理选中的数据
- // handleSelectionChange(selectData) {
- // this.selectTableData = selectData
- // this.selectConfigIds = selectData.map(item => {
- // return item.id
- // })
- // },
- // 修改每页数据条数
- handleSizeChange(val) {
- console.log(`每页 ${val} 条`)
- this.page=1
- this.size=val
- this.query()
- },
- // 修改页数
- handleCurrentChange(val) {
- console.log(`当前页: ${val}`)
- this.page=val
- this.query()
- }
- }
-}
-
-</script>
-
-<style lang='less' scoped="scoped">
-.el-pagination {
- padding: 15px 55px 0 0 !important;
-}
-.custom-table {
- width: 100%;
- height: 100%;
- .deploy-status {
- display: inline-block;
- width: 103px;
- height: 28px;
- color:#FFFFFF;
- border-radius: 3px;
- padding: 5px, 12px, 5px, 12px;
- background: rgba(227, 249, 233, 0.2);
- }
- .deployFail {
- color: #E9473E;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
- .deployNormal {
- color: #02DDEA;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
- .deploySuccess {
- color: #0CCB64;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
-}
-.range-config-manage {
- width: 100%;
- height: 100%;
- // display: flex;
- // flex-direction: column;
- // justify-content: flex-start;
- .list{
- width: 100%;
- height: 73%;
- // margin-left: 2.5%;
- // overflow-y: auto;
- // overflow-y: scroll;
- // overflow-x: hidden;
- // border: none;
- }
- .list::-webkit-scrollbar {
- width: 0px; /* 隐藏滚动条 */
- height: 0px;
- background-color: transparent; /* 让背景透明 */
-
- }
- /* 隐藏火狐浏览器滚动条 */
- @-moz-document url-prefix() {
- .trackSource {
- scrollbar-width: none;
- }
- }
- // 遮罩层
- .mask{
- position: fixed; /*将元素设置为固定定位*/
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: rgba(0,0,0,0.5); /*通过rgba函数来控制遮罩层的透明度*/
- display: none; /*将元素隐藏*/
- }
- }
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/mock.js b/src/views/rangeNodeManage/nodeList/mock.js
deleted file mode 100644
index 49bc588..0000000
--- a/src/views/rangeNodeManage/nodeList/mock.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const getTargetsResponse ={
- "code": 200,
- "message": "success",
- "result": {
- "items": [
- {
- "setting_id": 1,
- "traffic_collect_task_id": 1,
- "id": 1,
- "ip": "1.1.1.1",
- "pod_name": "pod_name1",
- "nick_name": "第一节点",
- "status": "未部署",
- "onion": "onion1",
- "create_time": "2023-12-26T10:51:15.363Z",
- "complete_time": "2023-12-26T10:51:15.363Z"
- },
- {
- "setting_id": 2,
- "traffic_collect_task_id": 2,
- "id": 2,
- "ip": "2.2.2.2",
- "pod_name": "pod_name2",
- "nick_name": "第二节点",
- "status": "已部署",
- "onion": "onion2",
- "create_time": "2023-12-26T10:51:15.363Z",
- "complete_time": "2023-12-26T10:51:15.363Z"
- }
- ],
- "total": 0,
- "page": 1,
- "size": 50,
- "pages": 0
- }
- }
-
-export { getTargetsResponse } \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/RuleList.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/RuleList.vue
deleted file mode 100644
index fac918e..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/RuleList.vue
+++ /dev/null
@@ -1,207 +0,0 @@
-<template>
- <div class="rule-section">
- <div class="task-box">
- <div class="header">
- <span>规则列表</span>
- <img @click="addRule" src="../../../../../img/icon/addTrafficBtn.png" alt="" style="width: 194px; height: 40px;">
- </div>
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- height="230px"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- >
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="100"/>
- <el-table-column
- align="center"
- prop="rule_name"
- label="规则名称"
- min-width="130"/>
- <el-table-column
- align="center"
- prop="rule"
- label="具体规则"
- min-width="130"
- >
- </el-table-column>
- <el-table-column
- align="center"
- prop="update_time"
- label="添加时间"
- min-width="130"
- >
- <template slot-scope="scope">
- {{ scope.row.update_time | formatDate }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="use_count"
- label="使用次数"
- min-width="130"/>
- <el-table-column
- align="center"
- label="操作"
- min-width="300"
- >
- <template slot-scope="scope">
- <el-button type="text" size="medium" @click="editRule(scope.row)">修改</el-button>
- <el-button type="text" size="medium" :loading="scope.row.delLoading" @click="delRule(scope.row)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- <div class="mask"></div>
- <RuleForm ref="ruleForm" :is-add="isAdd" @refresh="init"/>
- </div>
- </template>
-
- <script>
- import RuleForm from './module/RuleForm'
- export default {
- name: 'RuleList',
- components: { RuleForm },
- props: {},
- data() {
- return {
- tableData: [],
- isAdd: true,
- visible:false,
- loading: false
- }
- },
- created() {
- this.init()
- },
- methods: {
- init() {
- const reqParams = {
- page: 1,
- size: 99,
- }
- this.loading = true
- this.$axios.get(this.$http.api.getRuleList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.tableData = res?.result?.items
- this.tableData.map(item => {
- this.$set(item, 'delLoading', false)
- return item
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- // 添加流量采集规则
- addRule() {
- this.isAdd = true
- this.$refs.ruleForm.visible = true
- },
- // 编辑规则
- editRule(row) {
- this.isAdd = false
- this.$refs.ruleForm.rule_id = row.id
- this.$refs.ruleForm.form.rule_name = row.rule_name
- this.$refs.ruleForm.form.rule = row.rule
- this.$refs.ruleForm.visible = true
- },
- // 删除规则
- delRule(row) {
- this.$confirm('此操作将永久删除该规则, 是否继续?', '确认删除', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.del(row)
- }).catch(() => {
- this.$notify({
- title: '已取消删除',
- type: 'success',
- duration: 2500
- })
- });
- },
- del(row) {
- const url = this.$http.api.rule + '/' + row.id
- row.delLoading = true
- this.$axios.delete(url, {}).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除成功',
- type: 'success',
- duration: 2500
- })
- this.init()
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- row.delLoading = false
- })
- },
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.resetForm()
- }
- }
- }
- </script>
-
- <style lang="less" scoped>
- .rule-section{
- // height: 100%;
- .styleTable {
- background-color: transparent !important;
- }
- .base-input {
- width: 100%;
- float: left;
- margin-top: 2%;
- text-align: center;
- }
- .label-span {
- margin-right: 3%;
- display: inline-block;
- width: 60px;
- text-align: right;
- }
- .but-color {
- background-color: #02DDEA !important;
- }
- .task-box{
- width: 100%;
- min-height: 45%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .header{
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- width: 100%;
- height: 50px;
- line-height: 50px;
- margin-bottom: 1%;
- }
- .content {
- flex: 1;
- ::v-deep .el-textarea__inner {
- background-color: #1A2648;
- }
- }
- }
- }
- </style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/TaskList.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/TaskList.vue
deleted file mode 100644
index 616ad6d..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/TaskList.vue
+++ /dev/null
@@ -1,391 +0,0 @@
-<template>
- <div class="task-section">
- <div class="task-box">
- <div class="header">
- <span>任务列表</span>
- <img @click="addTask" src="../../../../../img/icon/batchCollectBtn.png" alt="" style="width: 194px; height: 40px;">
- </div>
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- v-loading="loading"
- height="230px"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- @expand-change="handleExpandChange"
- >
- <el-table-column type="expand">
- <template slot-scope="props">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- v-loading="loading"
- height="100%"
- style="width: 100%; margin: 5px 20px;"
- :data="taskNodeList"
- tooltip-effect="dark"
- highlight-current-row
- >
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatDate }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatDate }}
- </template>
- </el-table-column>
- </el-table>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="60"/>
- <el-table-column
- align="center"
- prop="task_name"
- label="任务名称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="traffic_collect_rule_id"
- label="采集规则"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="collecting"
- label="任务状态"
- min-width="80"
- >
- <template slot-scope="scope">
- {{ scope.row.collecting ? (scope.row.collecting === true ? '正在采集' : '采集失败') : '采集完成' }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="start_collect_time"
- label="开始时间"
- min-width="110"
- >
- <template slot-scope="scope">
- {{ scope.row.start_collect_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="end_collect_time"
- label="结束时间"
- min-width="110"
- >
- <template slot-scope="scope">
- {{ scope.row.end_collect_time | formatTime }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- label="操作"
- min-width="300"
- >
- <template slot-scope="scope">
- <el-button type="text" size="medium" :loading="startLoading" @click="startTask(scope.row)">开始</el-button>
- <el-button type="text" size="medium" :loading="stopLoading" @click="endTask(scope.row)">结束</el-button>
- <el-button type="text" size="medium" @click="editTask(scope.row)">修改</el-button>
- <el-button type="text" size="medium" @click="delTask(scope.row)">删除</el-button>
- <!-- <el-button type="text" size="medium" @click="viewNode(scope.row)">查看节点</el-button> -->
- <el-button type="text" size="medium" @click="downloadPack(scope.row)">下载pcap包</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- <div class="mask"></div>
- <TaskForm
- ref="taskForm"
- :node-list="nodeList"
- :is-add="isAdd"
- :target_id="target_id"
- @refresh="init">
- </TaskForm>
- <DownloadPack
- ref="downloadPack"
- @refresh="init">
- </DownloadPack>
- </div>
- </template>
-
- <script>
- import TaskForm from './module/TaskForm'
- import DownloadPack from './module/DownloadPack'
- export default {
- name: 'Console',
- components: { TaskForm, DownloadPack },
- props: {
- target_id: {
- typeof: String,
- default: 0
- },
- nodeList: {
- typeof: Array,
- require: true
- },
- },
- data() {
- return {
- tableData: [],
- taskNodeList: [],
- isAdd: true,
- visible:false,
- loading: false,
- startLoading: false,
- stopLoading: false
- }
- },
- created() {
- this.init()
- },
- methods: {
- init() {
- const reqParams = {
- page: 1,
- size: 99,
- }
- this.loading = true
- this.$axios.get(this.$http.api.getTaskList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- // this.total = res?.result?.total
- this.tableData = res?.result?.items
- this.tableData.map(item => {
- this.$set(item, 'delLoading', false)
- return item
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- // 创建批量采集流量任务
- addTask() {
- this.isAdd = true
- document.querySelector('.mask').style.display = 'block'
- this.$refs.taskForm.visible = true
- },
- // 编辑任务
- editTask(row) {
- this.isAdd = false
- this.$refs.taskForm.task_id = row.id ?? ''
- this.$refs.taskForm.form.task_name = row.task_name ?? ''
- this.$refs.taskForm.form.task_description = row.task_description ?? ''
- this.$refs.taskForm.form.node_list = row.node_list ?? []
- this.$refs.taskForm.form.traffic_collect_rule_id = row.traffic_collect_rule_id
- this.$refs.taskForm.form.filter_noise = row.filter_noise ?? ''
- this.$refs.taskForm.visible = true
- },
- // 开始
- startTask(row) {
- const reqParams = {
- task_id: row.id,
- command: 'start'
- }
- this.startLoading = true
- this.$axios.get(this.$http.api.taskStartStop, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '开始统计流量',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- this.startLoading = false
- }).finally(() => {
- })
- },
- // 结束
- endTask(row) {
- const reqParams = {
- task_id: row.id,
- command: 'stop'
- }
- this.stopLoading = true
- this.$axios.get(this.$http.api.taskStartStop, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.startLoading = false
- this.$notify({
- title: '结束统计流量',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- setTimeout(() => {
- this.stopLoading = false
- this.init()
- }, 5 * 1000)
- })
- },
-
- // 删除任务
- delTask(row) {
- this.$confirm('此操作将永久删除该任务, 是否继续?', '确认删除', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.del(row)
- }).catch(() => {
- this.$notify({
- title: '已取消删除',
- type: 'success',
- duration: 2500
- })
- });
- },
- del(row) {
- const url = this.$http.api.trafficTask + '/' + row.id
- row.delLoading = true
- this.$axios.delete(url, {delete_minio: true}).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '删除任务成功',
- type: 'success',
- duration: 2500
- })
- this.init()
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- row.delLoading = false
- })
- },
- // 展开行查看节点
- handleExpandChange(row, expandedRows) {
- this.getTaskNodeList(row)
- },
- // // 查看节点
- // viewNode(row) {
- // this.getTaskNodeList(row)
- // },
- // 获取节点列表
- getTaskNodeList(row) {
- const params = {
- page:1,
- size: 99,
- task_id: row.id
- }
- this.$axios.get(this.$http.api.getTrafficNodes, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.taskNodeList = res?.result?.items
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 下载pcap包
- downloadPack(row) {
- this.$refs.downloadPack.task_id = row.id
- this.$refs.downloadPack.init()
- document.querySelector('.mask').style.display = 'block'
- this.$refs.downloadPack.visible = true
- }
- }
- }
- </script>
-
- <style lang="less" scoped>
- .task-section{
- // height: 100%;
- .styleTable {
- background-color: transparent !important;
- }
- .base-input {
- width: 100%;
- float: left;
- margin-top: 2%;
- text-align: center;
- }
- .label-span {
- margin-right: 3%;
- display: inline-block;
- width: 60px;
- text-align: right;
- }
- .but-color {
- background-color: #02DDEA !important;
- }
- .task-box{
- width: 100%;
- min-height: 45%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .header{
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- width: 100%;
- height: 50px;
- line-height: 50px;
- margin-bottom: 1%;
- }
- .content {
- flex: 1;
- ::v-deep .el-textarea__inner {
- background-color: #1A2648;
- }
- }
- }
- ::v-deep .el-table tbody tr>td {
- // background: rgba(25, 33, 61, 0.5) !important;
- background-color: #0A162C !important;
- }
- }
- </style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/index.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/index.vue
deleted file mode 100644
index fe93dd2..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/index.vue
+++ /dev/null
@@ -1,110 +0,0 @@
-<template>
-<div class="console-dialog" v-if="visible">
- <!-- 在此处指定弹窗的样式和内容 -->
- <i class="el-icon-close" @click="close"></i>
- <div class="tag">
- <el-tag class="tags" style="color:#f8fdff">批量采集流量</el-tag>
- </div>
- <TaskList style="height: 42%;" :node-list="nodeList"></TaskList>
- <RuleList style="height: 42%;"></RuleList>
- <footer class="anDiv">
- <el-button class="glBut but-color" type="primary" @click="close">确定</el-button>
- </footer>
-</div>
-</template>
-
-<script>
-import TaskList from './TaskList'
-import RuleList from './RuleList'
-export default {
- name: 'Console',
- components: { TaskList, RuleList },
- props: {
- target_id: {
- typeof: String,
- required: true,
- default: 0
- }
- },
- data() {
- return {
- visible:false,
- nodeList: []
- }
- },
- methods: {
- getNodeList() {
- const reqParams = {
- page: 1,
- size: 99
- }
- if (this.target_id && this.target_id !== '') {
- reqParams.target_id = this.target_id
- }
- this.$axios.get(this.$http.api.getNodeList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.nodeList = res?.result?.items
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {})
- },
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.$emit('refresh')
- this.visible = false
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.console-dialog{
- z-index: 997;
- width: 1331px;
- height: 800px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../../img/background/NodeListDialog.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- .el-icon-close{
- float: right;
- padding-right: 8%;
- padding-top: 1.8%
- }
- .tag{
- text-align: left;
- margin-left: 2%;
- .tags{
- margin-top: 1%;
- font-size: 23px;
- border: none;
- background-color: transparent !important;
- color: #565e6e;
- }
- }
- .but-color {
- background-color: #02DDEA !important;
- }
- .anDiv{
- width: 100%;
- float: left;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/DownloadPack.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/DownloadPack.vue
deleted file mode 100644
index c9d7080..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/DownloadPack.vue
+++ /dev/null
@@ -1,223 +0,0 @@
-<template>
- <div
- class="custom-dialog"
- v-if="visible"
- >
- <span class="dialog-title">pcap包下载</span>
- <!-- 在此处指定弹窗的样式和内容 -->
- <i class="el-icon-close" style="float: right; padding-right: 10%;padding-top: 2.5%" @click="close"></i>
- <div class="basic-box">
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- v-loading="loading"
- height="420px"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionChange"
- >
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="bucket_name"
- label="桶名称"
- width="80"/>
- <el-table-column
- align="center"
- prop="file_name"
- label="文件名称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="size"
- label="文件大小"
- min-width="100"
- >
- </el-table-column>
- <el-table-column
- align="center"
- prop="last_modified"
- label="生成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.last_modified | formatTime }}
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut but-color" type="primary" @click="download" :loading="downLoading">下载</el-button>
- </div>
- </div>
- </div>
- </div>
-</template>
-
-<script>
-export default {
- name: 'RuleForm',
- // props: ['task_id'],
- data() {
- return {
- visible: false,
- loading: false,
- downLoading: false,
- task_id: '',
- tableData: [],
- selectFileNameList: []
- }
- },
- created() {
- },
- methods: {
- init() {
- const reqParams = {
- page: 1,
- size: 99,
- task_id: this.task_id
- }
- this.loading = true
- this.$axios.get(this.$http.api.getPackList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.tableData = res?.result?.items
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- handleSelectionChange(selectData) {
- this.selectFileNameList = selectData.map(item => {
- return {
- bucket_name: item.bucket_name,
- file_name: item.file_name
- }
- })
- },
- close() {
- this.resetForm()
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- },
- resetForm() {
- },
- // 下载
- download() {
- if (this.selectFileNameList.length <= 0) {
- this.$notify({
- title: '请勾选要下载的文件',
- type: 'warning',
- duration: 2500
- })
- return
- }
- const reqParams = {
- task_id: this.task_id,
- object_info_list: JSON.stringify(this.selectFileNameList)
- }
- this.downLoading = true
- this.$axios.getFile(this.$http.api.downloadPacp, reqParams).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载文件成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载文件失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.downLoading = false
- this.close()
- })
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
- .custom-dialog{
- z-index: 998;
- width: 620px;
- height: 555px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../../../img/background/dialog660-553.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- // background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- .dialog-title {
- font-size: 20px;
- float: left;
- margin: 11px 0 11px 20px;
- }
- .basic-box {
- width: 100%;
- min-height: 100%;
- padding: 2%;
- display: flex;
- flex-direction: column;
- .content {
- flex: 1;
- .bcmcDiv{
- width: 100%;
- float: left;
- margin-top: 5%;
- text-align: center;
- .bcmc {
- width: 60%;
- }
- }
- }
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-bottom: 10%;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 2%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- .but-color {
- background-color: #02DDEA;
- }
- }
- }
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/RuleForm.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/RuleForm.vue
deleted file mode 100644
index f280b5a..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/RuleForm.vue
+++ /dev/null
@@ -1,164 +0,0 @@
-<template>
- <div
- class="rule-dialog"
- v-if="visible"
- >
- <!-- 在此处指定弹窗的样式和内容 -->
- <i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
- <el-form
- ref="ruleForm"
- :model="form"
- :rules="rules"
- label-width="150px"
- class="rule-form"
- >
- <el-row>
- <el-col :span="20">
- <el-form-item label="规则名称" prop="rule_name">
- <el-input v-model="form.rule_name" placeholder="请输入规则名称"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="20">
- <el-form-item label="规则" prop="rule">
- <el-input type="textarea" v-model="form.rule" placeholder="请输入规则"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div class="submit-footer">
- <div>
- <el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">确定</el-button>
- </div>
- </div>
- <div class="mask"></div>
- </div>
-</template>
-
-<script>
-export default {
- name: 'RuleForm',
- props: ['isAdd'],
- data() {
- return {
- visible: false,
- loading: false,
- form: {
- rule_name: '', // 规则名称
- rule: '' // 规则
- },
- rule_id: '',
- rules: {
- rule_name: [
- { required: true, message: '请输入规则名称', trigger: 'blur' }
- ],
- rule: [
- { required: true, message: '请输入规则', trigger: 'blur' }
- ]
- }
- }
- },
- methods: {
- close() {
- this.resetForm()
- // document.querySelector('.mask').style.display = 'none'
- this.visible = false
- },
- submit() {
- this.$refs.ruleForm.validate((valid) => {
- if (valid) {
- if (this.isAdd) {
- this.add()
- } else {
- this.edit()
- }
- }
- })
- },
- add () {
- this.loading = true
- const url = this.$http.api.rule
- this.$axios.post(url, this.form).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.resetForm()
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '创建规则成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- edit() {
- this.loading = true
- const url = this.$http.api.rule + `/${this.rule_id}`
- this.$axios.put(url, this.form).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.resetForm()
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '编辑规则成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- resetForm() {
- this.form = {
- rule_name: '', // 规则名称
- rule: '' // 规则
- }
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
- .rule-dialog{
- width: 620px;
- height: 555px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../../../img/background/addRuleBg.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
- .rule-form {
- margin-top: 70px;
- text-align: left;
- }
- .submit-footer{
- width: 100%;
- float: left;
- margin-top: 200px;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 2%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- .but-color {
- background-color: #02DDEA;
- }
- }
- }
-</style>
diff --git a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/TaskForm.vue b/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/TaskForm.vue
deleted file mode 100644
index a7d2cc0..0000000
--- a/src/views/rangeNodeManage/nodeList/module/CollectTraffic/module/TaskForm.vue
+++ /dev/null
@@ -1,522 +0,0 @@
-<template>
-<div class="console-dialog" v-if="visible">
- <!-- 在此处指定弹窗的样式和内容 -->
- <i class="el-icon-close" @click="close"></i>
- <div class="tag">
- <el-tag class="tags" :style="{'color': (tag==='添加任务') ? '#f8fdff': '#565e6e'}">添加任务</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='被操作节点') ? '#f8fdff': '#565e6e'}">被操作节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='操作') ? '#f8fdff': '#565e6e'}">操作</el-tag>
- </div>
- <div class="basic-box" v-if="tag==='添加任务'">
- <el-form
- ref="addTaskForm"
- :model="form"
- :rules="taskRules"
- label-width="150px"
- class="basic-form"
- size="small"
- >
- <el-row>
- <el-col :span="12" :offset="6">
- <el-form-item label="任务名称" prop="task_name">
- <el-input v-model="form.task_name" placeholder="请输入任务名称"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" :offset="6">
- <el-form-item label="任务描述" prop="task_description">
- <el-input v-model="form.task_description" placeholder="请输入任务描述">
- </el-input>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <footer class="anDiv">
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点', true)">下一步</el-button>
- </footer>
- </div>
- <div class="table-box" v-if="tag==='被操作节点'">
- <div class="tip-message">请勾选多个节点</div>
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- height="100%"
- style="width: 100%;"
- :data="nodeList"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionNode"
- >
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <template slot-scope="scope">
- <div class="deploy-status">
- <svg-icon :icon-class="getStatus(scope.row.status).class"></svg-icon>
- <span :class="getStatus(scope.row.status).class">{{ getStatus(scope.row.status).label }}</span>
- </div>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatDate }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatDate }}
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('添加任务')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('操作', true)">下一步</el-button>
- </div>
- </div>
-
- </div>
- <div class="basic-box" v-if="tag==='操作'">
- <el-form
- ref="operateForm"
- :model="form"
- :rules="oprateRules"
- label-width="150px"
- class="basic-form"
- size="small"
- >
- <el-row>
- <el-col :span="12" :offset="6">
- <el-form-item label="选择规则" prop="traffic_collect_rule_id">
- <el-select v-model="form.traffic_collect_rule_id" placeholder="请选择规则" @focus="getRuleList">
- <el-option
- v-for="item in ruleDict"
- :key="item.value"
- :label="item.label"
- :value="item.value">
- </el-option>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" :offset="6">
- <el-form-item label="是否过滤噪音流量" prop="filter_noise">
- <el-radio-group v-model="form.filter_noise">
- <el-radio :label="true">是</el-radio>
- <el-radio :label="false">否</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">确认</el-button>
- </div>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-export default {
- name: 'TaskForm',
- props: {
- isAdd: {
- typeof: Boolean,
- required: true
- },
- nodeList: {
- typeof: Array,
- require: true
- },
- target_id: {
- typeof: String,
- required: true
- }
- },
- data() {
- return {
- visible:false,
- loading: false,
- tag:"添加任务",
- task_id: '',
- ruleDict: [],
- form: {
- task_name: '', // 任务名称
- task_description: '', // 任务描述
- node_list: [], // 节点列表
- traffic_collect_rule_id: null, // 选择规则
- filter_noise: true, // 是否过滤噪音流量
- },
- taskRules: {
- task_name:[
- { required: true, message: '请输入任务名称', trigger: 'blur' }
- ],
- task_description: [
- { required: true, message: '请输入任务描述', trigger: 'blur' }
- ]
- },
- oprateRules: {
- traffic_collect_rule_id: [
- { required: true, message: '请选择规则', trigger: 'blur' }
- ],
- filter_noise: [
- { required: true, message: '请选择是否过滤噪音流量', trigger: 'blur' }
- ]
- },
- setting_id: '',
- torDict: [],
- networkDict: [],
- imageDict: []
- }
- },
- created() {
- // 获取规则字典
- this.getRuleList()
- },
- methods: {
- // 选择添加任务
- handleSelectionNode(selectRows) {
- this.form.node_list = selectRows.map(row => {
- return row.id
- })
- },
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.tag = '添加任务'
- this.resetForm()
- },
- // 重置
- resetForm() {
- this.form = {
- task_name: '', // 任务名称
- task_description: '', // 任务描述
- node_list: [], // 节点列表
- traffic_collect_rule_id: null, // 选择规则
- filter_noise: true, // 是否过滤噪音流量
- }
- },
- // 选择哪个页面
- updateTag(val, isValid){
- if (val === '被操作节点' && isValid) {
- this.$refs.addTaskForm.validate((valid) => {
- if (valid) {
- this.tag=val
- }
- })
- } else if(val === '操作' && isValid) {
- if (this.form.node_list.length > 0) {
- this.tag=val
- } else {
- this.$notify({
- title: '请勾选要被操作的节点!',
- type: 'success',
- duration: 2500
- })
- return
- }
- } else {
- this.tag=val
- }
- },
- // 获取规则列表
- getRuleList() {
- const reqParams = {
- page: 1,
- size: 99,
- }
- this.loading = true
- this.$axios.get(this.$http.api.getRuleList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.ruleDict = res?.result?.items.map(item => {
- return {
- label: item.rule_name,
- value: item.id
- }
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- // 提交数据
- submit() {
- this.$refs.operateForm.validate((valid) => {
- if (valid) {
- if (this.isAdd) {
- this.add()
- } else {
- this.edit()
- }
- }
- })
- },
- add () {
- this.loading = true
- const url = this.$http.api.trafficTask
- this.$axios.post(url, this.form).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.resetForm()
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '创建任务成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- edit() {
- this.loading = true
- const url = this.$http.api.trafficTask + `/${this.task_id}`
- this.$axios.put(url, this.form).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.resetForm()
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '编辑任务成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- getStatus(status) {
- let statusInfo = {
- label: '',
- class: ''
- }
- switch (status) {
- case 'true':
- case 'pending':
- statusInfo.label = '正在部署'
- statusInfo.class = 'deployNormal'
- break;
- case 'false':
- statusInfo.label = '部署失败'
- statusInfo.class = 'deployFail'
- break;
- case 'complete':
- statusInfo.label = '部署完成'
- statusInfo.class = 'deploySuccess'
- break;
- default:
- break;
- }
- return statusInfo
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.console-dialog{
- z-index: 997;
- width: 1171px;
- height: 705px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../../../img/background/NodeListDialog.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
-
- .el-icon-close{
- float: right;
- padding-right: 7%;
- padding-top: 1.8%
- }
- .tag{
- margin-left: 9%;
- .tags{
- margin-right: 5%;
- margin-top: 1%;
- font-size: 23px;
- border: none;
- background-color: transparent !important;
- color: #565e6e;
- }
- }
- .basic-form {
- margin-top: 50px;
- text-align: left;
- ::v-deep .el-select {
- width: 100%;
- }
- }
- .but-color {
- background-color: #02DDEA !important;
- }
-
- .basic-box{
- .anDiv{
- width: 100%;
- float: left;
- margin-top: 450px;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
-
- }
- }
-
- .table-box{
- width: 100%;
- min-height: 100%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .tip-message{
- width: 100%;
- height: 50px;
- text-align: left;
- padding: 11px 0 12px 20px;
- font-size: 20px;
- background-color: #1A2648;
- border-radius: 4px;
- margin-bottom: 2%;
- }
- .content {
- flex: 1;
- display: flex;
- flex-direction: row;
- .deploy-status {
- display: inline-block;
- width: 103px;
- height: 28px;
- color:#FFFFFF;
- border-radius: 3px;
- padding: 5px, 12px, 5px, 12px;
- background: rgba(227, 249, 233, 0.2);
- }
- .deployFail {
- color: #E9473E;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
- .deployNormal {
- color: #02DDEA;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
- .deploySuccess {
- color: #0CCB64;
- width: 56px;
- height: 28px;
- margin-left: 10px;
- font-family: PingFang SC;
- font-size: 14px;
- font-weight: 400;
- line-height: 28px;
- letter-spacing: 0em;
- text-align: left;
- }
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-bottom: 7%;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/Console.vue b/src/views/rangeNodeManage/nodeList/module/Console.vue
deleted file mode 100644
index fec6b03..0000000
--- a/src/views/rangeNodeManage/nodeList/module/Console.vue
+++ /dev/null
@@ -1,521 +0,0 @@
-<template>
-<div class="console-dialog" v-if="visible">
- <!-- 在此处指定弹窗的样式和内容 -->
- <i class="el-icon-close" @click="close"></i>
- <div class="tag">
- <el-tag class="tags" :style="{'color': (tag==='主节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('主节点')">主节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='被操作节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('被操作节点')">被操作节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='控制台') ? '#f8fdff': '#565e6e'}" @click="updateTag('控制台')">控制台</el-tag>
- </div>
- <div class="basic-box" v-if="tag==='主节点'">
- <div class="tip-message">请选择主节点作为打开文件系统的依据</div>
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- height="100%"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionMain"
- >
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <!-- <template slot-scope="scope">
- {{ scope.row.has_deployed ? '已部署' : '未部署' }}
- </template> -->
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatDate }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatDate }}
- </template>
- </el-table-column>
- </el-table>
- </div>
- <footer class="anDiv">
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">下一步</el-button>
- </footer>
- </div>
- <div class="basic-box" v-if="tag==='被操作节点'">
- <div class="tip-message">请勾选多个节点</div>
- <div class="content">
- <el-table
- class="main-table styleTable"
- ref="multipleTable"
- height="100%"
- style="width: 100%;"
- :data="tableData"
- tooltip-effect="dark"
- highlight-current-row
- @selection-change="handleSelectionMain"
- >
- <el-table-column
- align="center"
- type="selection"
- width="80"/>
- <el-table-column
- align="center"
- prop="id"
- label="id"
- width="80"/>
- <el-table-column
- align="center"
- prop="nick_name"
- label="节点昵称"
- min-width="100"/>
- <el-table-column
- align="center"
- prop="role"
- label="角色"
- min-width="100">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.role"></svg-icon>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="ip"
- label="ip"
- min-width="150"/>
- <el-table-column
- align="center"
- prop="status"
- label="部署状态"
- min-width="100"
- >
- <!-- <template slot-scope="scope">
- {{ scope.row.has_deployed ? '已部署' : '未部署' }}
- </template> -->
- </el-table-column>
- <el-table-column
- align="center"
- prop="create_time"
- label="创建开始时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.create_time | formatDate }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- prop="complete_time"
- label="创建完成时间"
- min-width="100"
- >
- <template slot-scope="scope">
- {{ scope.row.complete_time | formatDate }}
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('主节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('控制台')">下一步</el-button>
- </div>
- </div>
-
- </div>
- <div class="basic-box" v-if="tag==='控制台'">
- <div class="tip-message">主节点名称:10-relaytwlgthavry
-已勾选的节点名称列表:11-relayyqbgcxuewy、12-relayztitnmkgfl…</div>
- <div class="content">
- <el-input
- type="textarea"
- :rows="25"
- placeholder="请输入命令"
- v-model="textarea">
- </el-input>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">确认</el-button>
- </div>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-export default {
- name: 'Console',
- props: {
- tableData: {
- typeof: Array,
- require: true
- },
- target_id: {
- typeof: String,
- required: true
- }
- },
- data() {
- return {
- visible:false,
- loading: false,
- tag:"主节点",
- setting_id: '',
- form: {
- role: '', // 角色选择
- tor_version: '', // tor版本
- image_id: '', // 选择镜像
- replicas: '', // 复本数
- bandwidth: '', // 宽带限制
- memory: '', // 内存限制
- service: '', // 服务器地址
- out_port: '', // 代理端口
- or_port: '', // or端口
- dir_port: '', // dir端口
- socks_port: '', // 客户端监听端口
- control_port: '', // 客户端控制端口
-
- country_id: '', // 国家
- network_id: '', // 网络
-
- deployType: '', // 部署方式
- direct: false, // 直接部署true 仅添加配置false
- start_tcpdump: false // 启动采集程序并部署 true
- },
- roleDict:[
- {label: '权威目录节点', value: 'da'},
- {label: '路由节点', value: 'relay'},
- {label: '出口节点', value: 'exit'},
- {label: '洋葱服务节点', value: 'onion'},
- {label: '客户端节点', value: 'client'},
- {label: '入口节点', value: 'guard'},
- {label: '其他节点', value: 'other'}
- ],
- torDict: [],
- networkDict: [],
- imageDict: []
- }
- },
- methods: {
- // 选择主节点
- handleSelectionMain() {},
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.tag = '主节点'
- this.resetForm()
- },
- // 重置
- resetForm() {
- this.form = {
- role: '', // 角色选择
- tor_version: '', // tor版本
- image_id: '', // 选择镜像
- replicas: '', // 复本数
- bandwidth: '', // 宽带限制
- memory: '', // 内存限制
- service: '', // 服务器地址
- out_port: '', // 代理端口
- or_port: '', // or端口
- dir_port: '', // dir端口
- socks_port: '', // 客户端监听端口
- control_port: '', // 客户端控制端口
-
- country_id: '', // 国家
- network_id: '', // 网络
-
- deployType: '', // 部署方式
- direct: false, // 直接部署true 仅添加配置false
- start_tcpdump: false // 启动采集程序并部署 true
- }
- },
- // 选择哪个页面
- updateTag(val){
- this.tag=val
- },
- // 角色选择
- selectRole(node) {
- if (node === 'other') {
- this.$emit('openRoleForm')
- }
- // 获取torDict
- this.$axios.get(this.$http.api.getTorDict, {role: this.form.role}).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.torDict = res?.result
- }
- }).catch(err => {
- console.log(err)
- })
- // 获取镜像字典
- this.getImageDict()
-
- },
- // tor选择
- selectTor(tor){
- // 获取镜像字典
- this.getImageDict()
- },
- // 获取imageDict
- getImageDict(){
- const params = {
- page:1,
- size: 99,
- image_name: this.form.role,
- image_version: this.form.tor_version
- }
- this.$axios.get(this.$http.api.getImageDict, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.imageDict = res?.result?.items.map(item => {
- return {
- label: item.image_name + '-' + item.image_version,
- value: item.id
- }
- })
- }
- }).catch(err => {
- console.log(err)
- })
- },
- // 获取网络
- getNetworkDict(){
- const params = {
- page:1,
- size: 99,
- country_id: this.form.country_id,
- }
- this.$axios.get(this.$http.api.getNetworkDict, params).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.networkDict = res?.result?.items.map(item => {
- return {
- label: item.cidr,
- value: item.id
- }
- })
- }
- }).catch(err => {
- console.log(err)
- })
- },
- selectDeploy(deployType) {
- switch (deployType) {
- case 'direct':
- this.form.direct = true
- break
- case 'only':
- this.form.direct = false
- break
- case 'start':
- this.form.start_tcpdump = true
- break
- default:
- this.form.direct = true
- break
- }
- },
- // 提交数据
- submit() {
- // const submitForm = this.setSubmitForm()
- // if (this.isAdd) {
- // this.add(submitForm)
- // } else {
- // this.edit(submitForm)
- // }
- },
- setSubmitForm() {
- const {role, image_id, replicas, bandwidth, memory } = this.form
- let submitForm = {role, image_id, replicas, bandwidth, memory }
- if (this.form.role === 'other') {
- submitForm.role = this.otherRole
- } else if (this.form.role==='da'||this.form.role==='relay'||this.form.role ==='guard'||this.form.role ==='exit') {
- submitForm.tor_version = this.form.tor_version
- submitForm.or_port = this.form.or_port
- submitForm.dir_port = this.form.dir_port
- } else if (this.form.role==='onion') {
- submitForm.tor_version = this.form.tor_version
- submitForm.service = this.form.service
- submitForm.socks_port = this.form.socks_port
- submitForm.control_port = this.form.control_port
- } else if (this.form.role==='client') {
- submitForm.tor_version = this.form.tor_version
- submitForm.out_port = this.form.out_port
- submitForm.socks_port = this.form.socks_port
- submitForm.control_port = this.form.control_port
- }
- return submitForm
- },
- add(submitForm) {
- this.loading = true
- const url = this.$http.api.setting + `/?target_id=${this.target_id}&network_id=${this.form.network_id}&direct=${this.form.direct}&start_tcpdump=${this.form.start_tcpdump}`
- this.$axios.post(url, submitForm).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '添加靶场配置成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- },
- edit(submitForm) {
- this.loading = true
- const url = this.$http.api.setting + `/?target_id=${this.target_id}&setting_id=${this.setting_id}&network_id=${this.form.network_id}&direct=${this.form.direct}&start_tcpdump=${this.form.start_tcpdump}`
- this.$axios.put(url, submitForm).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.close()
- this.$emit('refresh')
- this.$notify({
- title: '添加靶场配置成功',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.console-dialog{
- z-index: 997;
- width: 1331px;
- height: 800px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../img/background/NodeListDialog.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- .el-icon-close{
- float: right;
- padding-right: 8%;
- padding-top: 1.8%
- }
- .tag{
- margin-left: 15%;
- .tags{
- margin-right: 5%;
- margin-top: 1%;
- font-size: 23px;
- border: none;
- background-color: transparent !important;
- color: #565e6e;
- }
- }
-
- .base-input {
- width: 100%;
- float: left;
- margin-top: 2%;
- text-align: center;
- }
- .label-span {
- margin-right: 3%;
- display: inline-block;
- width: 60px;
- text-align: right;
- }
- .but-color {
- background-color: #02DDEA !important;
- }
- .basic-box{
- width: 100%;
- min-height: 100%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .tip-message{
- width: 100%;
- height: 50px;
- line-height: 50px;
- font-size: 20px;
- background-color: #1A2648;
- border-radius: 4px;
- margin-bottom: 2%;
- }
- .content {
- flex: 1;
- ::v-deep .el-textarea__inner {
- background-color: #1A2648;
- }
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-bottom: 7%;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
-
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/Download.vue b/src/views/rangeNodeManage/nodeList/module/Download.vue
deleted file mode 100644
index b76a9e5..0000000
--- a/src/views/rangeNodeManage/nodeList/module/Download.vue
+++ /dev/null
@@ -1,274 +0,0 @@
-<template>
-<div class="console-dialog" v-if="visible">
- <i class="el-icon-close" @click="close"></i>
- <div class="tag">
- <el-tag class="tags" :style="{'color': (tag==='主节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('主节点')">主节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='被操作节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('被操作节点')">被操作节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='文件管理') ? '#f8fdff': '#565e6e'}" @click="updateTag('文件管理')">文件管理</el-tag>
- </div>
- <div class="basic-box" v-show="tag==='主节点'">
- <div class="tip-message">请选择主节点作为打开文件系统的依据</div>
- <div class="content">
- <!-- 主节点 -->
- <MainNode
- :node-list="nodeList"
- @selectMainNode="selectMainNode"
- ></MainNode>
- </div>
- <footer class="anDiv">
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">下一步</el-button>
- </footer>
- </div>
- <div class="basic-box" v-show="tag==='被操作节点'">
- <div class="tip-message">请勾选多个节点</div>
- <div class="content">
- <!-- 被操作节点 -->
- <OperateNode
- :node-list="nodeList"
- @selectOperateNode="selectOperateNode"
- ></OperateNode>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('主节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('文件管理')">下一步</el-button>
- </div>
- </div>
-
- </div>
- <div class="basic-box" v-if="tag==='文件管理'">
- <div class="tip-message" style="height: 76px;">
- <span>{{`主节点名称:${master_node_name}`}}<br/>{{`已勾选的节点名称列表:${batch_node_name_list.join('、')}`}}</span>
- </div>
- <!-- 文件管理 -->
- <FileManager
- ref="fileManager"
- ></FileManager>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="download" :loading="loading">下载</el-button>
- </div>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-import MainNode from '../components/MainNode.vue'
-import OperateNode from '../components/OperateNode.vue'
-import FileManager from '../components/DownloadFileManager.vue'
-import qs from 'qs'
-export default {
- name: 'Download',
- components:{
- MainNode,
- OperateNode,
- FileManager
- },
- props: {
- target_id: {
- typeof: String,
- required: true
- }
- },
- data() {
- return {
- nodeList: [],
- downloadForm: {
- master_node_id: '',
- batch_node_id_list: [],
- current_dir: '',
- filename: ''
- },
- master_node_name: '',
- batch_node_name_list: [],
- visible:false,
- loading: false,
- tag:"主节点",
- form: {}
- }
- },
- methods: {
- // 获取节点列表
- getNodeList() {
- const reqParams = {
- page: 1,
- size: 99
- }
- if (this.target_id && this.target_id !== '') {
- reqParams.target_id = this.target_id
- }
- this.$axios.get(this.$http.api.getNodeList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.nodeList = res?.result?.items
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {})
- },
- // 选择主节点
- selectMainNode({ id, nick_name }) {
- this.$store.commit('range/setNodeId', id)
- this.downloadForm.master_node_id = id
- this.master_node_name = nick_name
- },
- // 选择被操作节点
- selectOperateNode(selectRows) {
- this.batch_node_name_list = []
- this.downloadForm.batch_node_id_list = selectRows.map(row => {
- this.batch_node_name_list.push(row.nick_name)
- return row.id
- })
- },
- // 选择上传文件
- selectUploadFile({path, file}) {
- this.downloadForm.current_dir = path
- this.downloadForm.file = file
- },
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.tag = '主节点'
- this.resetForm()
- },
- // 重置
- resetForm() {
- this.form = {}
- },
- // 选择哪个页面
- updateTag(val){
- this.tag=val
- },
- // 提交数据
- download() {
- this.downloadForm.current_dir = this.$refs.fileManager.selectNode.path
- this.downloadForm.filename = this.$refs.fileManager.filename
- const reqParams = qs.stringify(this.downloadForm, { arrayFormat: 'repeat' })
- const url = this.$http.api.batchDownload + '?' + reqParams
- this.$axios.getFile(url).then(res => {
- if (res.status == 200 || res.statusText == "OK") {
- const { data, headers } = res
- const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
- // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
- //const blob = new Blob([JSON.stringify(data)], ...)
- const blob = new Blob([data], {type: headers['content-type']})
- let dom = document.createElement('a')
- let url = window.URL.createObjectURL(blob)
- dom.href = url
- dom.download = decodeURI(fileName)
- dom.style.display = 'none'
- document.body.appendChild(dom)
- dom.click()
- dom.parentNode.removeChild(dom)
- window.URL.revokeObjectURL(url)
- this.$notify({
- title: '下载文件成功',
- type: 'success',
- duration: 2500
- })
- } else {
- this.$notify({
- title: '下载文件失败',
- type: 'success',
- duration: 2500
- })
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.close()
- })
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.console-dialog{
- z-index: 997;
- width: 1331px;
- height: 800px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../img/background/NodeListDialog.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- .el-icon-close{
- float: right;
- padding-right: 8%;
- padding-top: 1.8%
- }
- .tag{
- margin-left: 15%;
- .tags{
- margin-right: 5%;
- margin-top: 1%;
- font-size: 23px;
- border: none;
- background-color: transparent !important;
- color: #565e6e;
- }
- }
- .base-input {
- width: 100%;
- float: left;
- margin-top: 2%;
- text-align: center;
- }
- .label-span {
- margin-right: 3%;
- display: inline-block;
- width: 60px;
- text-align: right;
- }
- .but-color {
- background-color: #02DDEA !important;
- }
- .basic-box{
- width: 100%;
- min-height: 100%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .tip-message{
- width: 100%;
- height: 50px;
- text-align: left;
- padding: 11px 0 12px 20px;
- font-size: 20px;
- background-color: #1A2648;
- border-radius: 4px;
- margin-bottom: 2%;
- }
- .content {
- flex: 1;
- display: flex;
- flex-direction: row;
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-bottom: 7%;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/Header.vue b/src/views/rangeNodeManage/nodeList/module/Header.vue
deleted file mode 100644
index f4c97c7..0000000
--- a/src/views/rangeNodeManage/nodeList/module/Header.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<template>
-<div class="head">
- <div class="role-select">
- <el-select v-model="role" clearable placeholder="节点角色" @change="query">
- <el-option
- v-for="item in roleDict"
- :key="item.value"
- :label="item.label"
- :value="item.value">
- <svg-icon :icon-class="item.value ? item.value : 'other'"></svg-icon>
- <span style="margin-left: 10px;">{{ item.label }}</span>
- </el-option>
- </el-select>
- </div>
- <div class="deploy-select">
- <el-select v-model="status" clearable placeholder="节点部署状态" @change="query">
- <el-option
- v-for="item in statusDict"
- :key="item.value"
- :label="item.label"
- :value="item.value">
- </el-option>
- </el-select>
- </div>
- <el-button v-if="false" type="primary" @click="batchConsole">批量控制台</el-button>
- <el-button v-if="true" type="primary" @click="batchDownload">批量下载文件</el-button>
- <el-button v-if="true" type="primary" @click="batchUpload">批量上传文件</el-button>
- <el-button v-if="true" type="primary" @click="batchCollectTraffic">批量采集流量</el-button>
-</div>
-</template>
-
-<script>
-export default {
- name: 'Header',
- data() {
- return {
- role: '',
- status: '',
- roleDict:[
- {label: '全部节点', value: ''},
- {label: '权威目录节点', value: 'da'},
- {label: '路由节点', value: 'relay'},
- {label: '出口节点', value: 'exit'},
- {label: '洋葱服务节点', value: 'onion'},
- {label: '客户端节点', value: 'client'},
- {label: '入口节点', value: 'guard'}
- ],
- statusDict: [
- {value: 'pending', label: '正在部署'},
- {value: 'false', label: '部署失败'},
- {value: 'complete',label: '部署完成'}
- ]
- }
- },
- methods: {
- // 查询
- query() {
- let params = {}
- if (this.role !== '') {
- params.role = this.role
- }
- if (this.status !== '') {
- params.status = this.status
- }
- this.$emit('query', params)
- },
- // 批量控制台
- batchConsole() {
- this.$emit('batchConsole')
- },
- // 批量下载文件
- batchDownload() {
- this.$emit('batchDownload')
- },
- // 批量上传文件
- batchUpload() {
- this.$emit('batchUpload')
- },
- // 批量采集流量
- batchCollectTraffic() {
- this.$emit('batchCollectTraffic')
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.head{
- width: 100%;
- height: 15%;
- margin-top: 1%;
- text-align: right;
-
- /*background-color: #5daf34;*/
- .block{
- display: inline-block;
- margin-left: 2%;
-
- }
- .input{
- display: inline-block;
- height: 60%;
- width: 10%;
- margin-left: 0.5%;
- .el-input::placeholder {
- width: auto;
- }
- .icon-group {
- display: flex; /* 设置容器为 Flexbox 容器 */
- align-items: center; /* 垂直居中图片 */
- gap: 5px; /* 图片和文字之间的间距,可以根据需要进行调整 */
-
- }
- .icon-group img {
- transform: scale(1);
- margin-right: 15px;
- margin-top: 6px;
- }
-
- }
- .deploy-select{
- display: inline-block;
- height: 60%;
- width: 10%;
- margin-top: 0.5%;
- margin-left: 0.5%;
- margin-right: 1%;
- .el-input::placeholder {
- width: auto;
- }
- .icon-group {
- display: flex; /* 设置容器为 Flexbox 容器 */
- align-items: center; /* 垂直居中图片 */
- gap: 5px; /* 图片和文字之间的间距,可以根据需要进行调整 */
- }
- .icon-group img {
- transform: scale(1);
- margin-right: 15px;
- margin-top: 6px;
- }
- }
- ::v-deep .role-select{
- display: inline-block;
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/nodeList/module/Upload.vue b/src/views/rangeNodeManage/nodeList/module/Upload.vue
deleted file mode 100644
index 987749c..0000000
--- a/src/views/rangeNodeManage/nodeList/module/Upload.vue
+++ /dev/null
@@ -1,285 +0,0 @@
-<template>
-<div class="console-dialog" v-if="visible">
- <i class="el-icon-close" @click="close"></i>
- <div class="tag">
- <el-tag class="tags" :style="{'color': (tag==='主节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('主节点')">主节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='被操作节点') ? '#f8fdff': '#565e6e'}" @click="updateTag('被操作节点')">被操作节点</el-tag>
- <el-tag class="tags" :style="{'color': (tag==='文件管理') ? '#f8fdff': '#565e6e'}" @click="updateTag('文件管理')">文件管理</el-tag>
- </div>
- <div class="basic-box" v-show="tag==='主节点'">
- <div class="tip-message">请选择主节点作为打开文件系统的依据</div>
- <div class="content">
- <!-- 主节点 -->
- <MainNode
- :node-list="nodeList"
- @selectMainNode="selectMainNode"
- ></MainNode>
- </div>
- <footer class="anDiv">
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">下一步</el-button>
- </footer>
- </div>
- <div class="basic-box" v-show="tag==='被操作节点'">
- <div class="tip-message">请勾选多个节点</div>
- <div class="content">
- <!-- 被操作节点 -->
- <OperateNode
- :node-list="nodeList"
- @selectOperateNode="selectOperateNode"
- ></OperateNode>
- </div>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('主节点')">上一步</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('文件管理')">下一步</el-button>
- </div>
- </div>
-
- </div>
- <div class="basic-box" v-if="tag==='文件管理'">
- <div class="tip-message" style="height: 76px;">
- <span>{{`主节点名称:${master_node_name}`}}<br/>{{`已勾选的节点名称列表:${batch_node_name_list.join('、')}`}}</span>
- </div>
- <!-- 文件管理 -->
- <FileManager
- ref="fileManager"
- ></FileManager>
- <div class="anDiv">
- <div>
- <el-button class="glBut" type="primary" @click="close">取消</el-button>
- <el-button class="glBut but-color" type="primary" @click="updateTag('被操作节点')">上一步</el-button>
- <label
- class="file-upload-button"
- for="file-input-upload"
- >
- <span>上传</span>
- <input
- type="file"
- id="file-input-upload"
- @change="submit"
- style="display: none;"
- />
- </label>
- </div>
- </div>
- </div>
-</div>
-</template>
-
-<script>
-import MainNode from '../components/MainNode.vue'
-import OperateNode from '../components/OperateNode.vue'
-import FileManager from '../components/UploadFileManager.vue'
-import qs from 'qs'
-export default {
- name: 'Upload',
- components:{
- MainNode,
- OperateNode,
- FileManager
- },
- props: {
- target_id: {
- typeof: String,
- required: true
- }
- },
- data() {
- return {
- nodeList: [],
- uploadForm: {
- master_node_id: '',
- batch_node_id_list: [],
- current_dir: ''
- },
- file: '',
- master_node_name: '',
- batch_node_name_list: [],
- visible:false,
- loading: false,
- tag:"主节点",
- form: {}
- }
- },
- methods: {
- // 获取节点列表
- getNodeList() {
- const reqParams = {
- page: 1,
- size: 99
- }
- if (this.target_id && this.target_id !== '') {
- reqParams.target_id = this.target_id
- }
- this.$axios.get(this.$http.api.getNodeList, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.nodeList = res?.result?.items
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {})
- },
- // 选择主节点
- selectMainNode({ id, nick_name }) {
- this.$store.commit('range/setNodeId', id)
- this.uploadForm.master_node_id = id
- this.master_node_name = nick_name
- },
- // 选择被操作节点
- selectOperateNode(selectRows) {
- this.batch_node_name_list = []
- this.uploadForm.batch_node_id_list = selectRows.map(row => {
- this.batch_node_name_list.push(row.nick_name)
- return row.id
- })
- },
- // // 选择上传文件
- // selectUploadFile({path}) {
- // this.uploadForm.current_dir = path
- // // this.file = file
- // },
- // 关闭
- close() {
- document.querySelector('.mask').style.display = 'none'
- this.visible = false
- this.tag = '主节点'
- this.resetForm()
- },
- // 重置
- resetForm() {
- this.form = {}
- },
- // 选择哪个页面
- updateTag(val){
- this.tag=val
- },
- // 提交数据
- submit(e) {
- this.uploadForm.current_dir = this.$refs.fileManager.selectNode.path
- this.file = e.target.files[0]
- const params = qs.stringify(this.uploadForm, { arrayFormat: 'repeat' })
- const url = this.$http.api.batchUpload + '?' + params
- const submitForm = new FormData()
- submitForm.append('file', this.file)
- this.loading = true
- this.$axios.postFormData(url, submitForm).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.$notify({
- title: '批量上传成功',
- type: 'success',
- duration: 2500
- })
- // 更新当前路径下的文件信息
- this.$refs.fileManager.updateCurrentPath()
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- })
- }
- }
-}
-</script>
-
-<style lang="less" scoped>
-.console-dialog{
- z-index: 997;
- width: 1331px;
- height: 800px;
- position: absolute; /* 绝对定位 */
- top: 50%; /* 向下偏移50% */
- left: 50%; /* 向右偏移50% */
- transform: translate(-50%, -50%); /* 回移50% */
- background-image:url('../../../../img/background/NodeListDialog.svg');
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- .el-icon-close{
- float: right;
- padding-right: 8%;
- padding-top: 1.8%
- }
- .tag{
- margin-left: 15%;
- .tags{
- margin-right: 5%;
- margin-top: 1%;
- font-size: 23px;
- border: none;
- background-color: transparent !important;
- color: #565e6e;
- }
- }
- .base-input {
- width: 100%;
- float: left;
- margin-top: 2%;
- text-align: center;
- }
- .label-span {
- margin-right: 3%;
- display: inline-block;
- width: 60px;
- text-align: right;
- }
- .but-color {
- background-color: #02DDEA !important;
- }
-
- .file-upload-button {
- display: inline-block;
- padding: 5px 33px;
- background-color: #02DDEA;
- color: #1b7cc4;
- border: none;
- border-radius: 0;
- cursor: pointer;
- font-size: 14px;
- }
- .file-upload-button:hover {
- background-color: #02DDEA;
- }
-
- .basic-box{
- width: 100%;
- min-height: 100%;
- display: flex;
- flex-direction: column;
- padding: 2%;
- .tip-message{
- width: 100%;
- height: 50px;
- text-align: left;
- padding: 11px 0 12px 20px;
- font-size: 20px;
- background-color: #1A2648;
- border-radius: 4px;
- margin-bottom: 2%;
- }
- .content {
- flex: 1;
- display: flex;
- flex-direction: row;
- }
- .anDiv{
- width: 100%;
- float: left;
- margin-bottom: 7%;
- text-align: center;
- .glBut{
- width: 90px;
- height: 30px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- margin-left: 5%;
- margin-right: 5%;
- background-color: rgba(24, 133, 234, 0.2);
- color: #1b7cc4;
- }
- }
- }
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/topologyMap/index.vue b/src/views/rangeNodeManage/topologyMap/index.vue
deleted file mode 100644
index 5b225f6..0000000
--- a/src/views/rangeNodeManage/topologyMap/index.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-<template>
- <div class="topology-map">
- <!-- <img class="img-topology" src="../../../img/background/topology.svg"> -->
- <div class="img-topology"></div>
- </div>
-</template>
-
-<script>
-export default {
- name: 'TopologyMap',
-}
-</script>
-
-<style lang='less' scoped>
- .topology-map {
- width: 49%;
- height: 100%;
- background-image:url('../../../img/backgroundFourCorner.png');
- background-repeat: no-repeat;
- background-size: 100% 100%;
- }
- .img-topology {
- width: 100%;
- height: 100%;
- background-image:url('../../../img/background/topology.svg');
- background-position: center center;
- background-repeat: no-repeat;
- background-size: contain;
- }
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/worldMap/Map.vue b/src/views/rangeNodeManage/worldMap/Map.vue
deleted file mode 100644
index 1a8e0d2..0000000
--- a/src/views/rangeNodeManage/worldMap/Map.vue
+++ /dev/null
@@ -1,217 +0,0 @@
-<template>
-<div class='wrapper' v-loading="loading">
- <div class='chart' id='chart' style="width: 100%; height: 100%;"></div>
-</div>
-</template>
-
-<script>
-import { getTargetsResponse } from './mock.js'
-export default {
- data () {
- return {
- loading: false,
- worldChart: {},
- target_id: '',
- NodeList: [],
- namemap: {},
- geoCoordMap: {}
- }
- },
- props:{
- },
- watch: {
- '$store.state.range.targetId': {
- handler(newVal, oldVal) {
- this.target_id = newVal
- this.init()
- },
- immediate: true
- }
- },
- created() {
- },
- mounted () {
- },
- methods: {
- init() {
- this.initData()
- },
- initData() {
- // 获取world.json里面国家数据和坐标数据
- var json = require('/src/api/world.json')
- this.geoCoordMap = json.trapeze
- this.namemap = json.namemap
- // 获取接口节点数据
- // this.NodeList = getTargetsResponse?.result
-
- const reqParams = {}
- if (this.target_id && this.target_id !== '') {
- reqParams.target_id = this.target_id
- }
- this.loading = true
- this.$axios.get(this.$http.api.worldMap, reqParams).then(res => {
- if (res.code == 200 || res.code == "OK") {
- this.NodeList = res?.result
- }
- }).catch(err => {
- console.log(err)
- }).finally(() => {
- this.loading = false
- this.initWorldMap(this.namemap, this.geoCoordMap)
- })
- },
- initWorldMap(namemap, geoCoordMap) {
- // var that = this
- // 获取echarts的容器
- this.worldChart = this.$echarts.init(document.getElementById("chart"));
- var pointData = this.NodeList
- var series = [];
- [[, pointData]].forEach(function (item, i) {
- series.push({
- type: "effectScatter",
- coordinateSystem: "geo",
- zlevel: 2,
- rippleEffect: {
- //涟漪特效
- period: 4, //动画时间,值越小速度越快
- brushType: "stroke", //波纹绘制方式 stroke, fill
- scale: 4
- //波纹圆环最大限制,值越大波纹越大
- },
- label: {
- normal: {
- show: true,
- position: "right", //显示位置
- offset: [5, 0], //偏移设置
- formatter: "{b}" //圆环显示文字
- },
- emphasis: {
- show: true
- }
- },
- symbol: "circle",
- symbolSize: function (val) {
- return 5; //圆环大小
- },
- data: item[1].map(dataItem => {
- let countryName = ''
- for (let key in namemap) {
- if(key.toLowerCase() === dataItem.country.replace('-', ' ').toLowerCase()) {
- countryName = namemap[key]
- }
- }
- const location = [Number(dataItem.location_info.longitude), Number(dataItem.location_info.latitude), dataItem.id]
- return {
- name: dataItem.nick_name,
- value: location,
- nodeInfo: dataItem
- }
- })
- });
- });
-
- let option = {
- // backgroundColor: '#000',
- // 图表主标题
- title: {
- text: '世界地图展示各节点位置', // 主标题文本,支持使用 \n 换行
- top: 5, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
- left: 'left', // 值: 'left', 'center', 'right' 同上
- textStyle: { // 文本样式
- fontSize: 14,
- fontWeight: 400,
- color: '#ffffff'
- }
- },
- //悬浮提示
- tooltip: {
- trigger: "item",
- // backgroundColor: "#1540a1",
- borderColor: "#FFFFFF",
- showDelay: 0,
- hideDelay: 0,
- // enterable: true,
- transitionDuration: 0,
- // extraCssText: "z-index:100",formatter
- formatter: function (params, ticket, callback) {
- // console.log(params)
- //根据业务自己拓展要显示的内容
- var res = "";
- const { name, value, nodeInfo } = params.data
- res = "<span style='display:inline-block; text-align:left;'>id:" + value[2]
- + "<br/>昵称:" + name.toString()
- + "<br/>国家:" + nodeInfo.location_info.country
- + "<br/>ip:" + nodeInfo.ip
- + "<br/>经纬度:" + value[0] + ',' + value[1]
- + "</span>";
- return res;
- }
- },
- visualMap: {
- //图例值控制
- show: false,
- min: 0,
- max: 1000,
- text:['max','min'],
- realtime: false,
- calculable: true,
- color: ['orangered']
- // color: ['#0064d0','#c3e0ff'],
- },
- geo: {
- map: "world",
- label: {
- emphasis: {
- show: false
- }
- },
- roam: true, //是否允许缩放
- layoutCenter: ["50%", "50%"], //地图位置
- layoutSize: "180%",
- itemStyle: {
- normal: {
- areaColor: '#0064d0', //地图背景色
- // color: ["#04284e"], //地图背景色
- borderColor: "#5bc1c9" //省市边界线
- },
- emphasis: {
- color: "rgba(37, 43, 61, .5)" //选中区域的颜色
- // areaColor: '#3742ff' // 选中区域的颜色
- }
- },
- nameMap: this.namemap
- },
- series: series,
- loading: true // 开启Loading效果
- };
- this.worldChart.setOption(option);
- //点击事件,根据点击某个节点跳转到节点详情页
- this.worldChart.on("click", params => {
- if (params.value) {
- this.$store.commit('range/setNodeId', params.value[2])
- //保存是否正在采集流量
- this.$store.commit('node/setStartTraffic', params?.data?.nodeInfo?.collecting)
- //保存是否正在结束采集流量
- this.$store.commit('node/setEndTraffic', params?.data?.nodeInfo?.analysing)
- this.$router.push({ name: 'nodeDetail'})
- }
- });
- }
- // drawChart () {
- // this.initWorldMap(this.namemap, this.geoCoordMap)
- // }
- }
-}
-</script>
-<style lang="less" scoped>
-.wrapper {
- width: 100%;
- height: 100%;
-}
-.wrapper .chart {
- width: 100%;
- margin:0 auto;
- height: 100%;
- background-size: 100% 100%;
-}
-</style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/worldMap/index.vue b/src/views/rangeNodeManage/worldMap/index.vue
deleted file mode 100644
index d4da6c0..0000000
--- a/src/views/rangeNodeManage/worldMap/index.vue
+++ /dev/null
@@ -1,68 +0,0 @@
-<template>
- <div :class="['world-map', {'is--maximize': isFullscreen}]">
- <Map ref="worldMap"></Map>
- <span class="icon-span" slot="label">
- <svg-icon class="icon-zoom" :icon-class="fullscreenIcon" @click="zoomEvent"></svg-icon>
- </span>
- </div>
- </template>
-
- <script>
- import Map from './Map'
- export default {
- name: 'WorldMap',
- components: { Map },
- data() {
- return {
- isFullscreen: false,
- fullscreenIcon: 'fullscreen'
- }
- },
- methods: {
- zoomEvent() {
- this.isFullscreen = !this.isFullscreen
- this.fullscreenIcon = this.isFullscreen ? 'narrow' : 'fullscreen'
- this.$nextTick(() => {
- this.$refs.worldMap.worldChart.resize()
- })
- },
- }
-
- }
- </script>
-
- <style lang='less' scoped>
- .world-map {
- position: relative;
- width: 49%;
- height: 100%;
- background-image:url('../../../img/backgroundFourCorner.png');
- background-repeat: no-repeat;
- background-size: 100% 100%;
- .icon-span {
- position: absolute;
- top: 10px;
- right: -10px;
- padding: 12px 20px;
- .icon-zoom {
- font-size: 30px;
- color: #02DDEA;
- margin: 0 15px;
- }
- }
- }
- .is--maximize {
- position: fixed;
- top: 0;
- left: 0;
- width: 100% !important;
- height: 100% !important;
- padding: 0.5em 1em;
- // background-color: #17234e;
- background: url(../../../img/background/bgMain.svg);
- background-repeat: no-repeat; /* 可选,防止图像重复 */
- background-position: center; /* 居中显示 */
- background-size: cover; /* 宽度为100%,高度自适应保持宽高比 */
- z-index: 1000;
- }
- </style> \ No newline at end of file
diff --git a/src/views/rangeNodeManage/worldMap/mock.js b/src/views/rangeNodeManage/worldMap/mock.js
deleted file mode 100644
index 0ba865a..0000000
--- a/src/views/rangeNodeManage/worldMap/mock.js
+++ /dev/null
@@ -1,113 +0,0 @@
-const getTargetsResponse = {
- "code": 200,
- "message": "success",
- "result": [
- {
- "setting_id": 1,
- "traffic_collect_task_id": null,
- "id": 1,
- "ip": "171.25.193.64",
- "pod_name": "target-1-da-1-6cddf4649d-mfpx7",
- "nick_name": "daoranjcqlil",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:32",
- "complete_time": "2023-12-29T19:00:17",
- "role": "da",
- "country": "sweden",
- "cidr": "171.25.193.0/24"
- },
- {
- "setting_id": 2,
- "traffic_collect_task_id": null,
- "id": 2,
- "ip": "193.31.27.64",
- "pod_name": "target-1-relay-2-8df66cb66-slhnv",
- "nick_name": "relayjknwkekrof",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:34",
- "complete_time": "2023-12-29T19:05:01",
- "role": "relay",
- "country": "germany",
- "cidr": "193.31.27.0/24"
- },
- {
- "setting_id": 3,
- "traffic_collect_task_id": null,
- "id": 3,
- "ip": "80.228.207.64",
- "pod_name": "target-1-relay-3-6f57bf5448-snwgk",
- "nick_name": "relayuyunnharjw",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:36",
- "complete_time": "2023-12-29T19:05:00",
- "role": "relay",
- "country": "germany",
- "cidr": "80.228.207.0/24"
- },
- {
- "setting_id": 4,
- "traffic_collect_task_id": null,
- "id": 4,
- "ip": "116.202.169.64",
- "pod_name": "target-1-relay-4-557dcdfbd7-4lx5p",
- "nick_name": "relayslwwaewlzs",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:38",
- "complete_time": "2023-12-29T19:04:00",
- "role": "relay",
- "country": "germany",
- "cidr": "116.202.169.0/24"
- },
- {
- "setting_id": 6,
- "traffic_collect_task_id": null,
- "id": 6,
- "ip": "84.19.188.64",
- "pod_name": "target-1-relay-6-8559fc5858-j2v5m",
- "nick_name": "relayzvrsfipwmd",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:46",
- "complete_time": "2023-12-29T19:08:06",
- "role": "relay",
- "country": "germany",
- "cidr": "84.19.188.0/24"
- },
- {
- "setting_id": 7,
- "traffic_collect_task_id": null,
- "id": 7,
- "ip": "45.138.16.0",
- "pod_name": "target-1-exit-7-78984bf859-2hmnc",
- "nick_name": "exitpzidrsshzi",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:48",
- "complete_time": "2023-12-29T19:07:12",
- "role": "exit",
- "country": "netherlands",
- "cidr": "45.138.16.0/24"
- },
- {
- "setting_id": 8,
- "traffic_collect_task_id": null,
- "id": 8,
- "ip": "77.91.68.64",
- "pod_name": "target-1-exit-8-865cf99948-gw7br",
- "nick_name": "exitgqnnvqsoux",
- "status": "complete",
- "onion": null,
- "create_time": "2023-12-29T18:50:49",
- "complete_time": "2023-12-29T19:04:56",
- "role": "exit",
- "country": "russia",
- "cidr": "77.91.68.0/24"
- }
- ]
-}
-
-export { getTargetsResponse } \ No newline at end of file