V2 完成

This commit is contained in:
Gregory
2024-04-26 17:38:47 +08:00
parent ea9a916fa6
commit ac8bc7f895
27 changed files with 6485 additions and 0 deletions

BIN
src/img/logyy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -0,0 +1,418 @@
<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 {
datas:[],
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
},
// title: {
// text:"898989"
// },
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',
// // 添加样式
// textStyle: {
// textAlign: 'left' // 内容左对齐
// }
// },
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'
}
}
}
],
// 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: [
{
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
// }
]
}
]
};
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>

1102
src/views/menuMBGZ/index.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
<template>
<div class="head">
<div class="target-select">
<span style="font-size: 30px;float: left;padding-top: 1%">已探测目标信息</span>
</div>
<!-- <div class="input">-->
<!-- <el-input v-model="username" 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>
</template>
<script>
export default {
name: 'Header',
props: [],
data() {
return {
username: ''
}
},
watch: {},
methods: {
// 新增
addUser() {
this.$emit('addUser')
},
// 查询
query() {
let params = {}
if (this.username !== '') {
params.username = this.username
}
this.$emit('query', params)
}
}
}
</script>
<style lang="less" scoped>
.head{
width: 95%;
height: 7%;
margin-top: 1%;
margin-left: 2.5%;
text-align: right;
.target-select{
font-size: 10px;
float: left;
margin-top: 0.5%;
display: inline-block;
height: 60%;
width: 100%;
margin-left: 0.5%;
}
.add-btn {
height: 70%;
width: 10%;
margin-right: 2%;
color: #ffffff;
}
.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;
}
}
}
</style>

View File

@@ -0,0 +1,624 @@
<template>
<div class='wrapper'>
<div class='chart' id='chart' >
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props:['ip','isp','cou','protocol'],
watch:{
ip(newValue,oldValue){
console.log("TTTTTTTTTTTTTTTTTT1")
console.log("新:"+newValue +"旧:"+oldValue)
console.log("TTTTTTTTTTTTTTTTTT1")
this.ip=newValue;
this.handleChange();
},
isp(newValue,oldValue){
console.log("TTTTTTTTTTTTTTTTTT2")
console.log("新:"+newValue +"旧:"+oldValue)
console.log("TTTTTTTTTTTTTTTTTT2")
this.isp=newValue;
this.handleChange();
},
protocol(newValue,oldValue){
console.log("TTTTTTTTTTTTTTTTTT3")
console.log("新:"+newValue +"旧:"+oldValue)
console.log("TTTTTTTTTTTTTTTTTT3")
this.protocol=newValue;
this.handleChange();
},
cou(newValue,oldValue){
console.log("TTTTTTTTTTTTTTTTTT4")
console.log("新:"+newValue +"旧:"+oldValue)
console.log("TTTTTTTTTTTTTTTTTT4")
this.cou=newValue;
this.handleChange();
}
},
name: "indexDQ2",
data () {
return {
// ip:"",
// isp:"",
// cou:"",
// protocol:null,
switchLanguage:"",//用于页面中英文切换
// countryEnJson:"",//用于储存国家英文字典
maxValue:0,
newestInfo:"",
ws: null,
// listAdd:[],
chart:undefined,
// res :[],
ddaattaa:""
}
},
created() {
this.handleChange0();
},
mounted () {
this.handleChange()
// this.getWorld()
// 模拟初始数据获取
// 模拟数据更新
// setInterval(() => {
// this.getData();
// }, 3000);
},
methods: {
handleChange0(){
/****************************************************************************/
let data = {
}
this.$axios.get(this.$http.api.targetMap,data).then(res=> {
console.log("地图访问成功")
if(res.code=='200'){
console.log("地图访问成功OK")
this.ddaattaa=res.dataObject.earthAddTitle;
this.getWorld()
}
})
/*********************************************************************************/
// this.ddaattaa="{\"dataObject\":{\"newestCountry\":\"墨西哥\",\"maxValue\":8593,\"newestInfo\":\"墨西哥484\",\"earthAddTitle\":[{\"name\":\"美国\"" +
// ",\"title\":\"RECRUITMENTOFPERSONNELINMEXICOANDLATINAMERICA\",\"value\":893},{\"name\":\"印度\",\"title\":\"印度ixigo数据1700万\"," +
// "\"value\":1982},{\"name\":\"法国\",\"title\":\"France124K | NICEQUALITY\",\"value\":1645},{\"name\":\"英国\",\"title\":" +
// "\"100XAccountsHotmailUnitedKingdomFresh & FullAccess ⚡Capture ⚡PrivateAccs\",\"value\":1576},{\"name\":\"俄罗斯\"," +
// "\"title\":\"LeadershipoftheAirborneTroopsandothersofRussia\",\"value\":1279},{\"name\":\"德国\",\"title\":" +
// "\"1MGermanyUHQcombolist\",\"value\":1231},{\"name\":\"中国\",\"title\":\"900 - 山东 - 务工人员信息明细统计表\",\"value\":4275}," +
// "{\"name\":\"墨西哥\",\"title\":\"墨西哥务工人员信息明细统计表\",\"value\":8593}]}," +
// "\"code\":\"earth\"}"
// this.getWorld()
},
handleChange(){
/****************************************************************************/
let data = {
"ip":this.ip,
"isp":this.isp,
"cou":this.cou,
}
let data2 = {
"ip":this.ip,
"isp":this.isp,
"cou":this.cou,
"protocol":this.protocol,
}
this.$axios.get(this.$http.api.targetMap,this.protocol===null?data:data2).then(res=> {
console.log("地图访问成功")
if(res.code=='200'){
console.log("地图访问成功OK")
this.ddaattaa=res.dataObject.earthAddTitle;
this.getWorld()
}
})
/*********************************************************************************/
// this.ddaattaa="{\"dataObject\":{\"newestCountry\":\"墨西哥\",\"maxValue\":8593,\"newestInfo\":\"墨西哥484\",\"earthAddTitle\":[{\"name\":\"美国\"" +
// ",\"title\":\"RECRUITMENTOFPERSONNELINMEXICOANDLATINAMERICA\",\"value\":893},{\"name\":\"印度\",\"title\":\"印度ixigo数据1700万\"," +
// "\"value\":1982},{\"name\":\"法国\",\"title\":\"France124K | NICEQUALITY\",\"value\":1645},{\"name\":\"英国\",\"title\":" +
// "\"100XAccountsHotmailUnitedKingdomFresh & FullAccess ⚡Capture ⚡PrivateAccs\",\"value\":1576},{\"name\":\"俄罗斯\"," +
// "\"title\":\"LeadershipoftheAirborneTroopsandothersofRussia\",\"value\":1279},{\"name\":\"德国\",\"title\":" +
// "\"1MGermanyUHQcombolist\",\"value\":1231},{\"name\":\"中国\",\"title\":\"900 - 山东 - 务工人员信息明细统计表\",\"value\":4275}," +
// "{\"name\":\"墨西哥\",\"title\":\"墨西哥务工人员信息明细统计表\",\"value\":8593}]}," +
// "\"code\":\"earth\"}"
// this.getWorld()
},
showTitleView(newestInfo,newestCountry){
// console.log(newestInfo)
// let new_cname = dataArr[0]['name']+dataArr[0]['value']
let new_cname = newestInfo //中国44
// console.log("判断最后一条数据是否有变化")
// console.log("this.Cname:"+this.newestInfo)
// console.log("new_cname:"+new_cname)
if (this.newestInfo != new_cname){
console.log("RRRRRRRRRRRRR进来了啊")
this.newestInfo = new_cname;
// this.showTooltip(-1);
this.showTooltip(newestCountry);
// this.showWireframe(-1)
this.showWireframe(newestCountry)
setTimeout(this.hideTooltip,10000);
}
},
showWireframe(newestCountry) {
// // 取消高亮指定的数据图形
// this.chart.dispatchAction({
// type: 'downplay',
// seriesIndex: 0,
// dataIndex: index
// })
// 高亮指定的数据图形
this.chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
name: newestCountry
// dataIndex: index + 1
})
},
hideTooltip(){
this.chart.dispatchAction({
type: 'hideTip',
seriesIndex: 0,
dataIndex: -1
})
},
// showTooltip(index) {
showTooltip(newestCountry) {
// // 隐藏提示框
// this.chart.dispatchAction({
// type: 'hideTip',
// seriesIndex: 0,
// dataIndex: index
// })
// 显示提示框
this.chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
name:newestCountry
// dataIndex: index + 1
})
},
getWorld () { //ddaattaa
/****************************************************************************/
var json = require('/src/api/world.json');
let namemap = json.namemap;
let dataArr=[];
// this.maxValue=JSON.parse(this.ddaattaa).dataObject.maxValue
this.maxValue=20000
// dataArr = JSON.parse(this.ddaattaa).dataObject.earthAddTitle
dataArr = this.ddaattaa
this.drawChart(namemap, dataArr);
// this.showTitleView(
// JSON.parse(this.ddaattaa).dataObject.newestInfo,
// JSON.parse(this.ddaattaa).dataObject.newestCountry
// );
},
drawChart (namemap, dataArr) {
let maxValue=this.maxValue
// 基于准备好的dom初始化echarts实例
let chart = this.$echarts.init(document.getElementById('chart'))
// 监听屏幕变化自动缩放图表
window.addEventListener('resize', function () {
chart.resize()
})
///////////////////////////
//用于存储地图数据
var json = require('/src/api/world.json');
var pointMap =json.trapeze;
var geoCoordMap = pointMap;
var countryEnJson=json.country_en;
var zh_en=this.switchLanguage;
var max = 480,
min = 9; // todo
var maxSize4Pin = 50,
minSize4Pin = 20;
var convertData = function (dataD) {
var res = [];
if(dataD){
for (var i = 0; i < dataD.length; i++) {
var geoCoord = geoCoordMap[dataD[i].name];
if (geoCoord) {
res.push({
name: dataD[i].name,
name_en: countryEnJson[dataD[i].name],
zh_en:zh_en,
value: geoCoord.concat(dataD[i].value),
// value: geoCoord,
// size:dataD[i].value,
title: dataD[i].title,
});
}
}
}
return res;
};
// var convertDataA = function (dataD) {
// var res = [];
// if(dataD){
// for (var i = 0; i < dataD.length; i++) {
// var geoCoord = geoCoordMap[dataD[i].name];
// if (geoCoord) {
// res.push({
// name: dataD[i].name,
// value: geoCoord.concat(dataD[i].value),
// // value: geoCoord,
// title: dataD[i].title,
// num:dataD[i].value,
// });
// }
// }
// }
// return res;
// };
// 绘制图表
chart.setOption({
// 图表主标题
// title: {
// // text: '数据泄露分布地图', // 主标题文本,支持使用 \n 换行
// top: 20, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比
// left: 'center', // 值: 'left', 'center', 'right' 同上
// textStyle: { // 文本样式
// fontSize: 24,
// fontWeight: 600,
// color: '#fff'
// }
// },
// 提示框组件
tooltip: {
trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
// 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
// 使用函数模板 传入的数据值 -> value: number | Array
formatter: function (val) {
var text = '';
text += '<div style="display:flex;flex-direction:row;">'+
'<div style="background-color:#03D16D;height:auto;width:10px;margin-right:5px;"></div>'+
'<div style="display:flex;flex-direction:column;">'+
'<span>'+ val.data.name+'</span>'+
'<span >'+'分类信息:'+'</span>'+
'<span display:width="60px">'+ val.data.title+'</span>'+
'</div>'+
'</div>'
return text;
}
},
// visualMap: {
// type: 'continuous',
// min: 0,
// max: 100,
// range: [1, 10],
// center: [104.114129, 37.550339],
// },
// visualMap: {
// show: false,
// min: 0,
// max: 600,
// left: 'left',
// top: 'bottom',
// text: ['高', '低'], // 文本,默认为数值文本
// calculable: true,
// seriesIndex: [1],
// //控制地图颜色的显示区间
// inRange: {
// // color: ['#3B5077', '#031525'] // 蓝黑
// // color: ['#ffc0cb', '#800080'] // 红紫
// // color: ['#3C3B3F', '#605C3C'] // 黑绿
// // color: ['#0f0c29', '#302b63', '#24243e'] // 黑紫黑
// // color: ['#23074d', '#cc5333'] // 紫红
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#1488CC', '#2B32B2'] // 浅蓝
// // color: ['#00467F', '#A5CC82', '#ffc0cb'] // 蓝绿红
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// color: ['#22e5e8', '#0035f9', '#22e5e8'] // 蓝绿
//
// }
// },
geo: {
//地图的初始配置
// show: true,
map: 'world',
projection:'geoMercator', //使用墨卡托投影
// mapProjection: {
// // 使用等经纬度投影
// type: 'equidistantly'
// },
// zoom:1,
// label: {
// normal: {
// show: false
// },
// emphasis: {
// show: false
// }
// },
roam:false,
// center:undefined,
///////////////////////////////////////////////////////1/2
// 图形上的文本标签
label: {
show: false// 是否显示对应地名
},
// 地图区域的多边形 图形样式
itemStyle: {
// areaColor: '#3ca3e6', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
areaColor: '#0d1b4a', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
borderWidth: 0.5, // 描边线宽 为 0 时无描边
borderColor: '#00F1FF', // 图形的描边颜色 支持的颜色格式同 color不支持回调函数
borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
},
// 高亮状态下的多边形和标签样式
emphasis: {
label: {
show: false, // 是否显示标签
color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
},
itemStyle: {
areaColor: '#3742ff' // 地图区域的颜色
}
},
////////////////////////////////////////////////1/2
// 自定义地区的名称映射
nameMap: namemap,
},
series: [
{
// type: 'map', // 类型
type: 'scatter', // 使用墨卡托投影
coordinateSystem:'geo', //使用地理坐标系
// 系列名称用于tooltip的显示legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列
name: '数据泄露分布地图',
// mapType: 'world', // 地图类型
// // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启
// roam: false,
///////////////////////////////////////////////////////1/2
// 图形上的文本标签
// label: {
// show: false// 是否显示对应地名
// },
// // 地图区域的多边形 图形样式
// itemStyle: {
// // areaColor: '#3ca3e6', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
// areaColor: '#0d1b4a', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
// borderWidth: 0.5, // 描边线宽 为 0 时无描边
// borderColor: '#00F1FF', // 图形的描边颜色 支持的颜色格式同 color不支持回调函数
// borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
// },
// // 高亮状态下的多边形和标签样式
// emphasis: {
// label: {
// show: false, // 是否显示标签
// color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色
// },
// itemStyle: {
// areaColor: '#3742ff' // 地图区域的颜色
// }
// },
////////////////////////////////////////////////1/2
geoIndex:0,
// // 自定义地区的名称映射
// nameMap: namemap,
// 地图系列中的数据内容数组 数组项可以为单个数值
// data: dataArr,
data: convertData(dataArr),
},
// {
// type: 'map',
// map: 'world',
// geoIndex: 0,
// aspectScale: 0.75, //长宽比
// showLegendSymbol: false, // 存在legend时显示
// label: {
// show: false,
// // normal: {
// // show: true
// // },
// // emphasis: {
// // show: false,
// // textStyle: {
// // color: '#fff'
// // }
// // }
// },
// // roam: true,
// // itemStyle: {
// // normal: {
// // areaColor: '#031525',
// // borderColor: '#3B5077',
// // },
// // emphasis: {
// // areaColor: '#2B91B7'
// // }
// // },
// // 地图区域的多边形 图形样式
// itemStyle: {
// // areaColor: '#3ca3e6', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
// areaColor: '#0d1b4a', // 地图区域的颜色 如果设置了visualMapareaColor属性将不起作用
// borderWidth: 0.5, // 描边线宽 为 0 时无描边
// borderColor: '#00F1FF', // 图形的描边颜色 支持的颜色格式同 color不支持回调函数
// borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted'
// },
// // animation: true,
// namemap:namemap,
// data: dataArr
// // data: convertData(data)
// },
{
name: '点',
type: 'scatter',
coordinateSystem: 'geo',
symbol: 'pin', //气泡
symbolSize: function (size,val) {
var a = (maxSize4Pin - minSize4Pin) / (max - min);
var b = minSize4Pin - a * min;
// b = maxSize4Pin - a * max;
return a * val[2]*100 + b;
},
label: {
normal: {
show: false,
formatter: function (params) {
return params.value[2]
},
textStyle: {
color: '#fff',
fontSize: 9,
}
}
},
itemStyle: {
normal: {
color: 'rgba(255,255,0,0)', //标志颜色
}
},
zlevel: 1,
data: convertData(dataArr),
},
{
name: 'Top 500',//用于显示最高的前五个数据
type: 'effectScatter',
coordinateSystem: 'geo',
// data: convertData(data.sort(function (a, b) {
// return a.value - b.value;
// }).slice(0, 500)), namemap, dataArr
symbolSize: function (val) {
// return val[2] / 2.3;
return val[2] / (maxValue*0.03);
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
label: {
normal: {
formatter: '{b}',
position: 'right',
show: false
}
},
itemStyle: {
normal: {
color: 'rgba(255,9,14,0.8)',
shadowBlur: 10,
shadowColor: '#05C3F9'
}
},
zlevel: 1,
data: convertData(dataArr),
},
]
})
// 定时显示提示框和高亮效果
this.chart = chart;
// let index = -1
// let indexK = -1
// setInterval(function () {
// // 隐藏提示框
// chart.dispatchAction({
// type: 'hideTip',
// seriesIndex: 0,
// dataIndex: indexK
// })
// // 显示提示框
// chart.dispatchAction({
// type: 'showTip',
// seriesIndex: 0,
// dataIndex: indexK + 1
// })
// index=index+10000
// // if (index > data.length - 1) {
// // index = -1
// // }
// },3000)
// setInterval(function () {
// // 隐藏提示框
// chart.dispatchAction({
// type: 'hideTip',
// seriesIndex: 0,
// dataIndex: index
// })
// // 显示提示框
// chart.dispatchAction({
// type: 'showTip',
// seriesIndex: 0,
// dataIndex: index + 1
// })
// // 取消高亮指定的数据图形
// chart.dispatchAction({
// type: 'downplay',
// seriesIndex: 0,
// dataIndex: index
// })
// // 高亮指定的数据图形
// chart.dispatchAction({
// type: 'highlight',
// seriesIndex: 0,
// dataIndex: index + 1
// })
// // index++
// // if (index > data.length - 1) {
// // index = -1
// // }
// }, 1000)
}
}
}
</script>
<style scoped>
.wrapper {
/*margin-top: -80px;*/
/*width: 100%;*/
/*margin-left: -120px;*/
/*margin-top: -10%;*/
/*width: 100%;*/
/*height: 100%;*/
/*width: calc(100vw);*/
/*height: calc(100vh);*/
width: calc(100%);
height: calc(100%);
margin-left: -12%;
}
.wrapper .chart {
/*width: 120%;*/
/*height: 780px;*/
/*margin: 1px 2px 0;*/
/*!*border: 1px solid #0d1b4d;*!*/
/*!*background: url(../../../public/bg.jpg) no-repeat; #0d1b4d *!*/
/*background-size: 100% 100%;*/
width: 100%;
height: 100%;
/*margin: 0.2% 0.2% 0;*/
margin-top: 2%;
margin-left: 10%;
/*border: 1px solid #0d1b4d;*/
/*background: url(../../../public/bg.jpg) no-repeat; #0d1b4d */
background-size: 100% 100%;
z-index: 9;
/*position: absolute;*/
position: relative;
}
</style>

View File

@@ -0,0 +1,296 @@
<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 {
datas:[],
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
},
// title: {
// text:"898989"
// },
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'
}
}
},
],
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;
}
}
},
],
// 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
// // }
// ]
// }
//
// ]
};
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>

View File

@@ -0,0 +1,419 @@
<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>

View File

@@ -0,0 +1,225 @@
<template>
<div class="home" ref="appRef">
<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 class="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==='DNS查询时延') ? '#f8fdff': '#565e6e'}" @click="updateTag1('DNS查询时延')">DNS查询时延</el-tag>
<el-tag class="tags1" :style="{'color': (tag1==='TCP连接时延') ? '#f8fdff': '#565e6e'}" @click="updateTag1('TCP连接时延')">TCP连接时延</el-tag>
<el-tag class="tags" :style="{'color': (tag==='应答内容') ? '#f8fdff': '#565e6e'}" @click="updateTag('应答内容')">应答内容</el-tag>
</div>
<div v-if="tag==='应答内容'" class="answer">
<div style="display: flex;margin-right: 5px;">
<span style="margin-right: 2%;font-size: 25px;width: 15%">目标域名:</span>
<el-input v-model="input" placeholder="请输入目标IP"></el-input>
</div>
<el-button type="primary" style="margin-top: 2%;margin-bottom: 10%">查询</el-button>
</div>
<div class="top" v-if="tag==='目标时延'">
<div class="top-left">
<SourceView class="top-left-target" :left1data="left1data"/>
</div>
<TargetView class="top-right" :left1data="left1data"/>
</div>
<div class="top" v-if="tag==='应答内容'">
<div class="top-left">
<div class="top-left-target" >
<div style="display: flex">
<span style="font-size: 20px;margin-top: 1%;margin-left: 2%;margin-right: 2%;margin-top: 2%">应答结果参考来源</span>
<div class="project" style="margin-top: 2%">
<el-select v-model="powerValue" placeholder="能力筛选" clearable @change="query">
<el-option
v-for="item in powerFilter"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</div>
<div style="width: 90%;height: 75%;background-color: #324c98;margin-top: 1.5%;margin-left: auto; margin-right: auto;"></div>
</div>
<!-- <SourceView class="top-left-target"/>-->
</div>
<div class="top-right" >
<div style="display: flex">
<span style="font-size: 20px;margin-top: 1%;margin-left: 2%;margin-right: 2%;margin-top: 2%">目标解析器响应结果</span>
</div>
<div style="width: 90%;height: 75%;background-color: #324c98;margin-top: 3%;margin-left: auto; margin-right: auto;"></div>
</div>
<!-- <TargetView class="top-right"/>-->
</div>
<NodeView class="bottom" v-if="tag==='目标时延'"></NodeView>
</div>
</div>
</template>
<script>
import TargetView from './module/target.vue'
import ImageView from './module/image.vue'
import SourceView from './module/source.vue'
import NodeView from './module/node.vue'
export default {
name: 'home',
components: { TargetView, ImageView, SourceView, NodeView },
created() {
this.parentLevelRow = this.$route.query.row;
this.input=this.parentLevelRow.target_domain;
},
// mounted() {
// this.$router.push('/range/home')
// },
methods:{
updateTag(val){
if(val==='目标时延'){
this.tag=val
this.tag1="ICMP/v6延时"
}else {
this.tag=val
this.tag1=""
}
},
updateTag1(val){
this.tag1=val;
this.tag='目标时延';
this.left1data.type=this.changePeram(val);
this.left1data.target=this.parentLevelRow.target;
},
changePeram(val){
switch (val) {
case 'ICMP/v6延时':
return 'icmp';
break;
case 'DNS查询时延':
return 'dns';
break;
case 'TCP连接时延':
return 'tcp';
break;
default:
console.log('No option selected');
break;
}
}
},
data() {
return {
left1data:{
target:'1.1.1.1',
type:'icmp',
},
leftYdata:[],
parentLevelRow:{},
tag:'目标时延',
tag1:"ICMP/v6延时",
input:"",
powerFilter:[
{
value:'8.8.8.8',
label:'谷歌8.8.8.8'
},
{
value:'0.0.0.0',
label:'**0.0.0.0'
},
{
value:'1.1.1.1',
label:'**1.1.1.1'
},
],
}
},
}
</script>
<style lang="less" scoped>
.answer {
width: 50%; /* 设置宽度为 50% */
margin: 0 auto; /* 水平居中 */
text-align: center; /* 内容居中 */
margin-top: 5%;
}
.tag{
margin-left: 9%;
.tags{
margin-right: 1%;
margin-left: 5%;
font-size: 23px;
border: none;
background-color: transparent !important;
color: #565e6e;
}
.tags1{
margin-right: 2%;
margin-top: 2%;
font-size: 18px;
border: none;
background-color: transparent !important;
color: #565e6e;
}
}
.home {
width: 100%;
height: 100%;
position: relative; /* 确保相对定位生效 */
}
.show {
height: 95%;
width: 95%;
position: absolute; /* 绝对定位 */
top: 50%; /* 向下偏移50% */
left: 50%; /* 向右偏移50% */
transform: translate(-50%, -50%); /* 回移50% */
/*display: flex;*/
/*flex-direction: column;*/
/*justify-content: space-between;*/
/*overflow-y: auto;*/
}
.top {
height: 49%;
display: flex;
flex-direction: row;
justify-content: space-between;
.top-left {
width: 49.5%;
display: flex;
flex-direction: column;
justify-content: space-between;
.top-left-target {
height: 90%;
background-image:url('../../img/background/homeTargetBg.svg');
background-repeat: no-repeat;
background-size: cover;
}
/*.top-left-iamge {*/
/* height: 48%;*/
/* background-image:url('../../img/background/homeTargetBg.svg');*/
/* background-repeat: no-repeat;*/
/* background-size: cover;*/
/*}*/
}
.top-right {
width: 49.5%;
height: 90%;
background-image:url('../../img/background/homeSourceBg.svg');
background-repeat: no-repeat;
background-size: cover;
}
}
.bottom {
height: 44%;
background-image:url('../../img/background/homeNodeBg.svg');
background-repeat: no-repeat;
background-size: cover;
}
</style>

View File

@@ -0,0 +1,135 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"items": [
{
"role_name": "admin",
"id": 1,
"create_time": "2024-01-31T10:22:45",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "developer",
"id": 2,
"create_time": "2024-01-31T11:29:17",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "experimenter",
"id": 3,
"create_time": "2024-01-31T11:33:05",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
}
]
}
],
"total": 3,
"page": 1,
"size": 10,
"pages": 1
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,126 @@
<template>
<div>
<span style="color: #dfe6ec;font-size: 20px;float: left;margin-left: 3%;margin-top: 2%">已探测目标</span>
<div class="box" id="show-loading" v-loading="loading">
<div class="card">
<div class="title">IPv6</div>
<div>
<span class="info-span">{{ target.v6dns }}</span>
<span class="unit-span"></span>
</div>
</div>
<div class="card">
<div class="title">DNSSEC</div>
<div>
<span class="info-span">{{ target.dnssec }}</span>
<span class="unit-span"></span>
</div>
</div>
<div class="card">
<div class="title">DoT</div>
<div>
<span class="info-span">{{ target.dot }}</span>
<span class="unit-span"></span>
</div>
</div>
<div class="card">
<div class="title">DoH</div>
<div>
<span class="info-span">{{ target.doh }}</span>
<span class="unit-span"></span>
</div>
</div>
</div>
</div>
</template>
<script>
import { Loading } from 'element-ui'
import { getTargetsResponse } from './imageMock.js'
export default {
name: 'imageView',
data() {
return {
loading: false,
imageData: {},
target:{
dnssec:0,
doh:0,
dot:0,
v6dns:0
}
}
},
created() {
this.init()
},
mounted() {
// this.init()
},
methods: {
init () {
// this.imageData = getTargetsResponse?.result
this.loading = true
this.$axios.get(this.$http.api.sysNum).then(res => {
if (res.code == 200) {
this.target.dnssec=res?.target?.dnssec
this.target.doh=res?.target?.doh
this.target.dot=res?.target?.dot
this.target.v6dns=res?.target?.v6dns
}
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
}
}
}
</script>
<style lang="less" scoped>
.box {
width: 100%;
height: 80%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.card {
flex: 1;
.title {
color: #FFF;
font-family: PingFang HK;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-bottom: 10px;
}
.info-span {
color: #03F4FA;
font-family: PingFang HK;
font-size: 32px;
font-style: normal;
font-weight: 500;
line-height: normal;
padding: 5px;
}
.unit-span {
color: #FFF;
opacity: 0.7;
font-family: PingFang HK;
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
}
}
.box .card:not(:last-child) {
border-right: 1px solid rgba(216, 216, 216, 0.2);
}
</style>

View File

@@ -0,0 +1,12 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"total_image_count": 45,
"system_image_count": 10,
"buildin_image_count": 34,
"define_image_count": 1
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,436 @@
<template>
<div class="node-card">
<span style="font-size: 20px;float: left;margin-top: 0.5%;margin-left: 2%;margin-bottom: 0.5%">节点信息</span>
<div class="list" >
<el-table class="custom-table"
ref="multipleTable"
:data="tableData"
height="100%"
style="width: 100%;"
tooltip-effect="dark"
highlight-current-row
>
<el-table-column type="index" align="center" min-width="100">
<template slot="header" slot-scope="scope">
<span>序号</span>
</template>
</el-table-column>
<el-table-column align="center"
prop="time"
label="时间"
min-width="100">
</el-table-column>
<el-table-column align="center"
prop="level"
label="日志级别"
min-width="100">
</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"
prop="user"
label="用户账号"
min-width="100">
</el-table-column>
<el-table-column align="center"
prop="ip"
label="用户IP"
min-width="100">
</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 * as echarts from 'echarts';
import { Loading } from 'element-ui'
import { getTargetsResponse } from './nodeMock.js'
export default {
name: 'NodeView',
data() {
return {
tableData:[],
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'
},
],
}
},
created() {
this.query()
},
mounted(){
// this.init()
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val}`);
this.size=val
this.query()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.page=val
this.query()
},
query(){
let data={
"per_page":this.size,
"page":this.page,
"begin":this.time1.toString(),
"end":this.time2.toString(),
"level":this.log_level,
"user":this.userAccount,
}
// 使用 Object.entries() 来遍历对象的键值对,并过滤掉值为空的属性
const filteredData = {};
for (const [key, value] of Object.entries(data)) {
if (value !== "") {
filteredData[key] = value;
}
}
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)
})
},
// 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>
<style lang="less" scoped>
.list{
width: 95%;
height: 85%;
margin-left: 2.5%;
overflow-y: auto;
overflow-y: scroll;
overflow-x: hidden;
border: none;
}
.project{
display: inline-block;
height: auto;
width: 10%;
margin-left: 0.5%;
margin-right: 3%;
margin-top: 1%;
margin-bottom: 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;
}
}
.node-card {
position: relative;
width: 100%;
height: 100%;
.node-chart {
width: 100%;
height: 100%;
}
.range-select {
position: absolute;
top: 12px;
right: 260px;
::v-deep .el-input {
width: 50%;
.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: #FFFFFF;
}
}
}
.tabs-container {
position: absolute;
top: 10px;
right: 36px;
::v-deep .el-tabs__nav-wrap::after {
background-color: transparent;
}
::v-deep .el-tabs__active-bar {
background-color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item {
color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item.is-active {
color: #FFFFFF;
}
}
}
</style>

View File

@@ -0,0 +1,15 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"total_count": 7,
"da_count": 1,
"relay_count": 4,
"exit_count": 2,
"onion_count": 0,
"client_count": 0,
"other_count": 0
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,309 @@
<template>
<div class="source-card">
<!-- <div class="source-chart" id="resource" v-loading="loading"></div>-->
<ZhuZhuangTu3 :active="0" ref="zhudouble" :bing="zhudouble"></ZhuZhuangTu3>
<!-- <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>
</template>
<script>
import * as echarts from 'echarts';
import ZhuZhuangTu3 from '../echarts/zhuzhuangtu3'
import { getTargetsResponse } from './sourceMock.js'
export default {
props: {
left1data: {
type: Object,
// required: true,
default: function() {
return {
target:'',
type: '',
}
}
}
},
watch: {
left1data: {
handler(newVal, oldVal) {
console.log('left1data changed:', newVal);
this.querydelay()
},
deep: true
}
},
name: 'SourceView',
components: {
ZhuZhuangTu3,
},
data() {
return {
loading: false,
sourceData: {},
sourceDataX: [],
sourceDataY: [],
cpuList: [],
memoryList: [],
activeName: 'CPU',
sourceChart: null,
rangeDict: [],
zhudouble:{
xdata:[],
ydata1:[], //ipv6
},
}
},
created() {
},
mounted(){
// this.init()
this.querydelay()
// this.getRangeDict()
},
methods: {
querydelay(){
const reqParams = {
"target": this.left1data.target,
"type": this.left1data.type,
}
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++) {
this.zhudouble.xdata.push(res.delay_data[i].Id);
this.zhudouble.ydata1.push(res.delay_data[i].CurrDelay);
}
}
this.$refs.zhudouble.bingfn(this.zhudouble)
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
// init() {
//
// this.loading = true
// this.$axios.get(this.$http.api.sysNumDate).then(res => {
// if (res.code == 200) {
// this.zhudouble.ydata1=[];
// this.zhudouble.ydata2=[];
// this.zhudouble.ydata3=[];
// this.zhudouble.ydata4=[];
// this.zhudouble.ydata5=[];
// this.zhudouble.xdata=[];
//
//
// Object.keys(res.date_data).forEach(date => {
// console.log(`Date: ${date}, dot value: ${res.date_data[date].dot}`);
// this.zhudouble.xdata.push(date)
// this.zhudouble.ydata1.push(res.date_data[date].v6dns)
// this.zhudouble.ydata2.push(res.date_data[date].dnssec)
// this.zhudouble.ydata3.push(res.date_data[date].dot)
// this.zhudouble.ydata4.push(res.date_data[date].doh)
// this.zhudouble.ydata5.push(res.date_data[date].v6dns+res.date_data[date].dnssec+res.date_data[date].dot+res.date_data[date].doh)
// });
// 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;
}
},
// // 获取靶场列表字典
// 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)
// })
// }
}
}
</script>
<style lang="less" scoped>
.source-card {
position: relative;
width: 100%;
height: 100%;
.source-chart {
width: 100%;
height: 100%;
}
.tabs-container {
position: absolute;
top: 10px;
right: 36px;
::v-deep .el-tabs__nav-wrap::after {
background-color: transparent;
}
::v-deep .el-tabs__active-bar {
background-color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item {
color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item.is-active {
color: #FFFFFF;
}
}
}
</style>

View File

@@ -0,0 +1,28 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"quick01": {
"total_memory": 3773.94921875,
"total_cpu": 24.433999999999997
},
"quick02": {
"total_memory": 1546.80078125,
"total_cpu": 76.94800000000001
},
"quick03": {
"total_memory": 1556.7578125,
"total_cpu": 79.413
},
"custom01": {
"total_memory": 0,
"total_cpu": 0
},
"custom02": {
"total_memory": 0,
"total_cpu": 0
}
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,263 @@
<template>
<div class="source-card">
<!-- <div class="source-chart" id="resource" v-loading="loading"></div>-->
<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>
</template>
<script>
import * as echarts from 'echarts';
import ZhuZhuangTu_jbs from '../echarts/zhuzhuangtu_jbs'
import { getTargetsResponse } from './sourceMock.js'
export default {
props: {
left1data: {
type: Object,
// required: true,
default: function() {
return {
target:'',
type: '',
}
}
}
},
watch: {
left1data: {
handler(newVal, oldVal) {
console.log('left1data changed:', newVal);
this.querydelay()
},
deep: true
}
},
name: 'SourceView',
components: {
ZhuZhuangTu_jbs,
},
data() {
return {
loading: false,
sourceData: {},
sourceDataX: [],
sourceDataY: [],
cpuList: [],
memoryList: [],
activeName: 'CPU',
sourceChart: null,
rangeDict: [],
zhudouble:{
data:[
['延时', '节点'],
],
},
}
},
created() {
},
mounted(){
this.init()
// this.getRangeDict()
},
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>
<style lang="less" scoped>
.source-card {
position: relative;
width: 100%;
height: 100%;
.source-chart {
width: 100%;
height: 100%;
}
.tabs-container {
position: absolute;
top: 10px;
right: 36px;
::v-deep .el-tabs__nav-wrap::after {
background-color: transparent;
}
::v-deep .el-tabs__active-bar {
background-color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item {
color: rgba(255, 255, 255,0.5);
}
::v-deep .el-tabs__item.is-active {
color: #FFFFFF;
}
}
}
</style>

View File

@@ -0,0 +1,12 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"total_target_count": 5,
"deploy_success_count": 0,
"deploy_fail_count": 0,
"no_deploy_count": 2
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,89 @@
<template>
<div class="head">
<div class="target-select">
<span style="font-size: 30px;float: left;padding-top: 1%">代理信息</span>
</div>
<!-- <div class="input">-->
<!-- <el-input v-model="username" 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>
</template>
<script>
export default {
name: 'Header',
props: [],
data() {
return {
username: ''
}
},
watch: {},
methods: {
// 新增
addUser() {
this.$emit('addUser')
},
// 查询
query() {
let params = {}
if (this.username !== '') {
params.username = this.username
}
this.$emit('query', params)
}
}
}
</script>
<style lang="less" scoped>
.head{
width: 95%;
height: 7%;
margin-top: 1%;
margin-left: 2.5%;
text-align: right;
.target-select{
font-size: 10px;
float: left;
margin-top: 0.5%;
display: inline-block;
height: 60%;
width: 10%;
margin-left: 0.5%;
}
.add-btn {
height: 70%;
width: 10%;
margin-right: 2%;
color: #ffffff;
}
.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;
}
}
}
</style>

View File

@@ -0,0 +1,414 @@
<template>
<div class="range-config-manage" ref="appRef">
<div class="show">
<Header
@addRole="addRole"
></Header>
<div>
<span style="font-size: 20px;margin-bottom: 1%;margin-top: 0.5%;float: left;margin-left: 3%;color: #00C0FF">默认创建的用户具有管理员权限</span>
</div>
<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"
type="index"
label="序号"
width="150"/>
<el-table-column
align="center"
prop="account"
label="账号"
width="280"/>
<el-table-column
align="center"
prop="username"
label="姓名"
width="250"/>
<el-table-column
align="center"
prop="time"
label="创建时间"
width="280"/>
<el-table-column
align="center"
prop="created_by"
label="创建人"
width="280"/>
<el-table-column
align="center"
prop="group"
label="权限组"
width="280"/>
<el-table-column
align="center"
label="操作"
width="250"
>
<template slot-scope="scope">
<el-button type="text" size="small" :loading="scope.row.delLoading" @click="del(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>
<UserForm
ref="userForm"
:is-add="isAdd"
:permission-dict="permissionDict"
@refresh="init">
</UserForm>
</div>
</div>
</template>
<script>
import Header from './module/Header.vue'
import UserForm from './module/UserForm.vue'
import { getTargetsResponse } from './mock.js'
export default {
name: "RangeConfigManage",
components:{ Header, UserForm },
data(){
return{
page: 1,
size: 10,
total: 0,
isAdd: false,
loading: false,
target_id: '',
tableData: [],
permissionDict: []
}
},
mounted() {
},
watch: {},
created() {
this.init()
},
methods:{
init(params={}) {
// TODO: 暂时注释接口
const reqParams = {
"page": this.page,
"per_page": this.size,
}
this.loading = true
this.$axios.get(this.$http.api.user, reqParams).then(res => {
if (res.code == 200) {
this.total = res?.total
this.tableData = res?.data
this.tableData.map(item => {
item.permissions.map(permi => {
this.$set(permi, 'delLoading', false)
return permi
})
return item
})
}
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
query(params) {
this.init(params)
},
// 打开添加角色dialog
addRole() {
this.isAdd = true
// this.$refs.userForm.title = '新增角色'
document.querySelector('.mask').style.display = 'block'
this.$refs.userForm.visible = true
},
// 删除权限
delPermission(permission, role_id) {
const url = this.$http.api.delPermission + '/' + role_id
permission.delLoading = true
this.$axios.put(url, {}, {permission_id: permission.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(() => {
permission.delLoading = false
})
},
// 删除
del(row) {
this.$confirm('此操作将永久删除该任务, 是否继续?', '确认删除', {
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
this.delUser(row)
}).catch(() => {
this.$notify({
type: 'info',
message: '已取消删除'
})
})
},
delUser(row) {
const url = this.$http.api.delRole + '/' + 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
})
},
// 详情
taskInfo(val) {
this.$router.push({ path: 'menuTaskInfo', query: { row: 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)
})
},
// 修改每页数据条数
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">
.popup{
z-index: 997;
width: 40%;
height: 70%;
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%,高度自适应保持宽高比 */
.tag{
margin-left: 9%;
.tags{
margin-right: 5%;
margin-top: 2%;
font-size: 23px;
border: none;
background-color: transparent !important;
color: #565e6e;
}
}
.jbpz{
margin-top: 10%;
margin-left: 23%;
height: 100%;
position:relative;
.project{
display: inline-block;
width: 100%;
margin-top: 3%;
text-align: center;
padding-right: 10%;
}
.tar{
display: flex;
margin-left: 23%;
width: 100%;
text-align: center;
::v-deep .el-upload-list {
margin: 0;
list-style: none;
width: 300px !important;
padding-left: 20%;
}
.uploadBgImg{
margin-top: 5%;
width: 300px;
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;
color: rgba(81, 84, 102, 0.84);
}
.uploadBgImg::file-selector-button{
padding: 0;
background-color: transparent;
cursor: pointer;
font-size: 0;
}
}
.srkType{
width: 100%;
float: left;
margin-top: 2%;
text-align: center;
.srk{
width: 40%;
margin-left: 2%;
background-color: #0c295b;
display: inline-block;
border: none;
}
}
.radioType{
width: 100%;
float: left;
margin-top: 2%;
text-align: center;
}
.anType{
height: 10%;
position:absolute;
bottom:4%;
left: 50%;
transform: translateX(-50%);
.glBut{
width: 90px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
background-color: rgba(24, 133, 234, 0.2);
color: #1b7cc4;
}
}
}
}
.custom-table {
width: 100%;
height: 100%;
.permission-btn {
display: inline-block;
margin: 6px;
padding: 5px 8px;
border-radius: 3px;
color:rgba(0, 0, 0, 0.90);
background: #02DDEA;
}
}
.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: 77%;
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>

View File

@@ -0,0 +1,135 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"items": [
{
"role_name": "admin",
"id": 1,
"create_time": "2024-01-31T10:22:45",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "developer",
"id": 2,
"create_time": "2024-01-31T11:29:17",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "experimenter",
"id": 3,
"create_time": "2024-01-31T11:33:05",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
}
]
}
],
"total": 3,
"page": 1,
"size": 10,
"pages": 1
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,54 @@
<template>
<div class="head">
<div class="target-select">
<span style="font-size: 30px;float: left;padding-top: 1%">用户列表</span>
</div>
<!-- <img class="add-btn" src="../../../img/btn/addRoleBtn.svg" @click="addRole">-->
<el-row>
<el-button type="primary" plain @click="addRole">新建用户</el-button>
</el-row>
</div>
</template>
<script>
export default {
name: 'Header',
props: [],
data() {
return {
role_name: ''
}
},
watch: {},
methods: {
// 新增
addRole() {
this.$emit('addRole')
}
}
}
</script>
<style lang="less" scoped>
.head{
width: 95%;
height: 7%;
margin-top: 1%;
margin-left: 2.5%;
text-align: right;
.target-select{
font-size: 10px;
float: left;
margin-top: 0.5%;
display: inline-block;
height: 60%;
width: 10%;
margin-left: 0.5%;
}
.add-btn {
height: 70%;
width: 10%;
color: #ffffff;
}
}
</style>

View File

@@ -0,0 +1,245 @@
<template>
<div
class="user-dialog"
v-if="visible"
>
<!-- <span class="dialog-title">{{ title }}</span>-->
<span class="dialog-title">用户创建</span>
<!-- 在此处指定弹窗的样式和内容 -->
<i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
<el-form
ref="userForm"
:model="form"
:rules="rules"
label-width="180px"
class="user-form"
>
<el-row style="margin-left: 5%;margin-top: 8%">
<el-col :span="19">
<el-form-item label="姓名" prop="username">
<el-input v-model="form.username" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="账号" prop="domain">
<el-input v-model="form.account" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="inject">
<el-input v-model="form.pwd" placeholder="请输入密码"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="submit-footer" style="margin-top: 10%">
<div>
<el-button class="glBut" type="primary" @click="close">取消</el-button>
<el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">确认创建</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'UserForm',
// props: ['isAdd', 'permissionDict'],
data() {
return {
agencyLabel:false,
visible: false,
loading: false,
title: '任务创建',
form: {
account:"", //代理名称
cur_user:"", //任务目标
pwd:"", //执行代理
username:"", //目标域名
},
role_id: '',
rules: {
account: [
// { required: true, message: '请输入任务名称', trigger: 'blur' },
{ message: '请输入任务名称', trigger: 'blur' },
{ max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
],
pwd: [
// { required: true, message: '请输入任务名称', trigger: 'blur' },
{ message: '请输入任务名称', trigger: 'blur' },
{ max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
],
username: [
// { required: true, message: '请输入任务名称', trigger: 'blur' },
{ message: '请输入任务名称', trigger: 'blur' },
{ max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
],
permissions: [
{ required: true, message: '请选择权限', trigger: 'change' }
],
},
roleDict:[],
strategy:[
{ value: 'auto', label: '自动选择', type: 'success' },
{ value: 'ddos', label: '拒绝服务', type: 'warning' },
{ value: 'sjqp', label: '数据欺骗', type: 'warning' },
],
agencyChange:[
{ value: '中国北京', label: '中国北京', type: 'success' },
{ value: '美国纽约', label: '美国纽约', type: 'warning' },
],
stateAwareMode:[
{ value: 'auto', label: '自动选择', type: 'success' },
{ value: 'tcp', label: 'TCP时延', type: 'warning' },
{ value: 'icmp', label: 'ICMP/v6', type: 'danger' },
{ value: 'dns', label: 'DNS解析时延', type: 'danger' },
{ value: 'record', label: '记录正确性验证', type: 'danger' },
],
operationalConfiguration:[
{ value: 'now', label: '立刻执行', type: 'success' },
{ value: 'man', label: '手动执行', type: 'warning' },
]
}
},
methods: {
getTagsByIP(val){
let data={
"ip":val?val:'1.1.1.1'
}
this.$axios.get(this.$http.api.targetQueryList,data).then(res=>{
if(res.code===200){
this.roleDict=res?.data[0]?.protect
}
}).catch(err=>{
console.log(err)
})
},
close() {
this.resetForm()
document.querySelector('.mask').style.display = 'none'
this.visible = false
},
submit() {
let data={
"account":this.form.account,
"cur_user":"获取当前用户",
"pwd":this.form.pwd,
"username":this.form.username,
}
this.$axios.post(this.$http.api.user,data).then(res=>{
if(res.code===200){
this.$message.success('创建成功!')
}else {
this.$message.error(res.msg)
}
}).catch(err=>{
console.log(err)
})
},
add () {
this.loading = true
const url = this.$http.api.addRole
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.editRole + `/${this.role_id}`
this.$axios.put(url, this.form.permissions).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.agencyLabel=false,
this.roleDict=[],
this.form = {
name:"", //代理名称
ip:"", //任务目标
agencyChange:"", //执行代理
domain:"", //目标域名
inject:"", //期望注入记录
strategy:"",//策略
stateAwareMode:"",//状态感知方式
switchoverTime:"", //策略切换时限
executeTime:"", //任务执行时限
operationalConfiguration:"",//运行配置
}
}
}
}
</script>
<style lang="less" scoped>
.user-dialog{
width: 563px;
height: 463px;
position: absolute; /* 绝对定位 */
top: 50%; /* 向下偏移50% */
left: 50%; /* 向右偏移50% */
transform: translate(-50%, -50%); /* 回移50% */
/*background-image:url('../../../img/background/dialog520-363.svg');*/
background-image:url('../../../img/tjpz.svg');
background-repeat: no-repeat; /* 可选,防止图像重复 */
background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
.dialog-title {
font-size: 20px;
float: left;
margin: 11px 0 11px 35px;
}
.user-form {
margin-top: 70px;
text-align: left;
::v-deep .el-form-item__content {
line-height: 15px;
}
}
.submit-footer{
width: 100%;
float: left;
margin-top: 50px;
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>

View File

@@ -0,0 +1,676 @@
<template>
<div class="range-config-manage" ref="appRef">
<div class="show">
<Header
@addRole="addRole"
></Header>
<div class="header2">
<div style="width: 45%; display: inline-block;">
<el-descriptions class="custom-descriptions" >
<el-descriptions-item label="任务名称" >{{parentLevelRow.name}}</el-descriptions-item>
<el-descriptions-item label="代理编号">{{parentLevelRow.id}}</el-descriptions-item>
<el-descriptions-item label="执行状态">
<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="danger" v-if="parentLevelRow.status==='finish'">已完成</el-tag>
</el-descriptions-item>
<el-descriptions-item label="任务目标">
{{parentLevelRow.target}}
<span style="color: #00C0FF;margin-left: 5%" @click="getInfoByIp(parentLevelRow)">查看实时状态</span>
</el-descriptions-item>
</el-descriptions>
</div>
<div style="width: 45%; display: inline-block;">
<el-row style="display: flex; flex-direction: row;">
<el-col>
<div style="display: flex; flex-direction: column; align-items: center;">
<el-button type="danger" class="enlarged-button" icon="el-icon-full-screen" circle @click="taskOps(parentLevelRow.id,'stop')"></el-button>
<span style="margin-top: 7%">停止</span>
</div>
</el-col>
<el-col>
<div style="display: flex; flex-direction: column; align-items: center;">
<el-button type="info" class="enlarged-button" icon="el-icon-video-pause" circle @click="taskOps(parentLevelRow.id,'suspend')"></el-button>
<span style="margin-top: 7%">暂停</span>
</div>
</el-col>
<el-col>
<div style="display: flex; flex-direction: column; align-items: center;">
<el-button type="success" class="enlarged-button" icon="el-icon-video-play" circle @click="taskOps(parentLevelRow.id,'start')"></el-button>
<span style="margin-top: 7%">开始</span>
</div>
</el-col>
</el-row>
</div>
</div>
<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"
type="index"
label="序号"
width="150"/>
<el-table-column
align="center"
prop="start_time"
label="开始执行时间"
width="280"/>
<el-table-column
align="center"
prop="status"
label="当前状态"
min-width="150"
style="width: 50%; height: 10%;"
>
<template slot-scope="scope">
<el-result icon="success" style="transform: scale(0.8)" v-if="scope.row.policy_id === index0tableDataId">
<template #title style="color: white;">执行中</template>
</el-result>
<el-result icon="warning" style="transform: scale(0.8)" v-if="scope.row.policy_id != index0tableDataId">
<template #title style="color: white;">无效</template>
</el-result>
</template>
</el-table-column>
<el-table-column
align="center"
prop="policy_name"
label="当前策略名称"
width="280"/>
<el-table-column
align="center"
prop="policy_param"
label="策略载荷生成参数"
width="280">
</el-table-column>
<el-table-column
align="center"
label="执行输出"
min-width="150">
<template slot-scope="scope">
<el-button type="primary" @click="newlyPztj=!newlyPztj,getLog(scope.row.policy_id)">查看</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
prop="policy_status"
label="效果评估"
width="280">
</el-table-column>
</el-table>
</div>
<div class="mask"></div>
<UserForm
ref="userForm"
:is-add="isAdd"
:permission-dict="permissionDict"
@refresh="init">
</UserForm>
<div class="popup" v-if="newlyPztj">
<span style="font-size: 30px;margin-left: 2%;margin-top: 20%">执行日志 <i class="el-icon-close" style="font-size:15px;float: right; padding-right: 7%;padding-top: 2.8%" @click="CustomizationImageFales()"></i></span>
<!-- 在此处指定弹窗的样式和内容 -->
<!-- <i class="el-icon-close" style="float: right; padding-right: 7%;padding-top: 2.8%" @click="CustomizationImageFales()"></i>-->
<div class="list" style="width: 90%;margin-left: 5%;margin-top: 5%">
<el-table
class="custom-table"
ref="multipleTable"
v-loading="loading"
element-loading-text="加载中..."
height="100%"
style="width: 100%;"
:data="tableDataLog"
tooltip-effect="dark"
highlight-current-row
>
<el-table-column
align="center"
type="index"
label="序号"
width="50"/>
<el-table-column
align="center"
prop="time"
label="时间"
width="160"/>
<el-table-column
align="center"
prop="ip"
label="IP"
width="130">
</el-table-column>
<el-table-column
align="center"
prop="targetip"
label="目标IP"
width="200"/>
<el-table-column
align="center"
prop="level"
label="日志级别"
width="100">
</el-table-column>
<el-table-column
align="center"
prop="info"
label="日志内容"
width="200">
</el-table-column>
</el-table>
</div>
<el-pagination
class="custom-paginationLog"
background
:current-page="page"
:page-sizes="[10, 20, 30, 40]"
:page-size="10"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChangeLog"
@current-change="handleCurrentChangeLog"
>
</el-pagination>
<footer style="margin-top: 10%">
<el-button class="glBut" type="primary" @click="CustomizationImageFales()">取消</el-button>
</footer>
</div>
</div>
</div>
</template>
<script>
import Header from './module/Header.vue'
import UserForm from './module/UserForm.vue'
import { getTargetsResponse } from './mock.js'
export default {
name: "RangeConfigManage",
components:{ Header, UserForm },
data(){
return{
logId:0,
parentLevelRow:{},
id_log:'',
page_log:1,
per_page_log:10,
newlyPztj:false,
page: 1,
size: 10,
total: 0,
isAdd: false,
loading: false,
target_id: '',
tableData: [],
tableDataLog: [],
index0tableDataId:0,
permissionDict: [],
}
},
mounted() {
},
watch: {},
created() {
this.parentLevelRow = this.$route.query.row;
this.init()
},
methods:{
getInfoByIp(val){
this.$router.push({ path: 'menuMBZTGZ', query: { row: val } });
},
CustomizationImageFales(){
this.newlyPztj=false;
document.querySelector('.mask').style.display = 'none'
},
init(params={}) {
// TODO: 暂时注释接口
const reqParams = {
"taskid": (this.parentLevelRow.id)?(this.parentLevelRow.id):0,
...params
}
this.loading = true
this.$axios.get(this.$http.api.taskInfo, reqParams).then(res => {
// if (res.code == 200 || res.code == "OK") {
// this.total = res?.data?.total
// this.total = 100
this.tableData = res?.data
this.index0tableDataId=res?.data[0].policy_id
this.tableData.map(item => {
item.permissions.map(permi => {
this.$set(permi, 'delLoading', false)
return permi
})
return item
})
// }
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
taskOps(id,type){
const reqParams = {
"taskid":id,
"ops": type,
}
this.loading = true
this.$axios.get(this.$http.api.taskOps, reqParams).then(res => {
if (res.code == 200) {
this.$message.success(type+'成功!')
}
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
getLog(val) {
// TODO: 暂时注释接口
document.querySelector('.mask').style.display = 'block',
this.logId=val
const reqParams = {
"id":this.logId,
"page": this.page_log,
"per_page": this.per_page_log,
}
this.loading = true
this.$axios.get(this.$http.api.taskInfoLog, reqParams).then(res => {
// if (res.code == 200 || res.code == "OK") {
// this.total = res?.data?.total
this.total = 100
this.tableDataLog = res?.data
this.tableData.map(item => {
item.permissions.map(permi => {
this.$set(permi, 'delLoading', false)
return permi
})
return item
})
// }
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
getLogPage() {
// TODO: 暂时注释接口
document.querySelector('.mask').style.display = 'block'
const reqParams = {
"id":this.logId,
"page": this.page_log,
"per_page": this.per_page_log,
}
this.loading = true
this.$axios.get(this.$http.api.taskInfoLog, reqParams).then(res => {
// if (res.code == 200 || res.code == "OK") {
// this.total = res?.data?.total
this.total = 100
this.tableDataLog = res?.data
this.tableData.map(item => {
item.permissions.map(permi => {
this.$set(permi, 'delLoading', false)
return permi
})
return item
})
// }
}).catch(err => {
console.log(err)
}).finally(() => {
this.loading = false
})
},
query(params) {
this.init(params)
},
// 打开添加角色dialog
addRole() {
this.isAdd = true
this.$refs.userForm.title = '新增角色'
document.querySelector('.mask').style.display = 'block'
this.$refs.userForm.visible = true
},
// 删除权限
delPermission(permission, role_id) {
const url = this.$http.api.delPermission + '/' + role_id
permission.delLoading = true
this.$axios.put(url, {}, {permission_id: permission.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(() => {
permission.delLoading = false
})
},
// 删除
del(row) {
this.$confirm('此操作将永久删除该角色, 是否继续?', '确认删除', {
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
this.delUser(row)
}).catch(() => {
this.$notify({
type: 'info',
message: '已取消删除'
})
})
},
delUser(row) {
const url = this.$http.api.delRole + '/' + 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
})
},
// 修改
edit(row) {
this.isAdd = false
this.$refs.userForm.title = '修改权限'
this.$refs.userForm.role_id = row.id
this.$refs.userForm.form.role_name = row.role_name
this.$refs.userForm.form.permissions = row.permissions.map(permission => permission.id)
this.getPermissionDict()
document.querySelector('.mask').style.display = 'block'
this.$refs.userForm.visible = true
},
// 获取权限字典
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) {
console.log(`每页 ${val}`)
this.page=1
this.size=val
this.query()
},
// 修改页数
handleCurrentChange(val) {
console.log(`当前页: ${val}`)
this.page=val
this.query()
},
handleSizeChangeLog(val) {
console.log(`每页 ${val}`)
this.page=1
this.size=val
this.getLogPage()
},
// 修改页数
handleCurrentChangeLog(val) {
console.log(`当前页: ${val}`)
this.page=val
this.getLogPage()
},
}
}
</script>
<style lang='less' scoped="scoped">
.custom-paginationLog{
/*float: right;*/
/*margin-left: 20%;*/
transform: scale(0.8);
/*display: flex;*/
/*justify-content: flex-end; !* 使用 Flexbox 将内容靠右 *!*/
/*/deep/ .el-pagination{*/
/* float: right;*/
/*}*/
}
/*.custom-paginationLog /deep/ .el-pagination /deep/ .is-background {*/
/* float: right;*/
/*}*/
.popup{
z-index: 997;
width: 50%;
height: 90%;
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%,高度自适应保持宽高比 */
.tag{
margin-left: 9%;
.tags{
margin-right: 5%;
margin-top: 2%;
font-size: 23px;
border: none;
background-color: transparent !important;
color: #565e6e;
}
}
.jbpz{
margin-top: 10%;
margin-left: 23%;
height: 100%;
position:relative;
.project{
display: inline-block;
width: 100%;
margin-top: 3%;
text-align: center;
padding-right: 10%;
}
.tar{
display: flex;
margin-left: 23%;
width: 100%;
text-align: center;
::v-deep .el-upload-list {
margin: 0;
list-style: none;
width: 300px !important;
padding-left: 20%;
}
.uploadBgImg{
margin-top: 5%;
width: 300px;
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;
color: rgba(81, 84, 102, 0.84);
}
.uploadBgImg::file-selector-button{
padding: 0;
background-color: transparent;
cursor: pointer;
font-size: 0;
}
}
.srkType{
width: 100%;
float: left;
margin-top: 2%;
text-align: center;
.srk{
width: 40%;
margin-left: 2%;
background-color: #0c295b;
display: inline-block;
border: none;
}
}
.radioType{
width: 100%;
float: left;
margin-top: 2%;
text-align: center;
}
.anType{
height: 10%;
position:absolute;
bottom:4%;
left: 50%;
transform: translateX(-50%);
.glBut{
width: 90px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
background-color: rgba(24, 133, 234, 0.2);
color: #1b7cc4;
}
}
}
}
.header2{
white-space: nowrap;
width: 100%;
height: auto;
margin-bottom: 1%;
margin-left: 2.5%;
.enlarged-button {
transform: scale(1.5); /* 将按钮和图标整体放大 1.5 倍 */
margin-left: 3%;
margin-right: 3%;
}
.custom-descriptions{
background-color: rgba(0,0,0,0);
/deep/ .el-descriptions-item{
background-color: rgba(19, 34, 99, 1);
}
}
/*.custom-descriptions /deep/ .el-descriptions{*/
/* background-color: #f04247; !* 设置背景颜色为灰色 *!*/
/*}*/
}
.custom-table {
width: 100%;
height: 100%;
.permission-btn {
display: inline-block;
margin: 6px;
padding: 5px 8px;
border-radius: 3px;
color:rgba(0, 0, 0, 0.90);
background: #02DDEA;
}
}
.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: 70%;
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>

View File

@@ -0,0 +1,135 @@
const getTargetsResponse = {
"code": 200,
"message": "success",
"result": {
"items": [
{
"role_name": "admin",
"id": 1,
"create_time": "2024-01-31T10:22:45",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "developer",
"id": 2,
"create_time": "2024-01-31T11:29:17",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "国家网络管理",
"id": 4,
"create_time": "2024-01-30T10:04:50"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
},
{
"permission_name": "用户管理",
"id": 6,
"create_time": "2024-01-30T10:05:30"
},
{
"permission_name": "角色管理",
"id": 7,
"create_time": "2024-01-30T10:06:22"
},
{
"permission_name": "首页",
"id": 8,
"create_time": "2024-01-30T10:07:01"
}
]
},
{
"role_name": "experimenter",
"id": 3,
"create_time": "2024-01-31T11:33:05",
"permissions": [
{
"permission_name": "靶场配置管理",
"id": 1,
"create_time": "2024-01-30T10:03:03"
},
{
"permission_name": "靶场节点管理",
"id": 2,
"create_time": "2024-01-30T10:03:48"
},
{
"permission_name": "个人管理",
"id": 3,
"create_time": "2024-01-30T10:04:18"
},
{
"permission_name": "镜像管理",
"id": 5,
"create_time": "2024-01-30T10:05:07"
}
]
}
],
"total": 3,
"page": 1,
"size": 10,
"pages": 1
}
}
export { getTargetsResponse }

View File

@@ -0,0 +1,50 @@
<template>
<div class="head">
<div class="target-select">
<span style="font-size: 30px;float: left;padding-top: 1%">任务详情</span>
</div>
</div>
</template>
<script>
export default {
name: 'Header',
props: [],
data() {
return {
role_name: ''
}
},
watch: {},
methods: {
// 新增
addRole() {
this.$emit('addRole')
}
}
}
</script>
<style lang="less" scoped>
.head{
width: 95%;
height: 7%;
margin-top: 1%;
margin-left: 2.5%;
text-align: right;
.target-select{
font-size: 10px;
float: left;
margin-top: 0.5%;
display: inline-block;
height: 60%;
width: 10%;
margin-left: 0.5%;
}
.add-btn {
height: 70%;
width: 10%;
color: #ffffff;
}
}
</style>

View File

@@ -0,0 +1,178 @@
<template>
<div
class="user-dialog"
v-if="visible"
>
<span class="dialog-title">{{ title }}</span>
<!-- 在此处指定弹窗的样式和内容 -->
<i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
<el-form
ref="userForm"
:model="form"
:rules="rules"
label-width="150px"
class="user-form"
>
<el-row>
<el-col :span="20">
<el-form-item label="角色名称" prop="role_name">
<el-input v-model="form.role_name" :disabled="!isAdd" placeholder="请输入名称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="权限" prop="permissions">
<el-checkbox-group v-model="form.permissions" style="display: inline-block;">
<el-checkbox v-for="permission in permissionDict" :label="permission.value" :key="permission.value">
{{ permission.label }}
</el-checkbox>
</el-checkbox-group>
</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: 'UserForm',
props: ['isAdd', 'permissionDict'],
data() {
return {
visible: false,
loading: false,
title: '新增角色',
form: {
role_name: '', // 角色名称
permissions: [] // 选中权限
},
role_id: '',
rules: {
role_name: [
{ required: true, message: '请输入角色名称', trigger: 'blur' }
],
permissions: [
{ required: true, message: '请选择权限', trigger: 'change' }
]
}
}
},
methods: {
close() {
this.resetForm()
document.querySelector('.mask').style.display = 'none'
this.visible = false
},
submit() {
this.$refs.userForm.validate((valid) => {
if (valid) {
if (this.isAdd) {
this.add()
} else {
this.edit()
}
}
})
},
add () {
this.loading = true
const url = this.$http.api.addRole
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.editRole + `/${this.role_id}`
this.$axios.put(url, this.form.permissions).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 = {
role_name: '', // 角色名称
permissions: [] // 选中权限
}
}
}
}
</script>
<style lang="less" scoped>
.user-dialog{
width: 520px;
height: 363px;
position: absolute; /* 绝对定位 */
top: 50%; /* 向下偏移50% */
left: 50%; /* 向右偏移50% */
transform: translate(-50%, -50%); /* 回移50% */
background-image:url('../../../img/background/dialog520-363.svg');
background-repeat: no-repeat; /* 可选,防止图像重复 */
background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
.dialog-title {
font-size: 20px;
float: left;
margin: 11px 0 11px 20px;
}
.user-form {
margin-top: 70px;
text-align: left;
::v-deep .el-form-item__content {
line-height: 15px;
}
}
.submit-footer{
width: 100%;
float: left;
margin-top: 50px;
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>