8.25
@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
1
public/screen/jsWebControl-1.0.0.min.js
vendored
Normal file
1
public/screen/jsencrypt.min.js
vendored
Normal file
BIN
src/assets/screen/back_01.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/back_02.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/content_title.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/screen/ending_01.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/screen/ending_02.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/going_01.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/screen/going_02.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/home_01.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/home_02.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/screen/order_01.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/screen/order_02.png
Normal file
After Width: | Height: | Size: 20 KiB |
261
src/components/Screen/ScreenVideoPlay.tsx
Normal 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-UDP,1-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-UDP,1-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-UDP,1-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;
|
@ -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>>>项目列表</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>>>项目列表</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>
|
||||
|
69
src/pages/MonitorScreen/Home/service.ts
Normal 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',
|
||||
});
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
361
src/pages/MonitorScreen/MonitorRoom/index.tsx
Normal 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>
|
||||
)
|
||||
}
|
20
src/pages/MonitorScreen/MonitorRoom/service.ts
Normal 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');
|
||||
}
|
374
src/pages/MonitorScreen/MonitorRoom/style.less
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
390
src/pages/MonitorScreen/ProjectMonitorRoom/index.tsx
Normal 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>
|
||||
)
|
||||
}
|
59
src/pages/MonitorScreen/ProjectMonitorRoom/service.ts
Normal 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',
|
||||
// });
|
||||
// }
|
196
src/pages/MonitorScreen/ProjectMonitorRoom/style.less
Normal 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;
|
||||
}
|
||||
}
|
@ -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>
|
||||
|