Files
fe_service_ebtp_frontend/src/pages/MonitorScreen/Home/index.tsx

620 lines
25 KiB
TypeScript
Raw Normal View History

2022-08-09 14:17:24 +08:00
import { Col, Descriptions, Radio, Row, Table } from 'antd';
2022-08-10 14:30:10 +08:00
import React, { useEffect, useRef, useState, useMemo } from 'react';
2022-08-09 14:17:24 +08:00
import './style.less';
2022-08-10 14:30:10 +08:00
import './china'
2022-08-09 14:17:24 +08:00
import * as echarts from 'echarts';
import warn_icon_01 from '@/assets/screen/warn_icon_01.png'
import warn_icon_02 from '@/assets/screen/warn_icon_02.png'
2022-08-10 14:30:10 +08:00
import crown_01 from '@/assets/screen/crown_01.png'
import crown_02 from '@/assets/screen/crown_02.png'
import crown_03 from '@/assets/screen/crown_03.png'
2022-08-09 14:17:24 +08:00
import moment from 'moment';
2022-08-25 14:08:06 +08:00
import { getApplicationData, getMonitorSample, getRoomProjectData, getTodayExpert, getTotalMapData, getWarnData } from './service';
import { debounce } from 'lodash';
import { RightCircleOutlined } from '@ant-design/icons';
import { history } from 'umi';
import ScreenVideoPlay from '@/components/Screen/ScreenVideoPlay';
2022-08-09 14:17:24 +08:00
2022-08-25 14:08:06 +08:00
export const onCell = (_: any, rowIndex: any) => ({ className: rowIndex % 2 == 0 ? "screen-table-odd-content" : "screen-table-even-content", });
export const onHeaderCell = () => ({ className: "screen-table-header", });
export const roomStatusMap = ["已预约", "评标中", "评标结束"];
const method = ["公开比选", "公开询价", "公开招募", "竞争性谈判", "单一来源"]
const zeroProvince = ["香港", "澳门", "台湾", "南海诸岛"];
export const proviceEnum = {
"0011": "北京",
"0012": "天津",
"0013": "河北",
"0014": "山西",
"0015": "内蒙古",
"0021": "辽宁",
"0022": "吉林",
"0023": "黑龙江",
"0031": "上海",
"0032": "江苏",
"0033": "浙江",
"0034": "安徽",
"0035": "福建",
"0036": "江西",
"0037": "山东",
"0041": "河南",
"0042": "湖北",
"0043": "湖南",
"0044": "广东",
"0045": "广西",
"0046": "海南",
"0050": "重庆",
"0051": "四川",
"0052": "贵州",
"0053": "云南",
"0054": "西藏",
"0061": "陕西",
"0062": "甘肃",
"0063": "青海",
"0064": "宁夏",
"0065": "新疆",
"001000": "集团"
}
2022-08-09 14:17:24 +08:00
const evalColumn: any[] = [
{
2022-08-25 14:08:06 +08:00
title: '省分',
dataIndex: 'provinceDictId',
key: 'provinceDictId',
2022-08-09 14:17:24 +08:00
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
2022-08-25 14:08:06 +08:00
render: (_: any, record: any) => proviceEnum[_],
2022-08-09 14:17:24 +08:00
},
{
title: '项目名称',
2022-08-25 14:08:06 +08:00
dataIndex: 'projectName',
key: 'projectName',
2022-08-09 14:17:24 +08:00
ellipsis: true,
onCell,
onHeaderCell,
},
{
2022-08-25 14:08:06 +08:00
title: '专家人数',
dataIndex: 'userNumber',
key: 'userNumber',
2022-08-09 14:17:24 +08:00
align: 'center',
onCell,
onHeaderCell,
},
{
2022-08-25 14:08:06 +08:00
title: '状态',
dataIndex: 'status',
key: 'status',
2022-08-09 14:17:24 +08:00
align: 'center',
onCell,
onHeaderCell,
2022-08-25 14:08:06 +08:00
render: (_: any, record: any) => roomStatusMap[_],
2022-08-09 14:17:24 +08:00
},
];
2022-08-25 14:08:06 +08:00
/**
*
* @returns
*/
export const LocalTime = () => {
const [time, setTime] = useState<string>('');
useEffect(() => {
const interval = setInterval(function () {
const date = moment().format("YYYY-MM-DD HH:mm:ss");
setTime(date);
}, 1000);
return () => {
clearInterval(interval)
};
}, [])
return (
<span>{time}</span>
)
}
2022-08-09 14:17:24 +08:00
2022-08-25 14:08:06 +08:00
const projectClick = () => {
history.push("/MonitorScreen/MonitorRoom");
}
const GraphChart = (props: { type: string, chartData: any[] }) => {
const { type, chartData } = props;
2022-08-09 14:17:24 +08:00
const random = Math.random().toString();
useEffect(() => {
type EChartsOption = echarts.EChartsOption;
const chartDom = document.getElementById(random)!;
const myChart = echarts.init(chartDom);
2022-08-10 14:30:10 +08:00
const categoryOption: EChartsOption = {
2022-08-09 14:17:24 +08:00
legend: { top: '3%', textStyle: { color: '#fff' } },
tooltip: {},
grid: { left: '8%', right: '4%', top: '16%', bottom: 60 },
dataset: {
2022-08-25 14:08:06 +08:00
source: chartData
2022-08-09 14:17:24 +08:00
},
xAxis: { type: 'category', axisLabel: { interval: 0, color: '#fff' } },
yAxis: { axisLabel: { color: '#fff' } },
// Declare several bar series, each will be mapped
// to a column of dataset.source by default.
series: [{ type: 'bar' }, { type: 'bar' }]
};
2022-08-10 14:30:10 +08:00
const pieOption: EChartsOption = {
2022-08-09 14:17:24 +08:00
legend: {
orient: 'vertical',
right: '3%',
top: 'middle',
textStyle: { color: '#fff' }
},
tooltip: {},
dataset: {
2022-08-25 14:08:06 +08:00
source: chartData
2022-08-09 14:17:24 +08:00
},
series: [
{
type: 'pie',
2022-08-25 14:08:06 +08:00
radius: ['40%', '70%'],
center: ['15%', '50%'],
2022-08-09 14:17:24 +08:00
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
2022-08-10 14:30:10 +08:00
fontSize: '20px',
2022-08-09 14:17:24 +08:00
fontWeight: 'bold',
color: '#fff'
}
2022-08-10 14:30:10 +08:00
},
encode: {
itemName: 'product',
2022-08-25 14:08:06 +08:00
value: 'reserve'
2022-08-09 14:17:24 +08:00
}
},
{
type: 'pie',
2022-08-25 14:08:06 +08:00
radius: ['40%', '70%'],
center: ['45%', '50%'],
2022-08-09 14:17:24 +08:00
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
2022-08-10 14:30:10 +08:00
fontSize: '20px',
2022-08-09 14:17:24 +08:00
fontWeight: 'bold',
color: '#fff'
}
},
encode: {
itemName: 'product',
2022-08-25 14:08:06 +08:00
value: 'ing'
2022-08-09 14:17:24 +08:00
}
},
{
type: 'pie',
2022-08-25 14:08:06 +08:00
radius: ['40%', '70%'],
center: ['75%', '50%'],
2022-08-09 14:17:24 +08:00
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '20px',
fontWeight: 'bold',
color: '#fff'
}
},
encode: {
itemName: 'product',
2022-08-25 14:08:06 +08:00
value: 'end'
2022-08-09 14:17:24 +08:00
}
}
]
};
2022-08-10 14:30:10 +08:00
const mapOption: EChartsOption = {
tooltip: {
trigger: 'item',
showDelay: 0,
transitionDuration: 0.2,
2022-08-25 14:08:06 +08:00
padding: [8, 12],
2022-08-10 14:30:10 +08:00
formatter: (params: any) => {
return `<div style="display:flex;justify-content:flex-start;align-items:center;font-weight:600">
2022-08-25 14:08:06 +08:00
<div style="width:8px;height:8px;border-radius:8px;background:#FFCC00;margin-right:8px"></div>${params.data?.name}
2022-08-10 14:30:10 +08:00
</div>
<div style="margin-top:8px;margin-left:16px;">
2022-08-25 14:08:06 +08:00
${params.data?.placeNumber}
2022-08-10 14:30:10 +08:00
</div>
<div style="margin-top:8px;margin-left:16px;">
2022-08-25 14:08:06 +08:00
${params.data?.openingNumber}
2022-08-10 14:30:10 +08:00
</div>
<div style="margin-top:8px;margin-left:16px;">
2022-08-25 14:08:06 +08:00
${params.data?.expertNumber}
2022-08-10 14:30:10 +08:00
</div>
<div style="margin-top:8px;margin-left:16px;">
2022-08-25 14:08:06 +08:00
${params.data?.cumulativePlaceNumber}
2022-08-10 14:30:10 +08:00
</div>`
}
},
visualMap: {
show: false,
min: 0,
max: 1000,
inRange: {
color: [
'#ECF3F4',
'#E3F4FF',
'#D1ECFD',
'#A0D6F8',
'#5DCAF2',
'#09A6F7',
'#0081C4',
'#26519E',
'#052D74',
'#001F53',
]
},
},
series: [
{
name: '累计评标次数',
type: 'map',
roam: false,
2022-08-25 14:08:06 +08:00
zoom: 1.2,
left: "20%",
2022-08-10 14:30:10 +08:00
map: 'china',
emphasis: {
label: {
show: false,
},
itemStyle: {
areaColor: '#FFCC00'
}
},
select: {
disabled: true,
},
2022-08-25 14:08:06 +08:00
data: chartData,
2022-08-10 14:30:10 +08:00
}
]
};
2022-08-09 14:17:24 +08:00
2022-08-10 14:30:10 +08:00
const option: EChartsOption = type == "pie" ? pieOption : type == "map" ? mapOption : categoryOption;
2022-08-09 14:17:24 +08:00
myChart.setOption(option);
2022-08-25 14:08:06 +08:00
const resize = () => {
myChart && myChart.resize();
};
window.addEventListener("resize", debounce(() => resize(), 100));
return () => {
window.removeEventListener("resize", debounce(() => resize(), 100));
}
}, [chartData])
2022-08-09 14:17:24 +08:00
return (
2022-08-10 14:30:10 +08:00
<div id={random} style={{ width: '100%', height: '100%', zIndex: 99 }}></div>
)
}
//异常预警
2022-08-25 14:08:06 +08:00
export const EarlyWarn = ({ img, name, num }: { img: string, name: string, num: string | number }) => {
2022-08-10 14:30:10 +08:00
return (
<div className='screen-warn-content'>
<img src={img} className='screen-warn-img' />
<div className='screen-warn-content'>
<div className='screen-warn-num'>{num}</div>
<div>{name}</div>
</div>
</div>
2022-08-09 14:17:24 +08:00
)
}
export default () => {
2022-08-25 14:08:06 +08:00
//中心地图及周边数据
const [centerMapData, setCenterMapData] = useState<any>();
//异常预警数据
const [earlyWarnData, setEarlyWarnData] = useState<any>();
//评标室项目数据
const [bidProjectData, setBidProjectData] = useState<any[]>([]);
//今日评标专家数量数据
const [todayExpertNum, setTodayExpertNum] = useState<any[]>([]);
//评标室应用情况数据
const [evalApplData, setEvalApplData] = useState<any[]>([]);
//当前播放的设备参数
const [cameraParams, setCameraParams] = useState<any>();
//当月&年转换
const [radioSelect, setRadioSelect] = useState<string>("1");
//评标室监控示例数据
const [sampleData, setSampleData] = useState<any>();
//监控视频Ref
const videoRef = useRef<any>();
//定时刷新间隔
const _time = 10000;
2022-08-10 14:30:10 +08:00
const categoryChart = useMemo(() => {
2022-08-25 14:08:06 +08:00
return todayExpertNum.length > 0 && <GraphChart type="category" chartData={todayExpertNum} />
}, [todayExpertNum])
2022-08-10 14:30:10 +08:00
const pieChart = useMemo(() => {
2022-08-25 14:08:06 +08:00
return evalApplData.length > 0 && <GraphChart type="pie" chartData={evalApplData} />
}, [evalApplData])
2022-08-10 14:30:10 +08:00
const mapChart = useMemo(() => {
2022-08-25 14:08:06 +08:00
return centerMapData?.list && <GraphChart type="map" chartData={centerMapData?.list} />
}, [centerMapData])
//星期&年切换
const onRadioChange = (e: any) => {
const type = e.target.value;
setRadioSelect(type);
getEvalApplData(type);
}
//获取中间地图数据
const getMapList = () => {
getTotalMapData({ pageNo: 1, pageSize: 10 }).then(res => {
if (res?.code == 200) {
const data = res?.data;
for (const ite of data.list) {
ite["name"] = ite.provinceDictName;
ite["value"] = ite.placeNumber;
}
for (const name of zeroProvince) {//有些省市字典没有默认放0
data.list.push({ name: name, value: 0, cumulativePlaceNumber: 0, expertNumber: 0, openingNumber: 0, placeNumber: 0 });
}
setCenterMapData(data);
}
})
}
//获取异常预警数据
const getWarnInfo = () => {
getWarnData().then(res => {
if (res?.code == 200) {
const data = res?.data;
setEarlyWarnData(data);
}
})
}
//获取评标室项目情况
const getEvaRoomData = () => {
getRoomProjectData({ pageNo: 1, pageSize: 20 }).then(res => {
if (res?.code == 200) {
const data = res?.data;
setBidProjectData(data);
}
})
}
//获取今日评标专家数量
const getExpertNumber = () => {
getTodayExpert().then(res => {
if (res?.code == 200) {
const data = res?.data;
let formatData = [['product', '专家人数', '专家签到数量'], ['招标项目', data[0].number + data[1].number, data[0].signNumber + data[1].signNumber]];
for (const ite of data) {
if (method.includes(ite.bidMethod)) {
formatData.push([ite.bidMethod, ite.number, ite.signNumber]);
}
}
setTodayExpertNum(formatData);
}
})
}
//获取评标室应用情况
const getEvalApplData = (type: string) => {
getApplicationData({ type }).then(res => {
if (res?.code == 200) {
const data = res?.data;
let formatData = [['product', 'reserve', 'ing', 'end'], ['招标项目', String(Number(data.reserveNumber[0].number) + Number(data.reserveNumber[1].number)), String(Number(data.ingNumber[0].number) + Number(data.ingNumber[1].number)), String(Number(data.endNumber[0].number) + Number(data.endNumber[1].number))]];
let comp = ['公开比选'];
let inqu = ['公开询价'];
let rect = ['公开招募'];
let nego = ['竞争性谈判'];
let only = ['单一来源'];
for (const ite of data.reserveNumber) {
if (ite.bidMethod == method[0]) {
comp.push(ite.number)
} else if (ite.bidMethod == method[1]) {
inqu.push(ite.number)
} else if (ite.bidMethod == method[2]) {
rect.push(ite.number)
} else if (ite.bidMethod == method[3]) {
nego.push(ite.number)
} else if (ite.bidMethod == method[4]) {
only.push(ite.number)
}
}
for (const ite of data.ingNumber) {
if (ite.bidMethod == method[0]) {
comp.push(ite.number)
} else if (ite.bidMethod == method[1]) {
inqu.push(ite.number)
} else if (ite.bidMethod == method[2]) {
rect.push(ite.number)
} else if (ite.bidMethod == method[3]) {
nego.push(ite.number)
} else if (ite.bidMethod == method[4]) {
only.push(ite.number)
}
}
for (const ite of data.endNumber) {
if (ite.bidMethod == method[0]) {
comp.push(ite.number)
} else if (ite.bidMethod == method[1]) {
inqu.push(ite.number)
} else if (ite.bidMethod == method[2]) {
rect.push(ite.number)
} else if (ite.bidMethod == method[3]) {
nego.push(ite.number)
} else if (ite.bidMethod == method[4]) {
only.push(ite.number)
}
}
formatData.push(comp);
formatData.push(inqu);
formatData.push(rect);
formatData.push(nego);
formatData.push(only);
setEvalApplData(formatData);
}
})
}
//获取首页评标室监控示例
const getSampleData = () => {
getMonitorSample().then(res => {
if (res?.code == 200) {
const data = res?.data;
if (data) {
setSampleData(data);
setCameraParams(data?.devicePageVOList[0].platform);
setTimeout(() => {
videoRef.current?.play(data?.devicePageVOList[0].deviceCode);
}, 4000);
}
}
})
}
useEffect(() => {
getMapList();
getWarnInfo();
getEvaRoomData();
getExpertNumber();
getEvalApplData("1");
getSampleData();
2022-08-10 14:30:10 +08:00
}, [])
2022-08-25 14:08:06 +08:00
//定时器
2022-08-09 14:17:24 +08:00
useEffect(() => {
const interval = setInterval(function () {
2022-08-25 14:08:06 +08:00
getWarnInfo();
getEvaRoomData();
}, _time);
2022-08-09 14:17:24 +08:00
return () => {
clearInterval(interval)
};
}, [])
2022-08-10 14:30:10 +08:00
2022-08-09 14:17:24 +08:00
return (
<div className="screen-bg">
<div className='top-block'>
</div>
<div className='top'>
<Row>
<Col span={6}>
<div className='top-left'>
</div>
</Col>
<Col span={12}>
<div className='top-title'>
<span></span>
</div>
</Col>
<Col span={6}>
<div className='top-right'>
2022-08-25 14:08:06 +08:00
<LocalTime />
2022-08-09 14:17:24 +08:00
</div>
</Col>
</Row>
</div>
<Row className="screen-content">
<Col span={18}>
<Row>
<Col span={8} className='screen-right4'>
<div className='screen-card'>
<div className='card-title'>
<span></span>
</div>
2022-08-10 14:30:10 +08:00
{categoryChart}
2022-08-09 14:17:24 +08:00
</div>
<div className='screen-card screen-top8'>
<div className='card-title'>
<span></span>
</div>
2022-08-25 14:08:06 +08:00
{
sampleData && <>
<div className='card-project-content'>
<p>{sampleData?.projectName}</p>
<p>{sampleData?.sectionName}</p>
<p>{sampleData?.devicePageVOList[0].deviceName}</p>
<p><span>{sampleData?.areaName}</span><span></span></p>
</div>
<div className='card-carema-c'>
{cameraParams && <ScreenVideoPlay videoRef={videoRef} cameraParams={cameraParams} status={0} />}
</div>
</>
}
2022-08-09 14:17:24 +08:00
</div>
</Col>
<Col span={16} className='screen-left4 screen-right4'>
<div className='middle-c'>
<div className='map-bg'>
2022-08-10 14:30:10 +08:00
{mapChart}
<div className='map-total-num'>
2022-08-25 14:08:06 +08:00
<span>{centerMapData?.number}</span>
2022-08-10 14:30:10 +08:00
</div>
<div className='map-grand'>
<div className='map-grand-title'></div>
<div>
<img src={crown_01} className='map-grand-img' />
2022-08-25 14:08:06 +08:00
<span>{centerMapData?.list?.[0].name}{centerMapData?.list?.[0].cumulativePlaceNumber}</span>
2022-08-10 14:30:10 +08:00
</div>
<div className='map-grand-content'>
<img src={crown_02} className='map-grand-img' />
2022-08-25 14:08:06 +08:00
<span>{centerMapData?.list?.[1].name}{centerMapData?.list?.[1].cumulativePlaceNumber}</span>
2022-08-10 14:30:10 +08:00
</div>
<div className='map-grand-content'>
<img src={crown_03} className='map-grand-img' />
2022-08-25 14:08:06 +08:00
<span>{centerMapData?.list?.[2].name}{centerMapData?.list?.[2].cumulativePlaceNumber}</span>
2022-08-10 14:30:10 +08:00
</div>
</div>
2022-08-09 14:17:24 +08:00
</div>
</div>
</Col>
<Col span={24} className='screen-top8 screen-right4'>
<div className='screen-card'>
<div className='screen-graph-top'>
2022-08-25 14:08:06 +08:00
<div className='screen-graph-left-title'>
</div>
{evalApplData.length > 0 && <Radio.Group buttonStyle="solid" size='small' value={radioSelect} onChange={onRadioChange}>
<Radio.Button value="1"></Radio.Button>
<Radio.Button value="2"> </Radio.Button>
</Radio.Group>}
2022-08-09 14:17:24 +08:00
</div>
<div className='screen-graph-chart'>
2022-08-10 14:30:10 +08:00
{pieChart}
2022-08-09 14:17:24 +08:00
</div>
2022-08-25 14:08:06 +08:00
<div className='screen-graph-bottom'>
<span className='screen-graph-title'></span>
<span className='screen-graph-title'></span>
<span className='screen-graph-title'></span>
2022-08-09 14:17:24 +08:00
</div>
2022-08-25 14:08:06 +08:00
{/* <div className='screen-graph-end'>
<span>&gt;&gt;</span>
</div> */}
2022-08-09 14:17:24 +08:00
</div>
</Col>
</Row>
</Col>
<Col span={6} className='screen-left4'>
<div className='screen-card'>
<div className='card-title'>
<span></span>
</div>
<div className='screen-warn'>
2022-08-25 14:08:06 +08:00
<EarlyWarn name="陌生人预警" img={warn_icon_01} num={earlyWarnData?.strangerCount ? earlyWarnData?.strangerCount : 0} />
<EarlyWarn name="评标室人数预警" img={warn_icon_02} num={earlyWarnData?.numberCount ? earlyWarnData?.numberCount : 0} />
2022-08-09 14:17:24 +08:00
</div>
</div>
2022-08-25 14:08:06 +08:00
<div className='screen-card screen-card-double screen-top8'>
2022-08-09 14:17:24 +08:00
<div className='card-title'>
2022-08-25 14:08:06 +08:00
<span><RightCircleOutlined style={{ marginLeft: "0.5rem", cursor: 'pointer' }} onClick={() => projectClick()} /></span>
2022-08-09 14:17:24 +08:00
</div>
2022-08-25 14:08:06 +08:00
{bidProjectData.length > 0 && <Table
2022-08-09 14:17:24 +08:00
pagination={false}
className="screen-table"
rowKey="id"
size="small"
2022-08-25 14:08:06 +08:00
dataSource={bidProjectData}
2022-08-09 14:17:24 +08:00
columns={evalColumn}
2022-08-25 14:08:06 +08:00
/>}
2022-08-09 14:17:24 +08:00
</div>
</Col>
</Row>
</div>
);
};;