Compare commits

...

3 Commits

Author SHA1 Message Date
LiuJiaNan 266f7c3394 地图首页 文件按块拆分 2026-07-17 18:19:33 +08:00
LiuJiaNan d577446a10 地图首页 文件按块拆分 2026-07-17 18:17:53 +08:00
LiuJiaNan 9310c86fd0 地图首页接口对接 2026-07-17 17:35:09 +08:00
42 changed files with 1401 additions and 1226 deletions

View File

@ -9,15 +9,13 @@ module.exports = {
// 应用后端分支名称,部署上线需要
javaGitBranch: "<branch-name>",
// 接口服务地址
// API_HOST: "https://gbs-gateway.qhdsafety.com",
API_HOST: "http://192.168.20.100:30140",
API_HOST: "https://gbs-gateway.qhdsafety.com",
},
production: {
// 应用后端分支名称,部署上线需要
javaGitBranch: "<branch-name>",
// 接口服务地址
// API_HOST: "",
API_HOST: "https://gbs-gateway.qhdsafety.com",
API_HOST: "",
},
},
// 应用唯一标识符

View File

@ -1,6 +1,46 @@
import { declareRequest } from '@cqsjjb/jjb-dva-runtime';
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export const getWeather = declareRequest(
'biLoading',
'Get > https://api.map.baidu.com/weather/v1/?district_id=130300&data_type=all&ak=dIqOi34IlTg5FkNck1vqoBpLhPAj36S1',
"indexInfoWeatherLoading",
"Get > /bi/weather/info",
);
export const getEventReportListUnfinished = declareRequest(
"indexInfoEmergencyRescueLoading",
"Post > @/emergencyRescue/eventReport/listUnfinished",
);
export const getProjectTaskScoreCount = declareRequest(
"indexInfoDomainLoading",
"Get > /domain/projectTask/scoreCount",
);
export const getHiddenStatisticsByCorp = declareRequest(
"indexInfoHiddenLoading",
"Post > @/hidden/hidden/statisticsByCorp",
);
export const getXgfStatisticsListCorpStatistics = declareRequest(
"indexInfoXgfManagerLoading",
"Post > @/xgfManager/xgfStatistics/listCorpStatistics",
);
export const getAlarmRecordScreenIotDeviceAlarmPage = declareRequest(
"indexInfoIotalarmLoading",
"Post > @/iotalarm/alarmRecord/screenIotDeviceAlarmPage",
);
export const getXgfStatisticsListRecordProjectStatistics = declareRequest(
"indexInfoXgfManagerProjectLoading",
"Get > /xgfManager/xgfStatistics/listRecordProjectStatistics",
);
export const getFixedCameraVideoList = declareRequest(
"indexInfoVideoPatrolLoading",
"Post > @/videopatrol/fixedCamera/getVideoList",
);
export const getFixedCameraPlayUrl = declareRequest(
"indexInfoVideoPatrolUrlLoading",
"Get > /videopatrol/fixedCamera/getPlayUrl",
);
export const getEightWorkInfoDangerWorkStatistics = declareRequest(
"indexInfoEightWorkLoading",
"Post > @/eightwork/eightworkInfo/dangerWorkStatistics",
);
export const getKeyProjectLargeScreenStatistics = declareRequest(
"indexInfoKeyProjectLoading",
"Post > @/keyProject/keyProject/largeScreenStatistics",
);

View File

@ -199,7 +199,7 @@ export const portUtilsList = [
{
img: bottomImg6,
checkImg: bottomImg6On,
label: "危险作业",
label: "重点作业",
type: "danger",
list: [
{

View File

@ -0,0 +1,37 @@
import moreIcon from "~/assets/images/public/bigScreen/more1.png";
import "./index.less";
/** 顶部“管理九项”导航仅负责展示当前大屏菜单。 */
function ManagementNav() {
const items = [
"安全管理台账",
"双重预防管理",
"相关方管理",
"现场重点监管",
"消防应急管理",
"安全教育培训",
"综合查询(同比、环比 )",
"综合考评管理",
"科技兴安",
];
return (
<div className="index-info-management-nav">
<div className="index-info-management-nav__title">
管理九项
<img src={moreIcon} alt="" />
</div>
<div className="index-info-management-nav__items">
{items.map((item, index) => (
<div
className={`index-info-management-nav__item ${index === 1 ? "index-info-management-nav__item--active" : ""}`}
key={item}
>
{item}
</div>
))}
</div>
</div>
);
}
export default ManagementNav;

View File

@ -0,0 +1,29 @@
.index-info-management-nav {
display: flex;
margin-bottom: 10px;
color: #fff;
}
.index-info-management-nav__title {
padding: 5px 10px;
background: #074abe;
border-radius: 2px;
}
.index-info-management-nav__items {
display: flex;
margin-left: 2px;
line-height: 30px;
background: rgba(1, 50, 115, 0.5);
}
.index-info-management-nav__item {
padding: 0 10px;
font-size: 13px;
}
.index-info-management-nav__item:hover,
.index-info-management-nav__item--active {
cursor: pointer;
background: #011d41;
}

View File

@ -0,0 +1,57 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import background from "~/assets/images/public/bigScreen/bg13.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责查询并展示相关方单位备案和项目执行统计。 */
function RecordStatsPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getXgfStatisticsListRecordProjectStatistics();
setList(data);
};
loadList();
}, []);
return (
<Panel
title="相关方单位备案与项目执行统计"
className="index-info-bottom__record-stats"
>
<Spin spinning={props.bi.indexInfoXgfManagerProjectLoading}>
<div
className="index-info-record-stats__table"
style={{ backgroundImage: `url(${background})` }}
>
<div className="index-info-record-stats__header">
<div>备案类型</div>
<div>主管部门</div>
<div>相关方单位备案情况</div>
<div>项目执行情况统计</div>
<div>人员培训情况统计</div>
</div>
<div className="index-info-record-stats__body">
<SeamlessScroll list={list} step={0.5}>
{list.map((item, index) => (
<div className="index-info-record-stats__row" key={index}>
<div>{item.qualificationsTypeName}</div>
<div>{item.managerDeptName}</div>
<div>{`${item.completedRecordCount}/${item.applyRecordCount}`}</div>
<div>{`${item.executingProjectCount}/${item.projectCount}`}</div>
<div>{`${item.trainingPassedCount}/${item.projectUserCount}`}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(RecordStatsPanel);

View File

@ -0,0 +1,37 @@
.index-info-bottom__record-stats {
padding: 10px;
border: 1px solid rgba(44, 105, 172, 0.6);
border-radius: 4px;
background: rgba(0, 41, 82, 0.68);
}
.index-info-record-stats__table {
width: 870px;
height: 160px;
margin-top: 10px;
color: #fff;
background-size: 100% 100%;
}
.index-info-record-stats__header,
.index-info-record-stats__row {
display: grid;
grid-template-columns: repeat(5, 1fr);
padding: 5px;
text-align: center;
}
.index-info-record-stats__header {
padding: 10px 5px;
font-weight: bold;
}
.index-info-record-stats__body {
height: 140px;
overflow-y: hidden;
}
.index-info-record-stats__row:hover {
background-color: rgba(14, 197, 208, 0.1);
box-shadow: 0 0 1px #00e7ff;
}

View File

@ -0,0 +1,87 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { message, Spin } from "antd";
import { useEffect, useState } from "react";
import AliPlayer from "zy-react-library/components/Video/AliPlayer";
import { randoms } from "zy-react-library/utils";
import background from "~/assets/images/public/bigScreen/bg14.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责加载摄像头列表、切换企业并请求当前播放地址。 */
function VideoPatrolPanel(props) {
const [list, setList] = useState([]);
const [active, setActive] = useState("");
const [playUrl, setPlayUrl] = useState("");
const loadPlayUrl = async (cameraNumber) => {
const { data, success } = await props.getFixedCameraPlayUrl({
indexCode: cameraNumber,
});
if (success)
setPlayUrl(data.url);
};
const selectCorp = (item) => {
setActive(item.corpinfoName);
if (!item.fixedCameraCOList.length) {
message.warning("暂无视频");
setPlayUrl("");
return;
}
loadPlayUrl(
item.fixedCameraCOList[
Math.floor(randoms(0, item.fixedCameraCOList.length - 1))
].cameraNumber,
);
};
useEffect(() => {
const loadVideoList = async () => {
const { data } = await props.getFixedCameraVideoList();
setList(data);
if (data.length) {
selectCorp(data[0]);
}
};
loadVideoList();
}, []);
return (
<Panel title="视频巡屏" className="index-info-bottom__video-patrol">
<div className="index-info-video-patrol__content">
<Spin spinning={props.bi.indexInfoVideoPatrolLoading}>
<div className="index-info-video-patrol__menu">
{list.map(item => (
<div
className={`index-info-video-patrol__menu-item ${item.corpinfoName === active ? "index-info-video-patrol__menu-item--active" : ""}`}
key={item.corpinfoName}
onClick={() => selectCorp(item)}
>
{item.corpinfoName}
</div>
))}
</div>
</Spin>
<div
className="index-info-video-patrol__screen"
style={{ backgroundImage: `url(${background})` }}
>
<Spin
spinning={
props.bi.indexInfoVideoPatrolLoading
|| props.bi.indexInfoVideoPatrolUrlLoading
}
>
{playUrl
? (
<AliPlayer source={playUrl} height="100%" isLive />
)
: (
<div className="index-info-video-patrol__empty">暂无视频</div>
)}
</Spin>
</div>
</div>
</Panel>
);
}
export default Connect([NS_BI], true)(VideoPatrolPanel);

View File

@ -0,0 +1,49 @@
.index-info-bottom__video-patrol {
padding: 10px;
border: 1px solid rgba(44, 105, 172, 0.6);
border-radius: 4px;
background: rgba(0, 41, 82, 0.68);
}
.index-info-video-patrol__content {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.index-info-video-patrol__menu {
width: 120px;
height: 180px;
padding: 5px;
overflow-y: auto;
color: #fff;
line-height: 30px;
text-align: center;
background: rgb(13, 56, 119);
border-radius: 5px;
}
.index-info-video-patrol__menu-item {
margin-bottom: 5px;
background: rgba(18, 96, 181, 0.4);
border-radius: 5px;
cursor: pointer;
}
.index-info-video-patrol__menu-item--active,
.index-info-video-patrol__menu-item:hover {
background: rgb(18, 96, 181);
}
.index-info-video-patrol__screen {
flex: 1;
margin-left: 10px;
padding: 10px;
background-size: 100% 100%;
}
.index-info-video-patrol__empty {
color: #fff;
line-height: 160px;
text-align: center;
}

View File

@ -1,92 +1,19 @@
import AliPlayer from "zy-react-library/components/Video/AliPlayer";
import img2 from "~/assets/images/public/bigScreen/bg13.png";
import img3 from "~/assets/images/public/bigScreen/bg14.png";
import img4 from "~/assets/images/public/bigScreen/more1.png";
import Title from "~/pages/Container/Map/components/Content/IndexInfo/Title";
// import ManagementNav from "./ManagementNav";
import RecordStatsPanel from "./RecordStatsPanel";
import VideoPatrolPanel from "./VideoPatrolPanel";
import "./index.less";
function BottomScreen() {
/** 底部区域仅组合管理导航、备案统计与视频巡屏。 */
function Bottom() {
return (
<div className="bottom-container_con">
<div className="top_container">
<div className="title">
管理九项
<img src={img4} alt="" />
</div>
<div className="con">
<div className="item">安全管理台账</div>
<div className="item active">双重预防管理</div>
<div className="item">相关方管理</div>
<div className="item">现场重点监管</div>
<div className="item">消防应急管理</div>
<div className="item">安全教育培训</div>
<div className="item">综合查询同比环比 )</div>
<div className="item">综合考评管理</div>
<div className="item">科技兴安</div>
</div>
</div>
<div className="bottom-container">
<div className="left">
<Title title="相关方单位备案与项目执行统计" />
<div className="main" style={{ backgroundImage: `url(${img2})` }}>
<div className="table">
<div className="head">
<div>备案类型</div>
<div>主管部门</div>
<div>相关方单位备案情况</div>
<div>项目执行情况统计</div>
<div>人员培训情况统计</div>
</div>
<div className="table-container">
<div className="table-item">新益公司</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
</div>
<div className="table-container">
<div className="table-item">新益公司</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
</div>
<div className="table-container">
<div className="table-item">新益公司</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
</div>
<div className="table-container">
<div className="table-item">新益公司</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
<div className="table-item">23/26</div>
</div>
</div>
</div>
</div>
<div className="right">
<Title title="视频巡屏" />
<div className="main">
<div className="menu">
<div className="list active">新益公司</div>
<div className="list">二公司</div>
<div className="list">六公司</div>
<div className="list">七公司</div>
<div className="list">九公司</div>
</div>
<div className="video-container" style={{ backgroundImage: `url(${img3})` }}>
<AliPlayer source="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4" height="100%" isLive />
</div>
</div>
</div>
<div className="index-info-bottom">
{/* <ManagementNav /> */}
<div className="index-info-bottom__content">
<RecordStatsPanel />
<VideoPatrolPanel />
</div>
</div>
);
}
export default BottomScreen;
export default Bottom;

View File

@ -1,160 +1,23 @@
.index_info_container {
.bottom-container_con {
width: calc(100% - 880px);
height: 240px;
position: absolute;
z-index: 2;
bottom: -1030px;
left: 50%;
transform: translateX(-50%);
.top_container {
display: flex;
color: #ffffff;
margin-bottom: 10px;
.title {
background: #074abe;
color: #ffffff;
padding: 5px 10px;
border-radius: 2px;
}
.con {
display: flex;
background: rgba(1, 50, 115, 0.5);
line-height: 30px;
margin-left: 2px;
.item {
padding: 0 10px;
font-size: 13px;
&:hover {
cursor: pointer;
background: #011d41;
}
}
.active {
background: #011d41;
}
}
}
.bottom-container {
display: flex;
justify-content: space-between;
gap: 10px;
.left {
width: 66%;
background: rgba(0, 41, 82, 0.68);
border-radius: 4px;
border: 1px solid rgba(44, 105, 172, 0.6);
padding: 10px;
.main {
width: 870px;
height: 160px;
background-size: 100% 100%;
margin-top: 10px;
color: #ffffff;
.table {
margin-top: 10px;
.head {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 10px 5px;
text-align: center;
font-weight: bold;
}
.table-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 5px;
margin: 0 auto;
text-align: center;
.fc1 {
color: #0c90ff;
}
.fc2 {
color: #62b13f;
}
.fc3 {
color: #ffa105;
}
&:hover {
background-color: rgba(14, 197, 208, 0.1);
box-shadow: 0 0 1px #00e7ff;
}
}
}
}
}
.right {
width: 33%;
background: rgba(0, 41, 82, 0.68);
border-radius: 4px;
border: 1px solid rgba(44, 105, 172, 0.6);
padding: 10px;
.main {
display: flex;
justify-content: space-between;
margin-top: 10px;
.menu {
width: 120px;
border-radius: 5px;
background-color: rgb(13, 56, 119);
box-shadow: inset 0px 2px 2px 0px rgba(35, 24, 21, 0.17);
height: 180px;
color: #ffffff;
text-align: center;
line-height: 30px;
padding: 5px;
.list {
border-radius: 5px;
background-color: rgba(18, 96, 181, 0.4);
box-shadow: 0 2px 1px 0 rgba(2, 32, 95, 0.4);
margin-bottom: 5px;
&:hover {
border-radius: 5px;
background-color: rgb(18, 96, 181);
box-shadow: 0px 2px 1px 0px rgba(2, 32, 95, 0.4);
cursor: pointer;
}
}
.active {
border-radius: 5px;
background-color: rgb(18, 96, 181);
box-shadow: 0px 2px 1px 0px rgba(2, 32, 95, 0.4);
cursor: pointer;
}
}
.video-container {
flex: 1;
margin-left: 10px;
padding: 10px;
}
}
}
}
}
.index-info-bottom {
position: absolute;
z-index: 2;
bottom: -1070px;
left: 50%;
width: calc(100% - 880px);
height: 240px;
transform: translateX(-50%);
}
.index-info-bottom__content {
display: flex;
justify-content: space-between;
gap: 10px;
}
.index-info-bottom__record-stats {
width: 66%;
}
.index-info-bottom__video-patrol {
width: 33%;
}

View File

@ -0,0 +1,89 @@
import detailBackground from "~/assets/images/public/bigScreen/bg9.png";
import summaryBackground from "~/assets/images/public/bigScreen/bg10.png";
import warningIcon from "~/assets/images/public/bigScreen/ico3.png";
import Panel from "../../Panel";
import "./index.less";
/** 展示当前重大危险源及报警处置的固定大屏信息。 */
function HazardSourcePanel() {
return (
<Panel
title="重大危险源运行情况"
className="index-info-left-panel__hazard-source"
>
<div className="index-info-hazard-source__warning">
<img src={warningIcon} alt="" />
北区二号罐液位过低
</div>
<div className="index-info-hazard-source__group">
<HazardSummary
background={summaryBackground}
title="二级重大危险源1个"
count="3"
disabled="2"
/>
<HazardSummary
background={summaryBackground}
title="三级重大危险源2个"
count="10"
disabled="0"
/>
</div>
<div className="index-info-hazard-source__group">
<div
className="index-info-hazard-source__detail-card"
style={{ backgroundImage: `url(${detailBackground})` }}
>
<div>
东罐区二号罐
<span>正常</span>
</div>
<div>
东罐区二号罐
<b>液位低</b>
</div>
<div>
东罐区二号罐
<span>正常</span>
</div>
</div>
<div
className="index-info-hazard-source__detail-card"
style={{ backgroundImage: `url(${detailBackground})` }}
>
<strong>报警处置情况</strong>
<p>温度待处置数/报警个数0/0</p>
<p>压力待处置数/报警个数0/0</p>
<p>液位待处置数/报警个数1/1</p>
</div>
</div>
</Panel>
);
}
function HazardSummary({ background, title, count, disabled }) {
return (
<div
className="index-info-hazard-source__summary-card"
style={{ backgroundImage: `url(${background})` }}
>
<strong>{title}</strong>
<div className="index-info-hazard-source__statistics">
<span>
储罐数
{count}
</span>
<span>
再用数
{count}
</span>
<span>
停用数
<b>{disabled}</b>
</span>
</div>
</div>
);
}
export default HazardSourcePanel;

View File

@ -0,0 +1,75 @@
.index-info-hazard-source__warning {
margin: 10px auto;
padding: 5px;
color: #fff;
font-weight: bold;
border: 1px solid rgba(255, 0, 0, 0.5);
border-radius: 2px;
background: rgba(16, 36, 93, 0.659);
}
.index-info-hazard-source__warning img {
vertical-align: middle;
}
.index-info-hazard-source__group {
display: flex;
justify-content: space-between;
}
.index-info-hazard-source__summary-card,
.index-info-hazard-source__detail-card {
width: 48%;
padding: 5px;
color: #fff;
background-size: 100% 100%;
font-size: 12px;
}
.index-info-hazard-source__summary-card {
height: 91px;
}
.index-info-hazard-source__detail-card {
height: 117px;
}
.index-info-hazard-source__statistics {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.index-info-hazard-source__statistics span {
width: 50%;
margin: 2px 0;
}
.index-info-hazard-source__statistics b,
.index-info-hazard-source__detail-card b {
color: #f90102;
}
.index-info-hazard-source strong {
display: block;
}
.index-info-hazard-source__detail-card strong {
color: #00aeff;
}
.index-info-hazard-source__detail-card p {
margin: 2px 0;
line-height: 22px;
}
.index-info-hazard-source__detail-card > div {
display: flex;
justify-content: space-between;
line-height: 30px;
border-bottom: 1px solid #163682;
}
.index-info-hazard-source__detail-card span {
color: #7ccf41;
}

View File

@ -0,0 +1,65 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import tableHeaderBackground from "~/assets/images/public/bigScreen/tablebg1.png";
import tableRowBackground from "~/assets/images/public/bigScreen/tablebg2.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责查询并展示各公司隐患整改统计。 */
function RectificationPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getHiddenStatisticsByCorp({
pageIndex: 1,
pageSize: 999,
});
setList(data);
};
loadList();
}, []);
return (
<Panel
title="当前各公司隐患整改情况"
className="index-info-left-panel__rectification"
>
<Spin spinning={props.bi.indexInfoHiddenLoading}>
<div className="index-info-rectification__table">
<div
className="index-info-rectification__header"
style={{ backgroundImage: `url(${tableHeaderBackground})` }}
>
<div>公司名称</div>
<div>发现隐患数</div>
<div>整改隐患数</div>
<div>待整改</div>
<div>待验收</div>
</div>
<div className="index-info-rectification__body">
<SeamlessScroll list={list} step={0.5}>
{list.map((item, index) => (
<div
className="index-info-rectification__row"
style={{ backgroundImage: `url(${tableRowBackground})` }}
key={index}
>
<div>{item.corpName}</div>
<div>{item.findHiddenCount}</div>
<div>{item.rectifyHiddenCount}</div>
<div>{item.waitRectifyHiddenCount}</div>
<div>{item.waitAcceptHiddenCount}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(RectificationPanel);

View File

@ -0,0 +1,29 @@
.index-info-rectification__table {
margin-top: 10px;
}
.index-info-rectification__header,
.index-info-rectification__row {
display: grid;
grid-template-columns: repeat(5, 1fr);
padding: 5px;
color: #fff;
font-size: 12px;
text-align: center;
}
.index-info-rectification__header {
background: rgba(39, 101, 175, 0.5);
}
.index-info-rectification__row {
margin: 5px auto;
background-color: rgba(17, 51, 122, 0.5);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.index-info-rectification__body {
height: 145px;
overflow-y: hidden;
}

View File

@ -0,0 +1,98 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import tableHeaderBackground from "~/assets/images/public/bigScreen/tablebg1.png";
import tableRowBackground from "~/assets/images/public/bigScreen/tablebg2.png";
import temperatureIcon from "~/assets/images/public/bigScreen/w_ico1.png";
import windIcon from "~/assets/images/public/bigScreen/w_ico2.png";
import { NS_BI } from "~/enumerate/namespace";
import { getWeatherIcon } from "~/utils/weather";
import Panel from "../../Panel";
import "./index.less";
/** 负责加载并展示天气预警与应急报警信息。 */
function WeatherPanel(props) {
const [weather, setWeather] = useState({});
const [emergencyList, setEmergencyList] = useState([]);
useEffect(() => {
const loadData = async () => {
const [{ result }, { data }] = await Promise.all([
props.getWeather(),
props.getEventReportListUnfinished(),
]);
setWeather({
...result.now,
alertTitle: result.alerts?.[0]?.title || "当前暂无气象预警",
});
setEmergencyList(data);
};
loadData();
}, []);
return (
<Panel title="天气预报情况" className="index-info-left-panel__weather">
<Spin spinning={props.bi.indexInfoWeatherLoading}>
<div className="index-info-weather__summary">
<div className="index-info-weather__condition">
<img src={getWeatherIcon(weather.text)} alt="" />
{weather.text || "暂无"}
</div>
<div className="index-info-weather__metric">
<img src={temperatureIcon} alt="" />
<div className="index-info-weather__metric-content">
<div>温度</div>
<span>{weather.temp ? `${weather.temp}` : "--"}</span>
</div>
</div>
<div className="index-info-weather__metric">
<img src={windIcon} alt="" />
<div className="index-info-weather__metric-content">
<div>风速</div>
<span>{weather.wind_class || "--"}</span>
</div>
</div>
</div>
<div className="index-info-weather__alert">
{weather.alertTitle || "天气数据加载失败"}
</div>
</Spin>
<Spin spinning={props.bi.indexInfoEmergencyRescueLoading}>
<div className="index-info-weather__table">
<div
className="index-info-weather__table-header"
style={{ backgroundImage: `url(${tableHeaderBackground})` }}
>
<div>公司名称</div>
<div>报警处置状态</div>
<div>应急报警信息</div>
</div>
<div className="index-info-weather__table-body">
<SeamlessScroll list={emergencyList} step={0.5}>
{emergencyList.map((item, index) => (
<div
className="index-info-weather__table-row"
style={{ backgroundImage: `url(${tableRowBackground})` }}
key={index}
>
<div>{item.executorCorpName}</div>
<div>
{
{ 1: "未执行", 2: "已执行", 3: "进行中", 4: "已完成" }[
item.isRescueExecuted
]
}
</div>
<div>{item.eventTitle}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(WeatherPanel);

View File

@ -0,0 +1,56 @@
.index-info-weather__summary {
display: flex;
align-items: center;
margin-top: 10px;
color: #fff;
}
.index-info-weather__condition,
.index-info-weather__metric {
display: flex;
align-items: center;
width: 33%;
}
.index-info-weather__condition img {
width: 40px;
height: 40px;
}
.index-info-weather__metric img {
width: 42px;
height: 42px;
margin-right: 5px;
}
.index-info-weather__metric-content span {
font-size: 18px;
color: #00e7ff;
}
.index-info-weather__alert {
margin-top: 10px;
color: #fe9e00;
font-weight: bold;
}
.index-info-weather__table {
margin-top: 10px;
}
.index-info-weather__table-header,
.index-info-weather__table-row {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
gap: 5px;
padding: 5px;
color: #fff;
font-size: 12px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.index-info-weather__table-body {
height: 100px;
overflow-y: hidden;
}

View File

@ -0,0 +1,160 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { useMount } from "ahooks";
import { Spin } from "antd";
import * as echarts from "echarts";
import { useRef } from "react";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责初始化领域工作统计图表,并在卸载时销毁图表实例。 */
function WorkStatusPanel(props) {
const chartInstance = useRef(null);
const chartRef = useRef(null);
const initEcharts = (main1Ref, chartInstance, data) => {
chartInstance.current = echarts.init(main1Ref.current);
const domainTypeName = data.map(item => item.domainTypeName);
const scoredCount = data.map(item => item.scoredCount);
const noScoreCount = data.map(item => item.noScoreCount);
const option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
grid: {
left: "10%",
top: "20%",
right: "10%",
bottom: "25%",
},
legend: {
data: ["已评分", "未评分"],
top: "0%",
right: "3%",
textStyle: {
color: "#FFFFFF",
fontSize: 12,
},
},
dataZoom: [
{
type: "inside",
xAxisIndex: 0,
start: 0,
end: 50,
zoomOnMouseWheel: "shift",
moveOnMouseWheel: true,
moveOnMouseMove: true,
},
{
type: "slider",
height: 6,
bottom: "7%",
show: true,
start: 0,
end: 40,
handleSize: 5,
handleStyle: {
color: "#DCE2E8",
},
xAxisIndex: [0],
filterMode: "filter",
showDetail: false,
},
],
xAxis: {
data: domainTypeName,
axisLine: {
show: false,
},
axisTick: {
show: false,
alignWithLabel: true,
},
axisLabel: {
show: true,
color: "#FFFFFF",
fontSize: 12,
margin: 12,
},
},
yAxis: [
{
type: "value",
nameTextStyle: {
color: "#FFFFFF",
fontSize: 12,
},
splitLine: {
show: true,
lineStyle: {
color: "#fff",
type: "dashed",
},
},
axisTick: {
show: false,
},
axisLine: {
show: false,
},
axisLabel: {
show: true,
color: "#FFFFFF",
fontSize: 12,
},
},
],
series: [
{
name: "已评分",
type: "bar",
barWidth: 10,
yAxisIndex: 0,
itemStyle: {
color: "#53ed06",
},
data: scoredCount,
},
{
name: "未评分",
type: "bar",
barWidth: 10,
yAxisIndex: 0,
itemStyle: {
color: "#FF0606",
},
data: noScoreCount,
},
],
};
chartInstance.current.setOption(option);
};
useMount(() => {
const loadChartData = async () => {
const { data } = await props.getProjectTaskScoreCount();
initEcharts(chartRef, chartInstance, data);
};
loadChartData();
return () => chartInstance.current?.dispose();
});
return (
<Panel
title="领域工作情况统计"
className="index-info-left-panel__work-status"
>
<Spin spinning={props.bi.indexInfoDomainLoading}>
<div ref={chartRef} className="index-info-work-status__chart" />
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(WorkStatusPanel);

View File

@ -0,0 +1,4 @@
.index-info-work-status__chart {
width: 100%;
height: 180px;
}

View File

@ -1,118 +0,0 @@
import * as echarts from "echarts";
export const initEcharts1 = (main1Ref, chartInstance, data) => {
chartInstance.current = echarts.init(main1Ref.current);
const companyNames = data.map(item => item.name);
const hazardCounts = data.map(item => item.hazardCount);
const unrectifiedCounts = data.map(item => item.unrectifiedCount);
const option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
grid: {
left: "10%",
top: "28%",
right: "10%",
bottom: "25%",
},
legend: {
data: ["已评分", "未评分"],
top: "0%",
right: "3%",
textStyle: {
color: "#FFFFFF",
fontSize: 12,
},
},
dataZoom: [
{
type: "slider",
height: 6,
bottom: "7%",
show: true,
start: 0,
end: 40,
handleSize: 5,
handleStyle: {
color: "#DCE2E8",
},
xAxisIndex: [0],
filterMode: "filter",
showDetail: false,
},
],
xAxis: {
data: companyNames,
axisLine: {
show: false,
},
axisTick: {
show: false,
alignWithLabel: true,
},
axisLabel: {
show: true,
color: "#FFFFFF",
fontSize: 12,
margin: 12,
interval: 0,
},
},
yAxis: [
{
type: "value",
nameTextStyle: {
color: "#FFFFFF",
fontSize: 12,
},
splitLine: {
show: true,
lineStyle: {
color: "#000000",
type: "solid",
},
},
axisTick: {
show: false,
},
axisLine: {
show: false,
},
axisLabel: {
show: true,
color: "#FFFFFF",
fontSize: 12,
},
},
],
series: [
{
name: "已评分",
type: "bar",
barWidth: 10,
yAxisIndex: 0,
itemStyle: {
color: "#C5993B",
},
data: hazardCounts,
},
{
name: "未评分",
type: "bar",
barWidth: 10,
yAxisIndex: 0,
itemStyle: {
color: "#FF0606",
},
data: unrectifiedCounts,
},
],
};
chartInstance.current.setOption(option);
};

View File

@ -1,222 +1,24 @@
import { useMount } from "ahooks";
import { useEffect, useRef, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import img9 from "~/assets/images/public/bigScreen/bg9.png";
import img8 from "~/assets/images/public/bigScreen/bg10.png";
import img7 from "~/assets/images/public/bigScreen/ico3.png";
import rightbg from "~/assets/images/public/bigScreen/leftbg.png";
import img5 from "~/assets/images/public/bigScreen/tablebg1.png";
import img6 from "~/assets/images/public/bigScreen/tablebg2.png";
import img3 from "~/assets/images/public/bigScreen/w_ico1.png";
import img4 from "~/assets/images/public/bigScreen/w_ico2.png";
import Title from "~/pages/Container/Map/components/Content/IndexInfo/Title";
import { getWeather, getWeatherIcon } from "~/utils/weather";
import { initEcharts1 } from "./echarts";
import HazardSourcePanel from "./HazardSourcePanel";
import RectificationPanel from "./RectificationPanel";
import WeatherPanel from "./WeatherPanel";
import WorkStatusPanel from "./WorkStatusPanel";
import "./index.less";
function LeftScreen() {
const [weather, setWeather] = useState({});
const [block1List, setBlock1List] = useState([
{ id: 1, companyName: "新益公司", status: 0, preventiveMeasures: "远离大树、电线杆、简易房等..." },
{ id: 2, companyName: "华泰化工", status: 1, preventiveMeasures: "加固设备、检查管道连接..." },
{ id: 3, companyName: "宏达制造", status: 2, preventiveMeasures: "暂停户外作业、检查电气设备..." },
{ id: 4, companyName: "金鼎能源", status: 0, preventiveMeasures: "关闭通风设备、加强监测..." },
{ id: 5, companyName: "瑞丰新材料", status: 1, preventiveMeasures: "疏散人员、设置警戒线..." },
{ id: 6, companyName: "恒通物流", status: 2, preventiveMeasures: "暂停运输作业、固定货物..." },
{ id: 7, companyName: "天成建筑", status: 0, preventiveMeasures: "停止高空作业、加固脚手架..." },
{ id: 8, companyName: "绿源环保", status: 1, preventiveMeasures: "启动应急预案、检测环境指标..." },
{ id: 9, companyName: "安泰消防", status: 2, preventiveMeasures: "配备消防器材、加强巡查..." },
{ id: 10, companyName: "创新科技", status: 0, preventiveMeasures: "断电保护、转移重要设备..." },
]);
const [block4List, setBlock4List] = useState([
{ id: 1, companyName: "新益公司", foundHazards: 123, resolvedHazards: 120, pendingResolution: 2, pendingAcceptance: 1 },
{ id: 2, companyName: "华泰化工", foundHazards: 85, resolvedHazards: 80, pendingResolution: 3, pendingAcceptance: 2 },
{ id: 3, companyName: "宏达制造", foundHazards: 67, resolvedHazards: 65, pendingResolution: 1, pendingAcceptance: 1 },
{ id: 4, companyName: "金鼎能源", foundHazards: 156, resolvedHazards: 145, pendingResolution: 8, pendingAcceptance: 3 },
{ id: 5, companyName: "瑞丰新材料", foundHazards: 42, resolvedHazards: 40, pendingResolution: 1, pendingAcceptance: 1 },
{ id: 6, companyName: "恒通物流", foundHazards: 78, resolvedHazards: 75, pendingResolution: 2, pendingAcceptance: 1 },
{ id: 7, companyName: "天成建筑", foundHazards: 93, resolvedHazards: 88, pendingResolution: 4, pendingAcceptance: 1 },
{ id: 8, companyName: "绿源环保", foundHazards: 56, resolvedHazards: 54, pendingResolution: 1, pendingAcceptance: 1 },
{ id: 9, companyName: "安泰消防", foundHazards: 112, resolvedHazards: 110, pendingResolution: 1, pendingAcceptance: 1 },
{ id: 10, companyName: "创新科技", foundHazards: 71, resolvedHazards: 69, pendingResolution: 1, pendingAcceptance: 1 },
]);
const chartInstance = useRef(null);
const main1Ref = useRef(null);
const loadWeather = async () => {
const result = await getWeather();
setWeather({
...result.now,
alertTitle: result.alerts?.[0]?.title || "当前暂无气象预警",
});
};
useEffect(() => {
loadWeather();
}, []);
useMount(() => {
initEcharts1(main1Ref, chartInstance, [
{ name: "新益公司", hazardCount: 123, unrectifiedCount: 23 },
{ name: "华泰化工", hazardCount: 85, unrectifiedCount: 15 },
{ name: "宏达制造", hazardCount: 67, unrectifiedCount: 12 },
{ name: "金鼎能源", hazardCount: 156, unrectifiedCount: 32 },
{ name: "瑞丰新材料", hazardCount: 42, unrectifiedCount: 8 },
{ name: "恒通物流", hazardCount: 78, unrectifiedCount: 18 },
{ name: "天成建筑", hazardCount: 93, unrectifiedCount: 23 },
{ name: "绿源环保", hazardCount: 56, unrectifiedCount: 11 },
{ name: "安泰消防", hazardCount: 112, unrectifiedCount: 22 },
{ name: "创新科技", hazardCount: 71, unrectifiedCount: 16 },
]);
return () => {
if (chartInstance.current) {
chartInstance.current.dispose();
chartInstance.current = null;
}
};
});
/** 左侧信息区域仅负责按页面展示顺序组合业务区块。 */
function LeftPanel() {
return (
<div className="left-container">
<div className="left-container_bg" style={{ backgroundImage: `url(${rightbg})` }}></div>
<div className="block1">
<Title title="天气预报情况" />
<div className="main">
<div className="list1">
<img src={getWeatherIcon(weather?.text)} alt="" className="img1" />
<div>{weather?.text || "暂无数据"}</div>
</div>
<div className="list1">
<img src={img3} alt="" className="img" />
<div className="info">
<div>温度</div>
<div className="temp">{weather?.temp ? `${weather?.temp}` : "--"}</div>
</div>
</div>
<div className="list1">
<img src={img4} alt="" className="img" />
<div className="info">
<div>风速</div>
<div className="temp">{weather?.wind_class || "--"}</div>
</div>
</div>
</div>
<div className="info">{weather?.alertTitle || "天气数据加载失败"}</div>
<div className="table">
<div className="head" style={{ backgroundImage: `url(${img5})` }}>
<div>公司名称</div>
<div>报警处置状态</div>
<div>应急报警信息</div>
</div>
<div className="scroll">
<SeamlessScroll list={block1List} step={0.5}>
{block1List.map((item, index) => (
<div className="table-container" style={{ backgroundImage: `url(${img6})` }} key={index}>
<div className="table-item">{item.companyName}</div>
<div className={`table-item ${item.status === 0 ? "fc1" : ""} ${item.status === 1 ? "fc2" : ""} ${item.status === 2 ? "fc3" : ""} `}>
{item.status === 0 ? "未处置" : item.status === 1 ? "已处置" : "处置中"}
</div>
<div className="table-item">{item.preventiveMeasures}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</div>
<div className="block2">
<Title title="重大危险源运行情况" />
<div className="main">
<div className="warning">
<img src={img7} alt="" />
北区二号罐液位过低
</div>
<div className="main_item">
<div className="list" style={{ backgroundImage: `url(${img8})`, height: 91 }}>
<div className="title">二级重大危险源1</div>
<div className="main_con">
<div className="item">储罐数3</div>
<div className="item ">再用数3</div>
<div className="item ">
停用数
<span className="fcr">2</span>
</div>
</div>
</div>
<div className="list" style={{ backgroundImage: `url(${img8})`, height: 91 }}>
<div className="title">三级重大危险源2</div>
<div className="main_con">
<div className="item">储罐数10</div>
<div className="item ">再用数10</div>
<div className="item ">
停用数
<span className="fcr">0</span>
</div>
</div>
</div>
</div>
<div className="main_item">
<div className="list" style={{ backgroundImage: `url(${img9})`, height: 117 }}>
<div className="item_list">
<div className="info">东罐区二号罐</div>
<div className="state">正常</div>
</div>
<div className="item_list">
<div className="info">东罐区二号罐</div>
<div className="state fcr">液位低</div>
</div>
<div className="item_list">
<div className="info">东罐区二号罐</div>
<div className="state">正常</div>
</div>
</div>
<div className="list" style={{ backgroundImage: `url(${img9})`, height: 117 }}>
<div className="title fcb">报警处置情况</div>
<div className="main_con1">
<div className="item">温度待处置数/报警个数0/0 </div>
<div className="item ">压力待处置数/报警个数0/0</div>
<div className="item ">液位待处置数/报警个数1/1</div>
</div>
</div>
</div>
</div>
</div>
<div className="block3">
<Title title="领域工作情况统计" />
<div className="main">
<div ref={main1Ref} style={{ width: "100%", height: "180px" }} />
</div>
</div>
<div className="block4">
<Title title="当前各公司隐患整改情况" />
<div className="main">
<div className="table">
<div className="head" style={{ backgroundImage: `url(${img5})` }}>
<div>公司名称</div>
<div>发现隐患数</div>
<div>整改隐患数</div>
<div>待整改</div>
<div>待验收</div>
</div>
<div className="scroll">
<SeamlessScroll list={block4List} step={0.5}>
{block4List.map((item, index) => (
<div className="table-container" style={{ backgroundImage: `url(${img6})` }} key={index}>
<div className="table-item">{item.companyName}</div>
<div className="table-item">{item.foundHazards}</div>
<div className="table-item">{item.resolvedHazards}</div>
<div className="table-item">{item.pendingResolution}</div>
<div className="table-item">{item.pendingAcceptance}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</div>
</div>
<div className="index-info-left-panel">
<div
className="index-info-left-panel__background"
style={{ backgroundImage: `url(${rightbg})` }}
/>
<WeatherPanel />
<HazardSourcePanel />
<WorkStatusPanel />
<RectificationPanel />
</div>
);
}
export default LeftScreen;
export default LeftPanel;

View File

@ -1,247 +1,24 @@
.index_info_container {
.left-container_bg{
width: 600px;
height: 100%;
background-size: 100% 100%;
background-repeat: no-repeat;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.left-container {
width: 400px;
position: absolute;
left: 20px;
top: 60px;
max-height: calc(100vh - 75px);
.block1 {
border-radius: 4px;
.main {
display: flex;
align-items: center;
margin-top: 10px;
.list1 {
display: flex;
color: #ffffff;
align-items: center;
width: 33%;
text-align: center;
.img1 {
width: 40px;
height: 40px;
}
.img {
width: 42px;
height: 42px;
margin-right: 5px;
}
.temp {
font-size: 18px;
color: #00e7ff;
}
}
}
.info {
color: #fe9e00;
font-weight: bold;
margin-top: 10px;
}
.table {
margin-top: 10px;
.head {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
color: #ffffff;
padding: 5px;
font-size: 12px;
}
.scroll {
height: 100px;
overflow-y: hidden;
.table-container {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
color: #ffffff;
padding: 5px;
font-size: 12px;
margin: 5px auto;
.fc1 {
color: #0c90ff;
}
.fc2 {
color: #62b13f;
}
.fc3 {
color: #ffa105;
}
}
}
}
}
.block2 {
margin-top: 10px;
border-radius: 4px;
.main {
.warning {
border-style: solid;
border-width: 1px;
border-color: rgb(255, 0, 0, 0.5);
border-radius: 2px;
background-color: rgba(16, 36, 93, 0.659);
color: #ffffff;
padding: 5px;
vertical-align: middle;
font-weight: bold;
margin: 10px auto;
}
.mt10 {
margin-top: 10px;
}
.main_item {
display: flex;
justify-content: space-between;
.list {
width: 48%;
background-size: 100% 100%;
padding: 5px;
color: #ffffff;
.title {
font-weight: bold;
}
.main_con {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.item {
width: 50%;
margin: 2px 0;
font-size: 12px;
.fcr {
color: #f90102;
}
}
}
.fcb {
color: #00aeff;
}
.main_con1 {
.item {
margin: 2px 0;
font-size: 12px;
line-height: 22px;
.fcr {
color: #f90102;
}
}
}
.item_list {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #163682;
font-size: 12px;
line-height: 30px;
.info {
width: 60%;
}
.state {
width: 40%;
text-align: right;
color: #7ccf41;
}
.fcr {
color: #f90102;
}
}
}
}
}
}
.block3 {
margin-top: 10px;
border-radius: 4px;
}
.block4 {
margin-top: 10px;
border-radius: 4px;
.main {
.table {
margin-top: 10px;
.head {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 5px;
font-size: 12px;
background: rgba(39, 101, 175, 0.5);
text-align: center;
}
.scroll {
height: 120px;
overflow-y: hidden;
.table-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 5px;
font-size: 12px;
margin: 5px auto;
background: rgba(17, 51, 122, 0.5);
text-align: center;
.fc1 {
color: #0c90ff;
}
.fc2 {
color: #62b13f;
}
.fc3 {
color: #ffa105;
}
}
}
}
}
}
}
.index-info-left-panel {
width: 400px;
position: absolute;
top: 60px;
left: 20px;
max-height: calc(100vh - 75px);
}
.index-info-left-panel__background {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 600px;
height: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.index-info-left-panel__hazard-source,
.index-info-left-panel__work-status,
.index-info-left-panel__rectification {
margin-top: 10px;
}

View File

@ -0,0 +1,21 @@
import titleBackground from "~/assets/images/public/bigScreen/smalltitle.png";
import "./index.less";
/**
* 大屏信息区块的统一外层负责展示标题背景并包裹区块业务内容
*/
function Panel({ title, children, className = "" }) {
return (
<section className={`index-info-panel ${className}`.trim()}>
<div
className="index-info-panel__title"
style={{ backgroundImage: `url(${titleBackground})` }}
>
{title}
</div>
<div className="index-info-panel__content">{children}</div>
</section>
);
}
export default Panel;

View File

@ -1,11 +1,11 @@
.index_info_container {
&_title {
color: #ffffff;
font-weight: bold;
padding-left: 30px;
.index-info-panel {
&__title {
width: 100%;
height: 30px;
background-size: 100% 100%;
padding-left: 30px;
color: #ffffff;
font-weight: bold;
background-repeat: no-repeat;
background-size: 100% 100%;
}
}

View File

@ -0,0 +1,59 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import tableHeaderBackground from "~/assets/images/public/bigScreen/tablebg1.png";
import tableRowBackground from "~/assets/images/public/bigScreen/tablebg2.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责查询并展示物联网设备报警记录。 */
function AlarmPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getAlarmRecordScreenIotDeviceAlarmPage();
setList(data);
};
loadList();
}, []);
return (
<Panel title="物联网设备报警情况" className="index-info-right-panel__alarm">
<Spin spinning={props.bi.indexInfoIotalarmLoading}>
<div className="index-info-alarm__table">
<div
className="index-info-alarm__header"
style={{ backgroundImage: `url(${tableHeaderBackground})` }}
>
<div>设备类型</div>
<div>所属单位</div>
<div>报警类型</div>
<div>处置状态</div>
</div>
<div className="index-info-alarm__body">
<SeamlessScroll list={list} step={0.5}>
{list.map((item, index) => (
<div
className="index-info-alarm__row"
style={{ backgroundImage: `url(${tableRowBackground})` }}
key={index}
>
<div>{item.alarmSourceName}</div>
<div>{item.corpName}</div>
<div>{item.alarmTypeName}</div>
<div>
{{ 10: "报警中", 20: "未处置", 30: "已消警" }[item.status]}
</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(AlarmPanel);

View File

@ -0,0 +1,29 @@
.index-info-alarm__table {
margin-top: 10px;
}
.index-info-alarm__header,
.index-info-alarm__row {
display: grid;
grid-template-columns: repeat(4, 1fr);
padding: 5px;
color: #fff;
text-align: center;
}
.index-info-alarm__header {
background-color: rgba(39, 101, 175, 0.5);
background-size: 100% 100%;
}
.index-info-alarm__row {
margin: 5px auto;
background-color: rgba(17, 51, 122, 0.5);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.index-info-alarm__body {
height: 290px;
overflow-y: hidden;
}

View File

@ -0,0 +1,38 @@
import closedBackground from "~/assets/images/public/bigScreen/bg11.png";
import gateBackground from "~/assets/images/public/bigScreen/bg12.png";
import Panel from "../../Panel";
import "./index.less";
/** 展示当前口门与封闭区的固定统计信息。 */
function GatePanel() {
const items = [
["一级口门进出统计", gateBackground],
["进入申请待审批", gateBackground],
["封闭区域人员情况", closedBackground],
["封闭区域作业情况", closedBackground],
];
return (
<Panel
title="当前口门、封闭区情况"
className="index-info-right-panel__gate"
>
<div className="index-info-gate__list">
{items.map(([title, background]) => (
<div
className="index-info-gate__item"
style={{ backgroundImage: `url(${background})` }}
key={title}
>
<strong>{title}</strong>
<div>
<span>人数2100</span>
<span>车数1125</span>
</div>
</div>
))}
</div>
</Panel>
);
}
export default GatePanel;

View File

@ -0,0 +1,20 @@
.index-info-gate__list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.index-info-gate__item {
width: 49%;
margin-top: 10px;
padding: 5px 10px;
color: #fff;
text-align: center;
background-size: 100% 100%;
}
.index-info-gate__item div {
display: flex;
justify-content: space-between;
margin-top: 5px;
}

View File

@ -0,0 +1,60 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import tableHeaderBackground from "~/assets/images/public/bigScreen/tablebg1.png";
import tableRowBackground from "~/assets/images/public/bigScreen/tablebg2.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 负责加载并展示相关方单位的资质、项目与人员统计。 */
function PartnerPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getXgfStatisticsListCorpStatistics();
setList(data);
};
loadList();
}, []);
return (
<Panel
title="相关方单位情况统计"
className="index-info-right-panel__partner"
>
<Spin spinning={props.bi.indexInfoXgfManagerLoading}>
<div className="index-info-partner__table">
<div
className="index-info-partner__header"
style={{ backgroundImage: `url(${tableHeaderBackground})` }}
>
<div>相关方单位名称</div>
<div>资质申请情况</div>
<div>项目执行情况</div>
<div>执行人员情况</div>
</div>
<div className="index-info-partner__body">
<SeamlessScroll list={list} step={0.5}>
{list.map((item, index) => (
<div
className="index-info-partner__row"
style={{ backgroundImage: `url(${tableRowBackground})` }}
key={index}
>
<div>{item.corpName}</div>
<div>{`${item.qualificationsPassedCount}/${item.qualificationsApplyCount}`}</div>
<div>{`${item.executingProjectCount}/${item.applyProjectCount}`}</div>
<div>{`${item.trainingPassedCount}/${item.projectUserCount}`}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(PartnerPanel);

View File

@ -0,0 +1,29 @@
.index-info-partner__table {
margin-top: 10px;
}
.index-info-partner__header,
.index-info-partner__row {
display: grid;
grid-template-columns: 1.5fr 1fr 1fr 1fr;
padding: 5px;
color: #fff;
text-align: center;
}
.index-info-partner__header {
background-color: rgba(39, 101, 175, 0.5);
background-size: 100% 100%;
}
.index-info-partner__row {
margin: 5px auto;
background-color: rgba(17, 51, 122, 0.5);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.index-info-partner__body {
height: 180px;
overflow-y: hidden;
}

View File

@ -0,0 +1,79 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useEffect, useState } from "react";
import threePersonIcon from "~/assets/images/public/bigScreen/ico6.png";
import dangerIcon from "~/assets/images/public/bigScreen/ico7.png";
import nightIcon from "~/assets/images/public/bigScreen/ico8.png";
import newWorkIcon from "~/assets/images/public/bigScreen/ico9.png";
import { NS_BI } from "~/enumerate/namespace";
import Panel from "../../Panel";
import "./index.less";
/** 展示重点作业类型及危险作业接口返回的实时数量。 */
function WorkPanel(props) {
const [list, setList] = useState([
{
name: "三人以上作业",
doingCount: 0,
appliedCount: 0,
image: threePersonIcon,
},
{ name: "危险作业", doingCount: 0, appliedCount: 0, image: dangerIcon },
{
name: "夜间作业",
doingCount: 0,
appliedCount: 0,
image: nightIcon,
},
{ name: "四新作业", doingCount: 0, appliedCount: 0, image: newWorkIcon },
]);
useEffect(() => {
const loadStatistics = async () => {
const { data: eightWorkData } = await props.getEightWorkInfoDangerWorkStatistics();
const { data: keyProjectData } = await props.getKeyProjectLargeScreenStatistics();
setList((prevState) => {
prevState[1].doingCount = eightWorkData.doingCount;
prevState[1].appliedCount = eightWorkData.appliedCount;
prevState[0].doingCount = keyProjectData.morePeopleStartCount;
prevState[0].appliedCount = keyProjectData.morePeopleApplyCount;
prevState[2].doingCount = keyProjectData.fourNewHomeworkStartCount;
prevState[2].appliedCount = keyProjectData.fourNewHomeworkApplyCount;
prevState[3].doingCount = keyProjectData.nightWorkStartCount;
prevState[3].appliedCount = keyProjectData.nightWorkApplyCount;
return [...prevState];
});
};
loadStatistics();
}, []);
return (
<Panel title="重点作业管理统计" className="index-info-right-panel__work">
<Spin spinning={props.bi.indexInfoEightWorkLoading}>
<div className="index-info-work__list">
{list.map(item => (
<div className="index-info-work__item" key={item.name}>
<img src={item.image} alt="" />
<div>
<strong>{item.name}</strong>
<p>
当前作业数
{item.doingCount}
</p>
<p>
申请数
{item.appliedCount}
</p>
</div>
</div>
))}
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI], true)(WorkPanel);

View File

@ -0,0 +1,21 @@
.index-info-work__list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.index-info-work__item {
display: flex;
align-items: center;
width: 50%;
margin-top: 10px;
color: #fff;
}
.index-info-work__item > div {
padding-left: 10px;
}
.index-info-work__item p {
margin: 0;
}

View File

@ -1,184 +1,24 @@
import { useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import img8 from "~/assets/images/public/bigScreen/bg11.png";
import img9 from "~/assets/images/public/bigScreen/bg12.png";
import img2 from "~/assets/images/public/bigScreen/ico6.png";
import img3 from "~/assets/images/public/bigScreen/ico7.png";
import img4 from "~/assets/images/public/bigScreen/ico8.png";
import img7 from "~/assets/images/public/bigScreen/ico9.png";
import rightbg from "~/assets/images/public/bigScreen/leftbg.png";
import img5 from "~/assets/images/public/bigScreen/tablebg1.png";
import img6 from "~/assets/images/public/bigScreen/tablebg2.png";
import Title from "~/pages/Container/Map/components/Content/IndexInfo/Title";
import AlarmPanel from "./AlarmPanel";
import GatePanel from "./GatePanel";
import PartnerPanel from "./PartnerPanel";
import WorkPanel from "./WorkPanel";
import "./index.less";
function RightScreen() {
const [block1List, setBlock1List] = useState([
{ id: 1, companyName: "方宇物业", pendingApprovalProjects: 2, pendingTrainingSubmissions: 3, pendingTrainees: 4 },
{ id: 2, companyName: "华泰建设工程", pendingApprovalProjects: 5, pendingTrainingSubmissions: 8, pendingTrainees: 12 },
{ id: 3, companyName: "宏达设备维护", pendingApprovalProjects: 3, pendingTrainingSubmissions: 6, pendingTrainees: 9 },
{ id: 4, companyName: "金鼎安全服务", pendingApprovalProjects: 7, pendingTrainingSubmissions: 10, pendingTrainees: 15 },
{ id: 5, companyName: "瑞丰技术服务", pendingApprovalProjects: 4, pendingTrainingSubmissions: 5, pendingTrainees: 7 },
{ id: 6, companyName: "恒通物流运输", pendingApprovalProjects: 6, pendingTrainingSubmissions: 9, pendingTrainees: 11 },
{ id: 7, companyName: "天成环保科技", pendingApprovalProjects: 8, pendingTrainingSubmissions: 12, pendingTrainees: 18 },
{ id: 8, companyName: "绿源消防设施", pendingApprovalProjects: 2, pendingTrainingSubmissions: 4, pendingTrainees: 6 },
{ id: 9, companyName: "安泰检测评估", pendingApprovalProjects: 5, pendingTrainingSubmissions: 7, pendingTrainees: 10 },
{ id: 10, companyName: "创新信息技术", pendingApprovalProjects: 3, pendingTrainingSubmissions: 5, pendingTrainees: 8 },
]);
const [block4List, setBlock4List] = useState([
{ id: 1, companyName: "新益公司", detectionSystem: "火灾检测系统", alarmReason: "燃气泄露", dispositionStatus: "未处置" },
{ id: 2, companyName: "华泰化工", detectionSystem: "温度监控系统", alarmReason: "超温报警", dispositionStatus: "已处置" },
{ id: 3, companyName: "宏达制造", detectionSystem: "压力检测系统", alarmReason: "压力异常", dispositionStatus: "处置中" },
{ id: 4, companyName: "金鼎能源", detectionSystem: "气体检测系统", alarmReason: "有毒气体超标", dispositionStatus: "未处置" },
{ id: 5, companyName: "瑞丰新材料", detectionSystem: "液位监控系统", alarmReason: "液位过高", dispositionStatus: "已处置" },
{ id: 6, companyName: "恒通物流", detectionSystem: "烟雾探测系统", alarmReason: "烟雾浓度超标", dispositionStatus: "处置中" },
{ id: 7, companyName: "天成建筑", detectionSystem: "振动监测系统", alarmReason: "设备振动异常", dispositionStatus: "未处置" },
{ id: 8, companyName: "绿源环保", detectionSystem: "水质检测系统", alarmReason: "PH值异常", dispositionStatus: "已处置" },
{ id: 9, companyName: "安泰消防", detectionSystem: "火警联动系统", alarmReason: "火焰探测报警", dispositionStatus: "处置中" },
{ id: 10, companyName: "创新科技", detectionSystem: "电气监控系统", alarmReason: "电流过载", dispositionStatus: "未处置" },
]);
/** 右侧信息区域仅负责按页面展示顺序组合业务区块。 */
function RightPanel() {
return (
<div className="right-container">
<div className="right-container_bg" style={{ backgroundImage: `url(${rightbg})` }}></div>
<div className="block1">
<Title title="相关方单位情况统计" />
<div className="main">
<div className="table">
<div className="head" style={{ backgroundImage: `url(${img5})` }}>
<div>相关方单位名称</div>
<div>资质申请情况</div>
<div>项目执行情况</div>
<div>执行人员情况</div>
</div>
<div className="scroll">
<SeamlessScroll list={block1List} step={0.5}>
{block1List.map((item, index) => (
<div className="table-container" style={{ backgroundImage: `url(${img6})` }} key={index}>
<div className="table-item">{item.companyName}</div>
<div className="table-item">{item.pendingApprovalProjects}</div>
<div className="table-item">{item.pendingTrainingSubmissions}</div>
<div className="table-item">{item.pendingTrainees}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</div>
</div>
<div className="block2">
<Title title="重点作业管理统计" />
<div className="main">
<div className="item">
<div className="img">
<img src={img2} alt="" />
</div>
<div className="info">
<div className="title">三人以上作业</div>
<div>
<p> 当前作业数13</p>
<p>申请数14</p>
</div>
</div>
</div>
<div className="item">
<div className="img">
<img src={img3} alt="" />
</div>
<div className="info">
<div className="title">危险作业</div>
<div>
<p> 当前作业数13</p>
<p>申请数14</p>
</div>
</div>
</div>
<div className="item">
<div className="img">
<img src={img4} alt="" />
</div>
<div className="info">
<div className="title">夜间作业</div>
<div>
<p> 当前作业数13</p>
<p>申请数14</p>
</div>
</div>
</div>
<div className="item">
<div className="img">
<img src={img7} alt="" />
</div>
<div className="info">
<div className="title">四新作业</div>
<div>
<p> 当前作业数13</p>
<p>申请数14</p>
</div>
</div>
</div>
</div>
</div>
<div className="block3">
<Title title="当前口门、封闭区情况" />
<div className="main">
<div className="item" style={{ backgroundImage: `url(${img9})` }}>
<div className="title">一级口门进出统计</div>
<div className="num">
<div>人数2100</div>
<div>车数1125</div>
</div>
</div>
<div className="item" style={{ backgroundImage: `url(${img9})` }}>
<div className="title">进入申请待审批</div>
<div className="num">
<div>人数2100</div>
<div>车数1125</div>
</div>
</div>
<div className="item" style={{ backgroundImage: `url(${img8})` }}>
<div className="title">封闭区域人员情况</div>
<div className="num">
<div>人数2100</div>
<div>车数1125</div>
</div>
</div>
<div className="item" style={{ backgroundImage: `url(${img8})` }}>
<div className="title">封闭区域作业情况</div>
<div className="num">
<div>人数2100</div>
<div>车数1125</div>
</div>
</div>
</div>
</div>
<div className="block4">
<Title title="物联网设备报警情况" />
<div className="main">
<div className="table">
<div className="head" style={{ backgroundImage: `url(${img5})` }}>
<div>设备类型</div>
<div>所属单位</div>
<div>报警类型</div>
<div>处置状态</div>
</div>
<div className="scroll">
<SeamlessScroll list={block4List} step={0.5}>
{block4List.map((item, index) => (
<div className="table-container" style={{ backgroundImage: `url(${img6})` }} key={index}>
<div className="table-item">{item.companyName}</div>
<div className="table-item">{item.detectionSystem}</div>
<div className="table-item">{item.alarmReason}</div>
<div className="table-item">{item.dispositionStatus}</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</div>
</div>
<div className="index-info-right-panel">
<div
className="index-info-right-panel__background"
style={{ backgroundImage: `url(${rightbg})` }}
/>
<PartnerPanel />
<WorkPanel />
<GatePanel />
<AlarmPanel />
</div>
);
}
export default RightScreen;
export default RightPanel;

View File

@ -1,196 +1,28 @@
.index_info_container {
.right-container_bg{
width: 600px;
height: 100%;
background-size: 100% 100%;
background-repeat: no-repeat;
position: fixed;
top: 0;
right: 0;
z-index: -1;
transform: rotate(180deg);
}
.right-container {
width: 400px;
position: absolute;
right: 20px;
top: 60px;
max-height: calc(100vh - 75px);
.block1 {
border-radius: 4px;
.main {
display: flex;
align-items: center;
.table {
width: 100%;
margin-top: 10px;
.head {
display: grid;
grid-template-columns: 1fr 1fr 1.5fr 1fr;
color: #ffffff;
padding: 5px;
background: rgba(39, 101, 175, 0.5);
text-align: center;
background-size: 100% 100%;
}
.scroll {
height: 180px;
overflow-y: hidden;
.table-container {
display: grid;
grid-template-columns: 1fr 1fr 1.5fr 1fr;
color: #ffffff;
padding: 5px;
margin: 5px auto;
background: rgba(17, 51, 122, 0.5);
text-align: center;
.fc1 {
color: #0c90ff;
}
.fc2 {
color: #62b13f;
}
.fc3 {
color: #ffa105;
}
}
}
}
}
}
.block2 {
margin-top: 10px;
border-radius: 4px;
.main {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.item {
width: 50%;
display: flex;
align-items: center;
margin-top: 10px;
.title {
font-weight: bold;
}
.info {
padding-left: 10px;
color: #ffffff;
p {
margin: 0;
}
}
}
}
}
.block3 {
margin-top: 20px;
border-radius: 4px;
.main {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.item {
width: 49%;
text-align: center;
background-size: 100% 100%;
color: #ffffff;
padding: 5px 10px;
margin-top: 10px;
.title {
font-weight: bold;
}
.num {
display: flex;
justify-content: space-between;
margin-top: 5px;
}
}
}
}
.block4 {
margin-top: 20px;
border-radius: 4px;
.main {
.table {
margin-top: 10px;
.head {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 5px;
background: rgba(39, 101, 175, 0.5);
text-align: center;
background-size: 100% 100%;
}
.scroll {
height: 280px;
overflow-y: hidden;
.table-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
color: #ffffff;
padding: 5px;
margin: 5px auto;
background: rgba(17, 51, 122, 0.5);
text-align: center;
.fc1 {
color: #0c90ff;
}
.fc2 {
color: #62b13f;
}
.fc3 {
color: #ffa105;
}
}
}
}
}
}
}
.index-info-right-panel {
width: 400px;
position: absolute;
top: 60px;
right: 20px;
max-height: calc(100vh - 75px);
}
.index-info-right-panel__background {
position: fixed;
top: 0;
right: 0;
z-index: -1;
width: 600px;
height: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
transform: rotate(180deg);
}
.index-info-right-panel__work {
margin-top: 10px;
}
.index-info-right-panel__gate,
.index-info-right-panel__alarm {
margin-top: 20px;
}

View File

@ -1,12 +0,0 @@
import img1 from "~/assets/images/public/bigScreen/smalltitle.png";
import "./index.less";
function Title(props) {
return (
<div className="index_info_container_title" style={{ backgroundImage: `url(${img1})` }}>
{props.title}
</div>
);
}
export default Title;

View File

@ -2,7 +2,7 @@ import Bottom from "./Bottom";
import Btn from "./Btn";
import LeftPanel from "./LeftPanel";
import RightPanel from "./RightPanel";
import Search from "./Search";
// import Search from "./Search";
import "./index.less";
function IndexInfo(props) {
@ -11,7 +11,7 @@ function IndexInfo(props) {
<LeftPanel />
<Bottom />
<RightPanel />
<Search />
{/* <Search /> */}
<Btn history={props.history} />
</div>
);

View File

@ -91,7 +91,7 @@ function IndexLeft() {
<div className="img">
<img src={getWeatherIcon(weatherData.text)} alt="" />
</div>
<div className="text">{weatherData.text || "暂无数据"}</div>
<div className="text">{weatherData.text || "暂无"}</div>
</div>
<div className="items">
<div className="item">

View File

@ -55,7 +55,7 @@ function QiXiang() {
<div className="img">
<img src={getWeatherIcon(weatherData.text)} alt="" />
</div>
<div className="text">{weatherData.text || "暂无数据"}</div>
<div className="text">{weatherData.text || "暂无"}</div>
</div>
<div className="items">
<div className="item">

View File

@ -54,7 +54,7 @@ export function mapReducer(state, action) {
case MAP_ACTION.RESET_BOTTOM_UTILS:
return {
...state,
bottomUtilsCurrentIndex: state.bottomUtilsCurrentIndex || -1,
bottomUtilsCurrentIndex: -1,
bottomUtilsResetVersion: state.bottomUtilsResetVersion + 1,
};
case MAP_ACTION.RESET_RIGHT_UTILS:

View File

@ -184,7 +184,7 @@ function CenterPanel() {
<div className="img">
<img src={getWeatherIcon(weatherData.text)} alt="" />
</div>
<div className="text">{weatherData.text || "暂无数据"}</div>
<div className="text">{weatherData.text || "暂无"}</div>
</div>
<div className="items">
<div className="item">

View File

@ -25,8 +25,6 @@ const WEATHER_URL = "https://api.map.baidu.com/weather/v1/?district_id=130300&da
* @returns {Promise<object>} 百度天气接口 result 数据
*/
export async function getWeather(options = {}) {
return {}; // TODO: Remove this line
const response = await fetch(WEATHER_URL, { signal: options.signal });
if (!response.ok) {
message.error("天气接口请求失败,请检查网络或稍后再试");