This commit is contained in:
jl-zhoujl2
2022-08-25 14:08:06 +08:00
parent 5cc64e921d
commit 2a69d4531d
25 changed files with 2198 additions and 297 deletions

View File

@ -55,6 +55,16 @@ export default [
path: '/MonitorScreen/Home',
component: './MonitorScreen/Home',
},
{
name: 'MonitorRoom',
path: '/MonitorScreen/MonitorRoom',
component: './MonitorScreen/MonitorRoom',
},
{
name: 'ProjectMonitorRoom',
path: '/MonitorScreen/ProjectMonitorRoom',
component: './MonitorScreen/ProjectMonitorRoom',
},
],
},

File diff suppressed because one or more lines are too long

1
public/screen/jsencrypt.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,261 @@
import React, { useEffect, useImperativeHandle, useRef } from 'react';
import { debounce } from 'lodash';
interface ScreenVideoPlayProps {
videoRef: React.MutableRefObject<any | undefined>,
cameraParams: any,
status: number,//0-预览 1-回放
}
/**
* 视频监控组件(海康插件)
* @param props
* @returns
*/
const ScreenVideoPlay: React.FC<ScreenVideoPlayProps> = (props) => {
const { videoRef, cameraParams, status } = props;
const playWnd = useRef<any>(null);
let oWebControl: any = null;
let initCount = 0;
let pubKey = '';
useEffect(() => {
if (oWebControl != null) {
oWebControl.JS_RequestInterface({
funcName: "stopAllPreview"
});
}
initPlugin();
}, [cameraParams?.appSecret])
// 创建播放实例
function initPlugin() {
oWebControl = new WebControl({
szPluginContainer: "playWnd", // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15909,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: function () { // 创建WebControl实例成功
oWebControl.JS_StartService("window", { // WebControl实例创建成功后需要启动服务
dllPath: "./VideoPluginConnect.dll" // 值"./VideoPluginConnect.dll"写死
}).then(function () { // 启动插件服务成功
// oWebControl.JS_SetWindowControlCallback({ // 设置消息回调
// cbIntegrationCallBack: cbIntegrationCallBack
// });
oWebControl.JS_CreateWnd("playWnd", playWnd.current.clientWidth, playWnd.current.clientHeight).then(function () { //JS_CreateWnd创建视频播放窗口宽高可设定
init(); // 创建播放实例成功后初始化
});
}, function () { // 启动插件服务失败
});
},
cbConnectError: function () { // 创建WebControl实例失败
oWebControl = null;
// $("#playWnd").html("插件未启动,正在尝试启动,请稍候...");
WebControl.JS_WakeUp("VideoWebPlugin://"); // 程序未启动时执行error函数采用wakeup来启动程序
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000)
} else {
// $("#playWnd").html("插件启动失败,请检查插件是否安装!");
}
},
cbConnectClose: function (bNormalClose: any) {
// 异常断开bNormalClose = false
// JS_Disconnect正常断开bNormalClose = true
oWebControl = null;
}
});
return oWebControl;
}
//初始化
function init() {
getPubKey(function () {
////////////////////////////////// 请自行修改以下变量值 ////////////////////////////////////
var appkey = cameraParams.appKey; //综合安防管理平台提供的appkey必填
var secret = setEncrypt(cameraParams.appSecret); //综合安防管理平台提供的secret必填
var ip = cameraParams.platformManagementIp; //综合安防管理平台IP地址必填
var playMode = status; //初始播放模式0-预览1-回放
var port = Number(cameraParams.platformManagementPort); //综合安防管理平台端口若启用HTTPS协议默认443
var snapDir = "D:\\SnapDir"; //抓图存储路径
var videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径
var layout = "1x1"; //playMode指定模式的布局
var enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互这里总是填1
var encryptedFields = 'secret'; //加密字段默认加密领域为secret
var showToolbar = status; //是否显示工具栏0-不显示非0-显示
var showSmart = 1; //是否显示智能信息如配置移动侦测后画面上的线框0-不显示非0-显示
// var buttonIDs = "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮
var buttonIDs = ""; //自定义工具条按钮
////////////////////////////////// 请自行修改以上变量值 ////////////////////////////////////
oWebControl.JS_RequestInterface({
funcName: "init",
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
// snapDir: snapDir, //抓图存储路径
// videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs: buttonIDs //自定义工具条按钮
})
}).then(function (oData: any) {
oWebControl.JS_Resize(playWnd.current.clientWidth, playWnd.current.clientHeight); // 初始化后resize一次规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
});
});
}
//获取公钥
function getPubKey(callback: any) {
oWebControl.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024
})
}).then(function (oData: any) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback()
}
})
}
//RSA加密
function setEncrypt(value: any) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
// 设置窗口裁剪当因滚动条滚动导致窗口需要被遮住的情况下需要JS_CuttingPartWindow部分窗口
function setWndCover() {
var iWidth = window.innerWidth;
var iHeight = window.innerHeight;
var oDivRect = playWnd.current.getBoundingClientRect();
var iCoverLeft = (oDivRect.left < 0) ? Math.abs(oDivRect.left) : 0;
var iCoverTop = (oDivRect.top < 0) ? Math.abs(oDivRect.top) : 0;
var iCoverRight = (oDivRect.right - iWidth > 0) ? Math.round(oDivRect.right - iWidth) : 0;
var iCoverBottom = (oDivRect.bottom - iHeight > 0) ? Math.round(oDivRect.bottom - iHeight) : 0;
iCoverLeft = (iCoverLeft > playWnd.current.clientWidth) ? playWnd.current.clientWidth : iCoverLeft;
iCoverTop = (iCoverTop > playWnd.current.clientHeight) ? playWnd.current.clientHeight : iCoverTop;
iCoverRight = (iCoverRight > playWnd.current.clientWidth) ? playWnd.current.clientWidth : iCoverRight;
iCoverBottom = (iCoverBottom > playWnd.current.clientHeight) ? playWnd.current.clientHeight : iCoverBottom;
oWebControl.JS_RepairPartWindow(0, 0, playWnd.current.clientWidth + 1, playWnd.current.clientHeight); // 多1个像素点防止还原后边界缺失一个像素条
if (iCoverLeft != 0) {
oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, playWnd.current.clientHeight);
}
if (iCoverTop != 0) {
oWebControl.JS_CuttingPartWindow(0, 0, playWnd.current.clientWidth + 1, iCoverTop); // 多剪掉一个像素条,防止出现剪掉一部分窗口后出现一个像素条
}
if (iCoverRight != 0) {
oWebControl.JS_CuttingPartWindow(playWnd.current.clientWidth - iCoverRight, 0, iCoverRight, playWnd.current.clientHeight);
}
if (iCoverBottom != 0) {
oWebControl.JS_CuttingPartWindow(0, playWnd.current.clientHeight - iCoverBottom, playWnd.current.clientWidth, iCoverBottom);
}
}
//视频预览功能
function startPreview(caremaCode: any) {
var cameraIndexCode = caremaCode; //获取输入的监控点编号值,必填
var streamMode = 0; //主子码流标识0-主码流1-子码流
var transMode = 1; //传输协议0-UDP1-TCP
var gpuMode = 0; //是否启用GPU硬解0-不启用1-启用
var wndId = -1; //播放窗口序号在2x2以上布局下可指定播放窗口
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, "");
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, "");
if (oWebControl != null) {
oWebControl?.JS_RequestInterface({
funcName: "startPreview",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId: wndId //可指定播放窗口
})
})
}
};
//视频回放
function videoPlayback(caremaCode: any, startTime: any, endTime: any) {
var cameraIndexCode = caremaCode; //获取输入的监控点编号值,必填
var startTimeStamp = new Date(startTime?.replace('-', '/').replace('-', '/')).getTime(); //回放开始时间戳,必填
var endTimeStamp = new Date(endTime?.replace('-', '/').replace('-', '/')).getTime(); //回放结束时间戳,必填
var recordLocation = 0; //录像存储位置0-中心存储1-设备存储
var transMode = 1; //传输协议0-UDP1-TCP
var gpuMode = 0; //是否启用GPU硬解0-不启用1-启用
var wndId = -1; //播放窗口序号在2x2以上布局下可指定播放窗口
oWebControl.JS_RequestInterface({
funcName: "startPlayback",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
startTimeStamp: Math.floor(startTimeStamp / 1000).toString(), //录像查询开始时间戳,单位:秒
endTimeStamp: Math.floor(endTimeStamp / 1000).toString(), //录像结束开始时间戳,单位:秒
recordLocation: recordLocation, //录像存储类型0-中心存储1-设备存储
transMode: transMode, //传输协议0-UDP1-TCP
gpuMode: gpuMode, //是否启用GPU硬解0-不启用1-启用
wndId: wndId //可指定播放窗口
})
})
};
useEffect(() => {
// 监听resize事件使插件窗口尺寸跟随DIV窗口变化
// 监听滚动条scroll事件使插件窗口跟随浏览器滚动而移动
const resize = () => {
if (oWebControl != null) {
oWebControl.JS_Resize(playWnd.current.clientWidth, playWnd.current.clientHeight);
setWndCover();
}
};
window.addEventListener("resize", debounce(() => resize(), 100));
window.addEventListener("scroll", debounce(() => resize(), 100));
return () => {
window.removeEventListener("resize", debounce(() => resize(), 100));
window.removeEventListener("scroll", debounce(() => resize(), 100));
if (oWebControl != null) {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_Disconnect().then(function () { // 断开与插件服务连接成功
},
function () { // 断开与插件服务连接失败
});
}
}
}, [])
//选择暴露给父组件的参数或方法
useImperativeHandle(
videoRef,
() => ({
play(caremaCode: any) {
startPreview(caremaCode);
},
back(caremaCode: any, startTime: any, endTime: any) {
videoPlayback(caremaCode, startTime, endTime);
}
}),
[],
);
return <div id="playWnd" ref={playWnd} style={{ height: "100%", width: "100%" }}></div>;
};
export default ScreenVideoPlay;

View File

@ -9,146 +9,115 @@ 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'
import moment from 'moment';
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';
const onCell = (_: any, rowIndex: any) => ({ className: rowIndex % 2 == 0 ? "screen-table-odd-content" : "screen-table-even-content", });
const onHeaderCell = () => ({ className: "screen-table-header", });
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": "集团"
}
const evalColumn: any[] = [
{
title: '省分',
dataIndex: 'provinceDictId',
key: 'provinceDictId',
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
render: (_: any, record: any) => proviceEnum[_],
},
{
title: '项目名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
onCell,
onHeaderCell,
},
{
title: '时间',
dataIndex: 'time',
key: 'time',
align: 'center',
onCell,
onHeaderCell,
},
{
title: '所属单位',
dataIndex: 'unit',
key: 'unit',
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
},
{
title: '评标地点',
dataIndex: 'place',
key: 'place',
align: 'center',
dataIndex: 'projectName',
key: 'projectName',
ellipsis: true,
onCell,
onHeaderCell,
},
{
title: '专家人数',
dataIndex: 'number',
key: 'number',
dataIndex: 'userNumber',
key: 'userNumber',
align: 'center',
onCell,
onHeaderCell,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
onCell,
onHeaderCell,
render: (_: any, record: any) => roomStatusMap[_],
},
];
const todayEvalColumn: any[] = [
{
title: '项目名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
width: '20%',
onCell,
onHeaderCell,
},
{
title: '中标供应商名称',
dataIndex: 'supplierName',
key: 'supplierName',
ellipsis: true,
align: 'center',
onCell,
onHeaderCell,
},
{
title: '拟签约金额',
dataIndex: 'money',
key: 'money',
align: 'center',
ellipsis: true,
width: '25%',
onCell,
onHeaderCell,
},
];
/**
* 当前时间
* @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>
)
}
const dataSource = [
{
id: '1',
name: '中国联通集团股份有限公司',
time: "11:00",
unit: '北京',
place: '评标地点',
number: '5',
supplierName: '通信工程局有限责任公司',
money: '100000',
},
{
id: '2',
name: '中国联通集团股份有限公司',
time: "11:00",
unit: '北京',
place: '评标地点',
number: '7',
supplierName: '通信工程局有限责任公司',
money: '100000',
},
{
id: '3',
name: '中国联通集团股份有限公司',
time: "11:00",
unit: '北京',
place: '评标地点',
number: '7',
supplierName: '通信工程局有限责任公司',
money: '100000',
},
{
id: '4',
name: '中国联通集团股份有限公司',
time: "11:00",
unit: '北京',
place: '评标地点',
number: '7',
supplierName: '通信工程局有限责任公司',
money: '100000',
},
{
id: '5',
name: '中国联通集团股份有限公司',
time: "11:00",
unit: '北京',
place: '评标地点',
number: '7',
supplierName: '通信工程局有限责任公司',
money: '100000',
},
];
const GraphChart = (props: { type: string }) => {
const { type } = props;
const projectClick = () => {
history.push("/MonitorScreen/MonitorRoom");
}
const GraphChart = (props: { type: string, chartData: any[] }) => {
const { type, chartData } = props;
const random = Math.random().toString();
/**
* 地图数据
*/
const randomData = () => {
return Math.round(Math.random() * 1000);
}
useEffect(() => {
type EChartsOption = echarts.EChartsOption;
const chartDom = document.getElementById(random)!;
@ -158,15 +127,7 @@ const GraphChart = (props: { type: string }) => {
tooltip: {},
grid: { left: '8%', right: '4%', top: '16%', bottom: 60 },
dataset: {
dimensions: ['product', '专家人数', '专家签到数量'],
source: [
{ product: '招标项目', '专家人数': 43.3, '专家签到数量': 85.8, },
{ product: '公开比选', '专家人数': 83.1, '专家签到数量': 73.4, },
{ product: '公开询价', '专家人数': 86.4, '专家签到数量': 65.2, },
{ product: '公开招募', '专家人数': 72.4, '专家签到数量': 53.9, },
{ product: '竞争性谈判', '专家人数': 72.4, '专家签到数量': 53.9, },
{ product: '单一来源', '专家人数': 72.4, '专家签到数量': 53.9, },
]
source: chartData
},
xAxis: { type: 'category', axisLabel: { interval: 0, color: '#fff' } },
yAxis: { axisLabel: { color: '#fff' } },
@ -183,21 +144,13 @@ const GraphChart = (props: { type: string }) => {
},
tooltip: {},
dataset: {
source: [
['product', 'today', 'tomorrow', 'total'],
['招标项目', 86.5, 92.1, 85.7],
['公开比选', 41.1, 30.4, 65.1],
['公开询价', 24.1, 67.2, 79.5],
['公开招募', 55.2, 67.1, 69.2],
['竞争性谈判', 86.4, 65.2, 82.5],
['单一来源', 72.4, 53.9, 39.1],
]
source: chartData
},
series: [
{
type: 'pie',
radius: ['44%', '77%'],
center: ['15%', '45%'],
radius: ['40%', '70%'],
center: ['15%', '50%'],
label: {
show: false,
position: 'center'
@ -212,13 +165,13 @@ const GraphChart = (props: { type: string }) => {
},
encode: {
itemName: 'product',
value: 'today'
value: 'reserve'
}
},
{
type: 'pie',
radius: ['44%', '77%'],
center: ['45%', '45%'],
radius: ['40%', '70%'],
center: ['45%', '50%'],
label: {
show: false,
position: 'center'
@ -233,13 +186,13 @@ const GraphChart = (props: { type: string }) => {
},
encode: {
itemName: 'product',
value: 'tomorrow'
value: 'ing'
}
},
{
type: 'pie',
radius: ['44%', '77%'],
center: ['75%', '45%'],
radius: ['40%', '70%'],
center: ['75%', '50%'],
label: {
show: false,
position: 'center'
@ -254,7 +207,7 @@ const GraphChart = (props: { type: string }) => {
},
encode: {
itemName: 'product',
value: 'total'
value: 'end'
}
}
]
@ -264,22 +217,22 @@ const GraphChart = (props: { type: string }) => {
trigger: 'item',
showDelay: 0,
transitionDuration: 0.2,
padding: [5, 10],
padding: [8, 12],
formatter: (params: any) => {
return `<div style="display:flex;justify-content:flex-start;align-items:center;font-weight:600">
<div style="width:8px;height:8px;border-radius:8px;background:#FFCC00;margin-right:8px"></div>${params.data.name}
<div style="width:8px;height:8px;border-radius:8px;background:#FFCC00;margin-right:8px"></div>${params.data?.name}
</div>
<div style="margin-top:8px;margin-left:16px;">
评标室间数:${params.data.value}
评标室间数:${params.data?.placeNumber}
</div>
<div style="margin-top:8px;margin-left:16px;">
正在评标:${params.data.value}
正在评标:${params.data?.openingNumber}
</div>
<div style="margin-top:8px;margin-left:16px;">
评标专家:${params.data.value}
评标专家:${params.data?.expertNumber}
</div>
<div style="margin-top:8px;margin-left:16px;">
累计评标次数:${params.data.value}
累计评标次数:${params.data?.cumulativePlaceNumber}
</div>`
}
},
@ -307,6 +260,8 @@ const GraphChart = (props: { type: string }) => {
name: '累计评标次数',
type: 'map',
roam: false,
zoom: 1.2,
left: "20%",
map: 'china',
emphasis: {
label: {
@ -319,57 +274,28 @@ const GraphChart = (props: { type: string }) => {
select: {
disabled: true,
},
data: [
{ name: "上海", value: randomData() },
{ name: "北京", value: 200 },
{ name: "天津", value: randomData() },
{ name: "重庆", value: randomData() },
{ name: "河北", value: randomData() },
{ name: "河南", value: randomData() },
{ name: "云南", value: randomData() },
{ name: "辽宁", value: randomData() },
{ name: "黑龙江", value: randomData() },
{ name: "湖南", value: randomData() },
{ name: "安徽", value: randomData() },
{ name: "山东", value: randomData() },
{ name: "新疆", value: randomData() },
{ name: "江苏", value: randomData() },
{ name: "浙江", value: randomData() },
{ name: "江西", value: randomData() },
{ name: "湖北", value: randomData() },
{ name: "广西", value: randomData() },
{ name: "甘肃", value: randomData() },
{ name: "山西", value: randomData() },
{ name: "内蒙古", value: randomData() },
{ name: "陕西", value: randomData() },
{ name: "吉林", value: randomData() },
{ name: "福建", value: randomData() },
{ name: "贵州", value: randomData() },
{ name: "广东", value: randomData() },
{ name: "青海", value: randomData() },
{ name: "西藏", value: randomData() },
{ name: "四川", value: randomData() },
{ name: "宁夏", value: randomData() },
{ name: "海南", value: randomData() },
{ name: "台湾", value: randomData() },
{ name: "香港", value: randomData() },
{ name: "澳门", value: randomData() },
{ name: "南海诸岛", value: randomData() }
]
data: chartData,
}
]
};
const option: EChartsOption = type == "pie" ? pieOption : type == "map" ? mapOption : categoryOption;
myChart.setOption(option);
}, [])
const resize = () => {
myChart && myChart.resize();
};
window.addEventListener("resize", debounce(() => resize(), 100));
return () => {
window.removeEventListener("resize", debounce(() => resize(), 100));
}
}, [chartData])
return (
<div id={random} style={{ width: '100%', height: '100%', zIndex: 99 }}></div>
)
}
//异常预警
const EarlyWarn = ({ img, name, num }: { img: string, name: string, num: string | number }) => {
export const EarlyWarn = ({ img, name, num }: { img: string, name: string, num: string | number }) => {
return (
<div className='screen-warn-content'>
<img src={img} className='screen-warn-img' />
@ -382,21 +308,180 @@ const EarlyWarn = ({ img, name, num }: { img: string, name: string, num: string
}
export default () => {
const [time, setTime] = useState<string>('');
//中心地图及周边数据
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;
const categoryChart = useMemo(() => {
return <GraphChart type="category" />
}, [])
return todayExpertNum.length > 0 && <GraphChart type="category" chartData={todayExpertNum} />
}, [todayExpertNum])
const pieChart = useMemo(() => {
return <GraphChart type="pie" />
}, [])
return evalApplData.length > 0 && <GraphChart type="pie" chartData={evalApplData} />
}, [evalApplData])
const mapChart = useMemo(() => {
return <GraphChart type="map" />
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();
}, [])
//定时器
useEffect(() => {
const interval = setInterval(function () {
const date = moment().format("YYYY-MM-DD HH:mm:ss");
setTime(date);
}, 1000);
getWarnInfo();
getEvaRoomData();
}, _time);
return () => {
clearInterval(interval)
};
@ -410,7 +495,6 @@ export default () => {
<Row>
<Col span={6}>
<div className='top-left'>
{/* <span>当前时间2022-07-14 07:00:00</span> */}
</div>
</Col>
<Col span={12}>
@ -420,7 +504,7 @@ export default () => {
</Col>
<Col span={6}>
<div className='top-right'>
<span>{time}</span>
<LocalTime />
</div>
</Col>
</Row>
@ -439,13 +523,19 @@ export default () => {
<div className='card-title'>
<span></span>
</div>
<Descriptions size="small" column={2}>
<Descriptions.Item label="项目名称" span={2}>IT服务建设购置项目</Descriptions.Item>
<Descriptions.Item label="标段名称">IT服务建设购置项目</Descriptions.Item>
<Descriptions.Item label="监控设备名称">1</Descriptions.Item>
<Descriptions.Item label="评标室名称"></Descriptions.Item>
<Descriptions.Item label="省分"></Descriptions.Item>
</Descriptions>
{
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>
</>
}
</div>
</Col>
<Col span={16} className='screen-left4 screen-right4'>
@ -453,21 +543,21 @@ export default () => {
<div className='map-bg'>
{mapChart}
<div className='map-total-num'>
<span>50</span>
<span>{centerMapData?.number}</span>
</div>
<div className='map-grand'>
<div className='map-grand-title'></div>
<div>
<img src={crown_01} className='map-grand-img' />
<span>100</span>
<span>{centerMapData?.list?.[0].name}{centerMapData?.list?.[0].cumulativePlaceNumber}</span>
</div>
<div className='map-grand-content'>
<img src={crown_02} className='map-grand-img' />
<span>90</span>
<span>{centerMapData?.list?.[1].name}{centerMapData?.list?.[1].cumulativePlaceNumber}</span>
</div>
<div className='map-grand-content'>
<img src={crown_03} className='map-grand-img' />
<span>80</span>
<span>{centerMapData?.list?.[2].name}{centerMapData?.list?.[2].cumulativePlaceNumber}</span>
</div>
</div>
</div>
@ -476,20 +566,25 @@ export default () => {
<Col span={24} className='screen-top8 screen-right4'>
<div className='screen-card'>
<div className='screen-graph-top'>
<span className='screen-graph-title'>50</span>
<span className='screen-graph-title'>40</span>
<span className='screen-graph-title'>500</span>
<Radio.Group defaultValue="a" buttonStyle="solid" size='small'>
<Radio.Button value="a"></Radio.Button>
<Radio.Button value="b"> </Radio.Button>
</Radio.Group>
<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>}
</div>
<div className='screen-graph-chart'>
{pieChart}
</div>
<div className='screen-graph-end'>
<span>&gt;&gt;</span>
<div className='screen-graph-bottom'>
<span className='screen-graph-title'></span>
<span className='screen-graph-title'></span>
<span className='screen-graph-title'></span>
</div>
{/* <div className='screen-graph-end'>
<span>&gt;&gt;项目列表</span>
</div> */}
</div>
</Col>
</Row>
@ -500,35 +595,22 @@ export default () => {
<span></span>
</div>
<div className='screen-warn'>
<EarlyWarn name="陌生人预警" img={warn_icon_01} num={10} />
<EarlyWarn name="评标室人数预警" img={warn_icon_02} num={20} />
<EarlyWarn name="陌生人预警" img={warn_icon_01} num={earlyWarnData?.strangerCount ? earlyWarnData?.strangerCount : 0} />
<EarlyWarn name="评标室人数预警" img={warn_icon_02} num={earlyWarnData?.numberCount ? earlyWarnData?.numberCount : 0} />
</div>
</div>
<div className='screen-card screen-top8'>
<div className='screen-card screen-card-double screen-top8'>
<div className='card-title'>
<span>20</span>
<span><RightCircleOutlined style={{ marginLeft: "0.5rem", cursor: 'pointer' }} onClick={() => projectClick()} /></span>
</div>
<Table
{bidProjectData.length > 0 && <Table
pagination={false}
className="screen-table"
rowKey="id"
size="small"
dataSource={dataSource}
dataSource={bidProjectData}
columns={evalColumn}
/>
</div>
<div className='screen-card screen-top8'>
<div className='card-title'>
<span>10</span>
</div>
<Table
pagination={false}
className="screen-table"
rowKey="id"
size="small"
dataSource={dataSource}
columns={todayEvalColumn}
/>
/>}
</div>
</Col>
</Row>

View File

@ -0,0 +1,69 @@
import request from '@/utils/request';
/**
* 获取首页地图数据
* @param data
* @returns
*/
export async function getTotalMapData(data: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getProvinceBidEvaluation', {
method: 'POST',
data: data,
});
}
/**
* 首页-评标室监控-异常预警
* @param params
* @returns
*/
export async function getWarnData(params?: any) {
return request('/api/biz-service-ebtp-evaluation/v1/eval/room/alarm/screamOfAlarm', {
method: 'GET',
params: { ...params },
});
}
/**
* 首页-评标室项目情况
* @param data
* @returns
*/
export async function getRoomProjectData(data: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getUnderWayProject', {
method: 'POST',
data: data,
});
}
/**
* 首页-今日评标专家数量
* @returns
*/
export async function getTodayExpert() {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getBidMethodNumber', {
method: 'GET',
});
}
/**
* 首页-评标室应用情况
* @param data
* @returns
*/
export async function getApplicationData(data: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getCumulativeProject', {
method: 'POST',
data: data,
});
}
/**
* 首页-评标室监控示例数据
* @returns
*/
export async function getMonitorSample() {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getReserveSample', {
method: 'GET',
});
}

View File

@ -39,13 +39,17 @@
.top-left {
color: #fff;
font-size: large;
letter-spacing: 1px;
margin-top: 1rem;
display: flex;
justify-content: flex-end;
}
.top-right {
.top-left;
margin-top: 0.5rem;
justify-content: flex-start;
font-size: 1.2rem;
line-height: 1.2rem;
}
}
}
@ -76,50 +80,23 @@
height: calc(92.6% - 36px);
}
.screen-table {
margin-top: 0.5rem;
height: calc(100% - 36px - 0.5rem);
overflow: hidden;
.ant-table-container table>thead>tr:first-child th:first-child {
border-radius: 0;
}
.ant-table-container table>thead>tr:first-child th:last-child {
border-radius: 0;
}
.ant-table-tbody>tr.ant-table-row:hover>td {
background: #0e3583;
}
.screen-table-header {
background: #045da8;
color: #fff;
border: 0;
}
.screen-table-odd-content {
.screen-table-header;
background: #041a6d;
color: #2adff5;
}
.screen-table-even-content {
.screen-table-odd-content;
background: #0e3583;
}
}
.screen-graph-top {
color: #2cdbf5;
font-size: 1rem;
padding-top: 0.75rem;
display: flex;
justify-content: space-between;
align-items: center;
// height: 2.25rem;
padding-left: 2.5%;
padding-right: 5%;
padding-top: 1%;
position: absolute;
top: 0;
width: 100%;
z-index: 100;
.screen-graph-title {
display: inline-block;
width: 30%;
text-align: center;
.screen-graph-left-title {
font-size: 1rem;
line-height: 1rem;
color: #ffcd00;
}
.ant-radio-button-wrapper:first-child {
@ -145,16 +122,73 @@
}
}
.screen-graph-chart {
height: calc(~"100% - 25px - 0.75rem");
@media screen and (max-height:1080px) {
.screen-graph-top {
padding-top: 1%;
}
}
.screen-graph-end {
color: #2cdbf5;
position: absolute;
right: 4%;
bottom: 2px;
@media screen and (max-height:900px) {
.screen-graph-top {
padding-top: 0.5%;
}
}
.screen-graph-bottom {
color: #2cdbf5;
font-size: 0.875rem;
line-height: 0.875rem;
position: absolute;
bottom: 0.5rem;
width: 100%;
// padding-top: 0.75rem;
.screen-graph-title {
display: inline-block;
width: 30%;
text-align: center;
}
}
.screen-graph-chart {
height: calc(~"100%");
}
// .screen-graph-end {
// color: #2cdbf5;
// position: absolute;
// right: 4%;
// bottom: 2px;
// }
.card-project-content {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
&>p {
color: #fff;
margin-bottom: 0;
font-size: 0.75rem;
padding: 0 0.75rem;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&>span:last-child {
margin-left: 0.5rem;
}
}
}
.card-carema-c {
height: calc(~"100% - 110px - 0.5rem");
width: 100%;
border: 1px solid #fff
}
}
.screen-card-double {
height: calc(~"(100vh - 61px - 2.5rem) / 3 * 2");
}
.screen-warn-content {
@ -253,7 +287,7 @@
.map-grand {
position: absolute;
right: 2rem;
right: 4rem;
bottom: 2rem;
.map-grand-title {
@ -289,4 +323,43 @@
}
}
}
}
.screen-table {
margin-top: 0.5rem;
height: calc(100% - 36px - 0.5rem);
overflow: hidden;
.ant-table-container table>thead>tr:first-child th:first-child {
border-radius: 0;
}
.ant-table-container table>thead>tr:first-child th:last-child {
border-radius: 0;
}
.ant-table-tbody>tr.ant-table-row:hover>td {
background: #0e3583;
}
.screen-table-header {
background: #045da8;
color: #fff;
border: 0;
}
.screen-table-odd-content {
.screen-table-header;
background: #041a6d;
color: #2adff5;
}
.screen-table-even-content {
.screen-table-odd-content;
background: #0e3583;
}
.ant-table-small .ant-table-thead>tr>th {
background-color: #045da8;
}
}

View File

@ -0,0 +1,361 @@
import { Button, Col, Input, List, message, PaginationProps, Row, Tag, Tooltip } from "antd"
import moment from "moment";
import '../Home/style.less'
import './style.less';
import content_title from '@/assets/screen/content_title.png'
import React, { useEffect, useRef, useState } from "react"
import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons";
import { getMonitorList } from "./service";
import { isNotEmpty } from "@/utils/CommonUtils";
import { history } from "umi";
import { LocalTime, proviceEnum } from "../Home";
export const bidStatusMap = ["准备评标", "正在评标", "评标结束"];
const statusColorMap = ["bidding-text-order", "bidding-text-going", "bidding-text-ending"];
const provinceList = [{
"provincesRemark": "集团",
"provincesNumber": "001000",
}, {
"provincesNumber": "0011",
"provincesRemark": "北京",
},
{
"provincesNumber": "0012",
"provincesRemark": "天津",
},
{
"provincesNumber": "0013",
"provincesRemark": "河北",
},
{
"provincesNumber": "0014",
"provincesRemark": "山西",
},
{
"provincesNumber": "0015",
"provincesRemark": "内蒙古",
},
{
"provincesNumber": "0021",
"provincesRemark": "辽宁",
},
{
"provincesNumber": "0022",
"provincesRemark": "吉林",
},
{
"provincesNumber": "0023",
"provincesRemark": "黑龙江",
},
{
"provincesNumber": "0031",
"provincesRemark": "上海",
},
{
"provincesNumber": "0032",
"provincesRemark": "江苏",
},
{
"provincesNumber": "0033",
"provincesRemark": "浙江",
},
{
"provincesNumber": "0034",
"provincesRemark": "安徽",
},
{
"provincesNumber": "0035",
"provincesRemark": "福建",
},
{
"provincesNumber": "0036",
"provincesRemark": "江西",
},
{
"provincesNumber": "0037",
"provincesRemark": "山东",
},
{
"provincesNumber": "0041",
"provincesRemark": "河南",
},
{
"provincesNumber": "0042",
"provincesRemark": "湖北",
},
{
"provincesNumber": "0043",
"provincesRemark": "湖南",
},
{
"provincesNumber": "0044",
"provincesRemark": "广东",
},
{
"provincesNumber": "0045",
"provincesRemark": "广西",
},
{
"provincesNumber": "0046",
"provincesRemark": "海南",
},
{
"provincesNumber": "0050",
"provincesRemark": "重庆",
},
{
"provincesNumber": "0051",
"provincesRemark": "四川",
},
{
"provincesNumber": "0052",
"provincesRemark": "贵州",
},
{
"provincesNumber": "0053",
"provincesRemark": "云南",
},
{
"provincesNumber": "0054",
"provincesRemark": "西藏",
},
{
"provincesNumber": "0061",
"provincesRemark": "陕西",
},
{
"provincesNumber": "0062",
"provincesRemark": "甘肃",
},
{
"provincesNumber": "0063",
"provincesRemark": "青海",
},
{
"provincesNumber": "0064",
"provincesRemark": "宁夏",
},
{
"provincesNumber": "0065",
"provincesRemark": "新疆",
},];
const itemRender: PaginationProps['itemRender'] = (_, type, originalElement) => {
if (type === 'prev') {
return <LeftCircleOutlined className="pagination-icon" />;
}
if (type === 'next') {
return <RightCircleOutlined className="pagination-icon" />;
}
return originalElement;
};
export const homeClick = () => {
history.push("/MonitorScreen/Home");
}
export const previousClick = () => {
history.goBack();
}
export default () => {
//状态选择
const [selectBtn, setSelectBtn] = useState<string>("");
const selectStatus = useRef<string>("");
//当前选中的省分
const [selectedTag, setSelectedTag] = useState<string>("");
const selectProvince = useRef<string>("");
//当前页码
const pageNo = useRef<number>(1);
//总数
const [totalItem, setTotalItem] = useState<number>(0);
//当前页数据
const [listData, setListData] = useState<any[]>([]);
//关键字搜索条件
const search = useRef<string>("");
//定时刷新间隔
const _time = 10000;
const { CheckableTag } = Tag;
const handleChange = (tag: string, checked: boolean) => {
const nextSelectedTag = checked ? tag : '';
setSelectedTag(nextSelectedTag);
selectProvince.current = nextSelectedTag;
pageNo.current = 1;
getMonitorRoom();
};
const onPageChange = (page: number) => {
pageNo.current = page;
getMonitorRoom();
}
const onSearchBlur = (e: any) => {
search.current = e.target.value;
}
const onSearchClick = (e: any) => {
if (isNotEmpty(e) || isNotEmpty(search.current)) {
pageNo.current = 1;
getMonitorRoom();
}
}
const onBtnSelect = (btnName: string, status: string) => {
if (btnName == selectBtn) {
setSelectBtn("");
selectStatus.current = "";
} else {
setSelectBtn(btnName);
selectStatus.current = status;
}
pageNo.current = 1;
getMonitorRoom();
}
const onCardClick = (item: any) => {
if (item.status == "0") {
message.info("当前评标室未开启,请等待开启后查看");
return;
}
history.push({
pathname: "/MonitorScreen/ProjectMonitorRoom",
state: { monitorId: item.id },
})
}
//获取监控列表数据
const getMonitorRoom = () => {
const params = {
pageNo: pageNo.current,
pageSize: 6,
}
isNotEmpty(selectProvince.current) && (params["provinceDictId"] = selectProvince.current);
isNotEmpty(selectStatus.current) && (params["status"] = selectStatus.current);
isNotEmpty(search.current) && (params["keyword"] = search.current);
getMonitorList(params).then(res => {
if (res?.code == 200) {
setTotalItem(res?.data.total);
setListData(res?.data.records);
}
})
}
useEffect(() => {
getMonitorRoom();
}, [])
//定时器
useEffect(() => {
const interval = setInterval(function () {
getMonitorRoom();
}, _time);
return () => {
clearInterval(interval)
};
}, [])
return (
<div className="screen-bg">
<div className='top-block'>
</div>
<div className='top'>
<Row>
<Col span={6}>
<div className='top-left'>
<div className="screen-right4"><Input placeholder="请输入关键字搜索" onBlur={onSearchBlur} onPressEnter={onSearchClick} /></div>
<div className="screen-left4"><Button type="primary" onClick={() => onSearchClick("")}></Button></div>
</div>
</Col>
<Col span={12}>
<div className='top-title'>
<span></span>
</div>
</Col>
<Col span={6}>
<div className='top-right'>
<LocalTime />
</div>
</Col>
</Row>
</div>
<div className='list-content'>
<Row>
<Col span={6} className="list-content-col">
<div className="top-province">
<div className='top-province-label'>
<span></span>
</div>
<Tooltip
overlayClassName="screen-tag"
placement="bottomLeft"
overlayInnerStyle={{ width: '140%', backgroundColor: "rgba(4,20,47,0.85)", padding: "5px 10px" }}
title={
<Row>
{provinceList.map((tag, index) => (
<Col span={4} key={index}>
<CheckableTag
className='top-province-tag'
key={tag.provincesNumber}
checked={selectedTag === tag.provincesNumber}
onChange={checked => handleChange(tag.provincesNumber, checked)}
>
{tag.provincesRemark}
</CheckableTag>
</Col>
))}
</Row>
} >
<Row>
{provinceList.slice(0, 11).map((tag, index) => (
<Col span={4} className='top-province-col' key={index}>
<CheckableTag
className='top-province-tag'
key={tag.provincesNumber}
checked={selectedTag === tag.provincesNumber}
onChange={checked => handleChange(tag.provincesNumber, checked)}
>
{tag.provincesRemark}
</CheckableTag>
</Col>
))}
<Col span={4} className='top-province-col'>
<a className='top-province-all'></a>
</Col>
</Row>
</Tooltip>
</div>
</Col>
<Col span={12} className="top-btn">
{/* <Space size={16}> */}
<div><a className="top-home" onClick={() => homeClick()}></a></div>
<div><a className={selectBtn == "order" ? "top-order top-order-02" : "top-order"} onClick={() => onBtnSelect("order", "0")}></a></div>
<div><a className={selectBtn == "going" ? "top-going top-going-02" : "top-going"} onClick={() => onBtnSelect("going", "1")}></a></div>
<div><a className={selectBtn == "ending" ? "top-ending top-ending-02" : "top-ending"} onClick={() => onBtnSelect("ending", "2")}></a></div>
<div><a className="top-back" onClick={() => previousClick()}></a></div>
{/* </Space> */}
</Col>
<Col span={6}>
</Col>
</Row>
<List
grid={{ gutter: 16, column: 3 }}
pagination={{
defaultPageSize: 6,
onChange: onPageChange,
total: totalItem,
showTotal: (total, range) => `当前第 ${range[0]}-${range[1]} 条,共计 ${total}`,
// itemRender
}}
className="list-global"
dataSource={listData}
renderItem={item => (
<List.Item>
<div className="list-card" onClick={() => onCardClick(item)}>
<p className="list-card-title">
<img src={content_title} />
<span>{item.meetingName}</span>
</p>
<p><span className="project-text">{item.projectName}</span></p>
<p>{item.sectionName}</p>
<p>{item.startDate} {item.endDate}</p>
<p className="space-between"><span>{item.expertNumber}</span><span>{proviceEnum[item.provinceDictId]}</span></p>
<p className="space-between"><span><span className={statusColorMap[item.status]}>{bidStatusMap[item.status]}</span></span>{item.isAbnormal == "1" && <span className="error-text"></span>}</p>
</div>
</List.Item>
)}
/>
</div>
</div>
)
}

View File

@ -0,0 +1,20 @@
import request from '@/utils/request';
/**
* 获取评标室监控列表
* @param data
* @returns
*/
export async function getMonitorList(data: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getReviewRoomList', {
method: 'POST',
data: data,
});
}
/**
* 获取省
* @returns
*/
export async function getProvinceList() {
return request('/api/biz-service-ebtp-project/v1/dictprovincescode/queryAll');
}

View File

@ -0,0 +1,374 @@
@import '~antd/lib/style/themes/default.less';
@screen-img-url: "~@/assets/screen";
.btn-common-s {
background-repeat: no-repeat;
background-size: 80% 80%;
background-position: center;
height: 80px;
width: 80px;
display: block;
}
.btn-common-l {
.btn-common-s;
background-size: 80% 80%;
background-position: center;
height: 88px;
width: 166px;
}
.screen-tag-color {
.ant-tag-checkable:not(.ant-tag-checkable-checked):hover {
color: #f98500
}
.ant-tag-checkable:active,
.ant-tag-checkable-checked {
background-color: #f98500
}
}
.screen-tag {
.screen-tag-color;
padding-top: 0;
.ant-tooltip-arrow {
display: none;
}
}
.top-province-tag {
font-size: 0.875rem;
padding: 0 0.5625rem;
line-height: 1.6875rem;
margin-right: 0;
color: #fff;
}
.screen-bg {
.screen-tag-color;
.top-left {
.ant-input {
color: #fff;
background-color: #041a6d;
border: 1px solid #02439b;
&:hover {
border-color: #02439b;
}
&:focus {
border-color: #02439b;
box-shadow: 0 0 0 2px #02439b;
}
}
.ant-btn-primary {
background: #0174cf;
border-color: #0174cf;
&:hover &:focus &:active {
background: #0174cf;
border-color: #0174cf;
}
}
}
.list-content {
padding: 0 16px;
.list-content-col {
display: flex;
align-items: center;
}
}
.top-province {
display: flex;
align-items: baseline;
justify-content: flex-start;
}
.top-province-label {
width: 5.625rem;
&>span {
font-size: 0.875rem;
color: #fff;
}
}
.top-province-all {
font-size: 0.875rem;
color: #00e1ff;
}
.top-province-col {
display: flex;
justify-content: center;
align-items: center;
}
.top-btn {
display: flex;
justify-content: center;
padding: 8px 0;
.top-home {
background-image: url('@{screen-img-url}/home_01.png');
.btn-common-s;
&:hover {
background-image: url('@{screen-img-url}/home_02.png');
}
}
.top-order {
background-image: url('@{screen-img-url}/order_01.png');
.btn-common-l;
&:hover {
background-image: url('@{screen-img-url}/order_02.png');
}
}
.top-order-02 {
background-image: url('@{screen-img-url}/order_02.png');
}
.top-going {
background-image: url('@{screen-img-url}/going_01.png');
.btn-common-l;
&:hover {
background-image: url('@{screen-img-url}/going_02.png');
}
}
.top-going-02 {
background-image: url('@{screen-img-url}/going_02.png');
}
.top-ending {
background-image: url('@{screen-img-url}/ending_01.png');
.btn-common-l;
&:hover {
background-image: url('@{screen-img-url}/ending_02.png');
}
}
.top-ending-02 {
background-image: url('@{screen-img-url}/ending_02.png');
}
.top-back {
background-image: url('@{screen-img-url}/back_01.png');
.btn-common-s;
&:hover {
background-image: url('@{screen-img-url}/back_02.png');
}
}
}
.list-global {
.ant-list-item {
margin-bottom: 16 !important;
}
.list-card {
background: #041766;
border-radius: 4px;
border: 1px solid #5c69a1;
cursor: pointer;
padding: 1rem;
&:hover {
border-color: #fff;
}
.list-card-title {
color: #e5d50b;
font-size: 1.2rem;
line-height: 1.2rem;
&>img {
vertical-align: bottom;
height: 1.2rem;
}
&>span {
margin-left: 0.625rem;
}
}
.space-between {
display: flex;
justify-content: space-between;
}
&>p {
font-size: 1rem;
margin-bottom: 0.5rem;
&:last-child {
margin-bottom: 0.25rem;
}
color: #fff;
.project-text {
color: #2bddf4;
}
.bidding-text-going {
color: #fb8600;
}
.bidding-text-ending {
color: #ee6766;
}
.bidding-text-order {
color: #72c1dd;
}
.error-text {
color: #d9001b;
&::before {
content: "·";
font-weight: 900;
margin-right: 0.25rem;
color: #d9001b;
}
}
}
}
@media screen and (max-height:1080px) {
.list-card {
height: 36vh;
max-height: 36vh;
padding: 1rem 1.2rem;
.list-card-title {
font-size: 1.4rem;
line-height: 1.4rem;
&>img {
height: 1.4rem;
}
}
&>p {
font-size: 1.1rem;
margin-bottom: 1.625rem;
}
}
}
@media screen and (max-height:900px) {
.list-card {
height: 32vh;
max-height: 32vh;
padding: 1rem;
.list-card-title {
font-size: 1.2rem;
line-height: 1.2rem;
&>img {
height: 1.2rem;
}
}
&>p {
font-size: 1rem;
margin-bottom: 0.5rem;
}
}
}
.ant-list-pagination {
margin-top: 0;
text-align: center;
}
.ant-pagination-item {
// border: none;
background: none;
border: 1px solid #8de3f3;
margin-right: 0.5rem;
&>a {
color: #8de3f3;
}
&:hover>a {
color: #f78404;
}
}
.ant-pagination-item:hover {
border-color: #f78404;
}
.ant-pagination-item:focus-visible {
border-color: #f78404;
}
.ant-pagination-item-active {
border-color: #f78404;
a {
color: #f78404;
}
&:hover &:focus-visible {
border-color: #f78404;
}
}
.ant-pagination-prev:focus-visible .ant-pagination-item-link,
.ant-pagination-next:focus-visible .ant-pagination-item-link,
.ant-pagination-prev:hover .ant-pagination-item-link,
.ant-pagination-next:hover .ant-pagination-item-link {
border-color: #8de3f3;
color: #8de3f3;
}
.ant-pagination-prev .ant-pagination-item-link,
.ant-pagination-next .ant-pagination-item-link {
background: none;
border-color: #8de3f3;
color: #8de3f3;
}
.pagination-icon {
font-size: 20px;
vertical-align: middle;
color: #8de3f3;
height: 24px;
}
.ant-pagination-total-text {
color: #8de3f3;
}
.ant-pagination-prev {
margin-right: 0.5rem;
}
}
}

View File

@ -0,0 +1,390 @@
import { Col, Radio, Row, Table, Tag, Tooltip, Image } from "antd"
import React, { useEffect, useRef, useState } from "react"
import { EarlyWarn, LocalTime, onCell, onHeaderCell } from "../Home";
import '../Home/style.less'
import '../MonitorRoom/style.less'
import './style.less';
import warn_icon_01 from '@/assets/screen/warn_icon_01.png'
import warn_icon_02 from '@/assets/screen/warn_icon_02.png'
import { getBidRoomData, getCameraList, getExpertReports, getLookBackList } from "./service";
import { bidStatusMap, homeClick, previousClick } from "../MonitorRoom";
import { getWarnData } from "../Home/service";
import ScreenVideoPlay from "@/components/Screen/ScreenVideoPlay";
import { pictureDisplayPath } from "@/utils/DownloadUtils";
import { getURLInformation } from "@/utils/CommonUtils";
const statusMap = ["未报道", "已报道"];
const peopleNumColumns: any[] = [
{
title: '时间',
dataIndex: 'eventTime',
key: 'eventTime',
align: 'center',
width: "40%",
onCell,
onHeaderCell,
},
{
title: '阈值',
dataIndex: 'thresholdOfPeople',
key: 'thresholdOfPeople',
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
render: (_: any, record: any) => `${_}`,
},
{
title: '实际人数',
dataIndex: 'realOfPeople',
key: 'realOfPeople',
align: 'center',
onCell,
onHeaderCell,
render: (_: any, record: any) => `${_}`,
},
];
const backPeopleNumColumns: any[] = [
{
title: '时间',
dataIndex: 'createDate',
key: 'createDate',
align: 'center',
width: "40%",
onCell,
onHeaderCell,
},
{
title: '阈值',
dataIndex: 'thresholdOfPeople',
key: 'thresholdOfPeople',
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
render: (_: any, record: any) => `${record.details[0].thresholdOfPeople}`,
},
{
title: '实际人数',
dataIndex: 'realOfPeople',
key: 'realOfPeople',
align: 'center',
onCell,
onHeaderCell,
render: (_: any, record: any) => `${record.details[0].realOfPeople}`,
},
];
const staffReportColumns: any[] = [
{
title: '人员',
dataIndex: 'userName',
key: 'userName',
align: 'center',
ellipsis: true,
onCell,
onHeaderCell,
},
{
title: '报道状态',
dataIndex: 'status',
key: 'status',
align: 'center',
onCell,
onHeaderCell,
render: (_: any, record: any) => statusMap[_],
},
{
title: '报道时间',
dataIndex: 'signDate',
key: 'signDate',
align: 'center',
width: "40%",
onCell,
onHeaderCell,
},
];
export default (props: any) => {
//tooltip visible
const [visible, setVisible] = useState<boolean>(false);
//camera select
const [cameraSelect, setCameraSelect] = useState<string>("1");
//选中的设备参数
const [cameraParams, setCameraParams] = useState<any>();
//right btn select
const [btnSelect, setBtnSelect] = useState<string>("0");
//props state
const monitorId = props.location.state?.monitorId ? props.location.state?.monitorId : getURLInformation("monitorId");
//基本信息数据
const [basicInfo, setBasicInfo] = useState<any>({});
//异常预警数据
const [earlyWarnData, setEarlyWarnData] = useState<any>();
//设备列表
const [caremaList, setCaremaList] = useState<any[]>([]);
//报道列表
const [expertList, setExpertList] = useState<any[]>([]);
//陌生人预警-回看
const [backStrangerList, setBackStrangerList] = useState<any[]>([]);
//人数预警-回看
const [backNumberList, setBackNumberList] = useState<any[]>([]);
//监控视频Ref
const videoRef = useRef<any>();
//定时刷新间隔
const _time = 10000;
const onChange = (e: any) => {
setBtnSelect(e.target.value);
}
const onCaremaPlay = (item: any) => {
setCameraSelect(item.id);
setCameraParams(item.platform);
videoRef.current.play(item.deviceCode);
}
//获取基本信息数据
const getRoomData = () => {
getBidRoomData(monitorId).then(res => {//获取基本信息
if (res?.code == 200) {
const data = res?.data;
for (const ite of data.userNumberList) {
if (ite.userType == "manager") {//项目经理
data["manager"] = ite.userNumber;
} else if (ite.userType == "purchase_expert") {//专家-招标人代表
data["purchaseExpert"] = ite.userNumber;
} else if (ite.userType == "expert") {//专家
data["expert"] = ite.userNumber;
}
}
if (data.sectionPayerList?.length > 0) {
let length = 0
for (const ite of data.sectionPayerList) {
length += ite.payerNumber;
}
data["supplierLength"] = length;
} else {
data["supplierLength"] = 0;
}
setBasicInfo(data);
getCaremaData(data);//获取监控点列表
if (data.status == "2") {//评标结束-回看
getBackList("2");//数量预警
getBackList("3");//陌生人预警
}
}
})
}
//获取异常预警数据
const getWarnInfo = () => {
getWarnData({ reserveId: monitorId }).then(res => {
if (res?.code == 200) {
const data = res?.data;
setEarlyWarnData(data);
}
})
}
//获取设备
const getCaremaData = (baseData: any) => {
getCameraList({ areaId: baseData.placeId }).then(res => {
if (res?.code == 200) {
const data = res?.data;
setCaremaList(data);
if (data?.length > 0) {
//获取回看时间
// getCaremaBackList(monitorId).then(response => {
// if (response?.code == 200) {
// const backData = response?.data;
setCameraSelect(data[0].id);
setCameraParams(data[0].platform);
setTimeout(() => {
if (data.status == "2") {//回看
videoRef.current?.back(data[0].deviceCode, baseData.startDate, baseData.endDate);
} else {
videoRef.current?.play(data[0].deviceCode);
}
}, 4000);
// }
// })
}
}
})
}
//获取专家报道列表
const getExpertList = () => {
getExpertReports({ reserveId: monitorId, pageNo: 1, pageSize: 20 }).then(res => {
if (res?.code == 200) {
const data = res?.data.records;
setExpertList(data);
}
})
}
//获取告警-回看数据
const getBackList = (type: string) => {
getLookBackList({ reserveId: monitorId, type }).then(res => {
if (res?.code == 200) {
const data = res?.data.records;
if (type == "2") {//2-人数预警
setBackNumberList(data);
} else if (type == "3") {//3-陌生人预警
setBackStrangerList(data);
}
}
})
}
useEffect(() => {
getRoomData();
getWarnInfo();
getExpertList();
}, [])
//定时器
useEffect(() => {
let interval: any
if (basicInfo?.status && basicInfo?.status != "2") {
interval = setInterval(function () {
getWarnInfo();
getExpertList();
}, _time);
}
return () => {
clearInterval(interval)
};
}, [basicInfo])
return (
<div className="screen-bg">
<div className='top-block'>
</div>
<div className='top'>
<Row>
<Col span={6}>
</Col>
<Col span={12}>
<div className='top-title'>
<span></span>
</div>
</Col>
<Col span={6}>
<div className='top-right'>
<LocalTime />
</div>
</Col>
</Row>
</div>
<div className='list-content'>
<Row>
<Col span={6}>
<div className="left-content-g">
<p>{basicInfo?.bidMethodDictName}</p>
<p>{basicInfo?.projectName}</p>
<p>{basicInfo?.projectNum}</p>
<p>{basicInfo?.sectionName}</p>
<p>{basicInfo?.startDate} {basicInfo?.endDate}</p>
<p>{basicInfo?.appManagerName}</p>
<p>{basicInfo?.peopleNumber}</p>
<div className="left-content-people">
<span><Tag color="rgba(2,125,180,1)"></Tag>{basicInfo?.manager} {basicInfo?.purchaseExpert} {basicInfo?.expert}</span>
</div>
</div>
</Col>
<Col span={12} className="top-btn">
<div><a className="top-home" onClick={() => homeClick()}></a></div>
<div className="top-title-global">
<div className="top-title-left"></div>
<div className="top-title-center"><span>{basicInfo?.areaName}</span></div>
<div className="top-title-right"><span>{bidStatusMap[basicInfo?.status]}</span></div>
</div>
<div><a className="top-back" onClick={() => previousClick()}></a></div>
</Col>
<Col span={6}>
<div className="right-warn-title"></div>
<div className="right-warn-content">
<EarlyWarn name="陌生人预警" img={warn_icon_01} num={earlyWarnData?.strangerCount ? earlyWarnData?.strangerCount : 0} />
<EarlyWarn name="评标室人数预警" img={warn_icon_02} num={earlyWarnData?.numberCount ? earlyWarnData?.numberCount : 0} />
</div>
</Col>
</Row>
<Row>
<Col span={6}></Col>
<Col span={18}>
<div className="answer-supplier">
<span>{basicInfo?.supplierLength}</span>
<Tooltip placement="bottomLeft" title={<>{basicInfo?.sectionPayerList?.map((item: any) => <p key={item.sectionName}>{item.sectionName}{item.payerNumber}{item.payerNames.join("、")}</p>)}</>} visible={visible} color="rgba(4,20,47,0.85)" overlayInnerStyle={{ width: '250%' }} overlayClassName="screen-tag">
<span>{basicInfo?.sectionPayerList?.[0]?.payerNames.slice(0, 5).join("、")}<a onMouseEnter={() => setVisible(true)} onMouseLeave={() => setVisible(false)}></a></span>
</Tooltip>
</div>
</Col>
{/* <Col span={6}></Col> */}
</Row>
<Row>
<Col span={17}>
<div className="left-monitor">
<div className="left-menu">
<div className="left-menu-title"></div>
<div className="left-menu-content">
{caremaList.map(item => <div className={cameraSelect == item.id ? "left-menu-btn left-menu-btn-select" : "left-menu-btn"} onClick={() => onCaremaPlay(item)} key={item.id}>{item.deviceName}</div>)}
</div>
</div>
<div className="right-content-c">
{cameraParams && <ScreenVideoPlay videoRef={videoRef} cameraParams={cameraParams} status={basicInfo?.status == "2" ? 1 : 0} />}
</div>
</div>
</Col>
<Col span={7}>
<div className="right-warn-list">
<Radio.Group buttonStyle="solid" onChange={onChange} value={btnSelect}>
<Radio.Button value="0"></Radio.Button>
<Radio.Button value="1"></Radio.Button>
<Radio.Button value="2"></Radio.Button>
</Radio.Group>
{btnSelect == "0" ? (
<div className="stranger-list">
{basicInfo?.status == "2"
? backStrangerList.slice(0, 5).map((item: any, index: any) => (
<div className="stranger-list-card" key={index}>
<div>
<p>{item.createDate}</p>
</div>
<div>
<Image src={pictureDisplayPath + "?filePath=" + item.details[0].filePath} height={"100%"} />
</div>
</div>
))
: earlyWarnData?.strangerDetails?.map((item: any, index: any) => (
<div className="stranger-list-card" key={index}>
<div>
<p>{item.eventTime}</p>
<p>{item.describeStranger}</p>
</div>
<div>
<Image src={pictureDisplayPath + "?filePath=" + item.filePath} height={"100%"} />
</div>
</div>
))}
</div>
) : btnSelect == "1" ? (
earlyWarnData?.numberDetails && <Table
pagination={false}
className="screen-table"
rowKey="id"
size="small"
dataSource={basicInfo?.status == "2" ? backNumberList?.[0].details : earlyWarnData?.numberDetails}
columns={basicInfo?.status == "2" ? backPeopleNumColumns : peopleNumColumns}
/>
) : (
expertList.length > 0 && <Table
pagination={false}
className="screen-table"
rowKey="id"
size="small"
dataSource={expertList}
columns={staffReportColumns}
/>
)}
</div>
</Col>
</Row>
</div>
</div>
)
}

View File

@ -0,0 +1,59 @@
import request from '@/utils/request';
/**
* 获取评标室内容数据
* @param id
* @returns
*/
export async function getBidRoomData(id: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/getReviewRoom/' + id, {
method: 'GET',
});
}
/**
* 设备列表
* @param params
* @returns
*/
export async function getCameraList(params: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/queryAreaCamera', {
method: 'GET',
params: params,
});
}
/**
* 专家报道列表
* @param data
* @returns
*/
export async function getExpertReports(data: any) {
return request('/api/biz-service-ebtp-evaluation/v1/screen/queryReportUser', {
method: 'POST',
data: data,
});
}
/**
* 回看列表
* @param params
* @returns
*/
export async function getLookBackList(params: any) {
return request('/api/biz-service-ebtp-evaluation/v1/eval/room/alarm/screamOfAlarm/back', {
method: 'POST',
params: params
});
}
// /**
// * 设备列表(回看)
// * @param id
// * @returns
// */
// export async function getCaremaBackList(id: any) {
// return request('/api/biz-service-ebtp-evaluation/v1/eval/room/reserve/' + id, {
// method: 'GET',
// });
// }

View File

@ -0,0 +1,196 @@
@import '~antd/lib/style/themes/default.less';
@screen-img-url: "~@/assets/screen";
.screen-flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.screen-bg {
.left-content-g {
position: absolute;
bottom: -32px;
width: 100%;
&>p {
color: #94edf7;
margin-bottom: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&:first-child {
color: #F59A23;
}
}
.left-content-people {
color: #fff;
margin-top: 8px;
}
}
.top-title-global {
width: 498px;
height: 80px;
display: flex;
.top-title-left {
flex: 1;
}
.top-title-center {
flex: 2;
color: #fff;
.screen-flex-center;
&>span {
font-size: 22px;
line-height: 22px;
}
}
.top-title-right {
.screen-flex-center;
flex: 1;
color: #facd91;
justify-content: flex-start;
}
}
.right-warn-title {
font-size: 20px;
line-height: 20px;
color: #ee6766;
padding-bottom: 1rem;
}
.right-warn-content {
.screen-flex-center;
justify-content: flex-start;
.screen-warn-content:last-child {
margin-left: 1.5rem;
}
}
.answer-supplier {
margin: 8px 0;
&>span {
color: #fff;
margin-bottom: 0;
&:first-child {
color: #81d3f8;
}
&>a {
color: #00e1ff;
margin-left: 8px;
}
}
}
@media screen and (max-height:1080px) {
.left-monitor,
.right-warn-list {
height: 77vh;
}
}
@media screen and (max-height:900px) {
.left-monitor,
.right-warn-list {
height: 70vh;
}
}
.left-monitor {
border: 1px solid #fff;
margin-right: 4px;
padding: 12px;
display: flex;
justify-content: flex-start;
.left-menu {
color: #fff;
width: 15%;
.left-menu-title {
font-size: 18px;
padding-bottom: 16px;
}
.left-menu-content {
.left-menu-btn {
height: 40px;
width: 100%;
line-height: 40px;
text-align: center;
cursor: pointer;
background: none;
}
.left-menu-btn-select {
background-color: #81d3f8;
}
}
}
.right-content-c {
width: 100%;
height: 100%;
border: 1px solid #fff;
}
}
.right-warn-list {
border: 1px solid #fff;
margin-left: 4px;
padding: 12px;
.stranger-list {
height: calc(100% - 76px);
.stranger-list-card {
border: 1px solid #2B5093;
background-color: #051666;
height: 20%;
margin-top: 8px;
padding: 8px;
color: #fff;
display: flex;
justify-content: space-between;
}
}
}
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
background: #02A7F0;
border-color: #02A7F0;
&:hover {
background: #02A7F0;
border-color: #02A7F0;
}
}
.ant-radio-button-wrapper-checked:not([class*=' ant-radio-button-wrapper-disabled']).ant-radio-button-wrapper:first-child {
border-right-color: #02A7F0;
}
.ant-radio-button-wrapper:hover {
color: #02A7F0;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before,
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover::before {
background-color: #02A7F0;
}
}

View File

@ -22,6 +22,10 @@
charset="utf-8"></script>
<script type="text/javascript" src="<%= context.config.publicPath +'officecontrol/ntkobackground.min.20220624.js'%>"
charset="utf-8"></script>
<script type="text/javascript" src="<%= context.config.publicPath +'screen/jsencrypt.min.js'%>"
charset="utf-8"></script>
<script type="text/javascript" src="<%= context.config.publicPath +'screen/jsWebControl-1.0.0.min.js'%>"
charset="utf-8"></script>
<link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon" />
<!-- <link rel="icon" href="./../assets/logo.svg"/> -->
</head>