保持无logo
This commit is contained in:
commit
50748d1972
|
@ -7,7 +7,7 @@ import subprocess
|
|||
from apps.host.models import HostModel
|
||||
from lib.ssh import SSH
|
||||
from apps.task.models import JobModel
|
||||
from sysom import settings
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class SshJob:
|
||||
|
|
|
@ -19,7 +19,11 @@ from lib.ssh import SSH
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
job_defaults = {'max_instances': 10}
|
||||
job_defaults = {
|
||||
'max_instances': 10,
|
||||
'misfire_grace_time': None,
|
||||
'coalesce': True,
|
||||
}
|
||||
scheduler = BackgroundScheduler(job_defaults=job_defaults)
|
||||
scheduler.start()
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ const Settings = {
|
|||
contentWidth: 'Fluid',
|
||||
fixedHeader: true,
|
||||
fixSiderbar: true,
|
||||
title: '统信有幄UMOP',
|
||||
logo: '/logo.png',
|
||||
title: '系统运维平台',
|
||||
logo: null,
|
||||
};
|
||||
export default Settings;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB |
|
@ -25,24 +25,6 @@ body,
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.ant-pro-top-nav-header-logo h1{
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
line-height: 48px;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ant-pro-top-nav-header-logo img{
|
||||
padding-right:20px;
|
||||
height:15px;
|
||||
vertical-align: text-top;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.65);
|
||||
}
|
||||
|
||||
.ant-pro-top-nav-header-menu{
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -2,4 +2,14 @@ export default {
|
|||
'component.tagSelect.expand': '展开',
|
||||
'component.tagSelect.collapse': '收起',
|
||||
'component.tagSelect.all': '全部',
|
||||
'component.ListCard.needed_to_repair': '需要修复的漏洞(CVE)',
|
||||
'component.ListCard.high_needed_to_repair': '需要修复的高危漏洞(CVE)',
|
||||
'component.ListCard.hosts_with_vul': '存在漏洞的主机',
|
||||
'component.ListCard.today_repaired': '今日已修复漏洞',
|
||||
'component.ListCard.cumulate_repaired': '累计已修复漏洞',
|
||||
'component.ListCard.latest_scan_time': '最新扫描时间',
|
||||
'component.ListCard.scan': '一键扫描',
|
||||
'component.ListCard.scanning': '扫描中',
|
||||
'component.ListCard.success': '扫描成功',
|
||||
'component.ListCard.failed': '扫描失败'
|
||||
};
|
||||
|
|
|
@ -66,6 +66,35 @@ export default {
|
|||
'pages.journal.audit.login': '登录行为',
|
||||
'pages.journal.audit.action': '操作行为',
|
||||
'pages.journal.audit.response_status': '返回状态',
|
||||
'pages.journal.task.task_id': '任务ID',
|
||||
'pages.journal.task.status': '状态',
|
||||
'pages.journal.task.params': '参数列表',
|
||||
'pages.journal.task.success': '成功',
|
||||
'pages.journal.task.fail': '失败',
|
||||
'pages.security.list.index':'序号',
|
||||
'pages.security.list.cve_id':'编号',
|
||||
'pages.security.list.pub_time':'发布时间',
|
||||
'pages.security.list.vul_level':'漏洞等级',
|
||||
'pages.security.list.hosts':'涉及主机',
|
||||
'pages.security.list.operation':'操作',
|
||||
'pages.security.list.high':'高危',
|
||||
'pages.security.list.medium':'中危',
|
||||
'pages.security.list.critical':'严重',
|
||||
'pages.security.list.low':'低危',
|
||||
'pages.security.list.repair':'修复',
|
||||
'pages.security.list.confirm':'确认修复吗',
|
||||
'pages.security.list.re':'正在修复中...',
|
||||
'pages.security.list.error':'修复出错了,',
|
||||
'pages.security.list.details':'查看详情,',
|
||||
'pages.security.Homelist.name':'软件名称',
|
||||
'pages.security.Homelist.vul_level':'严重程度',
|
||||
'pages.security.Homelist.fixed_version':'修复版本',
|
||||
'pages.security.Homelist.hostname':'主机名称',
|
||||
'pages.security.Homelist.ip':'IP地址',
|
||||
'pages.security.Homelist.created_by':'用户',
|
||||
'pages.security.Homelist.created_at':'创建时间',
|
||||
'pages.security.Homelist.status':'主机状态',
|
||||
'pages.security.Homelist.re':'修复中',
|
||||
'pages.security.Historical.title': '历史修复漏洞信息',
|
||||
'pages.security.Historical.id': '序号',
|
||||
'pages.security.Historical.cve_id': 'cve编号',
|
||||
|
@ -84,11 +113,5 @@ export default {
|
|||
'pages.security.Historical.fail': '失败',
|
||||
'pages.security.Historical.fix_details': 'CVE修复详情',
|
||||
'pages.security.Historical.fix_success': 'CVE修复成功',
|
||||
'pages.security.Historical.fix_fail': 'CVE修复失败,失败原因:',
|
||||
'pages.journal.task.task_id': '任务ID',
|
||||
'pages.journal.task.status': '状态',
|
||||
'pages.journal.task.params': '参数列表',
|
||||
'pages.journal.task.success': '成功',
|
||||
'pages.journal.task.fail': '失败',
|
||||
|
||||
};
|
||||
'pages.security.Historical.fix_fail': 'CVE修复失败,失败原因:'
|
||||
};
|
|
@ -0,0 +1,177 @@
|
|||
import { useRef ,useState} from 'react';
|
||||
import { useIntl, FormattedMessage ,history} from 'umi';
|
||||
import { Button,Modal,Progress,Card,Row,Col} from 'antd';
|
||||
import ProCard from '@ant-design/pro-card';
|
||||
import ProTable from '@ant-design/pro-table';
|
||||
import "./homelist.less";
|
||||
import {getOneById,manyApi} from '../service'
|
||||
const Cvetable=(params)=> {
|
||||
const request=async()=>{
|
||||
const msg=await getOneById(params.id);
|
||||
msg.data = [...msg.setlovodata]
|
||||
return msg
|
||||
}
|
||||
const [succesvisible, setsuccesvisible] = useState(false);
|
||||
const [errvisible, seterrvisible] = useState(false);
|
||||
const [vlue,setCount]=useState(0)
|
||||
const [selectedRowKeys, setselectedRowKeys] = useState(0);
|
||||
const [selectedRows,setselectedRows]=useState(0)
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys,selectedRows) => {
|
||||
setselectedRowKeys(selectedRowKeys)
|
||||
setselectedRows(selectedRows)
|
||||
},
|
||||
};
|
||||
const columns=[
|
||||
{
|
||||
title: <FormattedMessage id="pages.security.list.index" defaultMessage="index" />,
|
||||
dataIndex: 'index',
|
||||
align: "center",
|
||||
hideInSearch: true,
|
||||
render: (txt, record, index) => index + 1,
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.hostname" defaultMessage="hostname" />,
|
||||
dataIndex:'hostname',
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.ip" defaultMessage="ip" />,
|
||||
dataIndex:"ip",
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.created_by" defaultMessage="created_by" />,
|
||||
dataIndex:"created_by",
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.created_at" defaultMessage="created_at" />,
|
||||
dataIndex:"created_at",
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.status" defaultMessage="status" />,
|
||||
dataIndex:"status",
|
||||
align: "center",
|
||||
render: (txt, record) => {
|
||||
if (record.status === "running") {
|
||||
return <div className="numbersuccess">
|
||||
<FormattedMessage id="pages.hostTable.status.running" defaultMessage="Running" />
|
||||
</div>
|
||||
} else if(record.status === "offline"){
|
||||
return <div className="numbererr">
|
||||
<FormattedMessage id="pages.hostTable.status.offline" defaultMessage="Offline" />
|
||||
</div>
|
||||
}else{
|
||||
return <div className="numbererr">
|
||||
<FormattedMessage id="pages.hostTable.status.abnormal" defaultMessage="Offline" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: <FormattedMessage id="pages.security.list.operation" defaultMessage="operation" />,
|
||||
dataIndex: "option",
|
||||
align: "center",
|
||||
valueType: "option",
|
||||
render: (_, record) => [
|
||||
<a key="showDetail" onClick={async()=>{
|
||||
setsuccesvisible(true)
|
||||
seterrvisible(false)
|
||||
const time =setInterval(()=>{
|
||||
setCount(vlue=>vlue+1);
|
||||
},2500)
|
||||
const arry=[];
|
||||
const id=params.id
|
||||
arry.push({"cve_id":id, "hostname":[record.hostname ]})
|
||||
const msg=await manyApi({cve_id_list:arry});
|
||||
if(msg){
|
||||
setsuccesvisible(true)
|
||||
setCount(99);
|
||||
clearInterval(time)
|
||||
if(msg.message=="fix cve failed"){
|
||||
seterrvisible(true)
|
||||
setsuccesvisible(false);
|
||||
setCount(0);
|
||||
}else{
|
||||
setTimeout(() => {
|
||||
history.push("/security/list")
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
}}>
|
||||
{<FormattedMessage id="pages.security.list.repair" defaultMessage="repair" />}
|
||||
</a>,
|
||||
],
|
||||
},
|
||||
]
|
||||
const repair=async()=>{
|
||||
const arry=[];
|
||||
const leght =selectedRows.length;
|
||||
|
||||
if(leght>0){
|
||||
setsuccesvisible(true)
|
||||
seterrvisible(false)
|
||||
const time =setInterval(()=>{
|
||||
setCount(vlue=>vlue+1);
|
||||
|
||||
},2500)
|
||||
const id=params.id
|
||||
for(let i = 0; i < leght; i++){
|
||||
arry.push({"cve_id":id, "hostname":[selectedRows[i].hostname ]})
|
||||
}
|
||||
const msg=await manyApi({cve_id_list:arry});
|
||||
if(msg){
|
||||
setsuccesvisible(true)
|
||||
setCount(99);
|
||||
clearInterval(time)
|
||||
if(msg.message=="fix cve failed"){
|
||||
seterrvisible(true)
|
||||
setsuccesvisible(false);
|
||||
setCount(0);
|
||||
}else{
|
||||
setTimeout(() => {
|
||||
history.push("/security/list")
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
const [flags,setflags]=useState(false)
|
||||
const cancel=()=>{
|
||||
if(succesvisible==true){
|
||||
setflags(true)
|
||||
}else{
|
||||
history.push("/security/list")
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ProTable
|
||||
rowKey="hostname"
|
||||
columns={columns}
|
||||
search={false}
|
||||
request={request}
|
||||
rowSelection={rowSelection}
|
||||
/>
|
||||
<ProCard>
|
||||
<Row>
|
||||
<Col span={13}>
|
||||
{succesvisible?( <p>修复中< Progress width={40} percent={vlue} size="small" /></p>):null}
|
||||
{errvisible?(<p>修复出错了,<Button type="link" size="small" href={"/security/historical" }>查看详情</Button></p>):null}
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<Row className="allbtn">
|
||||
<Col><Button type="primary" onClick={repair}>一键修复</Button></Col>
|
||||
<Col style={{'line-height':'58px'}}><Button disabled={flags} onClick={cancel} style={{'margin-right':'10px'}}>返回</Button></Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</ProCard>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Cvetable;
|
|
@ -0,0 +1,51 @@
|
|||
import { useRef, useState } from "react";
|
||||
import { useIntl, FormattedMessage } from "umi";
|
||||
import ProTable from "@ant-design/pro-table";
|
||||
import {getOneById} from '../service'
|
||||
import "./homelist.less";
|
||||
|
||||
|
||||
const Toptable = (params) => {
|
||||
console.log(params.id)
|
||||
|
||||
const request=async()=>{
|
||||
const msg=await getOneById(params.id);
|
||||
msg.data = [...msg.setdata]
|
||||
return msg
|
||||
}
|
||||
|
||||
const columns=[
|
||||
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.name" defaultMessage="name" />,
|
||||
dataIndex:'name',
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.vul_level" defaultMessage="vul_level" />,
|
||||
dataIndex:"vul_level",
|
||||
key:"vul_level",
|
||||
|
||||
},
|
||||
{
|
||||
title:<FormattedMessage id="pages.security.Homelist.fixed_version" defaultMessage="fixed_version" />,
|
||||
dataIndex:"fixed_version",
|
||||
key:"fixed_version",
|
||||
}
|
||||
]
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
columns={columns}
|
||||
search={false}
|
||||
scroll={{ y: 200 }}
|
||||
rowKey="fixed_version"
|
||||
request={request}
|
||||
headerTitle={params.id}
|
||||
pagination={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Toptable;
|
|
@ -3,15 +3,18 @@
|
|||
margin-bottom: 20px;
|
||||
|
||||
}
|
||||
.numbersuccess{
|
||||
color: palegreen;
|
||||
}
|
||||
.numbererr{
|
||||
color: red
|
||||
}
|
||||
.ant-card-body{
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.allbtn{
|
||||
display:flex;
|
||||
flex-direction:row-reverse;
|
||||
align-items: center;
|
||||
}
|
||||
// .numbersuccess{
|
||||
// color: palegreen;
|
||||
// }
|
||||
// .numbererr{
|
||||
// color: red
|
||||
// }
|
||||
|
||||
}
|
|
@ -1,207 +1,22 @@
|
|||
import React ,{useState,useEffect}from 'react';
|
||||
import { Card, Table, Button,Progress,Row, Col} from "antd";
|
||||
import './homelist.less'
|
||||
import { useRef ,useState} from 'react';
|
||||
import { useIntl, FormattedMessage } from 'umi';
|
||||
import ProCard from '@ant-design/pro-card';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import Toptable from './Toptable'
|
||||
import Cvetable from './Cvetable'
|
||||
import './homelist.less'
|
||||
|
||||
import {getOneById,manyApi} from '../service'
|
||||
import Headcard from "../components/Headcard";
|
||||
function index(props) {
|
||||
const [data,setdata]=useState([])
|
||||
const [lovodata,setlovodata]=useState([])
|
||||
const [total,setTotal]=useState(0)
|
||||
const [selectedRowKeys, setselectedRowKeys] = useState([]);
|
||||
const [selectedRows, setselectedRows] = useState([]);
|
||||
const [title,settitle]=useState("")
|
||||
const [vlue,setCount]=useState(0)
|
||||
|
||||
useEffect(async()=>{
|
||||
const msg=await getOneById(props.match.params.id);
|
||||
setlovodata(msg.setlovodata)
|
||||
setdata(msg.setdata)
|
||||
settitle(msg.title)
|
||||
},[])
|
||||
const[succesvisible,setsuccesvisible]=useState(false);
|
||||
const [errvisible,seterrvisible]=useState(false)
|
||||
|
||||
const fn = () => {
|
||||
props.history.push("/security/historical");
|
||||
};
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
setselectedRowKeys(selectedRowKeys);
|
||||
setselectedRows(selectedRows);
|
||||
},
|
||||
};
|
||||
const columns=[
|
||||
|
||||
{
|
||||
title:"软件名称",
|
||||
dataIndex:'name',
|
||||
key:'name'
|
||||
},
|
||||
{
|
||||
title:"严重程度",
|
||||
dataIndex:"vul_level",
|
||||
key:"vul_level",
|
||||
|
||||
},
|
||||
{
|
||||
title:"修复版本",
|
||||
dataIndex:"fixed_version",
|
||||
key:"fixed_version",
|
||||
}
|
||||
]
|
||||
const lnvohost=[
|
||||
{
|
||||
title: "序号",
|
||||
key: "id",
|
||||
width: 80,
|
||||
align: "center",
|
||||
render: (txt, record, index) => index + 1,
|
||||
},
|
||||
{
|
||||
title:"主机名称",
|
||||
dataIndex:'hostname',
|
||||
key:'hostname'
|
||||
},
|
||||
{
|
||||
title:"IP地址",
|
||||
dataIndex:"ip",
|
||||
key:"ip",
|
||||
},
|
||||
{
|
||||
title:"用户",
|
||||
dataIndex:"created_by",
|
||||
key:"created_by",
|
||||
},
|
||||
{
|
||||
title:"创建时间",
|
||||
dataIndex:"created_at",
|
||||
key:"created_at",
|
||||
},
|
||||
{
|
||||
title:"主机状态",
|
||||
dataIndex:"status",
|
||||
key:"status",
|
||||
render:(txt,record)=>{
|
||||
if(record.status==="running"){
|
||||
return <div className="numbersuccess">运行中</div>
|
||||
}else{
|
||||
return <div className="numbererr">离线</div>
|
||||
}
|
||||
}
|
||||
},{
|
||||
title:"操作",
|
||||
render:(txt,record,index)=>{
|
||||
return (
|
||||
<div>
|
||||
<Button type="link" onClick={async()=>{
|
||||
setsuccesvisible(true)
|
||||
seterrvisible(false)
|
||||
const time =setInterval(()=>{
|
||||
setCount(vlue=>vlue+1);
|
||||
},2500)
|
||||
const arry=[];
|
||||
const id=props.match.params.id
|
||||
arry.push({"cve_id":id, "hostname":[record.hostname ]})
|
||||
const msg=await manyApi({cve_id_list:arry});
|
||||
if(msg){
|
||||
setsuccesvisible(true)
|
||||
setCount(99);
|
||||
clearInterval(time)
|
||||
if(msg.message=="fix cve failed"){
|
||||
seterrvisible(true)
|
||||
setsuccesvisible(false);
|
||||
setCount(0);
|
||||
}else{
|
||||
setTimeout(() => {
|
||||
props.history.push("/security/list")
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
}}>修复</Button>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const repair=async()=>{
|
||||
const arry=[];
|
||||
const leght =selectedRows.length;
|
||||
|
||||
if(leght>0){
|
||||
setsuccesvisible(true)
|
||||
seterrvisible(false)
|
||||
const time =setInterval(()=>{
|
||||
setCount(vlue=>vlue+1);
|
||||
|
||||
},2500)
|
||||
const id=props.match.params.id
|
||||
for(let i = 0; i < leght; i++){
|
||||
arry.push({"cve_id":id, "hostname":[selectedRows[i].hostname ]})
|
||||
}
|
||||
const msg=await manyApi({cve_id_list:arry});
|
||||
if(msg){
|
||||
setsuccesvisible(true)
|
||||
setCount(99);
|
||||
clearInterval(time)
|
||||
if(msg.message=="fix cve failed"){
|
||||
seterrvisible(true)
|
||||
setsuccesvisible(false);
|
||||
setCount(0);
|
||||
}else{
|
||||
setTimeout(() => {
|
||||
props.history.push("/security/list")
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
const paginationProps = {
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
total: total, // 数据总数
|
||||
pageSizeOptions: [10,20,50,100] ,
|
||||
defaultPageSize:20,
|
||||
// current: pageNum, // 当前页码
|
||||
showTotal: ((total,ranage) => `共 ${total} 条`),
|
||||
position:["bottomRight"],
|
||||
// size:"small"
|
||||
};
|
||||
return (
|
||||
|
||||
<div>
|
||||
<PageContainer>
|
||||
<Headcard paren={fn} isShow={true} upData={false}/>
|
||||
<Card className="list-table" title={title}>
|
||||
|
||||
<Table size="small" pagination={false} scroll={{ y: 100 }} rowKey="fixed_version" columns={columns} dataSource={data} />
|
||||
</Card>
|
||||
<Card title="涉及主机" className="lnvohost">
|
||||
<Table rowKey="hostname" size="small" rowSelection={rowSelection} pagination={ paginationProps} columns={lnvohost} dataSource={lovodata}> </Table>
|
||||
<Row>
|
||||
<Col span={13}>
|
||||
{succesvisible?( <p>修复中< Progress width={40} percent={vlue} size="small" /></p>):null}
|
||||
{errvisible?(<p>恢复出错了,<Button type="link" size="small" onClick={()=>props.history.push('/security/historical')}>查看详情</Button></p>):null}
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<Row className="allbtn">
|
||||
<Col><Button type="primary" onClick={repair}>一键修复</Button></Col>
|
||||
<Col style={{'line-height':'58px'}}><Button onClick={()=>{ props.history.push("/security/list") }} style={{'margin-right':'10px'}}>取消</Button></Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</PageContainer>
|
||||
</div>
|
||||
const { Divider } = ProCard;
|
||||
const Homelist=(props)=> {
|
||||
const id=props.match.params.id
|
||||
return (
|
||||
<PageContainer>
|
||||
<Divider/>
|
||||
<Toptable id={id}/>
|
||||
<Divider/>
|
||||
<Cvetable id={id}/>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default index;
|
||||
export default Homelist;
|
||||
|
|
|
@ -1,39 +1,46 @@
|
|||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Card, Table, Button, Progress, Modal, Tooltip, message, } from "antd";
|
||||
import { useRef ,useState} from 'react';
|
||||
import { useIntl, FormattedMessage } from 'umi';
|
||||
import ProCard from '@ant-design/pro-card';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Button,Modal,Progress} from 'antd';
|
||||
import ProTable from '@ant-design/pro-table';
|
||||
import Restoration from "../components/restoration"
|
||||
import ListCard from '../components/ListCard'
|
||||
import "./list.less";
|
||||
import { listApi, manyApi, updataApi } from "../service";
|
||||
import { PageContainer } from "@ant-design/pro-layout";
|
||||
import Headcard from "../components/Headcard";
|
||||
import { listApi, manyApi } from "../service";
|
||||
|
||||
function List(props) {
|
||||
// console.log(props)
|
||||
const [data, setdata] = useState([]);
|
||||
|
||||
useEffect(async () => {
|
||||
const msg = await listApi();
|
||||
|
||||
setdata(msg.data);
|
||||
}, []);
|
||||
const { Divider } = ProCard;
|
||||
const List=(props)=> {
|
||||
|
||||
const actionRef = useRef();
|
||||
const intl = useIntl();
|
||||
const fn = () => {
|
||||
props.history.push("/security/historical");
|
||||
};
|
||||
const [selectedRowKeys, setselectedRowKeys] = useState(0);
|
||||
const [selectedRows,setselectedRows]=useState(0)
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys,selectedRows) => {
|
||||
setselectedRowKeys(selectedRowKeys)
|
||||
setselectedRows(selectedRows)
|
||||
},
|
||||
};
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [succesvisible, setsuccesvisible] = useState(false);
|
||||
const [errvisible, seterrvisible] = useState(false);
|
||||
const [vlue, setCount] = useState(0);
|
||||
const [huan,sethuan]=useState(false)
|
||||
|
||||
|
||||
const showModal = () => {
|
||||
const leght = selectedRows.length;
|
||||
if (leght > 0) {
|
||||
const leght = selectedRows.length;
|
||||
if (leght > 0) {
|
||||
setIsModalVisible(true);
|
||||
}
|
||||
};
|
||||
const handleOk = async () => {
|
||||
const time = setInterval(() => {
|
||||
setCount((vlue) => vlue + 1);
|
||||
}, 2500);
|
||||
}, 4500);
|
||||
setIsModalVisible(false);
|
||||
setsuccesvisible(true);
|
||||
const arry = [];
|
||||
|
@ -44,7 +51,7 @@ function List(props) {
|
|||
hostname: selectedRows[i].hosts,
|
||||
});
|
||||
}
|
||||
const msg = await manyApi({ cve_id_list: arry });
|
||||
const msg = await manyApi({ cve_id_list: arry });
|
||||
if (msg) {
|
||||
setIsModalVisible(false);
|
||||
setsuccesvisible(true);
|
||||
|
@ -63,73 +70,67 @@ function List(props) {
|
|||
const handleCancel = () => {
|
||||
setIsModalVisible(false);
|
||||
};
|
||||
const geng=async()=>{
|
||||
sethuan(true)
|
||||
const msg = await updataApi();
|
||||
console.log(msg)
|
||||
if(msg.message=="success"){
|
||||
sethuan(false)
|
||||
props.history.push("/security");
|
||||
}else if(msg.message=="forbidden"){
|
||||
sethuan(false)
|
||||
message.warning('操作频率过快,请稍后再试!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
key: "index",
|
||||
width: 80,
|
||||
title: <FormattedMessage id="pages.security.list.index" defaultMessage="index" />,
|
||||
dataIndex: 'index',
|
||||
align: "center",
|
||||
|
||||
hideInSearch: true,
|
||||
render: (txt, record, index) => index + 1,
|
||||
},
|
||||
{
|
||||
title: "编号",
|
||||
dataIndex: "cve_id",
|
||||
key: "cve_id",
|
||||
title: <FormattedMessage id="pages.security.list.cve_id" defaultMessage="cve_id" />,
|
||||
dataIndex: 'cve_id',
|
||||
align: "center",
|
||||
hideInSearch: true
|
||||
},
|
||||
{
|
||||
title: "发布时间",
|
||||
dataIndex: "pub_time",
|
||||
key: "pub_time",
|
||||
title: <FormattedMessage id="pages.security.list.pub_time" defaultMessage="pub_time" />,
|
||||
dataIndex: 'pub_time',
|
||||
valueType: 'dateTime',
|
||||
align: "center",
|
||||
sorter: (a, b) => a.pub_time.length - b.pub_time.length,
|
||||
hideInSearch: true,
|
||||
sorter: (a, b) => a.pub_time - b.pub_time,
|
||||
},
|
||||
{
|
||||
title: "漏洞等级",
|
||||
dataIndex: "vul_level",
|
||||
key: "vul_level",
|
||||
title: <FormattedMessage id="pages.security.list.vul_level" defaultMessage="vul_level" />,
|
||||
dataIndex: 'vul_level',
|
||||
align: "center",
|
||||
render: (txt, record) => {
|
||||
if (record.vul_level == "high") {
|
||||
return <div>高危</div>;
|
||||
} else if (record.vul_level == "medium") {
|
||||
return <div>中危</div>;
|
||||
} else if (record.vul_level == "critical") {
|
||||
return <div>严重</div>;
|
||||
} else if (record.vul_level == "low") {
|
||||
return <div>低危</div>;
|
||||
} else if (record.vul_level == "") {
|
||||
return <div></div>;
|
||||
}
|
||||
filters: true,
|
||||
onFilter: true,
|
||||
hideInSearch: true,
|
||||
valueEnum: {
|
||||
high: {
|
||||
text: (
|
||||
<FormattedMessage id="pages.security.list.high" defaultMessage="high" />
|
||||
),
|
||||
},
|
||||
medium: {
|
||||
text: (
|
||||
<FormattedMessage id="pages.security.list.medium" defaultMessage="medium" />
|
||||
),
|
||||
},
|
||||
critical: {
|
||||
text: (
|
||||
<FormattedMessage id="pages.security.list.critical" defaultMessage="critical" />
|
||||
),
|
||||
},
|
||||
low: {
|
||||
text: (
|
||||
<FormattedMessage id="pages.security.list.low" defaultMessage="low" />
|
||||
),
|
||||
},
|
||||
},
|
||||
filters: [
|
||||
{ text: "严重", value: "critical" },
|
||||
{ text: "高危", value: "high" },
|
||||
{ text: "中危", value: "medium" },
|
||||
{ text: "低危", value: "low" },
|
||||
],
|
||||
onFilter: (value, record) => record.vul_level.includes(value),
|
||||
},
|
||||
|
||||
{
|
||||
title: <FormattedMessage id="pages.security.list.hosts" defaultMessage="hosts" />,
|
||||
dataIndex: 'hosts',
|
||||
width: "20%",
|
||||
title: "涉及主机",
|
||||
align: "center",
|
||||
dataIndex: "hosts",
|
||||
key: "hosts",
|
||||
valueType: 'select',
|
||||
hideInSearch: true,
|
||||
onCell: () => {
|
||||
return {
|
||||
style: {
|
||||
|
@ -141,105 +142,62 @@ function List(props) {
|
|||
},
|
||||
};
|
||||
},
|
||||
render: (text) => (
|
||||
<span placement="topLeft" title={text}>
|
||||
{text.toString()}
|
||||
render: (_,record,text) => (
|
||||
<span placement="topLeft" title={record.hosts.toString()} >
|
||||
{record.hosts.toString()}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
title: <FormattedMessage id="pages.security.list.operation" defaultMessage="operation" />,
|
||||
dataIndex: "option",
|
||||
align: "center",
|
||||
render: (txt, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() =>
|
||||
props.history.push(`/security/homelist/${record.cve_id}`)
|
||||
}
|
||||
>
|
||||
{" "}
|
||||
修复{" "}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
valueType: "option",
|
||||
render: (_, record) => [
|
||||
<a key="showDetail" href={"/security/homelist/" + record.cve_id}>
|
||||
{<FormattedMessage id="pages.security.list.repair" defaultMessage="repair" />}
|
||||
</a>,
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
];
|
||||
const [selectedRowKeys, setselectedRowKeys] = useState(0);
|
||||
const [selectedRows, setselectedRows] = useState(0);
|
||||
const [total, setTotal] = useState(0);
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
setselectedRowKeys(selectedRowKeys);
|
||||
setselectedRows(selectedRows);
|
||||
},
|
||||
};
|
||||
const paginationProps = {
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
total: total, // 数据总数
|
||||
pageSizeOptions: [10, 20, 50, 100],
|
||||
defaultPageSize: 20,
|
||||
// current: pageNum, // 当前页码
|
||||
showTotal: (total, ranage) => `共 ${total} 条`,
|
||||
position: ["bottomRight"],
|
||||
// size:"small"
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<PageContainer>
|
||||
<Headcard paren={fn} isShow={true} geng={geng} quan={huan} upData={true}/>
|
||||
<Card
|
||||
className="list-table"
|
||||
extra={
|
||||
<Button type="primary" size="small" onClick={showModal}>
|
||||
修复
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
rowSelection={rowSelection}
|
||||
rowKey="cve_id"
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
size="small"
|
||||
pagination={paginationProps}
|
||||
/>
|
||||
<Modal
|
||||
width={320}
|
||||
visible={isModalVisible}
|
||||
onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
centered={true}
|
||||
>
|
||||
<p className="stop">确定修复吗</p>
|
||||
<div>
|
||||
<PageContainer>
|
||||
<ListCard refreshTable={listApi} />
|
||||
<Divider />
|
||||
<ProTable rowKey="cve_id" columns={columns} search={false} request={listApi}
|
||||
toolBarRender={() => [
|
||||
<Restoration paren={fn}/>,
|
||||
<Button type="primary" key="primary" onClick={showModal}>
|
||||
{<FormattedMessage id="pages.security.list.repair" defaultMessage="repair" />}
|
||||
</Button>
|
||||
]}
|
||||
rowSelection={rowSelection}
|
||||
/>
|
||||
|
||||
<Modal width={320} visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} centered={true}>
|
||||
<p className="stop">
|
||||
{<FormattedMessage id="pages.security.list.confirm" defaultMessage="confirm" />}
|
||||
</p>
|
||||
</Modal>
|
||||
<Modal
|
||||
width={320}
|
||||
visible={succesvisible}
|
||||
footer={null}
|
||||
centered={true}
|
||||
<Modal width={320} visible={succesvisible} footer={null} centered={true}
|
||||
>
|
||||
<p> 正在修复中...</p>
|
||||
<p> {<FormattedMessage id="pages.security.list.re" defaultMessage="re" />}</p>
|
||||
<Progress percent={vlue} size="small" />
|
||||
</Modal>
|
||||
<Modal width={320} visible={errvisible} footer={null} centered={true}>
|
||||
<p>
|
||||
恢复出错了,
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
<p> {<FormattedMessage id="pages.security.list.error" defaultMessage="error" />}
|
||||
<Button type="link" size="small"
|
||||
onClick={() => props.history.push("/security/historical")}
|
||||
>
|
||||
查看详情
|
||||
{<FormattedMessage id="pages.security.list.details" defaultMessage="details" />}
|
||||
</Button>
|
||||
</p>
|
||||
</Modal>
|
||||
</Card>
|
||||
</PageContainer>
|
||||
</PageContainer>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
.blue{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: blue;
|
||||
}
|
||||
.tan{
|
||||
position: relative;
|
||||
|
@ -11,6 +12,13 @@ height: 20px;
|
|||
width: 200px;
|
||||
|
||||
}
|
||||
// .waring{
|
||||
// width: 25px;
|
||||
// height: 25px;
|
||||
// background-image: url(../../../../public/icons/waring.png);
|
||||
// background-repeat:no-repeat;
|
||||
|
||||
// }
|
||||
.ant-modal-body{
|
||||
|
||||
p{
|
||||
|
@ -21,9 +29,4 @@ height: 20px;
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
.Ooylined{
|
||||
float:right;
|
||||
|
||||
|
||||
}
|
|
@ -4,7 +4,6 @@ import { Button, Row, Col } from "antd";
|
|||
import "./Viewdetails.less";
|
||||
import { viewApi, summaryApi } from "../service";
|
||||
import { PageContainer } from "@ant-design/pro-layout";
|
||||
import Headcard from "../components/Headcard";
|
||||
import ProCard from "@ant-design/pro-card";
|
||||
|
||||
function index(props) {
|
||||
|
@ -30,7 +29,6 @@ function index(props) {
|
|||
return (
|
||||
<div>
|
||||
<PageContainer>
|
||||
{/* <Headcard paren={fn} isShow={false} upData={false} /> */}
|
||||
<ProCard className="card_result">
|
||||
<h3> <span>
|
||||
<FormattedMessage id="pages.hostTable.hostname" defaultMessage="Hostname" />
|
||||
|
@ -56,4 +54,4 @@ function index(props) {
|
|||
);
|
||||
}
|
||||
|
||||
export default index;
|
||||
export default index;
|
|
@ -1,41 +0,0 @@
|
|||
import React,{useState,useEffect} from 'react';
|
||||
import { Card, Button,Row,Col} from "antd";
|
||||
import {summaryApi} from '../service'
|
||||
import {SyncOutlined} from '@ant-design/icons';
|
||||
import '../List/list.less'
|
||||
|
||||
function Headcard(param) {
|
||||
console.log(param)
|
||||
const [affectcount,setaffectcount]=useState(0);
|
||||
const [cvecount,setcvecount]=useState(0);
|
||||
const [higtcount,sethigtcount]=useState(0)
|
||||
|
||||
useEffect(async() => {
|
||||
const msg=await summaryApi();
|
||||
setaffectcount(msg.affect)
|
||||
setcvecount(msg.cvecount)
|
||||
sethigtcount(msg.highcount)
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<span>{affectcount}台主机存在被攻击风险,涉及CVE漏洞{cvecount}个,其中高危漏洞{higtcount}个,请尽快修复。</span>
|
||||
{param.isShow?(<Button type="link" onClick={param.paren}>历史修复</Button>):""}
|
||||
{param.upData?(<Button type="link" onClick={param.geng}>更新</Button>):""}
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
{param.quan?( < SyncOutlined className="Ooylined" style={{fontSize:'22px',}} spin />):""}
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Headcard;
|
|
@ -0,0 +1,99 @@
|
|||
import { Statistic ,Button, message} from 'antd';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useIntl, FormattedMessage } from 'umi';
|
||||
import ProCard from '@ant-design/pro-card';
|
||||
import RcResizeObserver from 'rc-resize-observer';
|
||||
import {summaryApi,updataApi} from '../service'
|
||||
const { Divider } = ProCard;
|
||||
import '../List/list.less'
|
||||
import { size } from 'lodash-es';
|
||||
|
||||
|
||||
const ListCard=(props)=> {
|
||||
const intl = useIntl();
|
||||
const [responsive, setResponsive] = useState(false);
|
||||
const [complete, setComplete] = useState(false);
|
||||
const [StatisticList, setStatisticList] = useState()
|
||||
const getSummary = async() => {
|
||||
setComplete(true);
|
||||
let msg=await summaryApi();
|
||||
if(msg){
|
||||
setComplete(false);
|
||||
if(msg.success){
|
||||
message.success(intl.formatMessage({id:'component.ListCard.success',defaultMessage:'Scan success'}));
|
||||
setStatisticList(msg.data.fixed_cve)
|
||||
props.refreshTable();
|
||||
}else{
|
||||
message.error(intl.formatMessage({id:'component.ListCard.failed',defaultMessage:'Scan failed'}));
|
||||
}
|
||||
}
|
||||
}
|
||||
useEffect(async() => {
|
||||
let msg=await summaryApi();
|
||||
if(msg.success)
|
||||
setStatisticList(msg.data.fixed_cve)
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<RcResizeObserver
|
||||
key="resize-observer"
|
||||
onResize={(offset) => {
|
||||
setResponsive(offset.width < 596);
|
||||
}}>
|
||||
<ProCard.Group direction={responsive ? 'column' : 'row'}>
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.needed_to_repair',
|
||||
defaultMessage: 'Need to repair',
|
||||
})}
|
||||
value={StatisticList?.cve_count} valueStyle={{ color: "red", textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.high_needed_to_repair',
|
||||
defaultMessage: 'High-risk need to Repair',
|
||||
})}
|
||||
value={StatisticList?.high_cve_count} valueStyle={{ color: "red", textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.hosts_with_vul',
|
||||
defaultMessage: 'Hosts with vulnerabilities',
|
||||
})}
|
||||
value={StatisticList?.affect_host_count} valueStyle={{ color: "red", textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.today_repaired',
|
||||
defaultMessage: 'Today has been repaired',
|
||||
})}
|
||||
value={StatisticList?.cvefix_today_count} valueStyle={{ color: "red", textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.cumulate_repaired',
|
||||
defaultMessage: 'Cumulative revision',
|
||||
})}
|
||||
value={StatisticList?.cvefix_all_count} valueStyle={{ color: "red",textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title={intl.formatMessage({
|
||||
id: 'component.ListCard.latest_scan_time',
|
||||
defaultMessage: 'Latest scan time',
|
||||
})}
|
||||
value={StatisticList?.latest_scan_time} valueStyle={{ color: "white",fontSize:13,whiteSpace:'nowrap',textAlign:'center' }} />
|
||||
</ProCard>
|
||||
<ProCard>
|
||||
<Button onClick={getSummary} type="primary" loading={complete}>{complete ? <FormattedMessage id="component.ListCard.scanning" defaultMessage="Scanning" /> : <FormattedMessage id="component.ListCard.scan" defaultMessage="Scan" />}</Button>
|
||||
</ProCard>
|
||||
</ProCard.Group>
|
||||
</RcResizeObserver>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListCard;
|
|
@ -0,0 +1,12 @@
|
|||
import { Button, message } from "antd";
|
||||
|
||||
const restoration=(param)=> {
|
||||
// console.log(param)
|
||||
return (
|
||||
<div>
|
||||
<Button type="primary" key="primary" onClick={param.paren}>历史修复</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default restoration;
|
|
@ -18,7 +18,7 @@ const token = localStorage.getItem('token');
|
|||
}
|
||||
|
||||
export async function summaryApi(options) {
|
||||
const msg= await request('/api/v1/vul/summary', {
|
||||
const msg= await request('/api/v1/vul/summary/', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -27,12 +27,13 @@ const token = localStorage.getItem('token');
|
|||
...(options || {}),
|
||||
|
||||
});
|
||||
return {
|
||||
affect:msg.data.fixed_cve.affect_host_count,
|
||||
cvecount:msg.data.fixed_cve.cve_count,
|
||||
highcount:msg.data.fixed_cve.high_cve_count
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
// {
|
||||
// affect:msg.data.fixed_cve.affect_host_count,
|
||||
// cvecount:msg.data.fixed_cve.cve_count,
|
||||
// highcount:msg.data.fixed_cve.high_cve_count
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
@ -58,9 +59,9 @@ const token = localStorage.getItem('token');
|
|||
},
|
||||
...(options || {}),
|
||||
});
|
||||
msg.data.data = [...msg.data.hosts_datail];
|
||||
msg.data.data = [...msg.data.hosts_datail];
|
||||
return msg.data;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export async function getOneById(id,options) {
|
||||
|
@ -79,7 +80,7 @@ const token = localStorage.getItem('token');
|
|||
setdata:msg.data.software,
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -94,7 +95,7 @@ const token = localStorage.getItem('token');
|
|||
});
|
||||
|
||||
return msg;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export async function manyApi(body, options) {
|
||||
|
@ -121,7 +122,7 @@ const token = localStorage.getItem('token');
|
|||
...(options || {}),
|
||||
|
||||
});
|
||||
return msg
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ const VmcoreCard = () => {
|
|||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
<Statistic title="月宕机率" value={StatisticList?.rate_30days} suffix="%" valueStyle={{ color: "red" }} />
|
||||
<Statistic title="月宕机率" value={StatisticList?.rate_30days} precision={2} suffix="%" valueStyle={{ color: "red" }} />
|
||||
</ProCard>
|
||||
<Divider type={responsive ? 'horizontal' : 'vertical'} />
|
||||
<ProCard>
|
||||
|
|
Loading…
Reference in New Issue