Initial commit
This commit is contained in:
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,23 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
node_modules
|
|
||||||
/dist
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
|
|
||||||
# Log files
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
package-lock.json
|
|
||||||
10988
package-lock.json
generated
Normal file
10988
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,16 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<!-- 兼容旧版IE浏览器 -->
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<!-- 显示窗口的设置 -->
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<title>DNS</title>
|
<title>DNS</title>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.g = {
|
window.g = {
|
||||||
// baseURL:'172.16.0.120:31540', //开发环境
|
// baseURL:'172.16.0.120:31540', //开发环境
|
||||||
baseURL: '124.221.228.62:2525', //正式环境
|
// baseURL: '124.221.228.62:2525', //正式环境
|
||||||
|
baseURL: '124.221.228.62:12526', //正式环境
|
||||||
// queryTags:[],
|
// queryTags:[],
|
||||||
// switchLanguage:"en",
|
// switchLanguage:"en",
|
||||||
switchLanguage:"zh"
|
switchLanguage:"zh"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export default {
|
|||||||
//目标信息获取
|
//目标信息获取
|
||||||
targetQueryList:'/target/',
|
targetQueryList:'/target/',
|
||||||
targetMap:'target/map',
|
targetMap:'target/map',
|
||||||
|
targetNodes: 'target/nodes',
|
||||||
//目标信息筛选基础数据
|
//目标信息筛选基础数据
|
||||||
targetFilter:'/target/filter',
|
targetFilter:'/target/filter',
|
||||||
//目标信息时延
|
//目标信息时延
|
||||||
|
|||||||
1
src/api/world_v2.json
Normal file
1
src/api/world_v2.json
Normal file
File diff suppressed because one or more lines are too long
@@ -33,6 +33,7 @@ export default {
|
|||||||
if (!appRef) return
|
if (!appRef) return
|
||||||
// 当前宽高比
|
// 当前宽高比
|
||||||
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
|
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
|
||||||
|
console.log("currentSize: ", window.innerWidth, "++++", window.innerHeight)
|
||||||
if (appRef) {
|
if (appRef) {
|
||||||
if (currentRate > baseProportion) {
|
if (currentRate > baseProportion) {
|
||||||
// 表示更宽
|
// 表示更宽
|
||||||
|
|||||||
BIN
src/img/logo2.png
Normal file
BIN
src/img/logo2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
src/img/logo_new.png
Normal file
BIN
src/img/logo_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 402 KiB |
BIN
src/img/logo_new_2.png
Normal file
BIN
src/img/logo_new_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 395 KiB |
@@ -3,16 +3,17 @@
|
|||||||
<div class="headNew" >
|
<div class="headNew" >
|
||||||
<div class="headNewLeft" >
|
<div class="headNewLeft" >
|
||||||
<div class="headNewLeftText">
|
<div class="headNewLeftText">
|
||||||
<!-- <span>YYDNS</span>-->
|
<!-- YYDNS图标 -->
|
||||||
<!-- <img src="../img/logyy.jpg">-->
|
<!-- <img src="../img/logo2.png" style="width: 300px;margin-top:1%"> -->
|
||||||
<img src="../img/logyy_美图抠图20240424.png" style="width: 180px">
|
<!-- 信工所 + DNS 图标 -->
|
||||||
|
<img src="../img/logo_new_2.png" style="width: 300px;margin-top:6%;margin-left:10%">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="headNewCenter" >
|
<!-- <div class="headNewCenter" >
|
||||||
<div class="headNewCenterText">
|
<div class="headNewCenterText">
|
||||||
<span style="color: rgb(0,0,0,0);">{{ title || 'Dashboard' }}</span>
|
<span style="color: rgb(0,0,0,0);">{{ title || 'Dashboard' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="headNewRight" >
|
<div class="headNewRight" >
|
||||||
<div class="headNewRightAll" >
|
<div class="headNewRightAll" >
|
||||||
<img src="../img/user.png" style="margin-top: 0.5%;height: 10%;width: 10%">
|
<img src="../img/user.png" style="margin-top: 0.5%;height: 10%;width: 10%">
|
||||||
@@ -32,9 +33,6 @@
|
|||||||
export default {
|
export default {
|
||||||
name: "AppHeader",
|
name: "AppHeader",
|
||||||
props:['title','fTag','fInput','fFrom','FIsConfigQuery'],
|
props:['title','fTag','fInput','fFrom','FIsConfigQuery'],
|
||||||
// components:{
|
|
||||||
// router
|
|
||||||
// },
|
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
userName: localStorage.getItem('username'),
|
userName: localStorage.getItem('username'),
|
||||||
@@ -81,12 +79,6 @@
|
|||||||
rules:{
|
rules:{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (sessionStorage.getItem('switchLanguage') !== null) {
|
if (sessionStorage.getItem('switchLanguage') !== null) {
|
||||||
@@ -109,7 +101,6 @@
|
|||||||
// this.getallLanguage()
|
// this.getallLanguage()
|
||||||
// this.getallTags()
|
// this.getallTags()
|
||||||
// this.getallWebs()
|
// this.getallWebs()
|
||||||
|
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
logOut() {
|
logOut() {
|
||||||
@@ -119,7 +110,6 @@
|
|||||||
this.$router.push({path:'/'})
|
this.$router.push({path:'/'})
|
||||||
},
|
},
|
||||||
ChangeLanguage(){
|
ChangeLanguage(){
|
||||||
|
|
||||||
if(this.switchLanguage==='en'){
|
if(this.switchLanguage==='en'){
|
||||||
// console.log("当前为英文页面 要换成中文页面")
|
// console.log("当前为英文页面 要换成中文页面")
|
||||||
sessionStorage.setItem("switchLanguage","zh");
|
sessionStorage.setItem("switchLanguage","zh");
|
||||||
@@ -338,7 +328,8 @@
|
|||||||
/*margin-top: 3.1%;*/
|
/*margin-top: 3.1%;*/
|
||||||
margin-top: -8%;
|
margin-top: -8%;
|
||||||
/*margin-left: 35%;*/
|
/*margin-left: 35%;*/
|
||||||
margin-left: 10%;
|
margin-left: 5%;
|
||||||
|
float: left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.headNewCenter{
|
.headNewCenter{
|
||||||
@@ -351,7 +342,6 @@
|
|||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
margin-top: 1.6%;
|
margin-top: 1.6%;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.headNewRight{
|
.headNewRight{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import 'element-ui/lib/theme-chalk/index.css';
|
|||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import { Message, Notification } from 'element-ui';
|
import { Message, Notification } from 'element-ui';
|
||||||
|
|
||||||
|
// // 引入 Echarts 和世界地图数据
|
||||||
|
import 'echarts/map/js/world.js'
|
||||||
|
|
||||||
Vue.use(ElementUI);
|
Vue.use(ElementUI);
|
||||||
import './assets/css/iconfont/iconfont.css'
|
import './assets/css/iconfont/iconfont.css'
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
bing: {
|
bing: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
console.log(val)
|
console.log("val: " + val)
|
||||||
this.bingfn(val)
|
this.bingfn(val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -63,18 +63,53 @@
|
|||||||
myChart1.off('mouseover')
|
myChart1.off('mouseover')
|
||||||
|
|
||||||
var option = {
|
var option = {
|
||||||
animation:false, //动态展示
|
baseOption: {
|
||||||
|
timeline: {
|
||||||
|
axisType: 'category', // 轴的类型
|
||||||
|
show: true, // 显示组件
|
||||||
|
autoPlay: true, // 自动播放
|
||||||
|
playInterval: 5000, // 播放间隔
|
||||||
|
data: ['IPv6', 'DNSSEC', 'DoT', 'DoH'],
|
||||||
|
top:'3%', // timeline组件离容器上侧的距离
|
||||||
|
left:'30%',
|
||||||
|
right:'30%',
|
||||||
|
symbol: 'none', // 设置标记的图形
|
||||||
|
lineStyle: {
|
||||||
|
show: false // 不显示轴线
|
||||||
|
},
|
||||||
|
controlStyle: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#DCDCDC'
|
||||||
|
},
|
||||||
|
checkpointStyle: { // 『当前项』(checkpoint)的图形样式
|
||||||
|
symbol: 'none',
|
||||||
|
},
|
||||||
|
progress: {
|
||||||
|
label: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bolder',
|
||||||
|
color: '#F5F5F5'
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
fontSize: 20,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '5%',
|
left: '5%',
|
||||||
right: '5%',
|
right: '5%',
|
||||||
bottom: '5%',
|
bottom: '5%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
// title: {
|
xAxis: [
|
||||||
// text:"898989"
|
{
|
||||||
// },
|
|
||||||
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
type: 'category',
|
||||||
data: data.xdata,
|
data: data.xdata,
|
||||||
// data: ["2024-1-1","2024-1-2","2024-1-3","2024-1-4","2024-1-5","2024-1-6","2024-1-7"],
|
// data: ["2024-1-1","2024-1-2","2024-1-3","2024-1-4","2024-1-5","2024-1-6","2024-1-7"],
|
||||||
@@ -87,15 +122,43 @@
|
|||||||
interval:0,
|
interval:0,
|
||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
// tooltip: {
|
|
||||||
// trigger: 'axis',
|
],
|
||||||
// // 添加样式
|
yAxis: [
|
||||||
// textStyle: {
|
{
|
||||||
// textAlign: 'left' // 内容左对齐
|
type: 'value',
|
||||||
|
name: '数量统计(个)', // 水量单位
|
||||||
|
position: 'left', // 显示在左侧
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: "rgb(255,16,18)",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f4f2fd'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'value',
|
||||||
|
// name: '总量统计(个)', // 数量单位
|
||||||
|
// position: 'right', // 显示在右侧
|
||||||
|
// splitLine: {
|
||||||
|
// show: false,
|
||||||
|
// lineStyle: {
|
||||||
|
// color: "rgb(255,16,18)",
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
|
// axisLine: {
|
||||||
|
// lineStyle: {
|
||||||
|
// color: '#f4be6a'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
@@ -114,77 +177,16 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
yAxis: [
|
},
|
||||||
|
|
||||||
|
options: [
|
||||||
|
// IPv6
|
||||||
{
|
{
|
||||||
type: 'value',
|
|
||||||
name: '分类统计(个)', // 水量单位
|
|
||||||
position: 'left', // 显示在左侧
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
lineStyle: {
|
|
||||||
color: "rgb(255,16,18)",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#f4f2fd'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'value',
|
|
||||||
name: '总量统计(个)', // 数量单位
|
|
||||||
position: 'right', // 显示在右侧
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
lineStyle: {
|
|
||||||
color: "rgb(255,16,18)",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#f4be6a'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// yAxis: {
|
|
||||||
// type: 'value',
|
|
||||||
// splitLine: {//分割线配置
|
|
||||||
// show:false,
|
|
||||||
// lineStyle: {
|
|
||||||
// color: "rgb(255,16,18)",
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// axisLine:{
|
|
||||||
// lineStyle:{
|
|
||||||
// color:'#fdc909'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// yAxis:[
|
|
||||||
// {
|
|
||||||
// type:'value',
|
|
||||||
// name:'分类数量',
|
|
||||||
// interval: 5,
|
|
||||||
// axisLabel: {
|
|
||||||
// formatter:'{value}个'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type:'value',
|
|
||||||
// name:'总量',
|
|
||||||
// interval: 5,
|
|
||||||
// axisLabel: {
|
|
||||||
// formatter:'{value}个'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// ],
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name:'IPv6',
|
name:'IPv6',
|
||||||
barWidth: 20, //柱子宽度
|
barWidth: 45, //柱子宽度
|
||||||
data:data.ydata1,
|
data:data.ydata1,
|
||||||
// data:[45,89,56,58,66,12,96],
|
// data:[45,89,56,58,66,12,96],
|
||||||
color:["#2386bf"], //自定义颜色
|
color:["#2386bf"], //自定义颜色
|
||||||
@@ -196,11 +198,15 @@
|
|||||||
return params.value;
|
return params.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// DNS
|
||||||
|
{
|
||||||
|
series: [
|
||||||
{
|
{
|
||||||
name:'DNS',
|
name:'DNS',
|
||||||
barWidth: 20, //柱子宽度
|
barWidth: 45, //柱子宽度
|
||||||
data:data.ydata2,
|
data:data.ydata2,
|
||||||
// data:[450,890,560,580,660,155,85],
|
// data:[450,890,560,580,660,155,85],
|
||||||
color:["#434ff4"], //自定义颜色
|
color:["#434ff4"], //自定义颜色
|
||||||
@@ -212,11 +218,15 @@
|
|||||||
return params.value;
|
return params.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// DoT
|
||||||
|
{
|
||||||
|
series: [
|
||||||
{
|
{
|
||||||
name:'DoT',
|
name:'DoT',
|
||||||
barWidth: 20, //柱子宽度
|
barWidth: 45, //柱子宽度
|
||||||
data:data.ydata3,
|
data:data.ydata3,
|
||||||
// data:[150,290,560,380,660,105,815],
|
// data:[150,290,560,380,660,105,815],
|
||||||
color:["rgba(58,76,222,0.89)"], //自定义颜色
|
color:["rgba(58,76,222,0.89)"], //自定义颜色
|
||||||
@@ -228,11 +238,15 @@
|
|||||||
return params.value;
|
return params.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// DoH
|
||||||
|
{
|
||||||
|
series: [
|
||||||
{
|
{
|
||||||
name:'DoH',
|
name:'DoH',
|
||||||
barWidth: 20, //柱子宽度
|
barWidth: 45, //柱子宽度
|
||||||
data:data.ydata4,
|
data:data.ydata4,
|
||||||
// data:[650,790,560,180,660,15,85],
|
// data:[650,790,560,180,660,15,85],
|
||||||
color:["#117cf4"], //自定义颜色
|
color:["#117cf4"], //自定义颜色
|
||||||
@@ -244,27 +258,14 @@
|
|||||||
return params.value;
|
return params.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
]
|
||||||
,
|
|
||||||
{
|
|
||||||
name:'总量',
|
|
||||||
barWidth: 20, //柱子宽度
|
|
||||||
data:data.ydata5,
|
|
||||||
// data:[1120,7090,5660,1800,6060,105,805],
|
|
||||||
color:["#f4be6a"], //自定义颜色
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 1,
|
|
||||||
label:{
|
|
||||||
show:true,
|
|
||||||
position:'top',
|
|
||||||
formatter:function (params) {
|
|
||||||
return params.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
]
|
||||||
],
|
|
||||||
|
//#region
|
||||||
|
/*
|
||||||
graphic: [
|
graphic: [
|
||||||
{
|
{
|
||||||
type:'group',
|
type:'group',
|
||||||
@@ -388,14 +389,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
*/
|
||||||
|
//#endregion
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
myChart1.setOption(option,true)
|
myChart1.setOption(option,true)
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
myChart1.resize();
|
myChart1.resize();
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default {
|
|||||||
components: { TargetView, ImageView, SourceView, NodeView }
|
components: { TargetView, ImageView, SourceView, NodeView }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.home {
|
.home {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<!-- 点击YYDNS前 -->
|
||||||
<div class="login" ref="appRef" v-if="label==false">
|
<div class="login" ref="appRef" v-if="label==false">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<p class="title" style="font-size: 48px;margin-top: 20%" @click="label=!label">进入YYDNS系统</p>
|
<p class="title" style="font-size: 48px;margin-top: 20%" @click="label=!label">进入YYDNS系统</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 点击YYDNS后 -->
|
||||||
<div class="login" ref="appRef" v-if="label==true">
|
<div class="login" ref="appRef" v-if="label==true">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<p class="title">登录到</p>
|
<p class="title">登录到</p>
|
||||||
|
|||||||
75
src/views/menuMBZTGZ/echarts/nodewordmap.vue
Normal file
75
src/views/menuMBZTGZ/echarts/nodewordmap.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 100%;height: 100%;">
|
||||||
|
<div style="width: 100%;height: 10%"><span style="margin-top: 1%;font-size: 20px;margin-left: 2%;float: left">节点分布</span></div>
|
||||||
|
<div ref="worldmap" style="width: 100%;height: 90%"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
|
const worldJson = require("../../../api/world_v2.json")
|
||||||
|
export default {
|
||||||
|
name: "WorldMap",
|
||||||
|
props: {
|
||||||
|
nodes:{
|
||||||
|
type: Array,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
nodes: {
|
||||||
|
deep: true,
|
||||||
|
handler(val) {
|
||||||
|
console.log(val)
|
||||||
|
this.drawMap(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 调整节点信息格式
|
||||||
|
getInfo(){
|
||||||
|
return this.nodes.map(node => {
|
||||||
|
return [node.Lng, node.Lat]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 绘制世界地图
|
||||||
|
drawMap(){
|
||||||
|
// 初始化myChart
|
||||||
|
var myChart = echarts.init(this.$refs.worldmap)
|
||||||
|
// 注册可用的地图
|
||||||
|
echarts.registerMap('world', worldJson)
|
||||||
|
var option = {
|
||||||
|
tooltip: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
geo: {
|
||||||
|
tooltip: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
map: 'world', // 使用registerMap注册的地图名称
|
||||||
|
roam: true, // 开启鼠标缩放和平移漫游
|
||||||
|
},
|
||||||
|
series: {
|
||||||
|
type: 'effectScatter',
|
||||||
|
coordinateSystem: 'geo',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#b02a02'
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
tooltip: 2
|
||||||
|
},
|
||||||
|
data: this.getInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myChart.setOption(option)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.drawMap()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped="scoped">
|
||||||
|
</style>
|
||||||
@@ -62,6 +62,100 @@
|
|||||||
myChart1.clear()
|
myChart1.clear()
|
||||||
myChart1.off('mouseover')
|
myChart1.off('mouseover')
|
||||||
|
|
||||||
|
|
||||||
|
var option = {
|
||||||
|
// dataset: {
|
||||||
|
// source: data.xdata
|
||||||
|
// },
|
||||||
|
grid: {
|
||||||
|
left: '5%',
|
||||||
|
right: '5%',
|
||||||
|
bottom: '5%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: data.xdata,
|
||||||
|
// data: ["2024-1-1","2024-1-2","2024-1-3","2024-1-4","2024-1-5","2024-1-6","2024-1-7"],
|
||||||
|
axisLine:{
|
||||||
|
lineStyle:{
|
||||||
|
color:'#f6fbfd'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel:{
|
||||||
|
interval:0,
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
},
|
||||||
|
// 使用 formatter 函数设置内容和样式
|
||||||
|
formatter: function(params) {
|
||||||
|
var result = '<div style="text-align:left;">'; // 左对齐样式
|
||||||
|
result += params[0].name + '<br>'; // 添加横坐标名称
|
||||||
|
|
||||||
|
params.forEach(function(item) {
|
||||||
|
result += item.marker + ' ' + item.seriesName + ': ' + item.value + '<br>'; // 添加数据项
|
||||||
|
});
|
||||||
|
|
||||||
|
result += '</div>';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '时延(ms)',
|
||||||
|
position: 'left', // 显示在左侧
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: "rgb(255,16,18)",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f4f2fd'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
visualMap: {
|
||||||
|
orient: 'horizontal', // 组件布局方向
|
||||||
|
top: '1%',
|
||||||
|
right: '5%', // 组件位置
|
||||||
|
min:0,
|
||||||
|
max:800, // 映射数据范围
|
||||||
|
// text: ['High Score', 'Low Score'],
|
||||||
|
dimension: 1, // 映射数据的维度
|
||||||
|
inRange: {
|
||||||
|
color: ['#11da11', '#E15457']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name:'时延',
|
||||||
|
barWidth: 20, //柱子宽度
|
||||||
|
data:data.ydata1,
|
||||||
|
// data:[45,89,56,58,66,12,96],
|
||||||
|
color:["#2386bf"], //自定义颜色
|
||||||
|
type: 'bar',
|
||||||
|
label:{
|
||||||
|
show:true,
|
||||||
|
position:'top',
|
||||||
|
formatter:function (params) {
|
||||||
|
return params.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
var option = {
|
var option = {
|
||||||
animation:false, //动态展示
|
animation:false, //动态展示
|
||||||
grid: {
|
grid: {
|
||||||
@@ -88,6 +182,7 @@
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
@@ -267,6 +362,7 @@
|
|||||||
//
|
//
|
||||||
// ]
|
// ]
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,419 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div style="width: 100%;height: 100%;">
|
|
||||||
<div style="width: 100%;height: 10%"><span style="margin-top: 1%;font-size: 20px;margin-left: 2%;float: left">时延报警</span></div>
|
|
||||||
<div ref="bingbox" style="width: 100%;height: 90%"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import * as echarts from 'echarts';
|
|
||||||
var myChart1=null
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
bing:{
|
|
||||||
type:Object,
|
|
||||||
default: function() {
|
|
||||||
return {
|
|
||||||
data:[],
|
|
||||||
// signdata: [],
|
|
||||||
// title:"",
|
|
||||||
// bingtype:'',
|
|
||||||
// AreaName:[],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
active:{
|
|
||||||
type:Number,
|
|
||||||
default: function() {
|
|
||||||
return {
|
|
||||||
active:""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
bing: {
|
|
||||||
deep: true,
|
|
||||||
handler(val) {
|
|
||||||
console.log(val)
|
|
||||||
this.bingfn(val)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
bingfn(data){
|
|
||||||
console.log(data)
|
|
||||||
let that = this
|
|
||||||
//当前视口宽度
|
|
||||||
let nowClientWidth = document.documentElement.clientWidth;
|
|
||||||
// 换算方法
|
|
||||||
let nowSize = function (val, initWidth = 1920) {
|
|
||||||
return val * (nowClientWidth / initWidth);
|
|
||||||
};
|
|
||||||
if (myChart1 != null) {
|
|
||||||
myChart1.clear()//销毁
|
|
||||||
}
|
|
||||||
myChart1= echarts.init(this.$refs.bingbox)
|
|
||||||
myChart1.clear()
|
|
||||||
myChart1.off('mouseover')
|
|
||||||
|
|
||||||
// var option = {
|
|
||||||
// animation:false, //动态展示
|
|
||||||
// grid: {
|
|
||||||
// left: '5%',
|
|
||||||
// right: '5%',
|
|
||||||
// bottom: '5%',
|
|
||||||
// containLabel: true
|
|
||||||
// },
|
|
||||||
// xAxis: {
|
|
||||||
// type: 'category',
|
|
||||||
// data: data.xdata,
|
|
||||||
// // data: ["2024-1-1","2024-1-2","2024-1-3","2024-1-4","2024-1-5","2024-1-6","2024-1-7"],
|
|
||||||
// axisLine:{
|
|
||||||
// lineStyle:{
|
|
||||||
// color:'#f6fbfd'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// axisLabel:{
|
|
||||||
// interval:0,
|
|
||||||
// show: true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// tooltip: {
|
|
||||||
// trigger: 'axis',
|
|
||||||
// axisPointer: {
|
|
||||||
// type: 'shadow'
|
|
||||||
// },
|
|
||||||
// // 使用 formatter 函数设置内容和样式
|
|
||||||
// formatter: function(params) {
|
|
||||||
// var result = '<div style="text-align:left;">'; // 左对齐样式
|
|
||||||
// result += params[0].name + '<br>'; // 添加横坐标名称
|
|
||||||
//
|
|
||||||
// params.forEach(function(item) {
|
|
||||||
// result += item.marker + ' ' + item.seriesName + ': ' + item.value + '<br>'; // 添加数据项
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// result += '</div>';
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// yAxis: [
|
|
||||||
// {
|
|
||||||
// type: 'value',
|
|
||||||
// name: '分类统计(个)', // 水量单位
|
|
||||||
// position: 'left', // 显示在左侧
|
|
||||||
// splitLine: {
|
|
||||||
// show: false,
|
|
||||||
// lineStyle: {
|
|
||||||
// color: "rgb(255,16,18)",
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// axisLine: {
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#f4f2fd'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'value',
|
|
||||||
// name: '总量统计(个)', // 数量单位
|
|
||||||
// position: 'right', // 显示在右侧
|
|
||||||
// splitLine: {
|
|
||||||
// show: false,
|
|
||||||
// lineStyle: {
|
|
||||||
// color: "rgb(255,16,18)",
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// axisLine: {
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#f4be6a'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// series: [
|
|
||||||
// {
|
|
||||||
// name:'IPv6',
|
|
||||||
// barWidth: 20, //柱子宽度
|
|
||||||
// data:data.ydata1,
|
|
||||||
// // data:[45,89,56,58,66,12,96],
|
|
||||||
// color:["#2386bf"], //自定义颜色
|
|
||||||
// type: 'bar',
|
|
||||||
// label:{
|
|
||||||
// show:true,
|
|
||||||
// position:'top',
|
|
||||||
// formatter:function (params) {
|
|
||||||
// return params.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name:'DNS',
|
|
||||||
// barWidth: 20, //柱子宽度
|
|
||||||
// data:data.ydata2,
|
|
||||||
// // data:[450,890,560,580,660,155,85],
|
|
||||||
// color:["#434ff4"], //自定义颜色
|
|
||||||
// type: 'bar',
|
|
||||||
// label:{
|
|
||||||
// show:true,
|
|
||||||
// position:'top',
|
|
||||||
// formatter:function (params) {
|
|
||||||
// return params.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name:'DoT',
|
|
||||||
// barWidth: 20, //柱子宽度
|
|
||||||
// data:data.ydata3,
|
|
||||||
// // data:[150,290,560,380,660,105,815],
|
|
||||||
// color:["rgba(58,76,222,0.89)"], //自定义颜色
|
|
||||||
// type: 'bar',
|
|
||||||
// label:{
|
|
||||||
// show:true,
|
|
||||||
// position:'top',
|
|
||||||
// formatter:function (params) {
|
|
||||||
// return params.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name:'DoH',
|
|
||||||
// barWidth: 20, //柱子宽度
|
|
||||||
// data:data.ydata4,
|
|
||||||
// // data:[650,790,560,180,660,15,85],
|
|
||||||
// color:["#117cf4"], //自定义颜色
|
|
||||||
// type: 'bar',
|
|
||||||
// label:{
|
|
||||||
// show:true,
|
|
||||||
// position:'top',
|
|
||||||
// formatter:function (params) {
|
|
||||||
// return params.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// ,
|
|
||||||
// {
|
|
||||||
// name:'总量',
|
|
||||||
// barWidth: 20, //柱子宽度
|
|
||||||
// data:data.ydata5,
|
|
||||||
// // data:[1120,7090,5660,1800,6060,105,805],
|
|
||||||
// color:["#f4be6a"], //自定义颜色
|
|
||||||
// type: 'line',
|
|
||||||
// yAxisIndex: 1,
|
|
||||||
// label:{
|
|
||||||
// show:true,
|
|
||||||
// position:'top',
|
|
||||||
// formatter:function (params) {
|
|
||||||
// return params.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// graphic: [
|
|
||||||
// {
|
|
||||||
// type:'group',
|
|
||||||
// left:'center',
|
|
||||||
// top:25,
|
|
||||||
// children:[
|
|
||||||
// {
|
|
||||||
// type: 'rect',
|
|
||||||
// shape: {
|
|
||||||
// width: 20,
|
|
||||||
// height: 20
|
|
||||||
// },
|
|
||||||
// style: {
|
|
||||||
// fill: '#2386bf' // 设置第一个色块的颜色
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'text',
|
|
||||||
// left: 25,
|
|
||||||
// style: {
|
|
||||||
// text: 'IPv6', // 设置第一个色块的含义
|
|
||||||
// fill: '#2386bf',
|
|
||||||
// fontSize: 12
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// ////////////////
|
|
||||||
// {
|
|
||||||
// type: 'rect',
|
|
||||||
// left: 75,
|
|
||||||
// shape: {
|
|
||||||
// width: 20,
|
|
||||||
// height: 20
|
|
||||||
// },
|
|
||||||
// style: {
|
|
||||||
// fill: '#434ff4' // 设置第二个色块的颜色
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'text',
|
|
||||||
// left: 100,
|
|
||||||
// style: {
|
|
||||||
// text: 'DNS', // 设置第二个色块的含义
|
|
||||||
// fill: '#434ff4',
|
|
||||||
// fontSize: 12
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// ///////////////
|
|
||||||
// {
|
|
||||||
// type: 'rect',
|
|
||||||
// left:150 ,
|
|
||||||
// shape: {
|
|
||||||
// width: 20,
|
|
||||||
// height: 20
|
|
||||||
// },
|
|
||||||
// style: {
|
|
||||||
// fill: 'rgba(58,76,222,0.89)' // 设置第二个色块的颜色
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'text',
|
|
||||||
// left: 175,
|
|
||||||
// style: {
|
|
||||||
// text: 'DoT', // 设置第二个色块的含义
|
|
||||||
// fill: 'rgba(58,76,222,0.89)',
|
|
||||||
// fontSize: 12
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// /////////////////////////////////
|
|
||||||
// {
|
|
||||||
// type: 'rect',
|
|
||||||
// left: 225,
|
|
||||||
// shape: {
|
|
||||||
// width: 20,
|
|
||||||
// height: 20
|
|
||||||
// },
|
|
||||||
// style: {
|
|
||||||
// fill: '#117cf4' // 设置第二个色块的颜色
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'text',
|
|
||||||
// left: 250,
|
|
||||||
// style: {
|
|
||||||
// text: 'DoH', // 设置第二个色块的含义
|
|
||||||
// fill: '#117cf4',
|
|
||||||
// fontSize: 12
|
|
||||||
// },
|
|
||||||
// z: 100
|
|
||||||
// },
|
|
||||||
// // //////////////////////////////
|
|
||||||
// // {
|
|
||||||
// // type: 'rect',
|
|
||||||
// // left: 300,
|
|
||||||
// // shape: {
|
|
||||||
// // width: 20,
|
|
||||||
// // height: 20
|
|
||||||
// // },
|
|
||||||
// // style: {
|
|
||||||
// // fill: '#f4be6a' // 设置第二个色块的颜色
|
|
||||||
// // },
|
|
||||||
// // z: 100
|
|
||||||
// // },
|
|
||||||
// // {
|
|
||||||
// // type: 'text',
|
|
||||||
// // left: 325,
|
|
||||||
// // style: {
|
|
||||||
// // text: '五线', // 设置第二个色块的含义
|
|
||||||
// // fill: '#f4be6a',
|
|
||||||
// // fontSize: 12
|
|
||||||
// // },
|
|
||||||
// // z: 100
|
|
||||||
// // }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ]
|
|
||||||
// };
|
|
||||||
|
|
||||||
var option = {
|
|
||||||
dataset: {
|
|
||||||
source:data.data
|
|
||||||
// source: [
|
|
||||||
// ['延时', '节点'],
|
|
||||||
// [89.3, 'Matcha Latte'],
|
|
||||||
// [57.1, 'Milk Tea'],
|
|
||||||
// [74.4, 'Cheese Cocoa'],
|
|
||||||
// [50.1, 'Cheese Brownie'],
|
|
||||||
// [89.7, 'Matcha Cocoa'],
|
|
||||||
// [68.1, 'Tea'],
|
|
||||||
// [19.6, 'Orange Juice'],
|
|
||||||
// [10.6, 'Lemon Juice'],
|
|
||||||
// [32.7, 'Walnut Brownie']
|
|
||||||
// ]
|
|
||||||
},
|
|
||||||
grid: {containLabel: true},
|
|
||||||
xAxis: {name: 'amount'},
|
|
||||||
yAxis: {type: 'category'},
|
|
||||||
visualMap: {
|
|
||||||
orient: 'horizontal',
|
|
||||||
left: 'center',
|
|
||||||
min: 0,
|
|
||||||
max: 50,
|
|
||||||
text: ['High Score', 'Low Score'],
|
|
||||||
// Map the score column to color
|
|
||||||
dimension: 0,
|
|
||||||
inRange: {
|
|
||||||
color: ['#11da11', '#E15457']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'bar',
|
|
||||||
encode: {
|
|
||||||
// Map the "amount" column to X axis.
|
|
||||||
x: 'score',
|
|
||||||
// Map the "product" column to Y axis
|
|
||||||
y: 'product'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
myChart1.setOption(option,true)
|
|
||||||
window.addEventListener("resize", () => {
|
|
||||||
myChart1.resize();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
myChart1.clear()
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
myChart1.clear()
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
// this.bingfn(this.bing)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped="scoped">
|
|
||||||
</style>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home" ref="appRef">
|
<div class="home" ref="appRef">
|
||||||
<div class="show">
|
<div class="show">
|
||||||
<div><span style="float: left;font-size: 20px;margin-left: 2%;color: #00C0FF;margin-top: 1%">{{"目标IP:"+parentLevelRow.target}}</span></div>
|
<div><span style="float: left;font-size: 20px;margin-left: 2%;color: #00C0FF;margin-top: 1%">{{"目标IP: "+parentLevelRow.target}}</span></div>
|
||||||
<div class="tag">
|
<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="tags1" :style="{'color': (tag1==='ICMP/v6延时') ? '#f8fdff': '#565e6e'}" @click="updateTag1('ICMP/v6延时')">ICMP/v6延时</el-tag>
|
<el-tag class="tags1" :style="{'color': (tag1==='ICMP/v6延时') ? '#f8fdff': '#565e6e'}" @click="updateTag1('ICMP/v6延时')">ICMP/v6延时</el-tag>
|
||||||
@@ -12,10 +12,9 @@
|
|||||||
<div v-if="tag==='应答内容'" class="answer">
|
<div v-if="tag==='应答内容'" class="answer">
|
||||||
<div style="display: flex;margin-right: 5px;">
|
<div style="display: flex;margin-right: 5px;">
|
||||||
<span style="margin-right: 2%;font-size: 25px;width: 15%">目标域名:</span>
|
<span style="margin-right: 2%;font-size: 25px;width: 15%">目标域名:</span>
|
||||||
<el-input v-model="input" placeholder="请输入目标IP"></el-input>
|
<el-input v-model="input" placeholder="请输入目标域名"></el-input>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" style="margin-top: 2%;margin-bottom: 10%">查询</el-button>
|
<el-button type="primary" style="margin-top: 2%;margin-bottom: 10%">查询</el-button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="top" v-if="tag==='目标时延'">
|
<div class="top" v-if="tag==='目标时延'">
|
||||||
<div class="top-left">
|
<div class="top-left">
|
||||||
@@ -52,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- <TargetView class="top-right"/>-->
|
<!-- <TargetView class="top-right"/>-->
|
||||||
</div>
|
</div>
|
||||||
<NodeView class="bottom" v-if="tag==='目标时延'"></NodeView>
|
<NodeView class="bottom" v-if="tag==='目标时延'" :taskid=parentLevelRow.id></NodeView>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -62,21 +61,20 @@ import TargetView from './module/target.vue'
|
|||||||
import ImageView from './module/image.vue'
|
import ImageView from './module/image.vue'
|
||||||
import SourceView from './module/source.vue'
|
import SourceView from './module/source.vue'
|
||||||
import NodeView from './module/node.vue'
|
import NodeView from './module/node.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'home',
|
name: 'menuMBZTGZ',
|
||||||
components: { TargetView, ImageView, SourceView, NodeView },
|
components: { TargetView, ImageView, SourceView, NodeView },
|
||||||
created() {
|
created() {
|
||||||
this.parentLevelRow = this.$route.query.row;
|
this.parentLevelRow = this.$route.query.row;
|
||||||
this.input=this.parentLevelRow.target_domain;
|
this.input=this.parentLevelRow.target_domain;
|
||||||
|
this.left1data.taskid = this.parentLevelRow.id;
|
||||||
|
this.left1data.target = this.parentLevelRow.target;
|
||||||
},
|
},
|
||||||
// mounted() {
|
// mounted() {
|
||||||
// this.$router.push('/range/home')
|
// this.$router.push('/range/home')
|
||||||
// },
|
// },
|
||||||
methods:{
|
methods:{
|
||||||
|
|
||||||
|
|
||||||
updateTag(val){
|
updateTag(val){
|
||||||
if(val==='目标时延'){
|
if(val==='目标时延'){
|
||||||
this.tag=val
|
this.tag=val
|
||||||
@@ -85,14 +83,13 @@ export default {
|
|||||||
this.tag=val
|
this.tag=val
|
||||||
this.tag1=""
|
this.tag1=""
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
updateTag1(val){
|
updateTag1(val){
|
||||||
this.tag1=val;
|
this.tag1=val;
|
||||||
this.tag='目标时延';
|
this.tag='目标时延';
|
||||||
this.left1data.type=this.changePeram(val);
|
this.left1data.type=this.changePeram(val);
|
||||||
this.left1data.target=this.parentLevelRow.target;
|
this.left1data.target=this.parentLevelRow.target; // 任务目标IP
|
||||||
|
this.left1data.taskid=this.parentLevelRow.id; // 任务id
|
||||||
},
|
},
|
||||||
changePeram(val){
|
changePeram(val){
|
||||||
switch (val) {
|
switch (val) {
|
||||||
@@ -114,7 +111,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
left1data:{
|
left1data:{
|
||||||
target:'1.1.1.1',
|
taskid:'',
|
||||||
|
target:'',
|
||||||
type:'icmp',
|
type:'icmp',
|
||||||
},
|
},
|
||||||
leftYdata:[],
|
leftYdata:[],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="list" >
|
<div class="list" >
|
||||||
<el-table class="custom-table"
|
<el-table class="custom-table"
|
||||||
ref="multipleTable"
|
ref="multipleTable"
|
||||||
:data="tableData"
|
:data="nodes"
|
||||||
height="100%"
|
height="100%"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
tooltip-effect="dark"
|
tooltip-effect="dark"
|
||||||
@@ -16,42 +16,39 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center"
|
<el-table-column align="center"
|
||||||
prop="time"
|
prop="Id"
|
||||||
label="时间"
|
label="ID"
|
||||||
min-width="100">
|
min-width="100">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center"
|
<el-table-column align="center"
|
||||||
prop="level"
|
prop="Ip"
|
||||||
label="日志级别"
|
label="IP地址"
|
||||||
min-width="100">
|
min-width="100">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="日志信息" min-width="300">
|
|
||||||
<template slot-scope="scope" >{{ scope.row.info.substr(0, 80)}}</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column align="center"
|
<el-table-column align="center"
|
||||||
prop="user"
|
prop="Name"
|
||||||
label="用户账号"
|
label="节点名称"
|
||||||
min-width="100">
|
min-width="100">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column align="center"
|
<el-table-column align="center"
|
||||||
prop="ip"
|
prop="Loc"
|
||||||
label="用户IP"
|
label="节点位置"
|
||||||
min-width="100">
|
min-width="100">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
<!-- <el-pagination-->
|
<!-- <el-pagination
|
||||||
<!-- background-->
|
background
|
||||||
<!-- :current-page="page"-->
|
:current-page="page"
|
||||||
<!-- :page-sizes="[10, 20, 30, 40]"-->
|
:page-sizes="[10, 20, 30, 40]"
|
||||||
<!-- :page-size="10"-->
|
:page-size="10"
|
||||||
<!-- :total="total"-->
|
:total="total"
|
||||||
<!-- layout="total, sizes, prev, pager, next, jumper"-->
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
<!-- @size-change="handleSizeChange"-->
|
@size-change="handleSizeChange"
|
||||||
<!-- @current-change="handleCurrentChange"-->
|
@current-change="handleCurrentChange"
|
||||||
<!-- >-->
|
>
|
||||||
<!-- </el-pagination>-->
|
</el-pagination> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -64,285 +61,27 @@ export default {
|
|||||||
name: 'NodeView',
|
name: 'NodeView',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tableData:[],
|
nodes:[]
|
||||||
total:0,
|
|
||||||
page:1,
|
|
||||||
size:10,
|
|
||||||
time1:'',
|
|
||||||
time2:'',
|
|
||||||
log_level:"",
|
|
||||||
userAccount:"",
|
|
||||||
pickerOptions: {
|
|
||||||
shortcuts: [{
|
|
||||||
text: '今天',
|
|
||||||
onClick(picker) {
|
|
||||||
picker.$emit('pick', new Date());
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: '昨天',
|
|
||||||
onClick(picker) {
|
|
||||||
const date = new Date();
|
|
||||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
|
||||||
picker.$emit('pick', date);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: '一周前',
|
|
||||||
onClick(picker) {
|
|
||||||
const date = new Date();
|
|
||||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
|
||||||
picker.$emit('pick', date);
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
|
|
||||||
log_levels:[
|
|
||||||
{
|
|
||||||
value:'ERROR',
|
|
||||||
label:'ERROR'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value:'INFO',
|
|
||||||
label:'INFO'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value:'WARNING',
|
|
||||||
label:'WARNING'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
props:['taskid'],
|
||||||
created() {
|
created() {
|
||||||
this.query()
|
this.query()
|
||||||
},
|
},
|
||||||
mounted(){
|
|
||||||
// this.init()
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
handleSizeChange(val) {
|
// 请求节点信息
|
||||||
console.log(`每页 ${val} 条`);
|
|
||||||
this.size=val
|
|
||||||
this.query()
|
|
||||||
},
|
|
||||||
handleCurrentChange(val) {
|
|
||||||
console.log(`当前页: ${val}`);
|
|
||||||
this.page=val
|
|
||||||
this.query()
|
|
||||||
},
|
|
||||||
query(){
|
query(){
|
||||||
let data={
|
const reqParams = {
|
||||||
"per_page":this.size,
|
"taskid": this.taskid,
|
||||||
"page":this.page,
|
|
||||||
"begin":this.time1.toString(),
|
|
||||||
"end":this.time2.toString(),
|
|
||||||
"level":this.log_level,
|
|
||||||
"user":this.userAccount,
|
|
||||||
}
|
}
|
||||||
// 使用 Object.entries() 来遍历对象的键值对,并过滤掉值为空的属性
|
this.loading = true
|
||||||
const filteredData = {};
|
this.$axios.get(this.$http.api.targetNodes, reqParams).then(res => {
|
||||||
for (const [key, value] of Object.entries(data)) {
|
this.nodes = res.nodes
|
||||||
if (value !== "") {
|
console.log("Node Page Nodes: ", this.nodes)
|
||||||
filteredData[key] = value;
|
}).catch(err => {
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$axios.get(this.$http.api.sysLog,filteredData).then(res=>{
|
|
||||||
console.log('getImages======',res)
|
|
||||||
if(res.code===200){
|
|
||||||
this.tableData=res?.log_data
|
|
||||||
// this.total=res?.total
|
|
||||||
this.total=100
|
|
||||||
}
|
|
||||||
}).catch(err=>{
|
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
// async init() {
|
|
||||||
// await this.getRangeDict()
|
|
||||||
// await this.initData()
|
|
||||||
// this.initEcharts()
|
|
||||||
// },
|
|
||||||
// initData() {
|
|
||||||
// // this.nodeData = getTargetsResponse?.result
|
|
||||||
// // for (const key in this.nodeData) {
|
|
||||||
// // this.nodeDataX.push(key)
|
|
||||||
// // this.nodeDataY.push(this.nodeData[key])
|
|
||||||
// // }
|
|
||||||
//
|
|
||||||
// const reqParams = {}
|
|
||||||
// if (this.target_id) {
|
|
||||||
// reqParams.target_id = this.target_id
|
|
||||||
// }
|
|
||||||
// if (this.activeName !== 'total') {
|
|
||||||
// reqParams.status = this.activeName
|
|
||||||
// }
|
|
||||||
// this.loading = true
|
|
||||||
// return this.$axios.get(this.$http.api.getNodeStatistics, reqParams).then(res => {
|
|
||||||
// if (res.code == 200 || res.code == "OK") {
|
|
||||||
// this.nodeDataX = []
|
|
||||||
// this.nodeDataY = []
|
|
||||||
// this.nodeData = res?.result || {}
|
|
||||||
// for (const key in this.nodeData) {
|
|
||||||
// this.nodeDataX.push(key)
|
|
||||||
// this.nodeDataY.push(this.nodeData[key])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }).catch(err => {
|
|
||||||
// console.log(err)
|
|
||||||
// }).finally(() => {
|
|
||||||
// this.loading = false
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// 获取靶场列表字典
|
|
||||||
// getRangeDict() {
|
|
||||||
// const reqParams = {
|
|
||||||
// page: 1,
|
|
||||||
// size: 99,
|
|
||||||
// }
|
|
||||||
// return 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: ''})
|
|
||||||
// this.target_id = this.rangeDict[0].value
|
|
||||||
// this.target_name = this.rangeDict[0].label
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// 改变靶场
|
|
||||||
// async changeRange(val) {
|
|
||||||
// this.target_name = this.rangeDict.find(item => item.value === val)?.label
|
|
||||||
// await this.initData()
|
|
||||||
// this.refreshData()
|
|
||||||
// },
|
|
||||||
// 改变靶场状态
|
|
||||||
// async changeRangeStatus() {
|
|
||||||
// await this.initData()
|
|
||||||
// this.refreshData()
|
|
||||||
// },
|
|
||||||
// 刷新图标数据
|
|
||||||
// refreshData(){
|
|
||||||
// if(!this.nodeChart){
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// //更新数据
|
|
||||||
// var option = this.nodeChart.getOption()
|
|
||||||
// option.title[0].text = `${this.target_name}节点统计`,
|
|
||||||
// option.xAxis[0].data = this.nodeDataX
|
|
||||||
// option.series[0].data = this.nodeDataY
|
|
||||||
// this.nodeChart.setOption(option)
|
|
||||||
// },
|
|
||||||
// 切换靶场状态
|
|
||||||
// tabClick(tab, event) {
|
|
||||||
// this.changeRangeStatus()
|
|
||||||
// },
|
|
||||||
//初始化节点柱状图
|
|
||||||
// initEcharts() {
|
|
||||||
// var chartDom = document.getElementById('node');
|
|
||||||
// this.nodeChart = echarts.init(chartDom);
|
|
||||||
// var option;
|
|
||||||
//
|
|
||||||
// option = {
|
|
||||||
// title: {
|
|
||||||
// text: `${this.target_name}节点统计`,
|
|
||||||
// left: 'center',
|
|
||||||
// top: '15',
|
|
||||||
// textStyle: {
|
|
||||||
// color: '#FFFFFF',
|
|
||||||
// fontSize: 16,
|
|
||||||
// fontWeight: 500
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// tooltip: {
|
|
||||||
// // trigger: 'axis',
|
|
||||||
// axisPointer: {
|
|
||||||
// // type: 'shadow'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// grid: {
|
|
||||||
// top: '25%',
|
|
||||||
// left: '3%',
|
|
||||||
// right: '4%',
|
|
||||||
// bottom: '8%',
|
|
||||||
// containLabel: true
|
|
||||||
// },
|
|
||||||
// xAxis: [
|
|
||||||
// {
|
|
||||||
// type: 'category',
|
|
||||||
// data: this.nodeDataX,
|
|
||||||
// axisTick: {
|
|
||||||
// // alignWithLabel: true
|
|
||||||
// show: false
|
|
||||||
// },
|
|
||||||
// axisLabel: {
|
|
||||||
// fontSize: '14',
|
|
||||||
// color: 'rgba(255, 255, 255, 0.7)'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// yAxis: [
|
|
||||||
// {
|
|
||||||
// type: 'value',
|
|
||||||
// name: '靶场中各类节点数量',
|
|
||||||
// nameTextStyle: {
|
|
||||||
// color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
// padding: [0, 0, 0, 70]
|
|
||||||
// },
|
|
||||||
// axisLabel: {
|
|
||||||
// fontSize: '12',
|
|
||||||
// color: 'rgba(255, 255, 255, 0.7)'
|
|
||||||
// },
|
|
||||||
// splitLine: {
|
|
||||||
// show: true,
|
|
||||||
// lineStyle: {
|
|
||||||
// color: ['rgba(199, 199, 200, 0.1)'],
|
|
||||||
// width: 1,
|
|
||||||
// type: 'dashed'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// series: [
|
|
||||||
// {
|
|
||||||
// // name: 'Direct',
|
|
||||||
// type: 'bar',
|
|
||||||
// barWidth: '20%',
|
|
||||||
// data: this.nodeDataY,
|
|
||||||
// itemStyle: {
|
|
||||||
// normal: {
|
|
||||||
// label: {
|
|
||||||
// show: true, // 是否显示
|
|
||||||
// position: 'top', // 显示位置
|
|
||||||
// color: '#FFFFFF',
|
|
||||||
// formatter: function (params) {
|
|
||||||
// // 核心部分 formatter 可以为字符串也可以是回调
|
|
||||||
// if (parseInt(params.value) === 0) {
|
|
||||||
// return '';
|
|
||||||
// } else {
|
|
||||||
// return params.data.label;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// // 每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
|
|
||||||
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
||||||
// { offset: 0, color: '#3280D7' },
|
|
||||||
// { offset: 1, color: '#4122E2' }
|
|
||||||
// ])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// };
|
|
||||||
// option && this.nodeChart.setOption(option);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export default {
|
|||||||
// required: true,
|
// required: true,
|
||||||
default: function() {
|
default: function() {
|
||||||
return {
|
return {
|
||||||
|
taskid:'',
|
||||||
target:'',
|
target:'',
|
||||||
type: '',
|
type: '',
|
||||||
}
|
}
|
||||||
@@ -69,21 +70,24 @@ export default {
|
|||||||
// this.getRangeDict()
|
// this.getRangeDict()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 获取数据
|
||||||
querydelay(){
|
querydelay(){
|
||||||
const reqParams = {
|
const reqParams = {
|
||||||
"target": this.left1data.target,
|
"target": this.left1data.target,
|
||||||
|
"taskid": this.left1data.taskid,
|
||||||
"type": this.left1data.type,
|
"type": this.left1data.type,
|
||||||
}
|
}
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$axios.get(this.$http.api.targetDelay, reqParams).then(res => {
|
this.$axios.get(this.$http.api.targetDelay, reqParams).then(res => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
|
this.zhudouble.xdata = []
|
||||||
|
this.zhudouble.ydata1 = []
|
||||||
for (let i = 0; i <res.delay_data.length>10?10:res.delay_data.length ; i++) {
|
for (let i = 0; i <res.delay_data.length>10?10:res.delay_data.length ; i++) {
|
||||||
this.zhudouble.xdata.push(res.delay_data[i].Id);
|
this.zhudouble.xdata.push(res.delay_data[i].Id);
|
||||||
this.zhudouble.ydata1.push(res.delay_data[i].CurrDelay);
|
this.zhudouble.ydata1.push(res.delay_data[i].CurrDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.$refs.zhudouble.bingfn(this.zhudouble)
|
this.$refs.zhudouble.bingfn(this.zhudouble)
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="source-card">
|
<div class="source-card">
|
||||||
<!-- <div class="source-chart" id="resource" v-loading="loading"></div>-->
|
<NodeWordMap :nodes="nodes"></NodeWordMap>
|
||||||
<ZhuZhuangTu_jbs :active="0" ref="zhudouble" :bing="zhudouble"></ZhuZhuangTu_jbs>
|
|
||||||
<!-- <div class="tabs-container">-->
|
|
||||||
<!-- <el-tabs v-model="activeName" @tab-click="tabClick">-->
|
|
||||||
<!-- <el-tab-pane label="CPU" name="CPU"></el-tab-pane>-->
|
|
||||||
<!-- <el-tab-pane label="MEMEORY" name="MEMEORY"></el-tab-pane>-->
|
|
||||||
<!-- </el-tabs>-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- </div>-->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from 'echarts';
|
import NodeWordMap from '../echarts/nodewordmap'
|
||||||
import ZhuZhuangTu_jbs from '../echarts/zhuzhuangtu_jbs'
|
|
||||||
|
|
||||||
import { getTargetsResponse } from './sourceMock.js'
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'TargetView',
|
||||||
props: {
|
props: {
|
||||||
left1data: {
|
left1data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
// required: true,
|
|
||||||
default: function() {
|
default: function() {
|
||||||
return {
|
return {
|
||||||
|
taskid:'',
|
||||||
target:'',
|
target:'',
|
||||||
type: '',
|
type: '',
|
||||||
}
|
}
|
||||||
@@ -40,196 +30,32 @@
|
|||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
name: 'SourceView',
|
components: { NodeWordMap },
|
||||||
components: {
|
|
||||||
ZhuZhuangTu_jbs,
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
nodes:[]
|
||||||
sourceData: {},
|
|
||||||
sourceDataX: [],
|
|
||||||
sourceDataY: [],
|
|
||||||
cpuList: [],
|
|
||||||
memoryList: [],
|
|
||||||
activeName: 'CPU',
|
|
||||||
sourceChart: null,
|
|
||||||
rangeDict: [],
|
|
||||||
zhudouble:{
|
|
||||||
data:[
|
|
||||||
['延时', '节点'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
querydelay() {
|
||||||
|
const reqParams = {
|
||||||
|
"taskid": this.left1data.taskid,
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
this.$axios.get(this.$http.api.targetNodes, reqParams).then(res => {
|
||||||
|
this.nodes = res.nodes
|
||||||
|
// console.log("Nodes: ", this.nodes)
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
this.init()
|
this.querydelay()
|
||||||
// this.getRangeDict()
|
console.log("**********target mounted")
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
init() {
|
|
||||||
const reqParams = {
|
|
||||||
"target": this.left1data.target,
|
|
||||||
"type": this.left1data.type,
|
|
||||||
}
|
|
||||||
console.log("GGGGGGGGGGGGGGGGGGGG")
|
|
||||||
console.log(reqParams)
|
|
||||||
console.log("GGGGGGGGGGGGGGGGGGGG")
|
|
||||||
this.loading = true
|
|
||||||
this.$axios.get(this.$http.api.targetDelay,reqParams).then(res => {
|
|
||||||
if (res.code == 200) {
|
|
||||||
for (let i = 0; i <res.delay_data.length>10?10:res.delay_data.length ; i++) {
|
|
||||||
let A=[];
|
|
||||||
A.push(res.delay_data[i].CurrDelay);
|
|
||||||
A.push(res.delay_data[i].Id);
|
|
||||||
this.zhudouble.data.push(A);
|
|
||||||
}
|
|
||||||
this.$refs.zhudouble.bingfn(this.zhudouble)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
|
||||||
this.initEcharts()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initEcharts() {
|
|
||||||
let that = this
|
|
||||||
var chartDom = document.getElementById('resource');
|
|
||||||
this.sourceChart = echarts.init(chartDom);
|
|
||||||
var option;
|
|
||||||
|
|
||||||
option = {
|
|
||||||
title: {
|
|
||||||
text: '靶场资源使用排序',
|
|
||||||
left: '10',
|
|
||||||
top: '15',
|
|
||||||
textStyle: {
|
|
||||||
color: '#FFFFFF',
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 500
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
// trigger: 'axis',
|
|
||||||
axisPointer: {
|
|
||||||
// type: 'shadow'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
top: '25%',
|
|
||||||
left: '3%',
|
|
||||||
right: '4%',
|
|
||||||
bottom: '8%',
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
xAxis: [
|
|
||||||
{
|
|
||||||
type: 'category',
|
|
||||||
data: this.sourceDataX,
|
|
||||||
axisTick: {
|
|
||||||
// alignWithLabel: true
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
fontSize: '14',
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
type: 'value',
|
|
||||||
axisLabel: {
|
|
||||||
fontSize: '12',
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
formatter: function(value) {
|
|
||||||
return value + ' (mcore)'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
color: ['rgba(199, 199, 200, 0.1)'],
|
|
||||||
width: 1,
|
|
||||||
type: 'dashed'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
// name: 'Direct',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: '20%',
|
|
||||||
data: this.sourceDataY,
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
label: {
|
|
||||||
show: true, // 是否显示
|
|
||||||
position: 'top', // 显示位置
|
|
||||||
color: '#FFFFFF',
|
|
||||||
formatter: function (params) {
|
|
||||||
// 核心部分 formatter 可以为字符串也可以是回调
|
|
||||||
if (parseInt(params.value) === 0) {
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
return params.data.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
|
|
||||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
||||||
{ offset: 0, color: '#01FFFF' },
|
|
||||||
{ offset: 1, color: '#2160B8' }
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
option && this.sourceChart.setOption(option);
|
|
||||||
//点击事件
|
|
||||||
this.sourceChart.on('click', function(params) {
|
|
||||||
const target_name = params.name
|
|
||||||
const target_id = that.rangeDict.find(item => item.label === target_name)?.value
|
|
||||||
that.$store.commit('globalAttrs/setCheckMenu', 'rangeConfigManage')
|
|
||||||
that.$store.commit('range/setTargetId', target_id)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 刷新图标数据
|
|
||||||
refreshData(data, tabName){
|
|
||||||
if(!this.sourceChart){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//更新数据
|
|
||||||
var option = this.sourceChart.getOption()
|
|
||||||
option.series[0].data = data
|
|
||||||
option.yAxis[0].axisLabel.formatter = function(value) {
|
|
||||||
if (tabName === 'MEMEORY') {
|
|
||||||
return value + ' (Mi)'
|
|
||||||
} else {
|
|
||||||
return value + ' (mcore)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.sourceChart.setOption(option)
|
|
||||||
},
|
|
||||||
tabClick(tab, event) {
|
|
||||||
switch (tab.name) {
|
|
||||||
case 'CPU':
|
|
||||||
this.refreshData(this.cpuList, 'CPU')
|
|
||||||
break;
|
|
||||||
case 'MEMEORY':
|
|
||||||
this.refreshData(this.memoryList, 'MEMEORY')
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.refreshData(this.cpuList, 'CPU')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,18 @@
|
|||||||
></Header>
|
></Header>
|
||||||
<div class="header2">
|
<div class="header2">
|
||||||
<div style="width: 45%; display: inline-block;">
|
<div style="width: 45%; display: inline-block;">
|
||||||
<el-descriptions class="custom-descriptions" >
|
<el-descriptions class="custom-descriptions">
|
||||||
<el-descriptions-item label="任务名称" >{{parentLevelRow.name}}</el-descriptions-item>
|
<el-descriptions-item label="任务名称" class="cell-item">{{parentLevelRow.name}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="代理编号">{{parentLevelRow.id}}</el-descriptions-item>
|
<el-descriptions-item label="代理编号" class="cell-item">{{parentLevelRow.id}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="执行状态">
|
<el-descriptions-item label="执行状态" class="cell-item">
|
||||||
<el-tag type="info" v-if="parentLevelRow.status==='stop'">暂停</el-tag>
|
<el-tag type="info" v-if="parentLevelRow.status==='stop'">暂停</el-tag>
|
||||||
<el-tag type="warning" v-if="parentLevelRow.status==='working'">执行中</el-tag>
|
<el-tag type="warning" v-if="parentLevelRow.status==='working'">执行中</el-tag>
|
||||||
<el-tag type="danger" v-if="parentLevelRow.status==='finish'">已完成</el-tag>
|
<el-tag type="danger" v-if="parentLevelRow.status==='finish'">已完成</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="任务目标">
|
<el-descriptions-item label="任务目标" class="cell-item">
|
||||||
{{parentLevelRow.target}}
|
{{parentLevelRow.target}}
|
||||||
<span style="color: #00C0FF;margin-left: 5%" @click="getInfoByIp(parentLevelRow)">查看实时状态</span>
|
<!-- <span style="color: #00C0FF;margin-left: 5%" @click="getInfoByIp(parentLevelRow)">查看实时状态</span> -->
|
||||||
|
<span style="color: #00C0FF;margin-left: 5%" @click="getInfoById(parentLevelRow)">查看实时状态</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,7 +99,7 @@
|
|||||||
label="执行输出"
|
label="执行输出"
|
||||||
min-width="150">
|
min-width="150">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="primary" @click="newlyPztj=!newlyPztj,getLog(scope.row.policy_id)">查看</el-button>
|
<el-button type="primary" @click="newlyPztj=!newlyPztj, getLog(scope.row.policy_id)">查看</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
@@ -200,7 +201,7 @@ import Header from './module/Header.vue'
|
|||||||
import UserForm from './module/UserForm.vue'
|
import UserForm from './module/UserForm.vue'
|
||||||
import { getTargetsResponse } from './mock.js'
|
import { getTargetsResponse } from './mock.js'
|
||||||
export default {
|
export default {
|
||||||
name: "RangeConfigManage",
|
name: "menuTaskInfo",
|
||||||
components:{ Header, UserForm },
|
components:{ Header, UserForm },
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
@@ -227,11 +228,14 @@ export default {
|
|||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
created() {
|
created() {
|
||||||
this.parentLevelRow = this.$route.query.row;
|
this.parentLevelRow = JSON.parse(this.$route.query.row);
|
||||||
this.init()
|
this.init()
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
getInfoByIp(val){
|
// getInfoByIp(val){
|
||||||
|
// this.$router.push({ path: 'menuMBZTGZ', query: { row: val } });
|
||||||
|
// },
|
||||||
|
getInfoById(val){
|
||||||
this.$router.push({ path: 'menuMBZTGZ', query: { row: val } });
|
this.$router.push({ path: 'menuMBZTGZ', query: { row: val } });
|
||||||
},
|
},
|
||||||
CustomizationImageFales(){
|
CustomizationImageFales(){
|
||||||
@@ -296,9 +300,9 @@ export default {
|
|||||||
this.$axios.get(this.$http.api.taskInfoLog, reqParams).then(res => {
|
this.$axios.get(this.$http.api.taskInfoLog, reqParams).then(res => {
|
||||||
// if (res.code == 200 || res.code == "OK") {
|
// if (res.code == 200 || res.code == "OK") {
|
||||||
// this.total = res?.data?.total
|
// this.total = res?.data?.total
|
||||||
this.total = 100
|
this.total = 10
|
||||||
this.tableDataLog = res?.data
|
this.tableDataLog = res?.data
|
||||||
this.tableData.map(item => {
|
this.tableDataLog.map(item => {
|
||||||
item.permissions.map(permi => {
|
item.permissions.map(permi => {
|
||||||
this.$set(permi, 'delLoading', false)
|
this.$set(permi, 'delLoading', false)
|
||||||
return permi
|
return permi
|
||||||
@@ -326,6 +330,7 @@ export default {
|
|||||||
// this.total = res?.data?.total
|
// this.total = res?.data?.total
|
||||||
this.total = 100
|
this.total = 100
|
||||||
this.tableDataLog = res?.data
|
this.tableDataLog = res?.data
|
||||||
|
console.log("***********", this.tableDataLog)
|
||||||
this.tableData.map(item => {
|
this.tableData.map(item => {
|
||||||
item.permissions.map(permi => {
|
item.permissions.map(permi => {
|
||||||
this.$set(permi, 'delLoading', false)
|
this.$set(permi, 'delLoading', false)
|
||||||
@@ -473,6 +478,10 @@ export default {
|
|||||||
/* float: right;*/
|
/* float: right;*/
|
||||||
/*}*/
|
/*}*/
|
||||||
}
|
}
|
||||||
|
.cell-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
/*.custom-paginationLog /deep/ .el-pagination /deep/ .is-background {*/
|
/*.custom-paginationLog /deep/ .el-pagination /deep/ .is-background {*/
|
||||||
/* float: right;*/
|
/* float: right;*/
|
||||||
/*}*/
|
/*}*/
|
||||||
@@ -585,7 +594,7 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin-bottom: 1%;
|
margin-bottom: 1%;
|
||||||
margin-left: 2.5%;
|
margin-left: 2%;
|
||||||
.enlarged-button {
|
.enlarged-button {
|
||||||
transform: scale(1.5); /* 将按钮和图标整体放大 1.5 倍 */
|
transform: scale(1.5); /* 将按钮和图标整体放大 1.5 倍 */
|
||||||
margin-left: 3%;
|
margin-left: 3%;
|
||||||
@@ -596,8 +605,6 @@ export default {
|
|||||||
/deep/ .el-descriptions-item{
|
/deep/ .el-descriptions-item{
|
||||||
background-color: rgba(19, 34, 99, 1);
|
background-color: rgba(19, 34, 99, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/*.custom-descriptions /deep/ .el-descriptions{*/
|
/*.custom-descriptions /deep/ .el-descriptions{*/
|
||||||
/* background-color: #f04247; !* 设置背景颜色为灰色 *!*/
|
/* background-color: #f04247; !* 设置背景颜色为灰色 *!*/
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ import Header from './module/Header.vue'
|
|||||||
import UserForm from './module/UserForm.vue'
|
import UserForm from './module/UserForm.vue'
|
||||||
import { getTargetsResponse } from './mock.js'
|
import { getTargetsResponse } from './mock.js'
|
||||||
export default {
|
export default {
|
||||||
name: "RangeConfigManage",
|
name: "menuTaskManagement",
|
||||||
components:{ Header, UserForm },
|
components:{ Header, UserForm },
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
@@ -118,18 +118,18 @@ export default {
|
|||||||
...params
|
...params
|
||||||
}
|
}
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$axios.get(this.$http.api.taskList, reqParams).then(res => {
|
this.$axios.get(this.$http.api.taskList, reqParams).then(res => { // 获取任务信息
|
||||||
// if (res.code == 200 || res.code == "OK") {
|
// if (res.code == 200 || res.code == "OK") {
|
||||||
// this.total = res?.data?.total
|
// this.total = res?.data?.total
|
||||||
this.total = 100
|
this.total = 100
|
||||||
this.tableData = res?.data
|
this.tableData = res?.data // 可选链(Optional Chaining)操作符
|
||||||
this.tableData.map(item => {
|
// this.tableData.map(item => {
|
||||||
item.permissions.map(permi => {
|
// item.permissions.map(permi => {
|
||||||
this.$set(permi, 'delLoading', false)
|
// this.$set(permi, 'delLoading', false)
|
||||||
return permi
|
// return permi
|
||||||
})
|
// })
|
||||||
return item
|
// return item
|
||||||
})
|
// })
|
||||||
// }
|
// }
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
@@ -201,27 +201,28 @@ export default {
|
|||||||
},
|
},
|
||||||
// 详情
|
// 详情
|
||||||
taskInfo(val) {
|
taskInfo(val) {
|
||||||
this.$router.push({ path: 'menuTaskInfo', query: { row: val } });
|
// this.$router.push({ path: 'menuTaskInfo', query: { row: val } });
|
||||||
},
|
this.$router.push({ path: 'menuTaskInfo', query: { row: JSON.stringify(val) } });
|
||||||
// 获取权限字典
|
|
||||||
getPermissionDict() {
|
|
||||||
const params = {
|
|
||||||
page: 1,
|
|
||||||
size: 99
|
|
||||||
}
|
|
||||||
this.$axios.get(this.$http.api.getPermissionList, params).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.permissionDict = res?.result?.items.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.permission_name,
|
|
||||||
value: item.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
// // 获取权限字典
|
||||||
|
// getPermissionDict() {
|
||||||
|
// const params = {
|
||||||
|
// page: 1,
|
||||||
|
// size: 99
|
||||||
|
// }
|
||||||
|
// this.$axios.get(this.$http.api.getPermissionList, params).then(res => {
|
||||||
|
// if (res.code == 200 || res.code == "OK") {
|
||||||
|
// this.permissionDict = res?.result?.items.map(item => {
|
||||||
|
// return {
|
||||||
|
// label: item.permission_name,
|
||||||
|
// value: item.id
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }).catch(err => {
|
||||||
|
// console.log(err)
|
||||||
|
// })
|
||||||
|
// },
|
||||||
// 修改每页数据条数
|
// 修改每页数据条数
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
console.log(`每页 ${val} 条`)
|
console.log(`每页 ${val} 条`)
|
||||||
|
|||||||
@@ -49,7 +49,6 @@
|
|||||||
<el-option
|
<el-option
|
||||||
v-for="item in strategy"
|
v-for="item in strategy"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
:value="item.value">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -134,10 +133,12 @@ export default {
|
|||||||
{ value: 'ddos', label: '拒绝服务', type: 'warning' },
|
{ value: 'ddos', label: '拒绝服务', type: 'warning' },
|
||||||
{ value: 'sjqp', label: '数据欺骗', type: 'warning' },
|
{ value: 'sjqp', label: '数据欺骗', type: 'warning' },
|
||||||
],
|
],
|
||||||
agencyChange:[
|
// 代理选择列表
|
||||||
{ value: '中国北京', label: '中国北京', type: 'success' },
|
// agencyChange:[
|
||||||
{ value: '美国纽约', label: '美国纽约', type: 'warning' },
|
// { value: '中国北京', label: '中国北京', type: 'success' },
|
||||||
],
|
// { value: '美国纽约', label: '美国纽约', type: 'warning' },
|
||||||
|
// ],
|
||||||
|
agencyChange:[],
|
||||||
stateAwareMode:[
|
stateAwareMode:[
|
||||||
{ value: 'auto', label: '自动选择', type: 'success' },
|
{ value: 'auto', label: '自动选择', type: 'success' },
|
||||||
{ value: 'tcp', label: 'TCP时延', type: 'warning' },
|
{ value: 'tcp', label: 'TCP时延', type: 'warning' },
|
||||||
@@ -149,10 +150,11 @@ export default {
|
|||||||
{ value: 'now', label: '立刻执行', type: 'success' },
|
{ value: 'now', label: '立刻执行', type: 'success' },
|
||||||
{ value: 'man', label: '手动执行', type: 'warning' },
|
{ value: 'man', label: '手动执行', type: 'warning' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created(){
|
||||||
|
this.getAgenayList();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getTagsByIP(val){
|
getTagsByIP(val){
|
||||||
let data={
|
let data={
|
||||||
@@ -165,8 +167,25 @@ export default {
|
|||||||
}).catch(err=>{
|
}).catch(err=>{
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
// 获取代理信息
|
||||||
|
getAgenayList(){
|
||||||
|
let data={
|
||||||
|
"atype":"gjst",
|
||||||
|
"status":1,
|
||||||
|
"idle":1
|
||||||
|
}
|
||||||
|
this.$axios.get(this.$http.api.agentQueryList,data).then(res=>{
|
||||||
|
if(res.code===200){
|
||||||
|
console.log("*****Length", res.total)
|
||||||
|
for (let i=0; i<res.total; i++) {
|
||||||
|
let id = res.agent_data[i].id
|
||||||
|
this.agencyChange.push({value:id})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(err=>{
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.resetForm()
|
this.resetForm()
|
||||||
@@ -175,16 +194,17 @@ export default {
|
|||||||
},
|
},
|
||||||
submit() {
|
submit() {
|
||||||
let data={
|
let data={
|
||||||
"target":this.form.domain,
|
// "target":this.form.domain,
|
||||||
"agent":this.form.agencyChange,
|
"agent":this.form.agencyChange,
|
||||||
"name":this.form.name,
|
"name":this.form.name,
|
||||||
"target_domain":"",
|
|
||||||
"target_rr":this.form.inject,
|
|
||||||
"policy_time":this.form.switchoverTime,
|
|
||||||
"run_time":this.form.executeTime,
|
|
||||||
"run_flag":this.form.operationalConfiguration,
|
|
||||||
"policy":this.form.strategy,
|
"policy":this.form.strategy,
|
||||||
|
"policy_time":this.form.switchoverTime,
|
||||||
|
"run_flag":this.form.operationalConfiguration,
|
||||||
|
"run_time":this.form.executeTime,
|
||||||
"scan":this.form.stateAwareMode,
|
"scan":this.form.stateAwareMode,
|
||||||
|
"target": this.form.ip,
|
||||||
|
"target_domain":this.form.domain,
|
||||||
|
"target_rr":this.form.inject,
|
||||||
}
|
}
|
||||||
console.log("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
|
console.log("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
|
||||||
console.log(data)
|
console.log(data)
|
||||||
|
|||||||
@@ -1,729 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="range-config-manage" ref="appRef">
|
|
||||||
<div class="show">
|
|
||||||
<Header
|
|
||||||
:range-dict="rangeDict"
|
|
||||||
:batch-deploy-loading="batchDeployLoading"
|
|
||||||
:batch-del-loading="batchDelLoading"
|
|
||||||
:batch-pipeline-loading="batchPipelineLoading"
|
|
||||||
:disabled-batch-pipline="disabledBatchPipline"
|
|
||||||
@addConfig="addConfig"
|
|
||||||
@query="query"
|
|
||||||
@batchDeploy="batchDeploy"
|
|
||||||
@batchDel="batchDel"
|
|
||||||
@batchPipeline="batchPipeline"
|
|
||||||
></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
|
|
||||||
@cell-mouse-enter="cellEnter"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
type="selection"
|
|
||||||
width="80"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
type="index"
|
|
||||||
label="序号"
|
|
||||||
width="80"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="tor_version"
|
|
||||||
label="Tor版本"
|
|
||||||
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="replicas"
|
|
||||||
label="复本数"
|
|
||||||
min-width="100"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="service"
|
|
||||||
label="服务"
|
|
||||||
min-width="150"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="bandwidth"
|
|
||||||
label="宽带"
|
|
||||||
min-width="100"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="memory"
|
|
||||||
label="内存"
|
|
||||||
min-width="100"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="out_port"
|
|
||||||
label="映射端口"
|
|
||||||
min-width="100"/>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="has_deployed"
|
|
||||||
label="部署状态"
|
|
||||||
min-width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
|
||||||
{{ scope.row.has_deployed ? '已部署' : '未部署' }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="network_id"
|
|
||||||
label="网络"
|
|
||||||
min-width="100">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-popover
|
|
||||||
placement="top"
|
|
||||||
width="180"
|
|
||||||
trigger="hover"
|
|
||||||
:visible-arrow="false"
|
|
||||||
popper-class= "pop-con"
|
|
||||||
:ref="`popover1` + scope.$index">
|
|
||||||
<div v-if="popVisiable === true" style="text-align: center; margin: 0;">
|
|
||||||
<p>国家:{{popoverData.country}}</p>
|
|
||||||
<p>网络:{{popoverData.network}}</p>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
class="network"
|
|
||||||
slot="reference"
|
|
||||||
@mouseenter="openAction(scope.$index)"
|
|
||||||
@mouseleave="cancelAction(scope.$index)"
|
|
||||||
>
|
|
||||||
{{ `网络${scope.row.network_id}`}}
|
|
||||||
</a>
|
|
||||||
</el-popover>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
label="操作"
|
|
||||||
min-width="300"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button type="text" size="medium" :disabled="scope.row.delLoading" @click="edit(scope.row)">修改</el-button>
|
|
||||||
<el-button type="text" size="medium" :disabled="scope.row.has_deployed==true || scope.row.delLoading" :loading="scope.row.deployLoading" @click="deploy(scope.row)">部署</el-button>
|
|
||||||
<el-button type="text" size="medium" :loading="scope.row.delLoading" @click="del(scope.row)">删除</el-button>
|
|
||||||
<el-button type="text" size="medium" :disabled="scope.row.delLoading" :loading="scope.row.restartLoading" @click="restart(scope.row)">重启</el-button>
|
|
||||||
<el-button type="text" size="medium" :disabled="scope.row.pipeline_id===0 || scope.row.delLoading" :loading="scope.row.pipelineLoading" @click="pipeline(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>
|
|
||||||
<ConfigForm
|
|
||||||
ref="configForm"
|
|
||||||
:is-add="isAdd"
|
|
||||||
:target_id="target_id"
|
|
||||||
:other-role="otherRole"
|
|
||||||
:country-dict="countryDict"
|
|
||||||
@refresh="init"
|
|
||||||
@openRoleForm="openRoleForm"
|
|
||||||
@clearRoleForm="clearRoleForm">
|
|
||||||
</ConfigForm>
|
|
||||||
<RoleForm
|
|
||||||
ref="roleForm"
|
|
||||||
v-model="otherRole"
|
|
||||||
@submitOtherRole="submitOtherRole">
|
|
||||||
</RoleForm>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import Header from './module/Header.vue'
|
|
||||||
import ConfigForm from './module/ConfigForm.vue'
|
|
||||||
import RoleForm from './module/RoleForm.vue'
|
|
||||||
import { getTargetsResponse } from './mock.js'
|
|
||||||
export default {
|
|
||||||
name: "RangeConfigManage",
|
|
||||||
components:{ Header, ConfigForm, RoleForm },
|
|
||||||
// props:['fTag','fInput','fFrom','FIsConfigQuery'],
|
|
||||||
data(){
|
|
||||||
return{
|
|
||||||
page: 1,
|
|
||||||
size: 10,
|
|
||||||
total: 0,
|
|
||||||
isAdd: false,
|
|
||||||
loading: false,
|
|
||||||
target_id: '',
|
|
||||||
otherRole: '',
|
|
||||||
tableData: [],
|
|
||||||
selectConfigIds: [],
|
|
||||||
countryDict: [],
|
|
||||||
rangeDict: [],
|
|
||||||
batchDeployLoading: false,
|
|
||||||
batchDelLoading: false,
|
|
||||||
batchPipelineLoading: false,
|
|
||||||
networkVisible: false,
|
|
||||||
popoverData: {},
|
|
||||||
popVisiable: false,
|
|
||||||
roleDict:{
|
|
||||||
da: '权威目录节点',
|
|
||||||
client: '客户端节点',
|
|
||||||
guard: '入口节点',
|
|
||||||
relay: '路由节点',
|
|
||||||
exit: '出口节点',
|
|
||||||
onion: '洋葱服务节点',
|
|
||||||
},
|
|
||||||
disabledBatchPipline: false,
|
|
||||||
delTimer: null,
|
|
||||||
counter: 0,
|
|
||||||
batchDelTimer: null,
|
|
||||||
batchCounter: 0,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'$store.state.range.targetId': {
|
|
||||||
handler(newVal, oldVal) {
|
|
||||||
this.target_id = newVal
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getCountryDict()
|
|
||||||
this.getRangeDict()
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
if(this.delTimer) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
}
|
|
||||||
if(this.batchDelTimer) {
|
|
||||||
clearInterval(this.batchDelTimer)
|
|
||||||
this.batchDelTimer = null
|
|
||||||
}
|
|
||||||
this.counter = 0
|
|
||||||
this.batchCounter = 0
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
init(params={}) {
|
|
||||||
// this.tableData = getTargetsResponse?.result?.items
|
|
||||||
// this.total = getTargetsResponse?.result?.total
|
|
||||||
|
|
||||||
// TODO: 暂时注释接口
|
|
||||||
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.getSettingList, 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, 'deployLoading', false)
|
|
||||||
this.$set(item, 'delLoading', false)
|
|
||||||
this.$set(item, 'restartLoading', false)
|
|
||||||
this.$set(item, 'pipelineLoading', false)
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
// 是否全部都没有流水线
|
|
||||||
this.disabledBatchPipline = this.tableData.findIndex(item => item.pipeline_id !== 0) === -1 ? true : false
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
query(params) {
|
|
||||||
this.init(params)
|
|
||||||
},
|
|
||||||
// 打开添加配置dialog
|
|
||||||
addConfig() {
|
|
||||||
this.isAdd = true
|
|
||||||
this.$refs.configForm.getTorDict()
|
|
||||||
this.$refs.configForm.getImageDict()
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.configForm.visible = true
|
|
||||||
},
|
|
||||||
// 当选择其它角色时,弹窗填写角色窗
|
|
||||||
openRoleForm() {
|
|
||||||
this.$refs.roleForm.visible = true
|
|
||||||
},
|
|
||||||
clearRoleForm() {
|
|
||||||
this.otherRole = ''
|
|
||||||
},
|
|
||||||
// 编辑Form重新请求镜像字典
|
|
||||||
submitOtherRole() {
|
|
||||||
this.$refs.configForm.getImageDict()
|
|
||||||
},
|
|
||||||
// 批量部署
|
|
||||||
batchDeploy() {
|
|
||||||
if (this.selectConfigIds.length === 0) {
|
|
||||||
this.$notify({
|
|
||||||
title: '请勾选要部署的数据!',
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.batchDeployLoading = true
|
|
||||||
this.$axios.post(this.$http.api.batchDeply, {setting_id_list: this.selectConfigIds}, {target_id: this.target_id}).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.$notify({
|
|
||||||
title: '批量部署成功',
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.init()
|
|
||||||
} else {
|
|
||||||
this.$notify({
|
|
||||||
title: res,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.batchDeployLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 批量删除
|
|
||||||
batchDel() {
|
|
||||||
if (this.selectConfigIds.length === 0) {
|
|
||||||
this.$notify({
|
|
||||||
title: '请勾选要删除的数据!',
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.batchDelLoading = true
|
|
||||||
this.$axios.delete(this.$http.api.asynBatchDel, {}, {setting_id_list: this.selectConfigIds}).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.init()
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.batchDelTimer = setInterval(() => {
|
|
||||||
this.getBatchTask(res?.result?.task_id || '')
|
|
||||||
},10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.batchDelLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 批量运行流水线
|
|
||||||
batchPipeline() {
|
|
||||||
if (this.selectConfigIds.length === 0) {
|
|
||||||
this.$notify({
|
|
||||||
title: '请勾选要运行流水线的数据!',
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.batchPipelineLoading = true
|
|
||||||
this.$axios.post(this.$http.api.batchPipeline, {setting_id_list: this.selectConfigIds}, {}).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.$notify({
|
|
||||||
title: '批量运行流水线成功',
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.batchPipelineLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 部署
|
|
||||||
deploy(row) {
|
|
||||||
row.deployLoading = true
|
|
||||||
this.$axios.post(this.$http.api.singleDeploy, {}, {setting_id: row.id}).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.deployLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 删除
|
|
||||||
del(row) {
|
|
||||||
const url = this.$http.api.asynDelSetting + '/' + row.id
|
|
||||||
const params = {
|
|
||||||
user_id: row.user_id
|
|
||||||
}
|
|
||||||
row.delLoading = true
|
|
||||||
this.$axios.delete(url, params).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
// this.init()
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
if (this.delTimer) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
}
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
},10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
// row.delLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 重启
|
|
||||||
restart(row) {
|
|
||||||
row.restartLoading = true
|
|
||||||
this.$axios.post(this.$http.api.singleDeploy, {}, { setting_id: row.id }).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.restartLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 运行流水线
|
|
||||||
pipeline(row) {
|
|
||||||
row.pipelineLoading = true
|
|
||||||
this.$axios.post(this.$http.api.pipeline, {}, { setting_id: row.id }).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.pipelineLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 修改
|
|
||||||
edit(row) {
|
|
||||||
this.isAdd = false
|
|
||||||
this.$refs.configForm.setting_id = row.id
|
|
||||||
this.$refs.configForm.form.role = row.role
|
|
||||||
this.$refs.configForm.form.tor_version = row.tor_version
|
|
||||||
this.$refs.configForm.form.image_id = row.image_id
|
|
||||||
this.$refs.configForm.form.replicas = row.replicas
|
|
||||||
this.$refs.configForm.form.bandwidth = row.bandwidth
|
|
||||||
this.$refs.configForm.form.memory = row.memory
|
|
||||||
this.$refs.configForm.form.service = row.service
|
|
||||||
this.$refs.configForm.form.out_port = row.out_port
|
|
||||||
this.$refs.configForm.form.or_port = row.or_port
|
|
||||||
this.$refs.configForm.form.dir_port = row.dir_port
|
|
||||||
this.$refs.configForm.form.socks_port = row.socks_port
|
|
||||||
this.$refs.configForm.form.control_port = row.control_port
|
|
||||||
this.$refs.configForm.form.country_id = row.country_id
|
|
||||||
this.$refs.configForm.form.network_id = row.network_id
|
|
||||||
this.$refs.configForm.form.direct = row.direct
|
|
||||||
this.$refs.configForm.form.start_tcpdump = row.start_tcpdump
|
|
||||||
if(row.start_tcpdump) {
|
|
||||||
this.$refs.configForm.form.deployType = 'start'
|
|
||||||
} else {
|
|
||||||
if(row.direct) {
|
|
||||||
this.$refs.configForm.form.deployType = 'direct'
|
|
||||||
} else {
|
|
||||||
this.$refs.configForm.form.deployType = 'only'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$refs.configForm.getTorDict()
|
|
||||||
this.$refs.configForm.getImageDict()
|
|
||||||
this.$refs.configForm.getNetworkDict()
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.configForm.visible = true
|
|
||||||
},
|
|
||||||
// 获取国家字典
|
|
||||||
getCountryDict() {
|
|
||||||
const params = {
|
|
||||||
page: 1,
|
|
||||||
size: 99
|
|
||||||
}
|
|
||||||
this.$axios.get(this.$http.api.getCountryDict, params).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.countryDict = res?.result?.items.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.country_name,
|
|
||||||
value: item.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 获取靶场列表字典
|
|
||||||
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: ''})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 处理选中的数据
|
|
||||||
handleSelectionChange(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()
|
|
||||||
},
|
|
||||||
// 获取网络
|
|
||||||
cellEnter(row, column){
|
|
||||||
if(column.label === "网络"){
|
|
||||||
this.popoverData = {}
|
|
||||||
this.popVisiable = false
|
|
||||||
// this.loading = true
|
|
||||||
const reqParams = {
|
|
||||||
network_id: row.network_id,
|
|
||||||
}
|
|
||||||
this.$axios.get(this.$http.api.getNetwork, reqParams).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.popoverData = res.result
|
|
||||||
this.popVisiable = true;
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
// this.loading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cancelAction(index){
|
|
||||||
let refName = "popover1" + index;
|
|
||||||
this.$refs[refName].doClose();
|
|
||||||
},
|
|
||||||
openAction(index){
|
|
||||||
let refName = "popover1" + index;
|
|
||||||
this.$refs[refName].doShow();
|
|
||||||
},
|
|
||||||
// 获取任务进度
|
|
||||||
getTask(task_id) {
|
|
||||||
const url = this.$http.api.task + '/' + task_id
|
|
||||||
this.$axios.get(url, {}).then(res => {
|
|
||||||
if(res.task_status !== 'PENDING' && res.task_status !== 'STARTED') {
|
|
||||||
if (res?.task_result?.code === 500 || res?.task_result?.message === 'false') {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行失败`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行完毕`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.counter++
|
|
||||||
if (this.counter >= 60) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 获取任务进度
|
|
||||||
getBatchTask(task_id) {
|
|
||||||
const url = this.$http.api.task + '/' + task_id
|
|
||||||
this.$axios.get(url, {}).then(res => {
|
|
||||||
if(res.task_status !== 'PENDING' && res.task_status !== 'STARTED') {
|
|
||||||
if (res?.task_result?.code === 500 || res?.task_result?.message === 'false') {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行失败`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行完毕`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearInterval(this.batchDelTimer)
|
|
||||||
this.batchDelTimer = null
|
|
||||||
this.batchCounter = 0
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.batchCounter++
|
|
||||||
if (this.batchCounter >= 30) {
|
|
||||||
clearInterval(this.batchDelTimer)
|
|
||||||
this.batchDelTimer = null
|
|
||||||
this.batchCounter = 0
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang='less' scoped="scoped">
|
|
||||||
.custom-table {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.range-config-manage{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
/*background-color: #010f4e;*/
|
|
||||||
// background-color: rgba(255, 25, 49, 0.4);
|
|
||||||
float: right;
|
|
||||||
position: relative; /* 确保相对定位生效 */
|
|
||||||
|
|
||||||
.show{
|
|
||||||
width: 95%;
|
|
||||||
height: 95%;
|
|
||||||
/*background-color: #67c23a;*/
|
|
||||||
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%,高度自适应保持宽高比 */
|
|
||||||
/*background-size: cover; !* 宽度为100%,高度自适应保持宽高比 *!*/
|
|
||||||
|
|
||||||
/*display: flex; !* 将容器设置为 Flex 容器 *!*/
|
|
||||||
/*justify-content: center; !* 水平居中子元素 *!*/
|
|
||||||
/*align-items: center; !* 垂直居中子元素 *!*/
|
|
||||||
|
|
||||||
.list{
|
|
||||||
width: 95%;
|
|
||||||
height: 84%;
|
|
||||||
margin-left: 2.5%;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
border: none;
|
|
||||||
::v-deep .network {
|
|
||||||
float: right;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #857BFF;
|
|
||||||
text-decoration: 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>
|
|
||||||
@@ -1,718 +0,0 @@
|
|||||||
const getTargetsResponse = {
|
|
||||||
"code": 200,
|
|
||||||
"message": "success",
|
|
||||||
"result": {
|
|
||||||
"total": 32,
|
|
||||||
"page": 1,
|
|
||||||
"size": 20,
|
|
||||||
"pages": 0,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"role": "da",
|
|
||||||
"replicas": 1,
|
|
||||||
"service": "string",
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"image_id": 0,
|
|
||||||
"out_port": 0,
|
|
||||||
"has_deployed": false,
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 0,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "relay",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 1,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "exit",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 2,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "onion",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 3,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "client",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 4,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "guard",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 5,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 6,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 7,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"role": "string",
|
|
||||||
"replicas": 1,
|
|
||||||
"service": "string",
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"image_id": 0,
|
|
||||||
"out_port": 0,
|
|
||||||
"has_deployed": false,
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 0,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 1,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 2,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 3,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 4,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 5,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 6,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 7,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"role": "string",
|
|
||||||
"replicas": 1,
|
|
||||||
"service": "string",
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"image_id": 0,
|
|
||||||
"out_port": 0,
|
|
||||||
"has_deployed": false,
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 0,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 1,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 2,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 3,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 4,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 5,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 6,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 7,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"role": "string",
|
|
||||||
"replicas": 1,
|
|
||||||
"service": "string",
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"image_id": 0,
|
|
||||||
"out_port": 0,
|
|
||||||
"has_deployed": false,
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 0,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 1,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 2,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 3,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 4,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 5,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 6,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "string",
|
|
||||||
"image_id": 0,
|
|
||||||
"replicas": 1,
|
|
||||||
"bandwidth": 10,
|
|
||||||
"memory": 100,
|
|
||||||
"service": "string",
|
|
||||||
"tor_version": "4.6.10",
|
|
||||||
"create_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"update_time": "2023-12-19T14:17:19.290Z",
|
|
||||||
"out_port": 0,
|
|
||||||
"socks_port": 19001,
|
|
||||||
"control_port": 19002,
|
|
||||||
"or_port": 7000,
|
|
||||||
"dir_port": 9030,
|
|
||||||
"id": 7,
|
|
||||||
"has_deployed": false,
|
|
||||||
"start_tcpdump": 0,
|
|
||||||
"user_id": 0,
|
|
||||||
"target_id": 0,
|
|
||||||
"network_id": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { getTargetsResponse }
|
|
||||||
@@ -1,658 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="config-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="basicForm"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="150px"
|
|
||||||
class="basic-form"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="角色选择" prop="role">
|
|
||||||
<el-select v-model="form.role" placeholder="请选择角色" @change="selectRole">
|
|
||||||
<el-option
|
|
||||||
v-for="item in roleDict"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.value === 'other' ? `${item.label}(${otherRole})` : `${item.label}(${item.value})`"
|
|
||||||
:value="item.value">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role!=='other'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="tor 版本" prop="tor_version" :rules="form.role!=='other' ? rules.tor_version : [{required: false}]">
|
|
||||||
<el-select v-model="form.tor_version" placeholder="tor 版本" @change="selectTor">
|
|
||||||
<el-option
|
|
||||||
v-for="item in torDict"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="选择镜像" prop="image_id">
|
|
||||||
<el-select v-model="form.image_id" placeholder="镜像名">
|
|
||||||
<el-option
|
|
||||||
v-for="item in imageDict"
|
|
||||||
: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="20">
|
|
||||||
<el-form-item label="复本数" prop="replicas">
|
|
||||||
<el-input v-model="form.replicas" placeholder="请输入内容 (默认值是1)"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="带宽限制" prop="bandwidth">
|
|
||||||
<el-input v-model="form.bandwidth" placeholder="请输入内容 (默认值是10)">
|
|
||||||
<p slot="suffix" class="el-input__icon">M</p>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="内存限制" prop="memory">
|
|
||||||
<el-input v-model="form.memory" placeholder="请输入内容 (默认值是100)">
|
|
||||||
<p slot="suffix" class="el-input__icon">Mi</p>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role==='onion'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="服务器地址" prop="service" :rules="form.role==='onion' ? rules.service : [{required: false}]">
|
|
||||||
<el-input v-model="form.service" placeholder="请输入内容 (onion角色必填)"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role==='client'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="代理端口" prop="out_port" :rules="form.role==='client' ? rules.out_port : [{required: false}]">
|
|
||||||
<!-- <el-input v-model="form.out_port" placeholder="请输入内容 (client角色必填,范围30000-32767)"></el-input> -->
|
|
||||||
<el-select v-model="form.out_port" placeholder="请选择代理端口" @visible-change="showOutPortSelect">
|
|
||||||
<el-option
|
|
||||||
v-for="item in outPortDict"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role==='da'||form.role==='relay'||form.role ==='guard'||form.role ==='exit'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="or端口" prop="or_port">
|
|
||||||
<el-input v-model="form.or_port" placeholder="请输入内容 (默认值是7000)"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role==='da'||form.role==='relay'||form.role ==='guard'||form.role ==='exit'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="dir端口" prop="dir_port">
|
|
||||||
<el-input v-model="form.dir_port" placeholder="请输入内容 (默认值是9030)"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role ==='onion'||form.role==='client'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="客户端监听端口" prop="socks_port">
|
|
||||||
<el-input v-model="form.socks_port" placeholder="请输入内容 (默认值是19001)"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row v-if="form.role ==='onion'||form.role==='client'">
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="客户端控制端口" prop="control_port">
|
|
||||||
<el-input v-model="form.control_port" placeholder="请输入内容 (默认值是19002)"></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="network-box" v-if="tag==='网络配置'">
|
|
||||||
<el-form
|
|
||||||
ref="netForm"
|
|
||||||
:model="form"
|
|
||||||
:rules="netFormRules"
|
|
||||||
label-width="150px"
|
|
||||||
class="basic-form"
|
|
||||||
>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="国家" prop="country_id">
|
|
||||||
<el-select v-model="form.country_id" placeholder="请选择国家" @change="getNetworkDict">
|
|
||||||
<el-option
|
|
||||||
v-for="item in countryDict"
|
|
||||||
: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="20">
|
|
||||||
<el-form-item label="网络" prop="network_id">
|
|
||||||
<el-select v-model="form.network_id" placeholder="请选择网络地址">
|
|
||||||
<el-option
|
|
||||||
v-for="item in networkDict"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</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="updateTag('部署', true)">下一步</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="deploy-box" v-if="tag==='部署'">
|
|
||||||
<div class="dmgxdjx">
|
|
||||||
<div style="margin-right: 45%">
|
|
||||||
<el-radio-group v-model="form.deployType" @change="selectDeploy">
|
|
||||||
<el-radio label="direct">直接部署</el-radio>
|
|
||||||
<el-radio label="only">仅添加配置</el-radio>
|
|
||||||
<el-radio label="start">启动采集程序并部署</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
</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: 'ConfigForm',
|
|
||||||
props: {
|
|
||||||
isAdd: {
|
|
||||||
typeof: Boolean,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
target_id: {
|
|
||||||
typeof: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
otherRole: {
|
|
||||||
typeof: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
countryDict: {
|
|
||||||
typeof: Array,
|
|
||||||
require: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible:false,
|
|
||||||
loading: false,
|
|
||||||
tag:"基本配置",
|
|
||||||
setting_id: '',
|
|
||||||
form: {
|
|
||||||
role: 'da', // 角色选择
|
|
||||||
tor_version: '', // tor版本
|
|
||||||
image_id: '', // 选择镜像
|
|
||||||
replicas: null, // 复本数
|
|
||||||
bandwidth: null, // 宽带限制
|
|
||||||
memory: null, // 内存限制
|
|
||||||
service: '', // 服务器地址
|
|
||||||
out_port: null, // 代理端口
|
|
||||||
or_port: null, // or端口
|
|
||||||
dir_port: null, // dir端口
|
|
||||||
socks_port: null, // 客户端监听端口
|
|
||||||
control_port: null, // 客户端控制端口
|
|
||||||
|
|
||||||
country_id: '', // 国家
|
|
||||||
network_id: '', // 网络
|
|
||||||
|
|
||||||
deployType: 'direct', // 部署方式
|
|
||||||
direct: true, // 直接部署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: [],
|
|
||||||
outPortDict: [],
|
|
||||||
imageDict: [],
|
|
||||||
rules: {
|
|
||||||
role: [
|
|
||||||
{ required: true, message: '请选择角色', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
tor_version: [
|
|
||||||
{ required: true, message: '请选择tor版本', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
image_id: [
|
|
||||||
{ required: true, message: '请选择镜像', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
service:[
|
|
||||||
{ required: true, message: '请输入服务器地址', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
out_port: [
|
|
||||||
{ required: true, message: '请输入代理端口', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
netFormRules: {
|
|
||||||
country_id: [
|
|
||||||
{ required: true, message: '请选择国家', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
network_id: [
|
|
||||||
{ required: true, message: '请选择网络', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getOutPortDict()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 关闭
|
|
||||||
close() {
|
|
||||||
document.querySelector('.mask').style.display = 'none'
|
|
||||||
this.visible = false
|
|
||||||
this.tag = '基本配置'
|
|
||||||
this.resetForm()
|
|
||||||
this.$emit('clearRoleForm')
|
|
||||||
},
|
|
||||||
// 重置
|
|
||||||
resetForm() {
|
|
||||||
this.form = {
|
|
||||||
role: 'da', // 角色选择
|
|
||||||
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', // 部署方式
|
|
||||||
direct: true, // 直接部署true 仅添加配置false
|
|
||||||
start_tcpdump: false // 启动采集程序并部署 true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 选择哪个页面
|
|
||||||
updateTag(val, isValid){
|
|
||||||
if (val === '网络配置' && isValid) {
|
|
||||||
this.$refs.basicForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.tag=val
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if(val === '部署' && isValid) {
|
|
||||||
this.$refs.netForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.tag=val
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.tag=val
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 角色选择
|
|
||||||
selectRole(node) {
|
|
||||||
if (node === 'other') {
|
|
||||||
this.$emit('openRoleForm')
|
|
||||||
}
|
|
||||||
// 获取torDict
|
|
||||||
this.getTorDict()
|
|
||||||
// 获取镜像字典
|
|
||||||
this.getImageDict()
|
|
||||||
},
|
|
||||||
// tor选择
|
|
||||||
selectTor(tor){
|
|
||||||
// 获取镜像字典
|
|
||||||
this.getImageDict()
|
|
||||||
},
|
|
||||||
// 获取torDick
|
|
||||||
getTorDict() {
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 获取imageDict
|
|
||||||
getImageDict(){
|
|
||||||
const params = {
|
|
||||||
page:1,
|
|
||||||
size: 99,
|
|
||||||
image_name: this.form.role,
|
|
||||||
image_version: this.form.tor_version
|
|
||||||
}
|
|
||||||
if (this.form.role === 'other' && this.otherRole) {
|
|
||||||
params.image_name = this.otherRole
|
|
||||||
params.image_type = 'define'
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showOutPortSelect() {
|
|
||||||
this.getOutPortDict()
|
|
||||||
},
|
|
||||||
// 获取代理端口字典
|
|
||||||
getOutPortDict(){
|
|
||||||
const params = {}
|
|
||||||
this.$axios.get(this.$http.api.getOutPortDict, params).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.outPortDict = res?.result
|
|
||||||
}
|
|
||||||
}).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 } = this.form
|
|
||||||
let submitForm = {role, image_id }
|
|
||||||
if (this.form.replicas) {
|
|
||||||
submitForm.replicas = this.form.replicas
|
|
||||||
}
|
|
||||||
if (this.form.bandwidth) {
|
|
||||||
submitForm.bandwidth = this.form.bandwidth
|
|
||||||
}
|
|
||||||
if (this.form.memory) {
|
|
||||||
submitForm.memory = this.form.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
|
|
||||||
if (this.form.or_port) {
|
|
||||||
submitForm.or_port = this.form.or_port
|
|
||||||
}
|
|
||||||
if (this.form.dir_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
|
|
||||||
if (this.form.socks_port) {
|
|
||||||
submitForm.socks_port = this.form.socks_port
|
|
||||||
}
|
|
||||||
if (this.form.control_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
|
|
||||||
if (this.form.socks_port) {
|
|
||||||
submitForm.socks_port = this.form.socks_port
|
|
||||||
}
|
|
||||||
if (this.form.control_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+ `/${this.setting_id}/?target_id=${this.target_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>
|
|
||||||
.config-dialog{
|
|
||||||
z-index: 997;
|
|
||||||
width: 620px;
|
|
||||||
height: 555px;
|
|
||||||
position: absolute; /* 绝对定位 */
|
|
||||||
top: 50%; /* 向下偏移50% */
|
|
||||||
left: 50%; /* 向右偏移50% */
|
|
||||||
transform: translate(-50%, -50%); /* 回移50% */
|
|
||||||
background-image:url('../../../img/tjpz.svg');
|
|
||||||
background-repeat: no-repeat; /* 可选,防止图像重复 */
|
|
||||||
background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
|
|
||||||
.el-icon-close{
|
|
||||||
float: right;
|
|
||||||
padding-right: 7%;
|
|
||||||
padding-top: 3%
|
|
||||||
}
|
|
||||||
.basic-form {
|
|
||||||
margin-top: 20px;
|
|
||||||
text-align: left;
|
|
||||||
::v-deep .el-select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tag{
|
|
||||||
margin-left: 9%;
|
|
||||||
.tags{
|
|
||||||
margin-right: 5%;
|
|
||||||
margin-top: 2%;
|
|
||||||
font-size: 23px;
|
|
||||||
border: none;
|
|
||||||
background-color: transparent !important;
|
|
||||||
color: #565e6e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.but-color {
|
|
||||||
background-color: #02DDEA !important;
|
|
||||||
}
|
|
||||||
.basic-box{
|
|
||||||
.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: 5%;
|
|
||||||
background-color: rgba(24, 133, 234, 0.2);
|
|
||||||
color: #1b7cc4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.network-box{
|
|
||||||
.anDiv{
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
margin-top: 50%;
|
|
||||||
text-align: center;
|
|
||||||
.glBut{
|
|
||||||
width: 90px;
|
|
||||||
height: 30px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 5%;
|
|
||||||
background-color: rgba(24, 133, 234, 0.2);
|
|
||||||
color: #1b7cc4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.deploy-box{
|
|
||||||
.dmgxdjx{
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
display: block;
|
|
||||||
margin-top: 3%;
|
|
||||||
margin-left: 20%;
|
|
||||||
text-align: left;
|
|
||||||
.el-radio {
|
|
||||||
display: block;
|
|
||||||
margin-top: 20%;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.anDiv{
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
margin-top: 49%;
|
|
||||||
text-align: center;
|
|
||||||
.glBut{
|
|
||||||
width: 90px;
|
|
||||||
height: 30px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 5%;
|
|
||||||
background-color: rgba(24, 133, 234, 0.2);
|
|
||||||
color: #1b7cc4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="head">
|
|
||||||
<div class="target-select">
|
|
||||||
<el-select class="range-select" style="width:220px;" 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>
|
|
||||||
<img src="../../../img/btn/addConfigBtn.svg" style="height: 70% ;width: 10%;margin-right: 2%;color: #ffffff" @click="addConfig">
|
|
||||||
<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"></svg-icon>
|
|
||||||
<span style="margin-left: 10px;">{{ item.label }}</span>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
<div class="deploy-select">
|
|
||||||
<el-select v-model="has_deployed" 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 type="primary" :loading="batchDeployLoading" @click="batchDeploy">批量部署</el-button>
|
|
||||||
<el-button type="primary" :loading="batchDelLoading" @click="batchDel">批量删除</el-button>
|
|
||||||
<el-button type="primary" :loading="batchPipelineLoading" @click="batchPipeline" :disabled="disabledBatchPipline">批量运行流水线</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Header',
|
|
||||||
props: ['rangeDict', 'batchDeployLoading', 'batchDelLoading', 'batchPipelineLoading', 'disabledBatchPipline'],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
target_id: '',
|
|
||||||
role: '',
|
|
||||||
has_deployed: '',
|
|
||||||
roleDict:[
|
|
||||||
{label: '权威目录节点', value: 'da'},
|
|
||||||
{label: '路由节点', value: 'relay'},
|
|
||||||
{label: '出口节点', value: 'exit'},
|
|
||||||
{label: '洋葱服务节点', value: 'onion'},
|
|
||||||
{label: '客户端节点', value: 'client'},
|
|
||||||
{label: '入口节点', value: 'guard'}
|
|
||||||
],
|
|
||||||
statusDict: [
|
|
||||||
{value: 'true', label: '已部署'},
|
|
||||||
{value: 'false',label: '未部署'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'$store.state.range.targetId': {
|
|
||||||
handler(newVal, oldVal) {
|
|
||||||
this.target_id = newVal
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 改变靶场
|
|
||||||
changeRange() {
|
|
||||||
this.$store.commit('range/setTargetId', this.target_id)
|
|
||||||
},
|
|
||||||
// 新增
|
|
||||||
addConfig() {
|
|
||||||
this.$emit('addConfig')
|
|
||||||
},
|
|
||||||
// 查询
|
|
||||||
query() {
|
|
||||||
let params = {}
|
|
||||||
if (this.has_deployed !== '') {
|
|
||||||
params.has_deployed = this.has_deployed
|
|
||||||
}
|
|
||||||
if (this.role !== '') {
|
|
||||||
params.role = this.role
|
|
||||||
}
|
|
||||||
this.$emit('query', params)
|
|
||||||
},
|
|
||||||
// 批量部署
|
|
||||||
batchDeploy() {
|
|
||||||
this.$emit('batchDeploy')
|
|
||||||
},
|
|
||||||
// 批量删除
|
|
||||||
batchDel() {
|
|
||||||
this.$emit('batchDel')
|
|
||||||
},
|
|
||||||
// 批量运行流水线
|
|
||||||
batchPipeline() {
|
|
||||||
this.$emit('batchPipeline')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.head{
|
|
||||||
width: 95%;
|
|
||||||
height: 7%;
|
|
||||||
margin-top: 1%;
|
|
||||||
margin-left: 2.5%;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.target-select{
|
|
||||||
font-size: 10px;
|
|
||||||
float: left;
|
|
||||||
margin-top: 0.5%;
|
|
||||||
display: inline-block;
|
|
||||||
height: 60%;
|
|
||||||
width: 10%;
|
|
||||||
margin-left: 0.5%;
|
|
||||||
.custom-popper .el-select-dropdown {
|
|
||||||
max-height: 3px;
|
|
||||||
}
|
|
||||||
.range-select {
|
|
||||||
::v-deep .el-input {
|
|
||||||
width: 80%;
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.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>
|
|
||||||
@@ -1,94 +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: 4.5%">角色</span>
|
|
||||||
<el-input
|
|
||||||
: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() {
|
|
||||||
this.$emit('submitOtherRole')
|
|
||||||
document.querySelector('.mask').style.display = 'none'
|
|
||||||
this.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.role-dialog{
|
|
||||||
z-index: 998;
|
|
||||||
width: 30%;
|
|
||||||
height: 20%;
|
|
||||||
position: absolute; /* 绝对定位 */
|
|
||||||
top: 50%; /* 向下偏移50% */
|
|
||||||
left: 50%; /* 向右偏移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: 10%;
|
|
||||||
text-align: center;
|
|
||||||
.glBut{
|
|
||||||
width: 90px;
|
|
||||||
height: 30px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 10%;
|
|
||||||
background-color: rgba(24, 133, 234, 0.2);
|
|
||||||
color: #1b7cc4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="range-manage" ref="appRef">
|
|
||||||
<div class="show">
|
|
||||||
<Header
|
|
||||||
@quickAdd="quickAdd"
|
|
||||||
@customAdd="customAdd"
|
|
||||||
@query="query"
|
|
||||||
></Header>
|
|
||||||
<div class="list" id="show-loading">
|
|
||||||
<div class="single" v-for="rangeItem in rangeList" :key="rangeItem.target_name">
|
|
||||||
<div class="title">
|
|
||||||
<span style="font-size: 20px;">{{rangeItem.target_name+' '+getDeployStatus(rangeItem,'deploy_status')}}</span>
|
|
||||||
<el-button :class="rangeItem.attribute==='public' ? 'gOsY' : 'gOsN'" >{{rangeItem.attribute==='public' ? '公用' : '私有'}}</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="cell">{{`正常节点:${getDeployStatus(rangeItem,'deploy_success_count')}个`}}</div>
|
|
||||||
<div class="cell">{{`异常节点:${getDeployStatus(rangeItem,'deploy_default_count')}个`}}</div>
|
|
||||||
<div class="cell">{{`节点数量:${getDeployStatus(rangeItem,'deploy_total_count')}个`}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="cell small">{{`创建人:${rangeItem.username}`}}</div>
|
|
||||||
<div class="cell large">{{`创建时间:${formatTime(rangeItem.create_time)}`}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="buttons">
|
|
||||||
<el-button class="glBut" type="primary" :disabled="rangeItem.delLoading" @click="edit(rangeItem)">修改</el-button>
|
|
||||||
<el-button class="glBut" type="primary" :loading="rangeItem.delLoading" @click="del(rangeItem)">删除</el-button>
|
|
||||||
<el-button class="glBut" type="primary" @click="goConfigManage(rangeItem.id)">配置管理</el-button>
|
|
||||||
<el-button class="glBut" type="primary" @click="goNodeManage(rangeItem.id)">节点管理</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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>
|
|
||||||
<QuickCreate ref="quickCreate" :is-add="isAdd" @refresh="init"></QuickCreate>
|
|
||||||
<CustomCreate ref="customCreate" :is-add="isAdd" @refresh="init"></CustomCreate>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Header from './module/Header.vue'
|
|
||||||
import QuickCreate from './module/QuickCreate.vue'
|
|
||||||
import CustomCreate from './module/CustomCreate.vue'
|
|
||||||
import { formatTime } from '../../utils'
|
|
||||||
import { Loading } from 'element-ui'
|
|
||||||
import { getTargetsResponse } from './mock.js'
|
|
||||||
export default {
|
|
||||||
name: "RangeMange",
|
|
||||||
components:{
|
|
||||||
Header,
|
|
||||||
QuickCreate,
|
|
||||||
CustomCreate
|
|
||||||
},
|
|
||||||
// props:['fTag','fInput','fFrom','FIsConfigQuery'],
|
|
||||||
data(){
|
|
||||||
return{
|
|
||||||
page: 1,
|
|
||||||
size: 10,
|
|
||||||
total: 0,
|
|
||||||
isAdd: false,
|
|
||||||
rangeList:[],
|
|
||||||
delTimer: null,
|
|
||||||
pendingTimer: null,
|
|
||||||
counter: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {},
|
|
||||||
watch: {},
|
|
||||||
filters: {},
|
|
||||||
created() {
|
|
||||||
// this.init()
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
if (this.pendingTimer) {
|
|
||||||
clearInterval(this.pendingTimer)
|
|
||||||
this.pendingTimer = null
|
|
||||||
}
|
|
||||||
if(this.delTimer) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
}
|
|
||||||
this.counter = 0
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
formatTime,
|
|
||||||
// 初始化数据
|
|
||||||
init(params={}) {
|
|
||||||
// this.rangeList = getTargetsResponse?.result?.items
|
|
||||||
// this.total = getTargetsResponse?.result?.total
|
|
||||||
const reqParams = {
|
|
||||||
page: this.page,
|
|
||||||
size: this.size,
|
|
||||||
...params
|
|
||||||
}
|
|
||||||
// TODO: 网络请求先注释,后期放开
|
|
||||||
let loadingInstance = Loading.service({ text: '加载中...', target: '#show-loading'}) // 开启loading
|
|
||||||
this.$axios.get(this.$http.api.getTargets, reqParams).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.total = res?.result?.total
|
|
||||||
this.rangeList = res?.result?.items
|
|
||||||
this.rangeList.map(item => {
|
|
||||||
this.$set(item, 'delLoading', false)
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
let index = this.rangeList?.findIndex(item => {
|
|
||||||
return item.target_deploy_statuses[0].deploy_status === '部署中' || item.target_deploy_statuses[0].deploy_status === '删除中'
|
|
||||||
})
|
|
||||||
if (index !== -1) {
|
|
||||||
if (!this.pendingTimer) {
|
|
||||||
this.pendingTimer = setInterval(() => {
|
|
||||||
this.timerUpdateList(params)
|
|
||||||
}, 10 * 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
loadingInstance.close()
|
|
||||||
if(this.rangeList.length === 0) {
|
|
||||||
this.$store.commit('range/setTargetId', '')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 查询
|
|
||||||
query(params) {
|
|
||||||
this.init(params)
|
|
||||||
},
|
|
||||||
// pendingTimer只刷新数据
|
|
||||||
timerUpdateList(params) {
|
|
||||||
const reqParams = {
|
|
||||||
page: this.page,
|
|
||||||
size: this.size,
|
|
||||||
...params
|
|
||||||
}
|
|
||||||
this.$axios.get(this.$http.api.getTargets, reqParams).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.total = res?.result?.total
|
|
||||||
this.rangeList = res?.result?.items
|
|
||||||
this.rangeList.map(item => {
|
|
||||||
this.$set(item, 'delLoading', false)
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
if(this.rangeList.length === 0) {
|
|
||||||
this.$store.commit('range/setTargetId', '')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 修改
|
|
||||||
edit(rangeItem) {
|
|
||||||
if (rangeItem.create_mode === 'define') {
|
|
||||||
// 自定义靶场修改
|
|
||||||
this.isAdd = false
|
|
||||||
this.$refs.customCreate.target_id = rangeItem.id
|
|
||||||
this.$refs.customCreate.user_id = rangeItem.user_id
|
|
||||||
this.$refs.customCreate.form.target_name = rangeItem.target_name
|
|
||||||
this.$refs.customCreate.form.description = rangeItem.description
|
|
||||||
this.$refs.customCreate.form.attribute = rangeItem.attribute
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.customCreate.visible = true
|
|
||||||
} else {
|
|
||||||
// 快速创建靶场修改
|
|
||||||
this.isAdd = false
|
|
||||||
this.$refs.quickCreate.target_id = rangeItem.id
|
|
||||||
this.$refs.quickCreate.user_id = rangeItem.user_id
|
|
||||||
this.$refs.quickCreate.form.target_name = rangeItem.target_name
|
|
||||||
this.$refs.quickCreate.form.description = rangeItem.description
|
|
||||||
if (rangeItem.ratio === 0.01 || rangeItem.ratio === 0.005 || rangeItem.ratio === 0.002 || rangeItem.ratio === 0.001) {
|
|
||||||
this.$refs.quickCreate.form.ratio = rangeItem.ratio.toString()
|
|
||||||
} else {
|
|
||||||
this.$refs.quickCreate.otherRatio = rangeItem.ratio.toString()
|
|
||||||
}
|
|
||||||
this.$refs.quickCreate.form.attribute = rangeItem.attribute
|
|
||||||
this.$refs.quickCreate.form.createType = rangeItem.create_mode
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.quickCreate.visible = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 删除
|
|
||||||
del(rangeItem) {
|
|
||||||
rangeItem.delLoading = true
|
|
||||||
const url = this.$http.api.asyncTarget + '/' + rangeItem.id
|
|
||||||
this.$axios.delete(url, {}).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
}, 10 * 1000)
|
|
||||||
// this.init()
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
// rangeItem.delLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 获取任务进度
|
|
||||||
getTask(task_id) {
|
|
||||||
const url = this.$http.api.task + '/' + task_id
|
|
||||||
this.$axios.get(url, {}).then(res => {
|
|
||||||
if(res.task_status !== 'PENDING' && res.task_status !== 'STARTED') {
|
|
||||||
if (res?.task_result?.code === 500 || res?.task_result?.message === 'false') {
|
|
||||||
this.$notify({
|
|
||||||
title: `${res.task_id}任务执行完毕,删除靶场失败`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.$notify({
|
|
||||||
title: `${res.task_id}任务执行完毕,删除靶场成功`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.init()
|
|
||||||
} else {
|
|
||||||
// this.$notify({
|
|
||||||
// title: `${res.task_id}任务执行中`,
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.counter++
|
|
||||||
if (this.counter >= 60) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 配置管理页面
|
|
||||||
goConfigManage(id) {
|
|
||||||
this.$store.commit('globalAttrs/setCheckMenu', 'rangeConfigManage')
|
|
||||||
this.$store.commit('range/setTargetId', id)
|
|
||||||
},
|
|
||||||
// 节点管理页面
|
|
||||||
goNodeManage(id) {
|
|
||||||
this.$store.commit('globalAttrs/setCheckMenu', 'rangeNodeManage')
|
|
||||||
this.$store.commit('range/setTargetId', id)
|
|
||||||
},
|
|
||||||
// 打开快速创建靶场
|
|
||||||
quickAdd() {
|
|
||||||
this.isAdd = true
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.quickCreate.visible = true
|
|
||||||
},
|
|
||||||
// 打开自定义创建靶场
|
|
||||||
customAdd() {
|
|
||||||
this.isAdd = true
|
|
||||||
document.querySelector('.mask').style.display = 'block'
|
|
||||||
this.$refs.customCreate.visible = true
|
|
||||||
},
|
|
||||||
getDeployStatus(rangeItem, deploy) {
|
|
||||||
if (rangeItem.target_deploy_statuses.length > 0) {
|
|
||||||
return rangeItem.target_deploy_statuses[0][deploy]
|
|
||||||
} else {
|
|
||||||
return '--'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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>
|
|
||||||
.range-manage{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
float: right;
|
|
||||||
position: relative; /* 确保相对定位生效 */
|
|
||||||
|
|
||||||
.show{
|
|
||||||
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%,高度自适应保持宽高比 */
|
|
||||||
.list{
|
|
||||||
display:flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-content: flex-start;
|
|
||||||
width: 95%;
|
|
||||||
height: 84%;
|
|
||||||
margin-left: 2.5%;
|
|
||||||
.single:hover{
|
|
||||||
border: 1px solid #159dd3;
|
|
||||||
}
|
|
||||||
.single{
|
|
||||||
width: 32%;
|
|
||||||
height: 23.5%;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid rgba(186, 208, 241, 0.10);
|
|
||||||
background: rgba(25, 33, 61, 0.40);
|
|
||||||
margin-left: 1.2%;
|
|
||||||
margin-bottom: 0.9%;
|
|
||||||
padding: 20px;
|
|
||||||
display: inline-block;
|
|
||||||
.title{
|
|
||||||
text-align: left;
|
|
||||||
.gOsY{
|
|
||||||
width: 15px;
|
|
||||||
height: 10px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 2%;
|
|
||||||
background-color: rgba(121, 175, 122, 0.3);
|
|
||||||
color: #36af04;
|
|
||||||
}
|
|
||||||
.gOsN{
|
|
||||||
width: 15px;
|
|
||||||
height: 10px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 2%;
|
|
||||||
background-color: rgba(207, 172, 93, 0.3);
|
|
||||||
color: #af8109;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.container{
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 10px 0 10px 0;
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell {
|
|
||||||
flex-grow: 1;
|
|
||||||
color: rgba(255, 255, 255, 0.6);
|
|
||||||
border: none;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell.small {
|
|
||||||
flex-basis: 33.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell.large {
|
|
||||||
flex-basis: 66.5%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttons{
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
.glBut{
|
|
||||||
width: 80px;
|
|
||||||
height: 30px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
// margin-left: 2%;
|
|
||||||
background-color: rgba(14, 61, 138, 0.50);
|
|
||||||
color: #02DDEA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 遮罩层
|
|
||||||
.mask{
|
|
||||||
position: fixed; /*将元素设置为固定定位*/
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: rgba(0,0,0,0.5); /*通过rgba函数来控制遮罩层的透明度*/
|
|
||||||
display: none; /*将元素隐藏*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
const getTargetsResponse = {
|
|
||||||
"code":200,
|
|
||||||
"message":"success",
|
|
||||||
"result":{
|
|
||||||
"items":[
|
|
||||||
{
|
|
||||||
"target_name":"tor测试靶场",
|
|
||||||
"description":"部署tor网络",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":23,
|
|
||||||
"user_id":2,
|
|
||||||
"create_time":"2023-12-07T14:24:53",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
{
|
|
||||||
"deploy_status":"部署成功",
|
|
||||||
"deploy_total_count":20,
|
|
||||||
"deploy_success_count":18,
|
|
||||||
"deploy_default_count":2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"target_name":"tor测试靶场2",
|
|
||||||
"description":"部署tor网络",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":24,
|
|
||||||
"user_id":2,
|
|
||||||
"create_time":"2023-12-07T14:37:54",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
{
|
|
||||||
"deploy_status":"未部署",
|
|
||||||
"deploy_total_count":0,
|
|
||||||
"deploy_success_count":0,
|
|
||||||
"deploy_default_count":0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"target_name":"string",
|
|
||||||
"description":"string",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":34,
|
|
||||||
"user_id":4,
|
|
||||||
"create_time":"2023-12-13T00:30:22",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"target_name":"XT-RANGE1",
|
|
||||||
"description":"XT测试靶场1",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":35,
|
|
||||||
"user_id":4,
|
|
||||||
"create_time":"2023-12-13T10:57:05",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"target_name":"XT-RANGE2",
|
|
||||||
"description":"XT测试靶场2",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":36,
|
|
||||||
"user_id":4,
|
|
||||||
"create_time":"2023-12-13T15:55:12",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"target_name":"XT-RANGE3",
|
|
||||||
"description":"XT测试靶场3",
|
|
||||||
"attribute":"public",
|
|
||||||
"id":37,
|
|
||||||
"user_id":4,
|
|
||||||
"create_time":"2023-12-13T15:55:12",
|
|
||||||
"target_deploy_statuses":[
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total":6,
|
|
||||||
"page":1,
|
|
||||||
"size":50,
|
|
||||||
"pages":1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { getTargetsResponse }
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="custom-dialog"
|
|
||||||
v-if="visible"
|
|
||||||
>
|
|
||||||
<!-- 在此处指定弹窗的样式和内容 -->
|
|
||||||
<i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
|
|
||||||
<el-form
|
|
||||||
ref="customForm"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="150px"
|
|
||||||
class="custom-form"
|
|
||||||
>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="靶场名称" prop="target_name">
|
|
||||||
<el-input v-model="form.target_name" placeholder="请输入内容"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="靶场描述" prop="description">
|
|
||||||
<el-input type="textarea" v-model="form.description" placeholder="请输入内容"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="所有权" prop="attribute">
|
|
||||||
<el-radio v-model="form.attribute" label="private">私有</el-radio>
|
|
||||||
<el-radio v-model="form.attribute" label="public">公用</el-radio>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<div class="submit-footer">
|
|
||||||
<div>
|
|
||||||
<el-button class="glBut" type="primary" @click="resetForm">重置</el-button>
|
|
||||||
<el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">{{isAdd ? '提交' : '确定'}}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'CustomCreate',
|
|
||||||
props: {
|
|
||||||
isAdd: {
|
|
||||||
typeof: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible: false,
|
|
||||||
loading: false,
|
|
||||||
form: {
|
|
||||||
target_name: '', // 靶场名称
|
|
||||||
description: '', // 靶场描述
|
|
||||||
attribute: '' // 所有权
|
|
||||||
},
|
|
||||||
target_id: '',
|
|
||||||
user_id: '',
|
|
||||||
rules: {
|
|
||||||
target_name: [
|
|
||||||
{ required: true, message: '请输入靶场名称', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
description: [
|
|
||||||
{ required: false, message: '请输入描述', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
attribute: [
|
|
||||||
{ required: true, message: '请选择所有权', trigger: 'change' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.resetForm()
|
|
||||||
document.querySelector('.mask').style.display = 'none'
|
|
||||||
this.visible = false
|
|
||||||
},
|
|
||||||
submit() {
|
|
||||||
this.$refs.customForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
if (this.isAdd) {
|
|
||||||
this.add()
|
|
||||||
} else {
|
|
||||||
this.edit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
add () {
|
|
||||||
this.loading = true
|
|
||||||
const url = this.$http.api.target
|
|
||||||
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.target + `/${this.target_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 = {
|
|
||||||
target_name: '', // 靶场名称
|
|
||||||
description: '', // 靶场描述
|
|
||||||
attribute: '' // 所有权
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.custom-dialog{
|
|
||||||
width: 520px;
|
|
||||||
height: 363px;
|
|
||||||
position: absolute; /* 绝对定位 */
|
|
||||||
top: 50%; /* 向下偏移50% */
|
|
||||||
left: 50%; /* 向右偏移50% */
|
|
||||||
transform: translate(-50%, -50%); /* 回移50% */
|
|
||||||
background-image:url('../../../img/Group.svg');
|
|
||||||
background-repeat: no-repeat; /* 可选,防止图像重复 */
|
|
||||||
background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
|
|
||||||
|
|
||||||
.custom-form {
|
|
||||||
margin-top: 70px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.submit-footer{
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
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>
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="head">
|
|
||||||
<span style="font-size: 14px;float: left;padding-top: 1%">靶场列表</span>
|
|
||||||
<img src="../../../img/btn/quickCreateRangeBtn.svg" style="height: 70% ;width: 10%;margin-right: 7%;color: #ffffff" @click="quickAdd">
|
|
||||||
<img src="../../../img/btn/customCreateRangeBtn.svg" style="height: 70% ;width: 10%;margin-right: 7%;color: #ffffff" @click="customAdd">
|
|
||||||
<div class="input">
|
|
||||||
<el-input v-model="target_name" placeholder="名称查询输入" suffix icon="">
|
|
||||||
<template v-slot:suffix>
|
|
||||||
<div class="icon-group">
|
|
||||||
<img src="../../../img/inputl.png" alt="**">
|
|
||||||
<img src="../../../img/inputIcon.png" alt="*" @click="query">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</div>
|
|
||||||
<div class="state">
|
|
||||||
<el-select v-model="deploy_status" placeholder="全部状态" clearable @change="query">
|
|
||||||
<el-option
|
|
||||||
v-for="item in statusDict"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
<div class="project">
|
|
||||||
<el-select v-model="attribute" placeholder="全部工程" clearable @change="query">
|
|
||||||
<el-option
|
|
||||||
v-for="item in attributeDict"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
target_name: '', // 靶场名称
|
|
||||||
deploy_status: '',
|
|
||||||
attribute: '',
|
|
||||||
statusDict: [
|
|
||||||
{
|
|
||||||
value: '部署成功',
|
|
||||||
label: '部署成功'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '部署中',
|
|
||||||
label: '部署中'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '未部署',
|
|
||||||
label: '未部署'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '部署失败',
|
|
||||||
label: '部署失败'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributeDict: [
|
|
||||||
{
|
|
||||||
value: 'public',
|
|
||||||
label: '公用'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'private',
|
|
||||||
label: '私有'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
quickAdd() {
|
|
||||||
this.$emit('quickAdd')
|
|
||||||
},
|
|
||||||
customAdd() {
|
|
||||||
this.$emit('customAdd')
|
|
||||||
},
|
|
||||||
query() {
|
|
||||||
const params = {
|
|
||||||
target_name: this.target_name,
|
|
||||||
deploy_status: this.deploy_status,
|
|
||||||
attribute: this.attribute
|
|
||||||
}
|
|
||||||
this.$emit('query', params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.head{
|
|
||||||
width: 95%;
|
|
||||||
height: 7%;
|
|
||||||
margin-top: 1%;
|
|
||||||
margin-left: 2.5%;
|
|
||||||
text-align: right;
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.state{
|
|
||||||
display: inline-block;
|
|
||||||
height: 60%;
|
|
||||||
width: 10%;
|
|
||||||
margin-left: 0.5%;
|
|
||||||
.custom-popper .el-select-dropdown {
|
|
||||||
max-height: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.project{
|
|
||||||
display: inline-block;
|
|
||||||
height: 60%;
|
|
||||||
width: 10%;
|
|
||||||
margin-left: 0.5%;
|
|
||||||
margin-right: 3%;
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,437 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="quick-dialog" v-if="visible">
|
|
||||||
<!-- 在此处指定弹窗的样式和内容 -->
|
|
||||||
<i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
|
|
||||||
<el-form
|
|
||||||
ref="quickForm"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="150px"
|
|
||||||
class="quick-form"
|
|
||||||
>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="靶场名称" prop="target_name">
|
|
||||||
<el-input v-model="form.target_name" placeholder="请输入内容"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="靶场描述" prop="description">
|
|
||||||
<el-input type="textarea" v-model="form.description" placeholder="请输入内容"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="选择按真实tor网络模拟比例" class="long-item-label">
|
|
||||||
<el-radio-group v-model="form.ratio" @change="radioChange">
|
|
||||||
<el-radio label="0.01">1:100</el-radio>
|
|
||||||
<el-radio label="0.02">1:200</el-radio>
|
|
||||||
<el-radio label="0.002">1:500</el-radio>
|
|
||||||
<el-radio label="0.001">1:1000</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
<div style="margin-top: 2%">
|
|
||||||
<span style="font-size: 12px">其他</span>
|
|
||||||
<el-input v-model="otherRatio" class="other-ratio" placeholder="请输入内容" @focus="otherRadioInput"></el-input>
|
|
||||||
<span style="font-size: 14px;color: #4b5362">(范围在0.001-0.01之间)</span>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="所有权" prop="attribute">
|
|
||||||
<el-radio v-model="form.attribute" label="private">私有</el-radio>
|
|
||||||
<el-radio v-model="form.attribute" label="public">公用</el-radio>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item label="创建方式" prop="createType">
|
|
||||||
<el-radio v-model="form.createType" label="interface">接口模式</el-radio>
|
|
||||||
<el-radio v-model="form.createType" label="consensus">consensus模式</el-radio>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<div class="upload-file" v-if="form.createType==='consensus'">
|
|
||||||
<input class="uploadBgImg" type="file" name="file" @change="selectFile" />
|
|
||||||
<div v-if="fileName">{{ fileName }}</div>
|
|
||||||
</div>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<div class="submit-footer" :style="form.createType==='consensus'?'margin-top: 60px':'margin-top: 120px'">
|
|
||||||
<div>
|
|
||||||
<el-button class="glBut" type="primary" @click="resetForm">重置</el-button>
|
|
||||||
<el-button class="glBut but-color" style="width: 120px;" type="primary" @click="submitConfig" :loading="configLoading">仅添加配置</el-button>
|
|
||||||
<el-button class="glBut but-color" type="primary" @click="submit" :loading="createLoading">创建</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'QuickCreate',
|
|
||||||
props: {
|
|
||||||
isAdd: {
|
|
||||||
typeof: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible: false,
|
|
||||||
createLoading: false,
|
|
||||||
configLoading: false,
|
|
||||||
form: {
|
|
||||||
target_name: '', // 靶场名称
|
|
||||||
description: '', // 靶场描述
|
|
||||||
ratio: '', // 选择按真实tor网络模拟的比例
|
|
||||||
attribute: '', // 所有权
|
|
||||||
createType: '', // 创建方式
|
|
||||||
file: '' // 上传文件
|
|
||||||
},
|
|
||||||
target_id: '',
|
|
||||||
user_id: '',
|
|
||||||
fileName: '',
|
|
||||||
otherRatio: '',
|
|
||||||
delTimer: null,
|
|
||||||
counter: 0,
|
|
||||||
rules: {
|
|
||||||
target_name: [
|
|
||||||
{ required: true, message: '请输入靶场名称', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
description: [
|
|
||||||
{ required: false, message: '请输入描述', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
ratio: [
|
|
||||||
{ required: true, message: '请选择模拟比例', trigger: 'change' }
|
|
||||||
],
|
|
||||||
attribute: [
|
|
||||||
{ required: true, message: '请选择所有权', trigger: 'change' }
|
|
||||||
],
|
|
||||||
createType: [
|
|
||||||
{ required: true, message: '请选择创建方式', trigger: 'change' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
if(this.delTimer) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
}
|
|
||||||
this.counter = 0
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.resetForm()
|
|
||||||
document.querySelector('.mask').style.display = 'none'
|
|
||||||
this.visible = false
|
|
||||||
},
|
|
||||||
// 重置
|
|
||||||
resetForm() {
|
|
||||||
this.fileName = ''
|
|
||||||
this.otherRatio = ''
|
|
||||||
this.form = {
|
|
||||||
target_name: '', // 靶场名称
|
|
||||||
description: '', // 靶场描述
|
|
||||||
ratio: '', // 选择按真实tor网络模拟的比例
|
|
||||||
attribute: '', // 所有权
|
|
||||||
createType: '', // 创建方式
|
|
||||||
file: '' // 上传文件
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 仅添加配置
|
|
||||||
submitConfig() {
|
|
||||||
this.$refs.quickForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.configLoading = true
|
|
||||||
if (this.isAdd) {
|
|
||||||
this.add(false)
|
|
||||||
} else {
|
|
||||||
this.edit(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 创建
|
|
||||||
submit() {
|
|
||||||
this.$refs.quickForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.createLoading = true
|
|
||||||
if (this.isAdd) {
|
|
||||||
this.add(true)
|
|
||||||
} else {
|
|
||||||
this.edit(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
add (isCreate) {
|
|
||||||
if (this.form.createType === 'interface') {
|
|
||||||
// 接口模式
|
|
||||||
const url = isCreate ? this.$http.api.asyncQuickInterface + '/?direct=true' : this.$http.api.asyncQuickInterface + '/?direct=false'
|
|
||||||
const {target_name, description, ratio, attribute} = this.form
|
|
||||||
const submitForm = { target_name, description, ratio, attribute }
|
|
||||||
this.$axios.postForm(url, submitForm).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.close()
|
|
||||||
this.$emit('refresh')
|
|
||||||
// this.$notify({
|
|
||||||
// title: '创建靶场成功',
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
}, 10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.createLoading = false
|
|
||||||
this.configLoading = false
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// consensus模式
|
|
||||||
const url = isCreate ? this.$http.api.asyncQuickConsensus + '/?direct=true' : this.$http.api.asyncQuickConsensus + '/?direct=false'
|
|
||||||
const submitForm = new FormData()
|
|
||||||
for(const key in this.form) {
|
|
||||||
submitForm.append(key, this.form[key])
|
|
||||||
}
|
|
||||||
this.$axios.postFormData(url, submitForm).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.close()
|
|
||||||
this.$emit('refresh')
|
|
||||||
// this.$notify({
|
|
||||||
// title: '创建靶场成功',
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
},10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.createLoading = false
|
|
||||||
this.configLoading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
edit(isCreate) {
|
|
||||||
const editForm = JSON.parse(JSON.stringify(this.form))
|
|
||||||
if (this.otherRatio !== '') {
|
|
||||||
editForm.ratio = this.otherRatio
|
|
||||||
}
|
|
||||||
if(this.form.createType === 'interface') {
|
|
||||||
// 接口模式
|
|
||||||
const url = isCreate ? this.$http.api.asyncQuickInterface + `/${this.target_id}/?direct=true` : this.$http.api.asyncQuickInterface + `/${this.target_id}/?direct=false`
|
|
||||||
this.$axios.putForm(url, editForm).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.close()
|
|
||||||
this.$emit('refresh')
|
|
||||||
// this.$notify({
|
|
||||||
// title: '编辑靶场成功',
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
}, 10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.createLoading = false
|
|
||||||
this.configLoading = false
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// consensus模式
|
|
||||||
const url = isCreate ? this.$http.api.asyncQuickConsensus + `/${this.target_id}/?direct=true` : this.$http.api.asyncQuickConsensus + `/${this.target_id}/?direct=false`
|
|
||||||
const submitForm = new FormData()
|
|
||||||
for(const key in editForm) {
|
|
||||||
submitForm.append(key, editForm[key])
|
|
||||||
}
|
|
||||||
this.$axios.putFormData(url, submitForm).then(res => {
|
|
||||||
if (res.code == 200 || res.code == "OK") {
|
|
||||||
this.close()
|
|
||||||
this.$emit('refresh')
|
|
||||||
// this.$notify({
|
|
||||||
// title: '编辑靶场成功',
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
this.$notify({
|
|
||||||
title: res.message,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
this.delTimer = setInterval(() => {
|
|
||||||
this.getTask(res?.result?.task_id || '')
|
|
||||||
},10 * 1000)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.createLoading = false
|
|
||||||
this.configLoading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 模拟比例选择
|
|
||||||
radioChange(val) {
|
|
||||||
this.otherRatio = ''
|
|
||||||
},
|
|
||||||
// 模拟比例用输入框输入
|
|
||||||
otherRadioInput(val) {
|
|
||||||
this.form.ratio = ''
|
|
||||||
},
|
|
||||||
// 选择上传文件
|
|
||||||
selectFile(e) {
|
|
||||||
this.form.file = e.target.files[0]
|
|
||||||
this.fileName = e.target.files[0].name
|
|
||||||
},
|
|
||||||
// 获取任务进度
|
|
||||||
getTask(task_id) {
|
|
||||||
const url = this.$http.api.task + '/' + task_id
|
|
||||||
this.$axios.get(url, {}).then(res => {
|
|
||||||
if(res.task_status !== 'PENDING' && res.task_status !== 'STARTED') {
|
|
||||||
if (res?.task_result?.code === 500 || res?.task_result?.message === 'false') {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行完毕,靶场部署失败`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.$notify({
|
|
||||||
title: res?.task_result?.result || `${res.task_id}任务执行完毕,靶场部署成功`,
|
|
||||||
type: 'success',
|
|
||||||
duration: 2500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.$emit('refresh')
|
|
||||||
} else {
|
|
||||||
// this.$notify({
|
|
||||||
// title: `${res.task_id}任务执行中`,
|
|
||||||
// type: 'success',
|
|
||||||
// duration: 2500
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.counter++
|
|
||||||
if (this.counter >= 60) {
|
|
||||||
clearInterval(this.delTimer)
|
|
||||||
this.delTimer = null
|
|
||||||
this.counter = 0
|
|
||||||
this.$emit('refresh')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.quick-dialog{
|
|
||||||
width: 620px;
|
|
||||||
height: 675px;
|
|
||||||
position: absolute; /* 绝对定位 */
|
|
||||||
top: 50%; /* 向下偏移50% */
|
|
||||||
left: 50%; /* 向右偏移50% */
|
|
||||||
transform: translate(-50%, -50%); /* 回移50% */
|
|
||||||
background-image:url('../../../img/Group (2).svg');
|
|
||||||
background-repeat: no-repeat; /* 可选,防止图像重复 */
|
|
||||||
background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
|
|
||||||
.quick-form {
|
|
||||||
margin-top: 70px;
|
|
||||||
text-align: left;
|
|
||||||
.long-item-label {
|
|
||||||
::v-deep .el-form-item__label {
|
|
||||||
padding: 12px 12px 0 70px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.other-ratio{
|
|
||||||
width: 40%;
|
|
||||||
margin-left: 5%;
|
|
||||||
margin-right: 5%;
|
|
||||||
background-color: #0c295b;
|
|
||||||
display: inline-block;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.upload-file{
|
|
||||||
width: 100%;
|
|
||||||
/*margin-left: 10%;*/
|
|
||||||
text-align: center;
|
|
||||||
color: rgba(81, 84, 102, 0.84);
|
|
||||||
::v-deep .el-upload-list {
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
width: 400px !important;
|
|
||||||
padding-left: 20%;
|
|
||||||
}
|
|
||||||
.uploadBgImg{
|
|
||||||
width: 320px;
|
|
||||||
height: 40px;
|
|
||||||
background-image: url("../../../img/shangchuan.png");
|
|
||||||
background-repeat: no-repeat; /* 可选,防止图像重复 */
|
|
||||||
background-size: 100% auto; /* 宽度为100%,高度自适应保持宽高比 */
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 10%;
|
|
||||||
padding-top: 2%;
|
|
||||||
font-size: 0;
|
|
||||||
}
|
|
||||||
.uploadBgImg::file-selector-button{
|
|
||||||
padding: 0;
|
|
||||||
background-color: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.submit-footer{
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 + ' 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 + ' 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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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 }
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>echarts世界地图闪烁点 www.bootstrapmb.com</title>
|
|
||||||
<script type="text/javascript" src="echarts.min.js"></script>
|
|
||||||
<script type="text/javascript" src="world_new.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="main" style="width: 100%;height:120vh;"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// 获取echarts的容器
|
|
||||||
var chart = echarts.init(document.getElementById("main"));
|
|
||||||
var geoCoordMap = {
|
|
||||||
北京: [116.28, 39.54],
|
|
||||||
// 杭州: [120.10, 30.15],
|
|
||||||
// 南宁: [108.479, 23.1152],
|
|
||||||
// 广州: [113.5107, 23.2196],
|
|
||||||
重庆: [107.7539, 30.1904],
|
|
||||||
上海: [121.4648, 31.2891],
|
|
||||||
尼日利亚: [-4.388361, 11.186148],
|
|
||||||
洛杉矶: [-118.24311, 34.052713],
|
|
||||||
香港: [114.195466, 22.282751],
|
|
||||||
芝加哥: [-87.801833, 41.870975],
|
|
||||||
加纳库马西: [-4.62829, 7.72415],
|
|
||||||
曼彻斯特: [-1.657222, 51.886863],
|
|
||||||
汉堡: [10.01959, 54.38474],
|
|
||||||
阿拉木图: [45.326912, 41.101891],
|
|
||||||
伊尔库茨克: [89.116876, 67.757906],
|
|
||||||
巴西: [-48.678945, -10.493623],
|
|
||||||
埃及: [31.815593, 31.418032],
|
|
||||||
巴塞罗纳: [2.175129, 41.385064],
|
|
||||||
柬埔寨: [104.88659, 11.545469],
|
|
||||||
米兰: [9.189948, 45.46623],
|
|
||||||
蒙得维的亚: [-56.162231, -34.901113],
|
|
||||||
莫桑比克: [32.608571, -25.893473],
|
|
||||||
阿尔及尔: [3.054275, 36.753027],
|
|
||||||
阿联酋迪拜: [55.269441, 25.204514],
|
|
||||||
布达佩斯: [17.108519, 48.179162],
|
|
||||||
悉尼: [150.993137, -33.675509],
|
|
||||||
加州: [-121.910642, 41.38028],
|
|
||||||
墨尔本: [144.999416, -37.781726],
|
|
||||||
墨西哥: [-99.094092, 19.365711],
|
|
||||||
温哥华: [-123.023921, 49.311753]
|
|
||||||
};
|
|
||||||
var BJData = [[{
|
|
||||||
name: "北京",
|
|
||||||
value: 12580
|
|
||||||
}],[{
|
|
||||||
name: "重庆",
|
|
||||||
value: 10000000
|
|
||||||
}],[{
|
|
||||||
name: "上海",
|
|
||||||
value: 9100
|
|
||||||
}], [{
|
|
||||||
name: "尼日利亚",
|
|
||||||
value: 9100
|
|
||||||
}], [{
|
|
||||||
name: "洛杉矶",
|
|
||||||
value: 2370
|
|
||||||
}], [{
|
|
||||||
name: "香港",
|
|
||||||
value: 3130
|
|
||||||
}], [{
|
|
||||||
name: "芝加哥",
|
|
||||||
value: 2350
|
|
||||||
}], [{
|
|
||||||
name: "加纳库马西",
|
|
||||||
value: 5120
|
|
||||||
}], [{
|
|
||||||
name: "曼彻斯特",
|
|
||||||
value: 3110
|
|
||||||
}], [{
|
|
||||||
name: "汉堡",
|
|
||||||
value: 6280
|
|
||||||
}], [{
|
|
||||||
name: "阿拉木图",
|
|
||||||
value: 7255
|
|
||||||
}], [{
|
|
||||||
name: "伊尔库茨克",
|
|
||||||
value: 8125
|
|
||||||
}], [{
|
|
||||||
name: "巴西",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "埃及",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "巴塞罗纳",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "柬埔寨",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "米兰",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "蒙得维的亚",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "莫桑比克",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "阿尔及尔",
|
|
||||||
value: 31590
|
|
||||||
}], [{
|
|
||||||
name: "阿联酋迪拜",
|
|
||||||
value: 13590
|
|
||||||
}], [{
|
|
||||||
name: "布达佩斯",
|
|
||||||
value: 23590
|
|
||||||
}], [{
|
|
||||||
name: "悉尼",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "加州",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "墨尔本",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "墨西哥",
|
|
||||||
value: 3590
|
|
||||||
}], [{
|
|
||||||
name: "温哥华",
|
|
||||||
value: 3590
|
|
||||||
}]];
|
|
||||||
|
|
||||||
var series = [];
|
|
||||||
[[, BJData]].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) {
|
|
||||||
var level = 0 ;
|
|
||||||
var state= Math.floor(val[2]/5000) ;
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case 0: level=0; break;
|
|
||||||
case 1: level=1; break;
|
|
||||||
case 2: level=2; break;
|
|
||||||
case 3: level=3; break;
|
|
||||||
case 4: level=4; break;
|
|
||||||
case 5: level=5; break;
|
|
||||||
case 6: level=6; break;
|
|
||||||
case 7: level=7; break;
|
|
||||||
case 8: level=8; break;
|
|
||||||
case 9: level=9; break;
|
|
||||||
default: level=10;
|
|
||||||
}
|
|
||||||
return 5 + level; //圆环大小
|
|
||||||
},
|
|
||||||
data: item[1].map(function (dataItem) {
|
|
||||||
return {
|
|
||||||
name: dataItem[0].name/*+"\n"+dataItem[0].value*/,
|
|
||||||
value: geoCoordMap[dataItem[0].name]
|
|
||||||
.concat([dataItem[0].value])
|
|
||||||
};
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
option = {
|
|
||||||
backgroundColor: '#000',
|
|
||||||
//悬浮提示
|
|
||||||
tooltip: {
|
|
||||||
trigger: "item",
|
|
||||||
backgroundColor: "#1540a1",
|
|
||||||
borderColor: "#FFFFCC",
|
|
||||||
showDelay: 0,
|
|
||||||
hideDelay: 0,
|
|
||||||
// enterable: true,
|
|
||||||
transitionDuration: 0,
|
|
||||||
// extraCssText: "z-index:100",formatter
|
|
||||||
formatter: function (params, ticket, callback) {
|
|
||||||
//根据业务自己拓展要显示的内容
|
|
||||||
var res = "";
|
|
||||||
var name = params.name;
|
|
||||||
var value = params.value[params.seriesIndex + 1];
|
|
||||||
res = "<span style='color:#fff;'>" + name.toString().split(' ')[0]
|
|
||||||
+ "</span><br/>爬虫:" + name.toString().split(' ')[1];
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
visualMap: {
|
|
||||||
//图例值控制
|
|
||||||
min: 0,
|
|
||||||
max: 10000,
|
|
||||||
text:['High','Low'],
|
|
||||||
show: false,
|
|
||||||
calculable: true,
|
|
||||||
//color: ["#0bc7f3"],
|
|
||||||
color: ['orangered','yellow','lightskyblue']
|
|
||||||
},
|
|
||||||
geo: {
|
|
||||||
map: "world",
|
|
||||||
label: {
|
|
||||||
emphasis: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
roam: true, //是否允许缩放
|
|
||||||
layoutCenter: ["50%", "50%"], //地图位置
|
|
||||||
layoutSize: "180%",
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: ["#04284e"], //地图背景色
|
|
||||||
//color: ['orangered','yellow','lightskyblue']
|
|
||||||
borderColor: "#5bc1c9" //省市边界线
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
color: "rgba(37, 43, 61, .5)" //悬浮背景
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: series
|
|
||||||
};
|
|
||||||
chart.setOption(option);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user