运维服务中台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1462 lines
79 KiB

import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { Timeline, Card, Button, Modal, Form, Tooltip } from '@douyinfe/semi-ui';
import { push } from 'react-router-redux';
import './control.less'
import PerfectScrollbar from "perfect-scrollbar";
import repairFQA from '../../means/containers/repairFQA';
import { Setup } from "$components";
import ReactECharts from 'echarts-for-react';
import moment from "moment";
import SimpleBar from 'simplebar-react';
import AlarmChart from '../components/alarm-chart';
let newScrollbar;
let overviewScrollbar;
let memberScrollbar;
let equipmentScrollbar;
let webScrollbar;
let problemsScrollbar;
let alarmScrollbar;
let pomsListScrollbar
let problems
let member
let web
const Control = ({ dispatch, actions, user, history, loading, socket, pepProjectId, projectPoms }) => {
const { control, install } = actions
const [memberList, setMemberList] = useState([])//相关成员列表
const [equipmentList, setEquipmentList] = useState(['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''])//平台设备接入列表
const [webList, setWebList] = useState([])//关联web应用列表
const [problemsList, setProblemsList] = useState([])//异常&问题列表
const [setup, setSetup] = useState(false); //设置是否显现
const [tableType, setTableType] = useState(''); //localStorage存储名
const [tool, setTool] = useState(false); //工具添加修改弹窗
const [alter, setAlter] = useState(false); //工具添加或编辑
const [compile, setCompile] = useState({}); //工具编辑的内容
const [toolShow, setToolShow] = useState([]); //工具展示
const [toolData, setToolData] = useState(0); //工具数
const [tableSetup, setTableSetup] = useState([]); //单一表格设置信息
const [workData, setWorkData] = useState({}); //我的工作台数据
const [dataBI, setDataBI] = useState({}); //查询BI分析数据-数据
const [videoBI, setVideoBI] = useState([]); //查询BI分析数据-视频
const [appBI, setAppBI] = useState([]); //查询BI分析数据-应用
const [efficiencyBI, setEfficiencyBI] = useState({}); //查询BI分析数据-问题处置
const [query, setQuery] = useState({ limit: 23, page: 0, projectCorrelationId: '', types: '1' }); //最新动态
const [querydata1, setQueryData1] = useState([]); //最新动态数据
const [long, setLong] = useState(''); //最新动态设置
const [pomsList, setPomsList] = useState([]); //项目
const [projectId, setProjectId] = useState(''); //项目id
const [ask, setASk] = useState(true); //是否继续请求
const [setData, setSetData] = useState(); //设置总数
const [projectData, setProjectData] = useState([]); //项目总信息
const [socketData, setSocketData] = useState(); //推送数据
const [socketDat] = useState(); //推送数据
const exhibition = useRef({ workbench: [], statistical: [] }) //页面结构
const FormApi = useRef()
const querydata = useRef([])//最新动态数据
// const socketData = useRef(1) //推送数据
// websocket 使用测试
useEffect(() => {
if (socket) {
socket.on('alarmSendSocket', (msg) => {
if (msg?.msgDataMap) {
setSocketData(msg?.msgDataMap)
}
});
return () => {
socket.off("alarmSendSocket")
}
}
}, [socket])
useEffect(() => {
if (socketData) {
console.log(socketData)
console.log(problemsList)
let workbench = workData
let newest = []
let ProblemAlarm = []
if (socketData?.appear?.length > 0) {
socketData?.appear?.map(v => {
if (v.type == '应用异常') {
workbench.appNewAdd++
} else if (v.type == '设备异常') {
workbench.toolNewAdd++
} else {
workbench.dataNewAdd++
}
ProblemAlarm.push({
...v, url: v.alarmGroup, groupName: v.type, SourceName: v.source, StartTime: v.time, typeName: v.alarmGroup
})
if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) {
newest.push({
seed: 'discovery',
project: v.project,
sources: v.source,
type: v.type,
time: v.time,
id: v.id,
})
}
})
}
if (socketData?.confirm?.length > 0) {
socketData?.confirm?.map(v => {
if (v.type == '应用异常') {
workbench.appConfirme++
} else if (v.type == '设备异常') {
workbench.toolConfirme++
} else {
workbench.dataConfirme++
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'confirm')) {
newest.push({
seed: 'confirm',
project: v.project,
sources: v.source,
type: v.type,
time: v.time,
userName: v.user ? '' : v.user,
id: v.id,
})
}
})
dispatch(control.getConsoleAbnormal({ pepProjectId: pepProjectId || projectId })).then(res => {
if (res.success) {
if (res.payload.data?.length > 4) {
setProblemsList([...res.payload.data, ...res.payload.data])
let problemstop = 0
let problemsId = document.getElementById('problems');
if (problems) clearInterval(problems)
if (problemsId) {
function problemstart () {
problems = setInterval(() => {
problemstop += 5
problemsId.scrollTop = problemstop
if (problemsId.scrollTop >= problemsId.scrollHeight / 2) problemstop = 0, problemsId.scrollTop = problemstop
}, 500);
problemsId.onmouseover = () => clearInterval(problems)
}
problemsId.onmouseout = () => problemstart()
setTimeout(problemstart(), 1000);
}
} else {
setProblemsList(res.payload.data)
}
}
})
} else {
if (ProblemAlarm?.length > 0) {
ProblemAlarm.sort((a, b) => (moment(a.StartTime).isBefore(b.StartTime) ? 1 : -1))
setProblemsList([...ProblemAlarm, ...problemsList])
}
}
workbench.appSurplus += (workbench.appNewAdd - workbench.appConfirme)
workbench.toolSurplus += (workbench.toolNewAdd - workbench.toolConfirme)
workbench.dataSurplus += (workbench.dataNewAdd - workbench.dataConfirme)
setWorkData({ ...workbench })
if (socketData?.notice?.length > 0) {
socketData?.notice?.map(v => {
if (exhibition?.current?.dynamic?.find(v => v.key == 'notice') && pomsList?.map(u => u.pepProjectId)?.includes(v.projectCorrelationId)) {
newest.push({
seed: 'notice',
time: v.time,
project: v.project,
userName: v.pepUsers?.map(u => u.name),
alarmPushConfig: v.pushConfig?.cfgName,
tactics: v.pushConfig?.tactics,
interval: v.pushConfig?.tacticsParams?.interval,
deviceProportion: v.pushConfig?.tacticsParams?.deviceProportion,
id: v.projectCorrelationId,
})
}
})
}
newest.sort((a, b) => (moment(a.time).isBefore(b.time) ? 1 : -1))
querydata.current = [...newest, ...querydata.current]
setQueryData1([...querydata.current])
}
}, [socketData])
useEffect(() => {
if (projectPoms) {
setProjectData(projectPoms?.filter(v => v.pepProjectIsDelete != 1))
let data = projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name }))
setPomsList(data)
setProjectId(projectPoms[0]?.pepProjectId)
}
}, [projectPoms])
useEffect(() => {
//初始化表格显示设置
let data = ['overall', 'workbench', 'statistical', 'analyse', 'dynamic']
data.map(v => {
localStorage.getItem(v) == null
? localStorage.setItem(v, JSON.stringify(show[v]))
: ""
attribute(v)
})
const domProject = document.getElementById("news");
if (domProject) {
newScrollbar = new PerfectScrollbar("#news", {
suppressScrollX: true,
});
}
const domProject3 = document.getElementById("equipment");
if (domProject3) {
equipmentScrollbar = new PerfectScrollbar("#equipment", {
suppressScrollX: true,
});
}
const domProject4 = document.getElementById("web");
if (domProject4) {
webScrollbar = new PerfectScrollbar("#web", {
suppressScrollX: true,
})
}
const domProject5 = document.getElementById("problems");
if (domProject5) {
problemsScrollbar = new PerfectScrollbar("#problems", {
suppressScrollX: true,
});
}
const domProject6 = document.getElementById("alarm");
if (domProject6) {
alarmScrollbar = new PerfectScrollbar("#alarm", {
suppressScrollY: true,
});
}
return () => {
}
}, [])
useEffect(() => {
if (pepProjectId) setProjectId(pepProjectId)
// 工作台数据请求
dispatch(control.getConsoleCount({ pepProjectId: pepProjectId })).then(res => {
if (res.success) setWorkData(res.payload.data)
})
}, [pepProjectId])
useEffect(() => {
if (exhibition.current?.overall?.find(v => v.key == 'tool')) {
consoleToollink()
}
}, [exhibition.current])
useEffect(() => {
async function concentration2 () {
if (exhibition.current?.overall?.find(v => v.key == 'analyse')) {
// 查询BI分析数据-数据
await dispatch(control.getDataAlarmsAggDay({ pepProjectId: pepProjectId })).then(res => {
if (res.success) setDataBI(res.payload.data)
})
// 查询BI分析数据-视频异常
await dispatch(control.getVideoAlarmsAggDay({ pepProjectId: pepProjectId })).then(res => {
if (res.success) setVideoBI(res.payload.data)
})
// 查询BI分析数据-应用
await dispatch(control.getAppAlarmsAggDay({ pepProjectId: pepProjectId })).then(res => {
if (res.success) setAppBI(res.payload.data)
})
await dispatch(control.getAlarmsHandleStatistics({ projectCorrelationId: pepProjectId })).then(res => {
if (res.success) setEfficiencyBI(res.payload.data[0])
})
}
}
concentration2()
}, [pepProjectId, exhibition.current])
useEffect(() => {
async function concentration4 () {
// 统计概览--异常&问题
await dispatch(control.getConsoleAbnormal({ pepProjectId: pepProjectId || projectId })).then(res => {
if (res.success) {
if (res.payload.data?.length > 4) {
setProblemsList([...res.payload.data, ...res.payload.data])
let problemstop = 0
let problemsId = document.getElementById('problems');
if (problems) clearInterval(problems)
if (problemsId) {
function problemstart () {
problems = setInterval(() => {
problemstop += 5
problemsId.scrollTop = problemstop
if (problemsId.scrollTop >= problemsId.scrollHeight / 2) problemstop = 0, problemsId.scrollTop = problemstop
}, 500);
problemsId.onmouseover = () => clearInterval(problems)
}
problemsId.onmouseout = () => problemstart()
setTimeout(problemstart(), 1000);
}
} else {
setProblemsList(res.payload.data)
}
}
})
// 统计概览--相关成员与web应用
await dispatch(control.getConsoleUser({ pepId: pepProjectId || projectId })).then(res => {
if (res.success) {
// if (res.payload.data?.personnel?.length > 5) {
// setMemberList([...res.payload.data?.personnel, ...res.payload.data?.personnel])
// let membertop = 0
// let memberId = document.getElementById('member');
// if (member) clearInterval(member)
// if (memberId) {
// function startmember () {
// member = setInterval(() => {
// membertop += 5
// memberId.scrollTop = membertop
// if (memberId.scrollTop >= memberId.scrollHeight / 2) membertop = 0, memberId.scrollTop = membertop
// }, 500);
// memberId.onmouseover = () => clearInterval(member)
// }
// memberId.onmouseout = () => startmember()
// setTimeout(startmember(), 1000);
// }
// } else {
setMemberList(res.payload.data?.personnel)
// }
// if (res.payload.data?.webApp?.length > 3) {
// setWebList([...res.payload.data?.webApp, ...res.payload.data?.webApp])
// let webtop = 0
// let webId = document.getElementById('web');
// if (web) clearInterval(web)
// if (webId) {
// function webstart () {
// member = setInterval(() => {
// webtop += 5
// webId.scrollTop = webtop
// if (webId.scrollTop >= webId.scrollHeight / 2) webtop = 0, webId.scrollTop = webtop
// }, 500);
// webId.onmouseover = () => clearInterval(web)
// }
// webId.onmouseout = () => webstart()
// setTimeout(webstart(), 1000);
// }
// } else {
setWebList(res.payload.data?.webApp)
// }
}
})
}
if (exhibition.current?.overall?.find(v => v.key == 'statistical')) {
concentration4()
}
}, [projectId, exhibition.current])
useEffect(() => {
//查询最新动态
async function concentration3 () {
if (exhibition?.current?.dynamic?.length > 0) {
let type = []
if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) type.push(1)
if (exhibition?.current?.dynamic?.find(v => v.key == 'confirm')) type.push(4)
if (exhibition?.current?.dynamic?.find(v => v.key == 'notice')) type.push(2)
setQuery({ ...query, page: 0 })
await dispatch(control.getLatestDynamic({ ...query, projectCorrelationId: pepProjectId, page: 0, types: type.join(','), })).then(res => {
if (res.payload.data?.appear?.length || 0 + res.payload.data?.confirm?.length + res.payload.data?.notice?.length < 10) setASk(false)
let data = []
if (res.success) {
if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) {
res.payload.data?.appear?.map(v => data.push({
seed: 'discovery',
project: v.projectName,
sources: v.alarmInfo?.sourceName,
type: v.type,
time: v.time,
id: v.id,
}))
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'confirm')) {
res.payload.data?.confirm?.map(v => data.push({
seed: 'confirm',
project: v.projectName,
sources: v.alarmInfo?.source,
type: v.alarmInfo?.type,
time: v.confirmTime,
userName: v.userName == '自动恢复' ? '' : v.userName,
id: v.id,
}))
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'notice')) {
// EM 推送
res.payload.data?.notice?.map(v => data.push({
seed: 'notice',
time: v.time,
project: v.projectName,
userName: v.userName?.map(u => u.name),
alarmPushConfig: v.alarmPushConfig?.name,
tactics: v.tactics,
interval: v.tacticsParams?.interval,
deviceProportion: v.tacticsParams?.deviceProportion,
id: v.id,
}))
}
data.sort((a, b) => (moment(a.time).isBefore(b.time) ? 1 : -1))
// console.log(data)
querydata.current = data
setQueryData1(data)
}
})
}
}
if (exhibition.current?.overall?.find(v => v.key == 'dynamic')) {
concentration3()
}
const domProject1 = document.getElementById("overviewCalc");
if (domProject1) {
overviewScrollbar = new PerfectScrollbar("#overviewCalc", {
suppressScrollY: true,
});
}
const pomsList = document.getElementById("pomsList");
if (pomsList) {
pomsListScrollbar = new PerfectScrollbar("#pomsList", {
suppressScrollX: true,
});
}
const domProject5 = document.getElementById("problems");
if (domProject5) {
problemsScrollbar = new PerfectScrollbar("#problems", {
suppressScrollX: true,
});
}
}, [pepProjectId, exhibition.current])
useEffect(() => {
const line = document.getElementById("line")
const news = document.getElementById("news")
if (line && news) {
news.onscroll = (e) => {
e.stopPropagation();
if ((line.clientHeight - 578) < news.scrollTop + 10) {
setQuery({ ...query, page: query.page + 1 })
if (exhibition?.current?.dynamic?.length > 0) {
dispatch(control.getLatestDynamic({ ...query, projectCorrelationId: pepProjectId, page: query.page + 1 })).then(res => {
// news.scrollTop = news.scrollTop - 640
let data = querydata.current
if (res.success) {
let returnJudge = true
for (let k in res.payload.data) {
if (res.payload.data[k].length) {
returnJudge = false
break
}
}
if (returnJudge) {
return
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) {
res.payload.data?.appear?.map(v => data.push({
seed: 'discovery',
project: v.projectName,
sources: v.alarmInfo?.sourceName,
type: v.type,
time: v.time,
id: v.id,
}))
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'confirm')) {
res.payload.data?.confirm?.map(v => data.push({
seed: 'confirm',
project: v.projectName,
sources: v.alarmInfo?.source,
type: v.alarmInfo?.type,
time: v.confirmTime,
userName: v.userName,
id: v.id,
}))
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'notice')) {
res.payload.data?.notice?.map(v => data.push({
seed: 'notice',
time: v.time,
project: v.projectName,
userName: v.userName?.map(u => u.name),
alarmPushConfig: v.alarmPushConfig?.name,
tactics: v.tactics,
interval: v.tacticsParams?.interval,
deviceProportion: v.tacticsParams?.deviceProportion,
id: v.id,
}))
}
data.sort((a, b) => (moment(a.time).isBefore(b.time) ? 1 : -1))
querydata.current = data
setQueryData1(data)
}
})
}
}
}
}
}, [query])
useEffect(() => {
const domProject = document.getElementById("news");
if (domProject) {
if (domProject && newScrollbar) {
newScrollbar.update();
}
}
const pomsList = document.getElementById("pomsList");
if (pomsList) {
if (pomsList && pomsListScrollbar) {
pomsListScrollbar.update();
}
}
const domProject2 = document.getElementById("member");
if (domProject2) {
if (domProject2 && memberScrollbar) {
memberScrollbar.update();
}
}
const domProject3 = document.getElementById("equipment");
if (domProject3) {
if (domProject3 && equipmentScrollbar) {
equipmentScrollbar.update();
}
}
const domProject4 = document.getElementById("web");
if (domProject4) {
if (domProject4 && webScrollbar) {
webScrollbar.update();
}
}
const domProject5 = document.getElementById("problems");
if (domProject5) {
if (domProject5 && problemsScrollbar) {
problemsScrollbar.update();
}
}
const domProject6 = document.getElementById("alarm");
if (domProject6) {
if (domProject6 && alarmScrollbar) {
alarmScrollbar.update();
}
}
})
const consoleToollink = () => {
dispatch(control.getConsoleToollink()).then(res => {
if (res.success) {
setToolShow(res.payload.data)
setToolData(res.payload.data?.length)
}
})
}
let Select = {
overall: ['workbench', 'statistical', 'dataAnalyse', 'analyse', 'dynamic', 'tool'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'DeviceAccess', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
dynamic: ['discovery', 'notice', 'handle', 'confirm'],
}
let show = {
overall: ['workbench', 'dataAnalyse'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
dynamic: ['discovery', 'notice', 'confirm'],
}
let listAll = [
{ name: '关注的项目', sort: 1, key: 'project', data: workData?.projects || 0, img: 'url(/assets/images/console/lan_1.png)' },
{ name: '数据告警', sort: 2, key: 'data', data: workData?.dataSurplus || 0, img: 'url(/assets/images/console/lv_1.png)', url: '/problem/dataAlarm/dataLnterrupt' },
{ name: '应用告警', sort: 2, key: 'app', data: workData?.appSurplus || 0, img: 'url(/assets/images/console/hong_1.png)', url: '/problem/useAlarm/useAbnormal' },
{ name: '设备告警', sort: 2, key: 'device', data: workData?.toolSurplus || 0, img: 'url(/assets/images/console/hong_1.png)', url: '/problem/deviceAlarm/deviceAbnormal' },
{ name: '项目里程碑', sort: 1, key: 'milestone', },
{ name: '相关成员', sort: 2, key: 'personnel', },
{ name: '平台设备接入', sort: 3, key: 'DeviceAccess', },
{ name: '关联web应用', sort: 4, key: 'web', },
{ name: '异常&问题', sort: 5, key: 'problem', },
{ name: '数据中断', sort: 1, key: 'dataInterrupt', },
{ name: '数据异常', sort: 2, key: 'dataAbnormal', },
{ name: '策略命中', sort: 3, key: 'policyHit', },
{ name: '视频异常', sort: 4, key: 'videoException', },
{ name: '应用异常', sort: 5, key: 'appAbnormal', },
{ name: '设备异常', sort: 6, key: 'deviceAbnormal', },
{ name: '问题处置效率分析', sort: 7, key: 'problemAnalysis', },
{ name: '发现:系统主动感知到的异常问题动态', sort: 1, key: 'discovery', },
{ name: '通知:系统通过邮件、短信、企业微信等方式通知到运维人员的动态', sort: 2, key: 'notice', },
{ name: '处置:工单信息处理流程的动态', sort: 3, key: 'handle', },
{ name: '确认:完结状态的信息动态', sort: 4, key: 'confirm', },
{ name: '我的工作台', sort: 1, key: 'workbench', },
{ name: '统计概览', sort: 2, key: 'statistical', },
{ name: '数据分析', sort: 3, key: 'dataAnalyse', },
{ name: 'BI分析模块', sort: 4, key: 'analyse', },
{ name: '最新动态', sort: 5, key: 'dynamic', },
{ name: '我常用的工具', sort: 6, key: 'tool', },
]
useEffect(() => {
attribute('workbench')
}, [workData])
const attribute = (title) => {
let take = localStorage.getItem(title)
? JSON.parse(localStorage.getItem(title))
: [];
let data = Select[title].map(v => {
let dataTitle = listAll.find(vv => v == vv.key) || {}
return { name: dataTitle.name, value: dataTitle.key }
})
let TableDisplay = take?.map(v => listAll?.find(vv => v == vv.key))
TableDisplay.sort((a, b) => a.sort - b.sort)
exhibition.current = { ...exhibition.current, [title]: TableDisplay }
setTableSetup([{ list: data }])
}
return (
<>
<div style={{ padding: '0px 40px', width: '100%' }} className='console'>
{/* 头部 */}
<div style={{ margin: '4px 0px 14px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ color: '#4A4A4A', fontSize: 14 }}>
HI欢迎回来
</div>
<div style={{ fontFamily: 'YouSheBiaoTiHei', fontSize: 20, color: '#005ABD', marginLeft: 4 }}>
{user?.name}
</div>
</div>
<div style={{ width: 25, height: 25, cursor: "pointer" }}>
<img src="/assets/images/console/icon_all.png" alt="" style={{ width: '100%', height: '100%' }} onClick={() => {
setSetup(true)
setTableType('overall')
attribute('overall')
setSetData(6)
}} />
</div>
</div>
{/* 主体 */}
<div style={{ display: 'flex', width: '100%' }}>
{/* 左边 */}
<div style={{
width: exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool') ?
'calc(100% - 434px)' : "calc(100%)"
}}>
{/* 工作台和统计概览 */}
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: '20px 24px' }}>
{/* 我的工作台 */}
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>我的工作台</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>MY WORK STATION</div>
</div>
<div style={{ marginRight: 25 }}>
<img title='设置' src="/assets/images/problem/setup.png" style={{ width: 18, height: 18, cursor: "pointer" }} onClick={() => {
setSetup(true)
setTableType('workbench')
attribute('workbench')
setSetData(4)
}} />
</div>
</div>
<div style={{ marginTop: 30, display: 'flex' }}>
<div style={{ marginTop: 20, marginLeft: 36 }}>
<div style={{ display: 'flex', alignItems: 'center', }}>
<div style={{ width: 120, fontSize: 14, color: '#969799' }}>
剩余问题:
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91 }}>
{(workData?.appSurplus + workData?.dataSurplus + workData?.toolSurplus) || 0}
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 26 }}>
<div style={{ width: 120, fontSize: 14, color: '#969799' }}>
今日新增问题:
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91, display: 'flex' }}>
<div>
{(workData?.appNewAdd + workData?.dataNewAdd + workData?.toolNewAdd) || 0}
</div>
<div style={{ display: 'flex', alignItems: 'center', marginLeft: 4 }}>
<img title='设置' src="/assets/images/console/icon_up.png" style={{ width: 18, height: 18 }} />
</div>
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 26 }}>
<div style={{ width: 120, fontSize: 14, color: '#969799' }}>
今日处理:
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91 }}>
{(workData?.appConfirme + workData?.dataConfirme + workData?.toolConfirme) || 0}
</div>
</div>
</div>
{/* 循环类型 */}
<SimpleBar style={{ width: 'calc(100% - 200px)', whiteSpace: 'nowrap', }} forceVisible="x" >
{exhibition.current['workbench']?.map((item, index) => {
return (
pepProjectId && item.name == '关注的项目' ? '' : <div key={item.name} style={{ background: item.img, backgroundSize: "100% 100%", display: "inline-block", width: 270, height: 135, marginRight: 26 }}>
<div style={{ margin: '35px 0px 0px 134px' }}>
<div>
<span style={{ fontSize: 14, color: '#4A4A4A', fontWeight: 500, fontFamily: 'PingFangSC-Medium, PingFang SC' }}>{item.name}</span>
<span style={{ fontSize: 12, color: '#4A4A4A' }}>{item.name == '关注的项目' ? ' ( 个 )' : ' ( 条 )'}</span>
</div>
<div style={{ marginTop: 15, display: 'flex', alignItems: 'center' }}>
<div onClick={() => dispatch(push(item.url))} style={{ fontSize: 32, color: index == 0 ? '#0F7EFB' : index == 1 ? '#0091A1' : index == 2 ? '#FE9812' : '#FF7575', fontFamily: 'YouSheBiaoTiHei', cursor: 'pointer', }}>{item.data}</div>
{item.name == '关注的项目' ? '' : <div style={{ fontSize: 12, color: '#969799', marginLeft: 4 }}>待处理</div>}
</div>
</div>
</div>
)
})
}
</SimpleBar>
</div>
{/* 统计概览 */}
{
exhibition.current?.overall?.find(v => v.key == 'statistical') ? <>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 25 }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>统计概览</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>STATISTICAL OVERVIEW</div>
</div>
<div style={{ marginRight: 25 }}>
<img title='设置' src="/assets/images/problem/setup.png" style={{ width: 18, height: 18, cursor: "pointer" }} onClick={() => {
setSetup(true)
setTableType('statistical')
attribute('statistical')
setSetData(5)
}} />
</div>
</div>
{/* 统计概览 */}
<div id='overviewCalc' style={{ width: 'calc(100%)', position: 'relative' }}>
<div style={{ display: 'inline-flex', marginTop: 16 }}>
{/* 项目 */}
{
pepProjectId ?
'' :
<div id='pomsList' style={{
marginRight: 20, paddingRight: 24, position: 'relative', marginBottom: 30, width: 410, height: 221, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2
}}>
{pomsList?.map((v, index) => {
return <div key={'pomsList' + index} title={v.pepProjectName}
style={{
width: 400, cursor: 'pointer', lineHeight: '30px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', fontSize: 14, color: '#969799',
background: projectId == v.pepProjectId ? 'linear-gradient(252deg, #F9FBFF 0%, rgb(185 202 236) 100%)' : "",
}}
onClick={() => setProjectId(v.pepProjectId)}>{v.pepProjectName}</div>
})}
</div>}
{/* 项目里程碑 */}
{
exhibition.current?.statistical?.find(v => v.key == 'milestone') && projectId &&
projectData?.find(u => u.id == projectId)?.pepProjectName ?
<div style={{
marginBottom: 30, width: 466, height: 221, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2
}}>
<div style={{ margin: '20px 0px 20px 24px', color: '#4A4A4A', fontSize: 16, fontWeight: 'bold' }}>
项目里程碑
</div>
<div style={{ display: 'flex', marginBottom: 20, marginLeft: 24 }}>
<div style={{ display: 'flex' }}>
<div style={{ fontSize: 14, color: '#969799', marginRight: 4 }}>
立项时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A', width: 104 }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ fontSize: 14, color: '#969799', marginRight: 4 }}>
施工时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A' }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
</div>
<div style={{ display: 'flex', marginBottom: 24, marginLeft: 24 }}>
<div style={{ display: 'flex' }}>
<div style={{ fontSize: 14, color: '#969799', marginRight: 4 }}>
内验时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A', width: 104 }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ fontSize: 14, color: '#969799', marginRight: 4 }}>
外验时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A' }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
</div>
<div style={{ display: 'flex', marginBottom: 17, marginLeft: 24 }}>
<div style={{ fontSize: 14, color: '#969799', marginRight: 4 }}>
工程维保时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A' }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
<div style={{ display: 'flex', background: 'linear-gradient(252deg, #F9FBFF 0%, #DBE7FF 100%)', height: 38, justifyContent: 'space-between' }}>
<div style={{ display: 'flex', marginLeft: 24, alignItems: 'center' }}>
<div style={{ fontSize: 14, color: '#646566', marginRight: 4 }}>
售后维修时间
</div>
<div style={{ fontSize: 14, color: '#4A4A4A' }} title='项企项目数据为空或未开发'>
暂无
</div>
</div>
{/* <img src="/assets/images/console/onGoing.png" alt="进行中" /> */}
</div>
</div>
: ""}
{/* 相关成员 */}
{exhibition.current?.statistical?.find(v => v.key == 'personnel') ?
<div style={{ width: 360, height: 221, marginLeft: 20, paddingLeft: 24, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2 }}>
<div style={{ margin: '20px 0px 17px 0px', color: '#4A4A4A', fontSize: 16, fontWeight: 'bold' }}>
相关成员
</div>
<SimpleBar id='member' style={{ height: 160, }} forceVisible="y">
{/* <div id='member' style={{ position: 'relative', height: 161 }}> */}
{memberList?.map((item, index) => {
return (
<div key={index + 'member'} style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 15 }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 18, height: 18 }}>
<img src="/assets/images/console/member.png" alt="成员" style={{ width: '100%', height: '100%' }} />
</div>
<div style={{ marginLeft: 8, fontSize: 14, color: '#4A4A4A' }}>
{item.name}
</div>
<div style={{ fontSize: 12, color: '#969799' }}>
负责人
</div>
</div>
<div style={{ color: '#969799', fontSize: 14, marginRight: 22 }}>
<Tooltip content={item.department?.map((v, index) => index > 0 ? ',' + v : v)}>
<div className='Tooltip' style={{}}>
{item.department[0]}
</div>
</Tooltip>
</div>
</div>
)
})}
{/* </div> */}
</SimpleBar>
</div>
: ""}
{/* 平台设备接入 */}
{exhibition.current?.statistical?.find(v => v.key == 'DeviceAccess') ?
<div style={{ width: 360, height: 221, marginLeft: 20, paddingLeft: 24, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2 }}>
<div style={{ margin: '20px 0px 17px 0px', color: '#4A4A4A', fontSize: 16, fontWeight: 'bold', marginBottom: 16 }}>
平台设备接入
</div>
<div id='equipment' style={{ position: 'relative', height: 161 }}>
{
equipmentList.map((item, index) => {
return (
<div key={index + 'equipment'} style={{ marginBottom: 15, display: 'flex' }}>
<div style={{ color: '#969799', fontSize: 14, width: 167 }}>
5阶ZK1高清摄球机
</div>
<div style={{ color: '#4A4A4A', fontSize: 14, width: 81 }}>
视频
</div>
<div style={{ width: 18, height: 18, marginRight: 8 }}>
<img src="/assets/images/console/icon_online.png" alt="网络" style={{ width: '100%', height: '100%' }} />
{/* <img src="/assets/images/console/icon_offline.png" alt="网络" style={{ width: '100%', height: '100%' }} /> */}
</div>
<div style={{ color: '#0F7EFB', fontSize: 14 }}>
在线
</div>
{/* <div style={{color:'#969799',fontSize:14}}>
掉线
</div> */}
</div>
)
})
}
</div>
</div>
: ""}
{/* 关联web应用 */}
{exhibition.current?.statistical?.find(v => v.key == 'web') ?
<div style={{ width: 360, height: 221, marginLeft: 20, paddingLeft: 24, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2 }}>
<div style={{ margin: '20px 0px 17px 0px', color: '#4A4A4A', fontSize: 16, fontWeight: 'bold', marginBottom: 15 }}>
关联web应用
</div>
<SimpleBar id='member' style={{ height: 160, paddindRight: 20 }} forceVisible="y">
{
webList.map((item, index) => {
return (
<div key={index + 'webb'} style={{ marginBottom: 15, }}>
<div style={{ display: 'flex' }}>
<img style={{ width: 18, height: 18, marginRight: 8 }} src="/assets/images/console/icon_webpage.png" alt="web应用" />
<div style={{ color: '#646566', fontSize: 14, borderBottom: '1px dotted #0F7EFB' }}>
<a href={item.url} target="_blank">
{item.url}
</a>
</div>
</div>
<div style={{ color: '#4A4A4A', fontSize: 14, marginLeft: 26 }}>
{item.name}
</div>
</div>
)
})
}
</SimpleBar>
</div>
: ""}
{/* 异常&问题 */}
{exhibition.current?.statistical?.find(v => v.key == 'problem') ?
<div style={{ width: 399, height: 221, marginLeft: 20, marginRight: 20, paddingLeft: 24, border: '1px solid rgba(220,222,224,0.2)', boxShadow: '0px 2px 12px 1px #F2F3F5', borderRadius: 2 }}>
<div style={{ margin: '20px 0px 17px 0px', color: '#4A4A4A', fontSize: 16, fontWeight: 'bold' }}>
异常&问题
</div>
<div id='problems' style={{ position: 'relative', height: 161 }}>
{
problemsList?.map((v, index) => {
return (
<div style={{ marginBottom: 15, paddingRight: 30, }} key={'problems' + index} onClick={() => {
history.push({
pathname: v.url,
query: {
keywordTarget: v.groupName == '应用异常' ? "" : 'source',
keyword: v.SourceName,
}
})
}}>
<div style={{ fontSize: 14, color: '#646566' }} >
{v.SourceName}{v.groupName}{v.groupName == '视频异常' ? "" : ',诊断为 '} <span style={{ color: '#0F7EFB', borderBottom: '1px dotted #0F7EFB', cursor: "pointer" }} >{v.typeName}请前往确认</span>
</div>
<div style={{ color: '#969799', fontSize: 12, marginRight: 40, marginTop: 4 }}>
{moment(v.StartTime).format("YYYY-MM-DD HH:mm:ss")}
</div>
</div>
)
})
}
</div>
</div>
: ""}
</div>
</div></> : ""}
</div>
{/* 图表 */}
{
exhibition.current?.overall?.find(v => v.key == 'dataAnalyse') &&
<AlarmChart />
}
{/* BI分析模块 */}
{exhibition.current?.overall?.find(v => v.key == 'analyse') ?
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 24, marginTop: 22 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>BI分析模块</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>BI ANAL YSIS MODEL</div>
</div>
<div style={{ marginRight: 25 }}>
<img title='设置' src="/assets/images/problem/setup.png" style={{ width: 18, height: 18, cursor: "pointer" }} onClick={() => {
setSetup(true)
setTableType('analyse')
attribute('analyse')
setSetData(10)
}} />
</div>
</div>
<div style={{ width: '100%', height: '100%' }}>
{exhibition.current?.analyse?.map((v, index) => {
let startValue = ''
if (v.key !== 'problemAnalysis') {
switch (v.key) {
case 'videoException':
let videos = videoBI?.filter(u => moment(moment().day(moment().day() - 30).format('YYYY-MM-DD')).isBefore(u.day)) || []
if (videos.length) {
startValue = videos[0]?.day
} else {
startValue = videoBI?.slice(-1)[0]?.day
}
break;
case 'appAbnormal':
let apps = appBI?.filter(u => moment(moment().day(moment().day() - 30).format('YYYY-MM-DD')).isBefore(u.day)) || []
if (apps.length) {
startValue = apps[0]?.day
} else {
startValue = appBI?.slice(-1)[0]?.day
}
break;
default:
let datas = dataBI[v.key]?.filter(u => moment(moment().day(moment().day() - 30).format('YYYY-MM-DD')).isBefore(u.day)) || []
if (datas.length) {
startValue = datas[0]?.day
} else {
startValue = dataBI[v.key]?.slice(-1)[0]?.day
}
break;
}
}
return v.key == 'problemAnalysis' ? <div id={'ReactECharts' + index} style={{ marginTop: 20, padding: 10, width: '50%', display: "inline-block" }}>
<ReactECharts
option={{
title: {
text: v.name + ' (每周更新) ',
subtext: "上次更新: " + moment(efficiencyBI?.time).format('YYYY-MM-DD HH:mm:ss'),
textStyle: {
fontSize: 18
},
subtextStyle: {
fontSize: 12,
color: '#FE9812'
}
},
grid: {
show: false,
left: '10%',
// right: '4%',
// bottom: '3%',
// containLabel: true
},
xAxis: {
type: 'category',
name: "时间",
boundaryGap: true,
deduplication: null,
data: ['当日处理', '3日内', '7日内', '15日内', '30日内', '超过30日']
},
yAxis: {
min: 0,
max: 100,
type: 'value',
axisLabel: {
show: true,
interval: 0,
formatter: '{value}%'
}
},
series: [
{
data: [efficiencyBI?.day1, efficiencyBI?.day3, efficiencyBI?.day7, efficiencyBI?.day15, efficiencyBI?.day30, efficiencyBI?.day30m],
type: 'bar',
name: v.name,
smooth: true,
barWidth: '30%',
label: {
normal: {
show: true,
position: 'top'
}
},
areaStyle: {
color: '#0F7EFB',
},
emphasis: {
color: '#E8F3FF',
}
// data: []
},
]
}}
notMerge={true}
lazyUpdate={true}
theme={'ReactEChart' + index}
// onChartReady={this.onChartReadyCallback}
// onEvents={EventsDict}
// opts={}
/>
</div>
: <div id={'ReactECharts' + index} style={{ marginTop: 20, padding: 10, width: '50%', display: "inline-block" }}>
<ReactECharts
option={{
title: {
text: v.name,
},
grid: {
left: '10%',
// right: '4%',
// bottom: '3%',
// containLabel: true
},
dataZoom: [
{
type: 'slider',
startValue: startValue
},
{
type: 'inside',
},
],
tooltip: {
trigger: 'axis'
},
legend: {
data: [v.name, '已处理(含自动恢复)'],
right: '10%',
},
xAxis: {
type: 'category',
name: "时间",
boundaryGap: false,
data: v.key == 'videoException' ? videoBI?.map(u => u.day) : v.key == 'appAbnormal' ? appBI?.map(u => u.day) : dataBI[v.key]?.map(u => u.day) || []
},
yAxis: {
type: 'value',
name: "条数",
},
series: [
{
type: 'line',
name: v.name,
smooth: true,
areaStyle: {
color: '#0e9cff26',
},
data: v.key == 'videoException' ? videoBI?.map(u => u.total) : v.key == 'appAbnormal' ? appBI?.map(u => u.total) : dataBI[v.key]?.map(u => u.total) || []
},
{
type: 'line',
name: '已处理(含自动恢复)',
smooth: true,
areaStyle: {
color: '#0e9cff26',
},
data: v.key == 'videoException' ? videoBI?.map(u => u.done) : v.key == 'appAbnormal' ? appBI?.map(u => u.done) : dataBI[v.key]?.map(u => u.done) || []
},
]
}}
notMerge={true}
lazyUpdate={true}
theme={'ReactEChart' + index}
// onChartReady={this.onChartReadyCallback}
// onEvents={EventsDict}
// opts={}
/>
</div>
})}
</div>
</div> : ""}
</div>
{/* 右边 */}
{exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool')
&& <div style={{ width: 415, marginLeft: 20 }}>
{/* 最新动态 */}
{exhibition.current?.overall?.find(v => v.key == 'dynamic')
&& <div style={{ width: 415, background: '#FFFFFF', marginBottom: 20, boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 21, height: 639, }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>最新动态</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>RECENT NEWS</div>
</div>
<div style={{ marginRight: 25 }}>
<img title='设置' src="/assets/images/problem/setup.png" style={{ width: 18, height: 18, cursor: "pointer" }} onClick={() => {
setSetup(true)
setTableType('dynamic')
attribute('dynamic')
setLong('long')
setSetData(4)
}} />
</div>
</div>
<div id='news' style={{ height: 578, position: 'relative', marginTop: 10, overscrollBehavior: 'contain', }}>
<div id='line' style={{ width: '100%', }}>
<Timeline mode="center" style={{ marginLeft: '-56px', width: 400 }}>
{querydata.current?.map((v, index) => {
let title = ''
if (v.seed == 'discovery') {
title = v.project + '【' + v.sources + '】' + ',诊断为' + v.type
} else if (v.seed == 'confirm') {
title = v.userName ? (v.userName + '确认并关闭' + v.project + '【' + v.sources + '】' + v.type + '的问题') :
v.project + '【' + v.sources + '】' + v.type + '已恢复'
} else {
title =
'【信鸽-' + v.alarmPushConfig + '】已邮件通知'
+
v.userName?.map((u, i) => (i > 0 ? ',' + u : u))
+ '【' + v.project
+ '】【'
+
(v.tactics == 'immediately' ?
'发现在' + v.interval + '分钟内,有告警源新增' :
(v.tactics == 'continue' ? '告警源持续产生时间超过' + v.interval + '分钟' : '异常设备数量达到项目或结构物内设备总数量的' +
v.deviceProportion + '%,且持续时长超过' + v.interval + '小时' + '】-【' + v.time + '】'))
}
return (
<Timeline.Item key={index + 'time'} position='left' time={moment(v.time).format("YYYY-MM-DD HH:mm:ss")} className={index % 2 == 0 ? 'even' : 'odd'} >
<Tooltip content={title}>
<div className='Tooltip' style={{
width: 170,
height: '',
display: '-webkit-box',
overflow: 'hidden',
textOverflow: 'ellipsis',
color: '',
background: '',
}}>
{title}
</div>
</Tooltip>
</Timeline.Item>
)
})}
</Timeline>
</div>
</div>
</div>}
{/* 我常用的工具 */}
{exhibition.current?.overall?.find(v => v.key == 'tool') ?
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>我常用的工具</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>MY USUAL TOOLS</div>
</div>
</div>
{toolShow.length > 0 ?
toolShow?.map(v =>
<div
onMouseLeave={() => {
document.getElementById(v.id + 'name').style.display = 'none'
}}
id={v.id + v.name}
style={{ marginTop: 24, position: 'relative', display: "inline-block", cursor: 'pointer' }}>
<a href={v.link} target="_blank">
<Button
theme="solid"
type="primary"
style={{
height: 29, borderRadius: 2, marginRight: 10, marginBottom: 15,
background: '#0F7EFB', color: '#FFFFFF', border: '1px solid #0F7EFB',
}}
onContextMenu={(e) => {
e.preventDefault();
document.getElementById(v.id + 'name').style.display = 'block'
}}
>
{v.name}
</Button>
</a>
<div id={v.id + 'name'}
style={{
position: 'absolute', top: 12, right: -10, background: 'rgb(208 208 223 / 100%)', fontSize: 13,
width: 50, textAlign: "center", borderRadius: 4, padding: '0 10px', display: "none"
}}>
<div style={{ lineHeight: '30px' }}
onClick={() => {
setTool(true)
setAlter(true)
setCompile({ linkId: v.id, name: v.name, link: v.link, })
}}
>编辑</div>
<div style={{ lineHeight: '30px' }}
onClick={() => {
dispatch(control.deleteConsoleToollink(v.id)).then(res => {
if (res.success) consoleToollink()
})
}}
>删除</div>
</div>
</div>) : ""}
<Button
theme="solid"
type="primary"
style={{
width: '100%',
height: 40,
borderRadius: 2,
marginTop: 20,
background: '#F2F3F5',
color: '#0F7EFB',
border: '1px solid #F2F3F5'
}}
onClick={() => {
if (toolData == 0 || toolData < 10) {
setTool(true)
}
}}
>
添加
</Button>
{toolData && toolData >= 10 ? <div style={{ color: 'red', marginTop: 8 }}>最多可添加10个应用</div> : ""}
</div> : ""}
</div>}
</div>
</div>
{/* 页面各个设置弹窗 */}
{
setup ? (
<Setup
tableType={tableType}
tableList={tableSetup}
layout={long}
data={setData}
close={() => {
setSetup(false);
attribute(tableType);
setTableType('')
setLong('')
}}
/>
) : (
""
)
}
{/* 工具添加修改弹窗 */}
{
tool ? <Modal
title={alter ? '编辑' : "添加"}
visible={true}
width={600}
onCancel={() => {
setTool(false)
setAlter(false)
setCompile({})
}}
onOk={() => {
FormApi.current.validate().then((v) => {
console.log(v);
dispatch(control.putConsoleToollink({ linkId: compile?.linkId, name: v.name, link: v.link })).then(res => {
if (res.success) {
setTool(false)
setAlter(false)
setCompile({})
consoleToollink()
}
})
})
}}
>
<div style={{ paddingLeft: 20 }}>
<Form
onSubmit={(values) => console.log(values)}
getFormApi={(formApi) => (FormApi.current = formApi)}
>
<Form.Input
label='工具名称'
labelPosition="left"
rules={[{ required: true, message: "请输入工具名称,1~10个字符,支持中英文,数字及常见符号-_ /." }]}
field='name'
maxLength="10"
initValue={compile?.name || ''}
placeholder='请输入工具名称'
/>
<Form.TextArea maxCount={50} showClear
label='地址链接'
labelPosition="left"
placeholder='请输入URL'
initValue={compile?.link || ''}
rules={[{
required: true, message: "请输入正确地址链接", validator: (rule, value) => {
const strRegex = '^((https|http|ftp)://)?'//(https或http或ftp):// 可有可无
+ '(([\\w_!~*\'()\\.&=+$%-]+: )?[\\w_!~*\'()\\.&=+$%-]+@)?' //ftp的user@ 可有可无
+ '(([0-9]{1,3}\\.){3}[0-9]{1,3}' // IP形式的URL- 3位数字.3位数字.3位数字.3位数字
+ '|' // 允许IP和DOMAIN(域名)
+ '(localhost)|' //匹配localhost
+ '([\\w_!~*\'()-]+\\.)*' // 域名- 至少一个[英文或数字_!~*\'()-]加上.
+ '\\w+\\.' // 一级域名 -英文或数字 加上.
+ '[a-zA-Z]{1,6})' // 顶级域名- 1-6位英文
+ '(:[0-9]{1,5})?' // 端口- :80 ,1-5位数字
+ '((/?)|' // url无参数结尾 - 斜杆或这没有
+ '(/[\\w_!~*\'()\\.;?:@&=+$,%#-]+)+/?)$';//请求参数结尾- 英文或数字和[]内的各种字符
const re = new RegExp(strRegex, 'i'); // 大小写不敏感
if (re.test(encodeURI(value))) {
return true;
}
return false;
}
}]}
field='link'
/>
</Form>
</div>
</Modal> : ""
}
</>
)
}
function mapStateToProps (state) {
const { auth, global, members, webSocket, ProjectPoms } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
pepProjectId: global.pepProjectId,
// members: members.data,
socket: webSocket.socket,
projectPoms: ProjectPoms?.data?.rows
};
}
export default connect(mapStateToProps)(Control);