Compare commits

...

3 Commits

Author SHA1 Message Date
LiuJiaNan 8b819fa652 危险作业地图标点和详情弹窗 2026-07-22 10:38:03 +08:00
LiuJiaNan 1ce00bc82c port WeiXian 文件按块拆分 2026-07-22 09:10:11 +08:00
LiuJiaNan c68862b954 fix(api): 优化接口调用默认值及地图点位弹窗显示
- 各接口调用解构时添加 data 默认空数组或空对象,避免空值异常
- 地图标记点新增 isShowModal 参数,控制弹窗是否显示
- 点位点击事件中根据 isShowModal 判断是否触发弹窗显示事件
- 修正样式中 .scroll 容器高度及溢出处理
- 统一接口返回数据默认值处理,提升稳定性和健壮性
2026-07-22 08:52:47 +08:00
43 changed files with 2197 additions and 484 deletions

View File

@ -28,3 +28,7 @@ export const getPumpRoomScreenList = declareRequest(
"biFullLoading",
"Post > @/fireResource/pumpRoom/screenList",
);
export const getEightWorkInfoScreenWorkList = declareRequest(
"biFullLoading",
"Post > @/eightwork/eightworkInfo/screenWorkPage",
);

View File

@ -24,3 +24,15 @@ export const sensorDeviceInfo = declareRequest(
"biFullLoading",
`Get > /iotalarm/sensorDevice/{id}`,
);
export const eightWorkInfo = declareRequest(
"biFullLoading",
`Get > /eightwork/eightworkInfo/{id}`,
);
export const eightWorkSupplementaryInfo = declareRequest(
"biFullLoading",
`Post > @/eightwork/eightworkSupplementaryInfo/list`,
);
export const eightWorkMeasuresLogs = declareRequest(
"biFullLoading",
`Get > /eightwork/measuresLogs/listAll/{workId}`,
);

View File

@ -60,3 +60,15 @@ export const getFirePointDeviceList = declareRequest(
"portXiaoFangFirePointDeviceListLoading",
"Post > @/fireCheck/firePoint/deviceList",
);
export const getEightWorkInfoScreenStatusStatistics = declareRequest(
"portWeiXianEightWorkInfoScreenStatusStatisticsLoading",
"Post > @/eightwork/eightworkInfo/screenStatusStatistics",
);
export const getEightWorkInfoScreenWorkRecord = declareRequest(
"portWeiXianEightWorkInfoScreenWorkRecordLoading",
"Post > @/eightwork/eightworkInfo/screenWorkRecord",
);
export const getEightWorkInfoScreenWorkTrend = declareRequest(
"portWeiXianEightWorkInfoScreenWorkTrendLoading",
"Post > @/eightwork/eightworkInfo/screenWorkTrend",
);

View File

@ -28,51 +28,67 @@ export const branchOfficeUtilsList = [
list: [
{
label: "动火作业",
type: "hotWork",
type: "hot_work",
check: false,
markIcon: pointIco9,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "受限空间作业",
type: "confinedSpace",
type: "confinedspace_work",
check: false,
markIcon: pointIco10,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "临时用电作业",
type: "electricity",
type: "electricity_work",
check: false,
markIcon: pointIco11,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "高处作业",
type: "highWork",
type: "high_work",
check: false,
markIcon: pointIco12,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "断路作业",
type: "cutRoad",
type: "cutroad_work",
check: false,
markIcon: pointIco13,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "动土作业",
type: "breakGround",
type: "breakground_work",
check: false,
markIcon: pointIco14,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "吊装作业",
type: "hoisting",
type: "hoisting_work",
check: false,
markIcon: pointIco15,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "盲板抽堵作业",
type: "blindBoard",
type: "blindboard_work",
check: false,
markIcon: pointIco16,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "摄像头",

View File

@ -13,6 +13,17 @@ import { portUtilsList } from "./portUtilsList";
import { usePortUtilsAnimation } from "./usePortUtilsAnimation";
import "./index.less";
const dangerWorkTypes = [
"hot_work",
"confinedspace_work",
"electricity_work",
"high_work",
"cutroad_work",
"breakground_work",
"hoisting_work",
"blindboard_work",
];
const bottomUtilsAnimation = {
initial: { y: 100, opacity: 0 },
animate: { y: 0, opacity: 1, transition: { duration: 0.5, ease: "easeOut" } },
@ -107,12 +118,23 @@ function BottomUtils(props) {
const check = !list[index].list[index1].check;
if (check) {
if (item1.request) {
const { data } = await props[item1.request]({ portArea, corpinfoId: currentBranchOffice, pageIndex: 1, pageSize: 9999 });
const requestParams = { portArea, corpinfoId: currentBranchOffice, pageIndex: 1, pageSize: 9999 };
if (dangerWorkTypes.includes(item1.type)) {
requestParams.workType = item1.type;
}
const { data = [] } = await props[item1.request](requestParams);
if (dangerWorkTypes.includes(item1.type)) {
for (let i = 0; i < data.length; i++) {
data[i].latitude = data[i].info.latitude;
data[i].longitude = data[i].info.longitude;
}
}
mapMethods.current.addMarkPoint(data, {
markType: item1.type,
markIcon: item1.markIcon,
subLabel: item1.label,
titleKey: item1.titleKey,
isShowModal: item1.isShowModal,
});
}
}

View File

@ -216,67 +216,83 @@ export const portUtilsList = [
list: [
{
label: "动火作业",
type: "hotWork",
type: "hot_work",
check: false,
img: ico9,
checkImg: ico9On,
markIcon: pointIco9,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "受限空间作业",
type: "confinedSpace",
type: "confinedspace_work",
check: false,
img: ico10,
checkImg: ico10On,
markIcon: pointIco10,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "临时用电作业",
type: "electricity",
type: "electricity_work",
check: false,
img: ico11,
checkImg: ico11On,
markIcon: pointIco11,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "高处作业",
type: "highWork",
type: "high_work",
check: false,
img: ico12,
checkImg: ico12On,
markIcon: pointIco12,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "断路作业",
type: "cutRoad",
type: "cutroad_work",
check: false,
img: ico13,
checkImg: ico13On,
markIcon: pointIco13,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "动土作业",
type: "breakGround",
type: "breakground_work",
check: false,
img: ico14,
checkImg: ico14On,
markIcon: pointIco14,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "吊装作业",
type: "hoisting",
type: "hoisting_work",
check: false,
img: ico15,
checkImg: ico15On,
markIcon: pointIco15,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "盲板抽堵作业",
type: "blindBoard",
type: "blindboard_work",
check: false,
img: ico16,
checkImg: ico16On,
markIcon: pointIco16,
request: "getEightWorkInfoScreenWorkList",
titleKey: "checkNo",
},
{
label: "摄像头",

View File

@ -12,7 +12,7 @@ function RecordStatsPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getXgfStatisticsListRecordProjectStatistics();
const { data = [] } = await props.getXgfStatisticsListRecordProjectStatistics();
setList(data);
};

View File

@ -14,7 +14,7 @@ function VideoPatrolPanel(props) {
const [active, setActive] = useState("");
const [playUrl, setPlayUrl] = useState("");
const loadPlayUrl = async (cameraNumber) => {
const { data, success } = await props.getFixedCameraPlayUrl({
const { data = {}, success } = await props.getFixedCameraPlayUrl({
indexCode: cameraNumber,
});
if (success && data)
@ -35,7 +35,7 @@ function VideoPatrolPanel(props) {
};
useEffect(() => {
const loadVideoList = async () => {
const { data } = await props.getFixedCameraVideoList();
const { data = [] } = await props.getFixedCameraVideoList();
setList(data);
if (data.length) {
selectCorp(data[0]);

View File

@ -13,7 +13,7 @@ function RectificationPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getHiddenStatisticsByCorp({
const { data = [] } = await props.getHiddenStatisticsByCorp({
pageIndex: 1,
pageSize: 999,
});

View File

@ -18,14 +18,13 @@ function WeatherPanel(props) {
useEffect(() => {
const loadData = async () => {
const [{ result }, { data }] = await Promise.all([
props.getWeather(),
props.getEventReportListUnfinished(),
]);
const { result = {} } = await props.getWeather();
setWeather({
...result.now,
alertTitle: result.alerts?.[0]?.title || "当前暂无气象预警",
});
const { data = [] } = await props.getEventReportListUnfinished();
setEmergencyList(data);
};
loadData();

View File

@ -137,7 +137,7 @@ function WorkStatusPanel(props) {
};
useMount(() => {
const loadChartData = async () => {
const { data } = await props.getProjectTaskScoreCount();
const { data = [] } = await props.getProjectTaskScoreCount();
initEcharts(chartRef, chartInstance, data);
};

View File

@ -13,7 +13,7 @@ function AlarmPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getAlarmRecordScreenIotDeviceAlarmPage();
const { data = [] } = await props.getAlarmRecordScreenIotDeviceAlarmPage();
setList(data);
};

View File

@ -13,7 +13,7 @@ function PartnerPanel(props) {
const [list, setList] = useState([]);
useEffect(() => {
const loadList = async () => {
const { data } = await props.getXgfStatisticsListCorpStatistics();
const { data = [] } = await props.getXgfStatisticsListCorpStatistics();
setList(data);
};

View File

@ -29,8 +29,8 @@ function WorkPanel(props) {
]);
useEffect(() => {
const loadStatistics = async () => {
const { data: eightWorkData } = await props.getEightWorkInfoDangerWorkStatistics();
const { data: keyProjectData } = await props.getKeyProjectLargeScreenStatistics();
const { data: eightWorkData = {} } = await props.getEightWorkInfoDangerWorkStatistics();
const { data: keyProjectData = {} } = await props.getKeyProjectLargeScreenStatistics();
setList((prevState) => {
prevState[1].doingCount = eightWorkData.doingCount;
prevState[1].appliedCount = eightWorkData.appliedCount;

View File

@ -0,0 +1,178 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
};
useEffect(() => {
getData();
}, []);
const blindboardWorkParams = Array.isArray(info?.info?.blindboardWorkParams)
&& info.info.blindboardWorkParams.length > 0
? info.info.blindboardWorkParams
: [{}];
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={7} style={{ border: "none" }}>
<Divider orientation="left">盲板抽堵安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={7} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td colSpan={3}>{info?.info?.applyUnit}</td>
<td className="title">作业单位</td>
<td colSpan={2}>{info?.info?.step_21?.actUserDepartmentName}</td>
</tr>
<tr>
<td className="title">作业人</td>
<td colSpan={3}>{info?.info?.workUserName}</td>
<td className="title">作业类型</td>
<td colSpan={2}>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title center" rowSpan={2}>设备管道名称</td>
<td className="title center" colSpan={3}>管道参数</td>
<td className="title center" colSpan={3}>盲板参数</td>
</tr>
<tr>
<td className="title center">介质</td>
<td className="title center">温度</td>
<td className="title center">压力</td>
<td className="title center">材质</td>
<td className="title center">规格</td>
<td className="title center">编号</td>
</tr>
{blindboardWorkParams.map((item, index) => (
<tr key={item.id || index}>
{index === 0 && (
<>
<td className="center" rowSpan={blindboardWorkParams.length}>{info?.info?.devicePipelineName}</td>
<td className="center" rowSpan={blindboardWorkParams.length}>{info?.info?.mediumName}</td>
<td className="center" rowSpan={blindboardWorkParams.length}>{info?.info?.temperature}</td>
<td className="center" rowSpan={blindboardWorkParams.length}>{info?.info?.pressure}</td>
</>
)}
<td className="center">{item?.matertal}</td>
<td className="center">{item?.specification}</td>
<td className="center">{item?.number}</td>
</tr>
))}
<tr>
<td className="title">作业类别</td>
<td colSpan={6}>
{
{ blindboardWorkType001: "抽盲板", blindboardWorkType002: "堵盲板" }[info?.info?.blindboardWorkType]
}
</td>
</tr>
<tr>
<td className="title">盲板抽堵位置图</td>
<td colSpan={3}>
{info?.info?.workScopeAndMethodImage
&& <Image src={getFileUrl() + info?.info?.workScopeAndMethodImage} width={50} height={50} />}
</td>
<td className="title">作业单位</td>
<td colSpan={2}>{info?.info?.step_21?.actUserDepartmentName}</td>
</tr>
<tr>
<td className="title">监护人</td>
<td colSpan={3}>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
<td className="title">作业负责人</td>
<td colSpan={2}>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={6}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={6}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">实际作业开始时间</td>
<td colSpan={6}>{info?.info?.workStartTime}</td>
</tr>
<SafetyMeasures colSpan={7} workId={props.workId} />
<DisclaimerSign
firstColSpan={4}
lastColSpan={3}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业负责人意见"
colSpan={7}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="所在单位意见"
colSpan={7}
remarks={info?.info?.step_22?.remarks}
signPath={info?.info?.step_22?.signPath}
signTime={info?.info?.step_22?.status !== 0 && info?.info?.step_22?.signTime}
/>
<OpinionSign
title="审核部门意见"
colSpan={7}
remarks={info?.info?.step_23?.remarks}
signPath={info?.info?.step_23?.signPath}
signTime={info?.info?.step_23?.status !== 0 && info?.info?.step_23?.signTime}
/>
<OpinionSign
title="审批部门意见"
colSpan={7}
remarks={info?.info?.step_24?.remarks}
signPath={info?.info?.step_24?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_24?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={7}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_25?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,147 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">动土安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">作业地点</td>
<td>{info?.info?.workLocation}</td>
<td className="title">作业类型</td>
<td>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title">作业内容</td>
<td>{info?.info?.workContent}</td>
<td className="title">作业级别</td>
<td>{info?.info?.workLevelName}</td>
</tr>
<tr>
<td className="title">作业内容范围方式</td>
<td>{info?.info?.workScopeAndMethod}</td>
<td className="title">作业内容范围方式简图</td>
<td>
{info?.info?.workScopeAndMethodImage
&& <Image src={getFileUrl() + info?.info?.workScopeAndMethodImage} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业单位</td>
<td>{info?.info?.step_21?.actUserDepartmentName}</td>
<td className="title">监护人</td>
<td>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业负责人</td>
<td colSpan={3}>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={3}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={3}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">实际作业开始时间</td>
<td colSpan={3}>{info?.info?.workStartTime}</td>
</tr>
<SafetyMeasures colSpan={4} workId={props.workId} />
<DisclaimerSign
colSpan={2}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业负责人意见"
colSpan={4}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="所在单位意见"
colSpan={4}
remarks={info?.info?.step_22?.remarks}
signPath={info?.info?.step_22?.signPath}
signTime={info?.info?.step_22?.status !== 0 && info?.info?.step_22?.signTime}
/>
<OpinionSign
title="有关部门意见"
colSpan={4}
remarks={info?.info?.step_26?.remarks}
signPath={info?.info?.step_26?.signPath}
signTime={info?.info?.step_26?.status !== 0 && info?.info?.step_26?.signTime}
/>
<OpinionSign
title="审批部门意见"
colSpan={4}
remarks={info?.info?.step_24?.remarks}
signPath={info?.info?.step_24?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_24?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={4}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_25?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,209 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const [safetyMeasures, setSafetyMeasures] = useState([]);
const [otherSafetyMeasures, setOtherSafetyMeasures] = useState([]);
const [gasMonitoringRecord, setGasMonitoringRecord] = useState([]);
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
const { data: supplementaryInfo } = await props.eightWorkSupplementaryInfo({
eqWorkId: props.workId,
pageSize: 999,
pageIndex: 1,
});
setGasMonitoringRecord(supplementaryInfo.filter(item => item.type === "gas"));
const { data: measuresLogs } = await props.eightworkMeasuresLogs({ workId: props.workId });
setSafetyMeasures(measuresLogs.filter(item => item.type === 1));
setOtherSafetyMeasures(measuresLogs.filter(item => item.type === 2));
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={6} style={{ border: "none" }}>
<Divider orientation="left">有限空间作业许可证</Divider>
</td>
</tr>
<tr>
<td colSpan={6} style={{ border: "none" }} className="right">
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td colSpan={2}>{info?.info?.applyUnit}</td>
<td className="title">作业单位</td>
<td colSpan={2}>{info?.info?.workDepartmentName}</td>
</tr>
<tr>
<td className="title">有限空间名称及编号</td>
<td colSpan={2}>{info?.info?.limitedSpaceNameAndCode}</td>
<td className="title">作业内容</td>
<td colSpan={2}>{info?.info?.workContent}</td>
</tr>
<tr>
<td className="title">主要介质</td>
<td colSpan={2}>{info?.info?.chooseLimitedSpace?.mediumInfo}</td>
<td className="title" rowSpan={2}>应急装备</td>
<td rowSpan={2} colSpan={2}>{info?.info?.emergencyEquipment}</td>
</tr>
<tr>
<td className="title">主要危险因素</td>
<td colSpan={2}>{info?.info?.chooseLimitedSpace?.hazards}</td>
</tr>
<tr>
<td className="title">隔绝安全措施</td>
<td colSpan={5}>{info?.info?.isNeedWork === 1 ? "是" : "否"}</td>
</tr>
<tr>
<td colSpan={6}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "0 50px" }}>
<div>
<span style={{ padding: "0 10px" }}>作业负责人</span>
<span>{info?.info?.workChargeUserName}</span>
</div>
<div>
<span style={{ padding: "0 10px" }}>监护人</span>
<span>{info?.info?.workGuardianUserName}</span>
</div>
<div>
<span style={{ padding: "0 10px" }}>作业人</span>
<span>{info?.info?.workUserName}</span>
</div>
</div>
</td>
</tr>
<tr>
<td colSpan={6} style={{ border: "none", padding: 0 }}>
<table>
<tbody>
<tr>
<td className="center title" style={{ width: 80 }}>序号</td>
<td className="center title" style={{ width: "auto" }}>主要安全措施</td>
<td className="center title" style={{ width: 100 }}>是否涉及</td>
<td className="center title" style={{ width: 100 }}>确认人</td>
</tr>
{safetyMeasures.map((item, index) => (
<tr key={index}>
<td className="center">{index + 1}</td>
<td>{item.content}</td>
<td className="center">符合</td>
<td className="center">
{item.signPath && <Image src={getFileUrl() + item.signPath} width={50} height={50} />}
</td>
</tr>
))}
</tbody>
</table>
</td>
</tr>
<tr>
<td colSpan={6} style={{ border: "none", padding: 0 }}>
<table>
<tbody>
<tr>
<td className="center title" style={{ width: 80 }}>序号</td>
<td className="center title" style={{ width: "auto" }}>其它安全措施</td>
<td className="center title" style={{ width: 100 }}>确认人</td>
</tr>
{otherSafetyMeasures.map((item, index) => (
<tr key={index}>
<td className="center">{index + 1}</td>
<td>{item.content}</td>
<td className="center">
{item.signPath
? <Image src={getFileUrl() + item.signPath} width={50} height={50} />
: item.createName}
</td>
</tr>
))}
</tbody>
</table>
</td>
</tr>
{gasMonitoringRecord.length > 0 && (
<tr>
<td colSpan={6} style={{ border: "none", padding: 0 }}>
<table>
<tbody>
<tr>
<td className="center title">作业前分析项目</td>
<td className="center title">有毒有害物质含量</td>
<td className="center title">可燃气含量</td>
<td className="center title">氧气量</td>
<td className="center title">取样时间</td>
<td className="center title">取样位置</td>
<td className="center title">取样人</td>
</tr>
{gasMonitoringRecord.map((item, index) => (
<tr key={index}>
{index === 0 && <td className="center title" rowSpan={gasMonitoringRecord.length}>作业前数据</td>}
<td className="center">{item?.details?.toxicSubstanceContent}</td>
<td className="center">{item?.details?.combustibleGasContent}</td>
<td className="center">{item?.details?.oxygeAmount}</td>
<td className="center">{item?.details?.samplingTime}</td>
<td className="center">{item?.details?.samplingLocation}</td>
<td className="center">
{item?.details?.signImagePath
&& <Image src={getFileUrl() + item?.details?.signImagePath} width={50} height={50} />}
</td>
</tr>
))}
</tbody>
</table>
</td>
</tr>
)}
<tr>
<td className="title">作业单位负责人意见</td>
<td className="right" style={{ width: 200 }}>
<div>
{info?.info?.step_14?.signPath
&& <Image src={getFileUrl() + info?.info?.step_14?.signPath} width={50} height={50} />}
</div>
<div>{ info?.info?.step_14?.status !== 0 && info?.info?.step_14?.signTime}</div>
{/* <div className="remarks">{info?.info?.step_14?.remarks}</div> */}
</td>
<td className="title">管理单位发包部门意见</td>
<td className="right" style={{ width: 200 }}>
<div>
{info?.info?.step_15?.signPath
&& <Image src={getFileUrl() + info?.info?.step_15?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_15?.status !== 0 && info?.info?.step_15?.signTime}</div>
{/* <div className="remarks">{info?.info?.step_15?.remarks}</div> */}
</td>
<td className="title">管理单位安监部门意见</td>
<td className="right" style={{ width: 200 }}>
<div>
{info?.info?.step_16?.signPath
&& <Image src={getFileUrl() + info?.info?.step_16?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_16?.status !== 0 && info?.info?.step_16?.signTime}</div>
{/* <div className="remarks">{info?.info?.step_16?.remarks}</div> */}
</td>
</tr>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,147 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">断路安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">作业地点/断路地点</td>
<td>{info?.info?.workLocation}</td>
<td className="title">作业类型</td>
<td>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title">涉及相关单位部门</td>
<td>{info?.info?.relatedUnit}</td>
<td className="title">作业级别</td>
<td>{info?.info?.workLevelName}</td>
</tr>
<tr>
<td className="title">断路原因</td>
<td>{info?.info?.breakReason}</td>
<td className="title">断路地段示意图</td>
<td>
{info?.info?.workScopeAndMethodImage
&& <Image src={getFileUrl() + info?.info?.workScopeAndMethodImage} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">断路地段示意图相关说明</td>
<td>{info?.info?.workScopeAndMethod}</td>
<td className="title">监护人</td>
<td>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业负责人</td>
<td colSpan={3}>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={3}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={3}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">实际作业开始时间</td>
<td colSpan={3}>{info?.info?.workStartTime}</td>
</tr>
<SafetyMeasures workId={props.workId} colSpan={4} />
<DisclaimerSign
colSpan={2}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业负责人意见"
colSpan={4}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="所在单位意见"
colSpan={4}
remarks={info?.info?.step_22?.remarks}
signPath={info?.info?.step_22?.signPath}
signTime={info?.info?.step_22?.status !== 0 && info?.info?.step_22?.signTime}
/>
<OpinionSign
title="消防、安全管理部门意见"
colSpan={4}
remarks={info?.info?.step_27?.remarks}
signPath={info?.info?.step_27?.signPath}
signTime={info?.info?.step_27?.status !== 0 && info?.info?.step_27?.signTime}
/>
<OpinionSign
title="审批部门意见"
colSpan={4}
remarks={info?.info?.step_24?.remarks}
signPath={info?.info?.step_24?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_24?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={4}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,178 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { Fragment, useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const [gasMonitoringRecord, setGasMonitoringRecord] = useState([]);
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
const { data: supplementaryInfo } = await props.eightWorkSupplementaryInfo({
eqWorkId: props.workId,
pageSize: 999,
pageIndex: 1,
});
setGasMonitoringRecord(supplementaryInfo.filter(item => item.type === "gas"));
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">临时用电安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">作业地点</td>
<td>{info?.info?.workLocation}</td>
<td className="title">作业类型</td>
<td>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title">作业人电工证号</td>
<td>{info?.info?.electricNumber}</td>
<td className="title">作业级别</td>
<td>{info?.info?.workLevelName}</td>
</tr>
<tr>
<td className="title">电源接入点及许可用电功率</td>
<td>{info?.info?.pointPower}</td>
<td className="title">用电设备名称及额定功率</td>
<td>{info?.info?.equipmentNamePower}</td>
</tr>
<tr>
<td className="title">工作电压</td>
<td>{info?.info?.workVoltage}</td>
<td className="title">用电人</td>
<td>{info?.info?.electricUser}</td>
</tr>
<tr>
<td className="title">负责人电工号</td>
<td>{info?.info?.electricUserNo}</td>
<td className="title">监护人</td>
<td>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业人</td>
<td>{info?.info?.workUserName}</td>
<td className="title">作业负责人</td>
<td colSpan={3}>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={3}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={3}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">实际作业开始时间</td>
<td colSpan={3}>{info?.info?.workStartTime}</td>
</tr>
<tr>
<td className="title center" colSpan={4}>可燃气体分析运行的生产装置罐区和具有火灾爆炸危险场所</td>
</tr>
{
gasMonitoringRecord.length > 0
? gasMonitoringRecord.map(item => (
<Fragment key={item.id}>
<tr>
<td className="title">分析时间</td>
<td>{item?.details?.samplingTime}</td>
<td className="title">分析点</td>
<td>{item?.details?.samplingLocation}</td>
</tr>
<tr>
<td className="title">可燃气体检测结果</td>
<td>{item?.details?.combustibleGasContent}</td>
<td className="title">分析人</td>
<td>
{item?.details?.signImagePath
&& <Image src={getFileUrl() + item?.details?.signImagePath} width={50} height={50} />}
</td>
</tr>
</Fragment>
))
: <tr><td colSpan={4} className="center">暂无数据</td></tr>
}
<SafetyMeasures workId={props.workId} colSpan={4} />
<DisclaimerSign
colSpan={2}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业负责人意见"
colSpan={4}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="用电单位意见"
colSpan={4}
remarks={info?.info?.step_28?.remarks}
signPath={info?.info?.step_28?.signPath}
signTime={info?.info?.step_28?.status !== 0 && info?.info?.step_28?.signTime}
/>
<OpinionSign
title="配送电单位意见"
colSpan={4}
remarks={info?.info?.step_29?.remarks}
signPath={info?.info?.step_29?.signPath}
signTime={info?.info?.step_29?.status !== 0 && info?.info?.step_29?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={4}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_25?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,144 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">高处安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">作业地点</td>
<td>{info?.info?.workLocation}</td>
<td className="title">作业内容</td>
<td>{info?.info?.workContent}</td>
</tr>
<tr>
<td rowSpan={2} className="title">作业高度</td>
<td rowSpan={2}>{info?.info?.workHeight}</td>
<td className="title">作业类型</td>
<td>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title">作业级别</td>
<td>{info?.info?.workLevelName}</td>
</tr>
<tr>
<td className="title">作业单位</td>
<td>{info?.info?.step_21?.actUserDepartmentName}</td>
<td className="title">监护人</td>
<td>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业人</td>
<td>{info?.info?.workUserName}</td>
<td className="title">作业负责人</td>
<td>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={3}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={3}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">作业实施时间</td>
<td colSpan={3}>{`${info?.info?.workStartTime}${info?.info?.workEndTime}`}</td>
</tr>
<SafetyMeasures workId={props.workId} colSpan={4} />
<DisclaimerSign
colSpan={2}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业负责人意见"
colSpan={4}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="所在单位意见"
colSpan={4}
remarks={info?.info?.step_22?.remarks}
signPath={info?.info?.step_22?.signPath}
signTime={info?.info?.step_22?.status !== 0 && info?.info?.step_22?.signTime}
/>
<OpinionSign
title="审核部门意见"
colSpan={4}
remarks={info?.info?.step_23?.remarks}
signPath={info?.info?.step_23?.signPath}
signTime={info?.info?.step_23?.status !== 0 && info?.info?.step_23?.signTime}
/>
<OpinionSign
title="审批部门意见"
colSpan={4}
remarks={info?.info?.step_24?.remarks}
signPath={info?.info?.step_24?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_24?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={4}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_25?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,156 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import DisclaimerSign from "../eightWordPubilc/DisclaimerSign";
import OpinionSign from "../eightWordPubilc/OpinionSign";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">吊装安全作业票</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">吊装地点</td>
<td>{info?.info?.workLocation}</td>
<td className="title">作业类型</td>
<td>{info?.info?.operationTypeName}</td>
</tr>
<tr>
<td className="title">吊具名称</td>
<td>{info?.info?.hoistName}</td>
<td className="title">作业级别</td>
<td>{info?.info?.workLevelName}</td>
</tr>
<tr>
<td className="title">吊装作业人</td>
<td>{info?.info?.workUserName}</td>
<td className="title">司索人</td>
<td>{info?.info?.pullUserName}</td>
</tr>
<tr>
<td className="title">指挥人</td>
<td>{info?.info?.commandUserName}</td>
<td rowSpan={2} className="title">吊物内容</td>
<td rowSpan={2}>{info?.info?.workContent}</td>
</tr>
<tr>
<td className="title">吊物质量</td>
<td>{info?.info?.hoistWeight}</td>
</tr>
<tr>
<td className="title">作业单位</td>
<td>{info?.info?.step_21?.actUserDepartmentName}</td>
<td className="title">监护人</td>
<td>
{info?.info?.step_20?.signPath
&& <Image src={getFileUrl() + info?.info?.step_20?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">作业人</td>
<td>{info?.info?.workUserName}</td>
<td className="title">作业负责人</td>
<td>
{info?.info?.step_21?.signPath
&& <Image src={getFileUrl() + info?.info?.step_21?.signPath} width={50} height={50} />}
</td>
</tr>
<tr>
<td className="title">关联的其他特殊作业及安全作业票编号</td>
<td colSpan={3}>{info?.info?.linkSpecialWorks}</td>
</tr>
<tr>
<td className="title">风险辨识结果</td>
<td colSpan={3}>{info?.info?.riskResults}</td>
</tr>
<tr>
<td className="title">作业实施时间</td>
<td colSpan={3}>{`${info?.info?.workStartTime}${info?.info?.workEndTime}`}</td>
</tr>
<SafetyMeasures colSpan={4} workId={props.id} />
<DisclaimerSign
colSpan={2}
safetyRemarks={info?.info?.step_18?.remarks}
safetySignPath={info?.info?.step_18?.signPath}
safetySignTime={info?.info?.step_18?.status !== 0 && info?.info?.step_18?.signTime}
AcceptRemarks={info?.info?.step_19?.remarks}
AcceptSignPath={info?.info?.step_19?.signPath}
AcceptSignTime={info?.info?.step_19?.status !== 0 && info?.info?.step_19?.signTime}
/>
<OpinionSign
title="作业指挥负责人意见"
colSpan={4}
remarks={info?.info?.step_21?.remarks}
signPath={info?.info?.step_21?.signPath}
signTime={info?.info?.step_21?.status !== 0 && info?.info?.step_21?.signTime}
/>
<OpinionSign
title="所在单位意见"
colSpan={4}
remarks={info?.info?.step_22?.remarks}
signPath={info?.info?.step_22?.signPath}
signTime={info?.info?.step_22?.status !== 0 && info?.info?.step_22?.signTime}
/>
<OpinionSign
title="审核部门意见"
colSpan={4}
remarks={info?.info?.step_23?.remarks}
signPath={info?.info?.step_23?.signPath}
signTime={info?.info?.step_23?.status !== 0 && info?.info?.step_23?.signTime}
/>
<OpinionSign
title="审批部门意见"
colSpan={4}
remarks={info?.info?.step_24?.remarks}
signPath={info?.info?.step_24?.signPath}
signTime={info?.info?.step_24?.status !== 0 && info?.info?.step_24?.signTime}
/>
<OpinionSign
title="完工验收"
colSpan={4}
remarks={info?.info?.step_25?.remarks}
signPath={info?.info?.step_25?.signPath}
signTime={info?.info?.step_25?.status !== 0 && info?.info?.step_25?.signTime}
/>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,203 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Divider, Image } from "antd";
import dayjs from "dayjs";
import { Fragment, useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
import SafetyMeasures from "../eightWordPubilc/SafetyMeasures";
import "../eightWordPubilc/index.less";
function View(props) {
const [info, setInfo] = useState({});
const [delayedMonitoringRecord, setDelayedMonitoringRecord] = useState([]);
const [gasMonitoringRecord, setGasMonitoringRecord] = useState([]);
const getData = async () => {
const { data: basicInfo } = await props.eightWorkInfo({ id: props.id });
setInfo(basicInfo);
const { data: supplementaryInfo } = await props.eightWorkSupplementaryInfo({
eqWorkId: props.workId,
pageSize: 999,
pageIndex: 1,
});
setDelayedMonitoringRecord(supplementaryInfo.filter(item => item.type === "delay"));
setGasMonitoringRecord(supplementaryInfo.filter(item => item.type === "gas"));
};
useEffect(() => {
getData();
}, []);
return (
<div className="work_ticket_details">
<table>
<thead>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<Divider orientation="left">动火申请审批许可证</Divider>
</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none" }}>
<span>编号</span>
<span>{info.checkNo}</span>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="title">申请单位</td>
<td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td>
<td>{dayjs(info?.info?.applyTime || info?.createTime).format("YYYY-MM-DD HH:mm:ss")}</td>
</tr>
<tr>
<td className="title">动火部位</td>
<td>{info?.info?.work_place}</td>
<td className="title">动火方法</td>
<td>{info?.info?.work_way}</td>
</tr>
<tr>
<td className="title">动火等级</td>
<td>{info?.info?.workLevelName}</td>
<td className="title">作业内容</td>
<td>{info?.info?.workContent}</td>
</tr>
<tr>
<td className="title">动火时间</td>
<td colSpan={3}>{`${info?.info?.workStartTime} - ${info?.info?.workEndTime}`}</td>
</tr>
<tr>
<td className="title">现场负责人</td>
<td>{info?.info?.step_10?.actUserName}</td>
<td className="title">动火操作人</td>
<td>{info?.info?.hotWorkActUser?.map(item => item.name).join(", ")}</td>
</tr>
<tr>
<td className="title">动火监火人</td>
<td colSpan={3}>{info?.info?.workMonitor}</td>
</tr>
<tr>
<td className="title center" colSpan={4}>可燃气体分析运行的生产装置罐区和具有火灾爆炸危险场所</td>
</tr>
{
gasMonitoringRecord.length > 0
? gasMonitoringRecord.map(item => (
<Fragment key={item.id}>
<tr>
<td className="title">分析时间</td>
<td>{item?.details?.analysisTime}</td>
<td className="title">分析点</td>
<td>{item?.details?.analysisPointName}</td>
</tr>
<tr>
<td className="title">可燃气体检测结果</td>
<td>{item?.details?.analysisResult}</td>
<td className="title">分析人</td>
<td>{item?.details?.analysisUserName}</td>
</tr>
</Fragment>
))
: <tr><td colSpan={4} className="center">暂无数据</td></tr>
}
<tr>
<td className="title center" colSpan={4}>动火要求安全措施安全提示</td>
</tr>
<SafetyMeasures workId={props.workId} colSpan={4} />
<tr>
<td className="title">动火单位(部门)负责人意见</td>
<td className="right">
<div>
{info?.info?.step_4?.signPath
&& <Image src={getFileUrl() + info?.info?.step_4?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_4?.status !== 0 && info?.info?.step_4?.signTime}</div>
<div className="remarks">{info?.info?.step_4?.remarks}</div>
</td>
<td className="title">项目发包单位(部门)人员意见</td>
<td className="right">
<div>
{info?.info?.step_5?.signPath
&& <Image src={getFileUrl() + info?.info?.step_5?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_5?.status !== 0 && info?.info?.step_5?.signTime}</div>
<div className="remarks">{info?.info?.step_5?.remarks}</div>
</td>
</tr>
<tr>
<td className="title">现场管辖单位(部门)负责人意见</td>
<td className="right">
<div>
{info?.info?.step_6?.signPath
&& <Image src={getFileUrl() + info?.info?.step_6?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_6?.status !== 0 && info?.info?.step_6?.signTime}</div>
<div className="remarks">{info?.info?.step_6?.remarks}</div>
</td>
<td className="title">动火许可证签发单位意见</td>
<td className="right">
<div>
{info?.info?.step_7?.signPath
&& <Image src={getFileUrl() + info?.info?.step_7?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_7?.status !== 0 && info?.info?.step_7?.signTime}</div>
<div className="remarks">{info?.info?.step_7?.remarks}</div>
</td>
</tr>
<tr>
<td className="title">动火前管辖单位现场人员许可</td>
<td className="right">
<div>
{info?.info?.step_9?.signPath
&& <Image src={getFileUrl() + info?.info?.step_9?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_9?.status !== 0 && info?.info?.step_9?.signTime}</div>
<div className="remarks">{info?.info?.step_9?.remarks}</div>
</td>
<td className="title">动火后管辖单位现场人员验收</td>
<td className="right">
<div>
{info?.info?.step_11?.signPath
&& <Image src={getFileUrl() + info?.info?.step_11?.signPath} width={50} height={50} />}
</div>
<div>{info?.info?.step_11?.status !== 0 && info?.info?.step_11?.signTime}</div>
<div className="remarks">{info?.info?.step_11?.remarks}</div>
</td>
</tr>
<tr>
<td className="title center" colSpan={4}>延时监火记录</td>
</tr>
<tr>
<td colSpan={4} style={{ border: "none", padding: 0 }}>
<table>
<tbody>
<tr>
<td className="title center">监火人</td>
<td className="title center">时间</td>
<td className="title center">签字照片</td>
</tr>
{
delayedMonitoringRecord.length > 0
? delayedMonitoringRecord.map((item, index) => (
<tr key={index}>
<td className="center">{item?.details?.actUserName}</td>
<td className="center">{item?.details?.delayHotTime}</td>
<td className="center">
{item?.details?.delayHotPhoto
&& <Image src={getFileUrl() + item?.details?.delayHotPhoto} width={50} height={50} />}
</td>
</tr>
))
: <tr><td colSpan={3} className="center">暂无数据</td></tr>
}
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
);
}
export default Connect([NS_BI_MARK_INFO], true)(View);

View File

@ -0,0 +1,60 @@
import { Image } from "antd";
import { getFileUrl } from "zy-react-library/utils";
function DisclaimerSign({
colSpan,
firstColSpan,
lastColSpan,
safetyRemarks,
safetySignPath,
safetySignTime,
AcceptRemarks,
AcceptSignPath,
AcceptSignTime,
}) {
const showFirst = safetyRemarks || safetySignPath || safetySignTime;
const showLast = AcceptRemarks || AcceptSignPath || AcceptSignTime;
return (
<tr>
{
showFirst && (
<td colSpan={(firstColSpan || colSpan) + (!showLast ? (lastColSpan || colSpan) : 0)}>
<div className="flex">
<div>
<span>安全交底人</span>
<span>{safetyRemarks}</span>
</div>
<div className="right">
<div>
{safetySignPath && <Image src={getFileUrl() + safetySignPath} width={50} height={50} />}
</div>
<div>{safetySignTime}</div>
</div>
</div>
</td>
)
}
{
showLast && (
<td colSpan={(lastColSpan || colSpan) + (!showFirst ? (firstColSpan || colSpan) : 0)}>
<div className="flex">
<div>
<span>接受交底人</span>
<span>{AcceptRemarks}</span>
</div>
<div className="right">
<div>
{AcceptSignPath && <Image src={getFileUrl() + AcceptSignPath} width={50} height={50} />}
</div>
<div>{AcceptSignTime}</div>
</div>
</div>
</td>
)
}
</tr>
);
}
export default DisclaimerSign;

View File

@ -0,0 +1,46 @@
import { Image } from "antd";
import { Fragment } from "react";
import { getFileUrl } from "zy-react-library/utils";
function OpinionSign({
title,
colSpan,
remarks,
signPath,
signTime,
}) {
const show = signPath || remarks || signTime;
return (
<Fragment>
{
show && (
<tr>
<td colSpan={colSpan}>
<div className="flex">
<div>
<span>
{title}
</span>
<span className="remarks" style={{ display: "inline" }}>{remarks}</span>
</div>
<div className="right">
<div>
<span>签字</span>
<span>
{signPath && <Image src={getFileUrl() + signPath} width={50} height={50} />}
</span>
<div>{signTime}</div>
</div>
</div>
</div>
</td>
</tr>
)
}
</Fragment>
);
}
export default OpinionSign;

View File

@ -0,0 +1,72 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Image } from "antd";
import { useEffect, useState } from "react";
import { getFileUrl } from "zy-react-library/utils";
import { NS_BI_MARK_INFO } from "~/enumerate/namespace";
function SafetyMeasures(props) {
const [safetyMeasures, setSafetyMeasures] = useState([]);
const [otherSafetyMeasures, setOtherSafetyMeasures] = useState([]);
const getData = async () => {
const { data } = await props.eightWorkMeasuresLogs({ workId: props.workId });
setSafetyMeasures(data.filter(item => item.type === 1));
setOtherSafetyMeasures(data.filter(item => item.type === 2));
};
useEffect(() => {
getData();
}, []);
return (
<tr>
<td colSpan={props.colSpan} style={{ border: "none", padding: 0 }}>
<table>
<tbody>
<tr>
<td className="center title" style={{ width: 80 }}>序号</td>
<td className="center title" style={{ width: "auto" }}>安全措施</td>
<td className="center title" style={{ width: 100 }}>是否涉及</td>
<td className="center title" style={{ width: 100 }}>确认人</td>
</tr>
{safetyMeasures.map((item, index) => (
<tr key={index}>
<td className="center">{index + 1}</td>
<td>{item.content}</td>
<td className="center">符合</td>
<td className="center">
{item.signPath && <Image src={getFileUrl() + item.signPath} width={50} height={50} />}
</td>
</tr>
))}
{
otherSafetyMeasures.length > 0 && (
<tr>
<td className="center">{safetyMeasures.length + 1}</td>
<td colSpan={3}>
{
otherSafetyMeasures.map((item, index) => (
<div key={index} style={{ display: "flex", justifyContent: "space-between" }}>
<div>
<span>其它安全措施</span>
<span>{item.content}</span>
</div>
<div>
<span>编制人</span>
<span>{item.createName}</span>
</div>
</div>
))
}
</td>
</tr>
)
}
</tbody>
</table>
</td>
</tr>
);
}
export default Connect([NS_BI_MARK_INFO], true)(SafetyMeasures);

View File

@ -0,0 +1,46 @@
.work_ticket_details {
table {
width: 100%;
border-collapse: collapse;
border-spacing: 0;
color: #fff;
th, td {
border: 1px solid #0c1957;
padding: 8px;
}
.title{
font-weight: 600;
background-color: #0b1544;
width: 200px;
}
.center {
text-align: center;
}
.right {
text-align: right;
max-width: 0;
min-width: 200px;
}
.remarks {
text-align: left;
word-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
overflow-wrap: break-word;
display: inline-block;
max-width: 100%;
}
.flex {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
}
}

View File

@ -2,17 +2,26 @@ import { Button, Modal } from "antd";
import { useContext } from "react";
import { Context } from "~/pages/Container/Map/js/context";
import AlarmEquipment from "./AlarmEquipment";
import BlindBoardWork from "./BlindBoardWork";
import BreakGroundWork from "./BreakgroundWork";
import ConfinedSpaceWork from "./ConfinedSpaceWork";
import CutRoadWork from "./CutRoadWork";
import ElectricityWork from "./ElectricityWork";
import FireControlRoom from "./FireControlRoom";
import FirePointLocation from "./FirePointLocation";
import FirePumpRoom from "./FirePumpRoom";
import FireRescueTeam from "./FireRescueTeam";
import FireWaterSource from "./FireWaterSource";
import HighWork from "./HighWork";
import HoistingWork from "./HoistingWork";
import HotWork from "./HotWork";
import MeteorologicalMonitoring from "./MeteorologicalMonitoring";
const CustomModal = () => {
const { modalVisible, modalData, actions } = useContext(Context);
const renderContent = () => {
const markType = modalData.markType?.replace("标记点_", "");
return {
meteorologicalMonitoring: <MeteorologicalMonitoring />, // 气象监测
fireRescueTeam: <FireRescueTeam id={modalData.id} />, // 消防救援队
@ -21,7 +30,15 @@ const CustomModal = () => {
fireWaterSource: <FireWaterSource id={modalData.id} />, // 消防水源
firePointLocation: <FirePointLocation id={modalData.id} />, // 消防点位
alarmEquipment: <AlarmEquipment id={modalData.id} />, // 报警设备
}[modalData.markType?.replace("标记点_", "")];
hot_work: <HotWork id={modalData.id} workId={modalData.workId} />, // 动火作业
confinedspace_work: <ConfinedSpaceWork id={modalData.id} workId={modalData.workId} />, // 受限空间作业
electricity_work: <ElectricityWork id={modalData.id} workId={modalData.workId} />, // 临时用电作业
high_work: <HighWork id={modalData.id} workId={modalData.workId} />, // 高处作业
cutroad_work: <CutRoadWork id={modalData.id} workId={modalData.workId} />, // 断路作业
breakground_work: <BreakGroundWork id={modalData.id} workId={modalData.workId} />, // 动土作业
hoisting_work: <HoistingWork id={modalData.id} workId={modalData.workId} />, // 吊装作业
blindboard_work: <BlindBoardWork id={modalData.id} workId={modalData.workId} />, // 盲板抽堵作业
}[markType];
};
return (

View File

@ -24,7 +24,7 @@ function BasicInfoPanel(props) {
useEffect(() => {
const loadStatistics = async () => {
const { data } = await props.getCorpInfoCorpUserSummary({ portArea });
const { data = {} } = await props.getCorpInfoCorpUserSummary({ portArea });
const counts = [
data.branchCorpCount,
data.relatedCorpCount,

View File

@ -20,7 +20,7 @@ function PersonnelStatsPanel(props) {
const loadStatistics = async (enterpriseType) => {
setIsVisible(false);
const { data } = await props.getCorpInfoCorpUserStatisticPage({
const { data = [] } = await props.getCorpInfoCorpUserStatisticPage({
portArea,
enterpriseType,
});

View File

@ -51,7 +51,7 @@ function RiskStatsPanel(props) {
useEffect(() => {
const loadStatistics = async () => {
const { data } = await props.getRiskPointCorpRiskLevel({ portArea });
const { data = [] } = await props.getRiskPointCorpRiskLevel({ portArea });
const countByLevel = Object.fromEntries(
data.map(item => [item.level, item.count]),
);

View File

@ -0,0 +1,69 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { useContext, useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/port/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less";
const rankStyleNames = ["first", "second", "third"];
/** 负责查询并展示危险作业记录及其排行样式。 */
function WorkRecordPanel(props) {
const { portArea } = useContext(Context);
const [records, setRecords] = useState([]);
useEffect(() => {
const loadRecords = async () => {
const { data = [] } = await props.getEightWorkInfoScreenWorkRecord({
portArea,
pageIndex: 1,
pageSize: 9999,
});
setRecords(data);
};
loadRecords();
}, []);
return (
<Panel title="安全作业记录" className="port-danger-work__record">
<div className="port-danger-work-record__content">
<div className="port-danger-work-record__table">
<div className="port-danger-work-record__row">
<div className="port-danger-work-record__cell">序号</div>
<div className="port-danger-work-record__cell">作业类型</div>
<div className="port-danger-work-record__cell">状态</div>
<div className="port-danger-work-record__cell">下一步操作人</div>
</div>
<div className="port-danger-work-record__table-body">
<SeamlessScroll list={records} step={0.5}>
{records.map((item, index) => (
<div key={index} className="port-danger-work-record__row">
<div className="port-danger-work-record__cell">
<div
className={`port-danger-work-record__rank port-danger-work-record__rank--${rankStyleNames[index] || "default"}`}
>
{index + 1}
</div>
</div>
<div className="port-danger-work-record__cell">
{item.workTypeName}
</div>
<div className="port-danger-work-record__cell">
{item.statusName}
</div>
<div className="port-danger-work-record__cell">
{item.nextStepName}
</div>
</div>
))}
</SeamlessScroll>
</div>
</div>
</div>
</Panel>
);
}
export default Connect([NS_BI_STATISTICS], true)(WorkRecordPanel);

View File

@ -0,0 +1,71 @@
.port-danger-work__record {
margin-top: 10px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
}
.port-danger-work-record__content {
padding: 10px;
border: 1px solid;
border-top: none;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)
)
1;
}
.port-danger-work-record__table {
margin-top: 5px;
}
.port-danger-work-record__table-body {
height: 400px;
overflow-y: hidden;
}
.port-danger-work-record__row {
display: flex;
}
.port-danger-work-record__row:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.port-danger-work-record__cell {
flex: 1;
padding: 5px;
color: #fff;
font-size: 12px;
text-align: center;
}
.port-danger-work-record__cell:first-child {
flex: none;
flex-basis: 50px;
text-align: left;
}
.port-danger-work-record__cell:nth-child(2) {
flex-basis: 20%;
}
.port-danger-work-record__rank {
display: flex;
align-items: center;
justify-content: center;
width: 21px;
height: 15px;
margin: auto;
color: #fff;
font-size: 11px;
line-height: 1;
border-radius: 2px;
}
.port-danger-work-record__rank--first {
background: linear-gradient(135deg, #ff6d73, #f23f47);
}
.port-danger-work-record__rank--second {
background: linear-gradient(135deg, #ffb856, #ff871f);
}
.port-danger-work-record__rank--third {
background: linear-gradient(135deg, #ffe477, #f6be1b);
}
.port-danger-work-record__rank--default {
background: linear-gradient(135deg, #5a8fdc, #3367b4);
}

View File

@ -0,0 +1,78 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useContext, useEffect, useState } from "react";
import CountUp from "react-countup";
import iconBackground from "~/assets/images/map_bi/content/icobg.png";
import applyIcon from "~/assets/images/map_bi/content/icon27.png";
import approvingIcon from "~/assets/images/map_bi/content/icon28.png";
import archivedIcon from "~/assets/images/map_bi/content/icon29.png";
import labelBackground from "~/assets/images/map_bi/content/label.png";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/port/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less";
const defaultStatistics = [
{ image: applyIcon, label: "申请数", count: 0 },
{ image: approvingIcon, label: "审批中", count: 0 },
{ image: archivedIcon, label: "归档数", count: 0 },
];
/** 负责查询并展示危险作业申请、审批和归档状态统计。 */
function WorkStatusPanel(props) {
const { portArea } = useContext(Context);
const [statistics, setStatistics] = useState(defaultStatistics);
useEffect(() => {
const loadStatistics = async () => {
const { data = {} } = await props.getEightWorkInfoScreenStatusStatistics({
portArea,
});
const counts = [
data.appliedCount,
data.approvingCount,
data.archivedCount,
];
setStatistics(
defaultStatistics.map((item, index) => ({
...item,
count: counts[index],
})),
);
};
loadStatistics();
}, []);
return (
<Panel title="安全作业状态统计" className="port-danger-work__status">
<Spin
spinning={
props.biStatistics
.portWeiXianEightWorkInfoScreenStatusStatisticsLoading
}
>
<div className="port-danger-work-status__options">
{statistics.map((item) => (
<div key={item.label} className="port-danger-work-status__option">
<div
className="port-danger-work-status__icon"
style={{ backgroundImage: `url(${iconBackground})` }}
>
<img src={item.image} alt="" />
</div>
<div
className="port-danger-work-status__label"
style={{ backgroundImage: `url(${labelBackground})` }}
>
{item.label}<CountUp end={+item.count} />
</div>
</div>
))}
</div>
</Spin>
</Panel>
);
}
export default Connect([NS_BI_STATISTICS], true)(WorkStatusPanel);

View File

@ -0,0 +1,62 @@
.port-danger-work__status {
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
}
.port-danger-work-status__options {
display: flex;
justify-content: space-between;
padding: 13px 15px;
border: 1px solid;
border-top: none;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)
)
1;
}
.port-danger-work-status__option {
display: flex;
flex-direction: column;
align-items: center;
}
.port-danger-work-status__icon {
width: 70px;
height: 70px;
padding-top: 13px;
text-align: center;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.port-danger-work-status__icon img {
width: 25px;
height: 26px;
animation: portDangerWorkStatusSlideY 2s infinite;
}
.port-danger-work-status__label {
display: flex;
justify-content: center;
width: 120px;
height: 24px;
margin-top: 6px;
color: #fff;
font-size: 12px;
line-height: 25px;
text-align: center;
background-repeat: no-repeat;
background-size: 100% 100%;
}
@keyframes portDangerWorkStatusSlideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}

View File

@ -0,0 +1,143 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { useMount } from "ahooks";
import { Spin } from "antd";
import * as echarts from "echarts";
import { useContext, useRef } from "react";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/port/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less";
/** 将接口的作业趋势记录转换为图表横轴、图例与序列数据。 */
function formatWorkTrendData(data) {
const workDates = [...new Set(data.map(item => item.workDate))];
const workTypes = [
...new Map(data.map(item => [item.workType, item.workTypeName])),
];
return {
xData: workDates,
date: workTypes.map(([workType]) =>
data
.filter(item => item.workType === workType)
.map(item => Number(item.count)),
),
name: workTypes.map(([, workTypeName]) => workTypeName),
};
}
/** 负责初始化安全作业趋势图表并在卸载时释放图表实例。 */
function WorkTrendPanel(props) {
const { portArea } = useContext(Context);
const chartRef = useRef(null);
const chartInstance = useRef(null);
const initEcharts = (mainRef, chartInstance, data) => {
const colors = [
"29,128,219",
"1,245,255",
"228,187,45",
"45,118,228",
"188,45,228",
"228,72,45",
"58,45,228",
"221,44,67",
];
const series = data.date.map((seriesData, index) => ({
name: data.name[index],
type: "line",
symbol: "circle",
showAllSymbol: true,
symbolSize: 0,
smooth: true,
lineStyle: { width: 2, color: `rgba(${colors[index]},1)` },
itemStyle: { color: `rgba(${colors[index]},1)` },
tooltip: { show: true },
areaStyle: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{ offset: 0, color: `rgba(${colors[index]},0.3)` },
{ offset: 1, color: `rgba(${colors[index]},0)` },
],
false,
),
shadowColor: "rgba(25,163,223, 0.5)",
shadowBlur: 20,
},
data: seriesData,
}));
chartInstance.current = echarts.init(mainRef.current);
chartInstance.current.setOption({
tooltip: { trigger: "axis" },
legend: {
top: "0",
align: "left",
type: "plain",
data: data.name,
textStyle: { color: "#fff", fontSize: 12 },
itemWidth: 18,
},
grid: { top: "20%", left: "10%", right: "5%", bottom: "15%" },
xAxis: [
{
type: "category",
boundaryGap: false,
axisLine: { show: true, lineStyle: { color: "#15578b" } },
axisLabel: {
color: "#fff",
fontSize: 12,
formatter(value) {
return value.substring(5);
},
},
splitLine: { show: false, lineStyle: { color: "#fff" } },
axisTick: { show: false },
data: data.xData,
},
],
yAxis: [
{
min: 0,
splitLine: {
show: true,
lineStyle: { color: "rgba(221,221,221,0.1)" },
},
axisLine: { show: false, lineStyle: { color: "#fff" } },
axisLabel: { show: true, color: "#fff", padding: 10 },
},
],
series,
});
};
useMount(() => {
const loadTrendData = async () => {
const { data = [] } = await props.getEightWorkInfoScreenWorkTrend({
portArea,
});
initEcharts(chartRef, chartInstance, formatWorkTrendData(data));
};
loadTrendData();
return () => chartInstance.current?.dispose();
});
return (
<Panel title="安全作业情况统计" className="port-danger-work__trend">
<div className="port-danger-work-trend__content">
<Spin
spinning={
props.biStatistics.portWeiXianEightWorkInfoScreenWorkTrendLoading
}
>
<div ref={chartRef} className="port-danger-work-trend__chart" />
</Spin>
</div>
</Panel>
);
}
export default Connect([NS_BI_STATISTICS], true)(WorkTrendPanel);

View File

@ -0,0 +1,23 @@
.port-danger-work__trend {
margin-top: 10px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
}
.port-danger-work-trend__content {
padding: 10px 15px;
border: 1px solid;
border-top: none;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)
)
1;
}
.port-danger-work-trend__chart {
width: 100%;
height: 240px;
}

View File

@ -1,140 +0,0 @@
import * as echarts from "echarts";
export const initEcharts1 = (mainRef, chartInstance, data) => {
const colors = [
"29,128,219",
"1,245,255",
"228,187,45",
"45,118,228",
"188,45,228",
"228,72,45",
"58,45,228",
"221,44,67",
];
const date = data.date;
const name = data.name;
const series = [];
for (let i = 0; i < date.length; i++) {
series.push({
name: name[i],
type: "line",
symbol: "circle",
showAllSymbol: true,
symbolSize: 0,
smooth: true,
lineStyle: {
width: 2,
color: `rgba(${colors[i]},1)`,
},
itemStyle: {
color: `rgba(${colors[i]},1)`,
},
tooltip: {
show: true,
},
areaStyle: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: `rgba(${colors[i]},0.3)`,
},
{
offset: 1,
color: `rgba(${colors[i]},0)`,
},
],
false,
),
shadowColor: "rgba(25,163,223, 0.5)",
shadowBlur: 20,
},
data: date[i],
});
}
chartInstance.current = echarts.init(mainRef.current);
const option = {
tooltip: {
trigger: "axis",
},
legend: {
top: "0",
align: "left",
type: "plain",
data: name,
textStyle: {
color: "#fff",
fontSize: 12,
},
itemWidth: 18,
},
grid: {
top: "20%",
left: "10%",
right: "5%",
bottom: "15%",
},
xAxis: [
{
type: "category",
boundaryGap: false,
axisLine: {
show: true,
lineStyle: {
color: "#15578b",
},
},
axisLabel: {
color: "#fff",
fontSize: 12,
formatter(data) {
return data.substring(5);
},
},
splitLine: {
show: false,
lineStyle: {
color: "#fff",
},
},
axisTick: {
show: false,
},
data: data.clickDate,
},
],
yAxis: [
{
min: 0,
splitLine: {
show: true,
lineStyle: {
color: "rgba(221,221,221,0.1)",
},
},
axisLine: {
show: false,
lineStyle: {
color: "#fff",
},
},
axisLabel: {
show: true,
color: "#fff",
padding: 10,
},
},
],
series,
};
chartInstance.current.setOption(option);
};

View File

@ -1,137 +1,16 @@
import { useMount } from "ahooks";
import { useContext, useRef, useState } from "react";
import CountUp from "react-countup";
import anquan_bg1 from "~/assets/images/map_bi/content/anquan_bg1.png";
import anquan_bg2 from "~/assets/images/map_bi/content/anquan_bg2.png";
import anquan_bg3 from "~/assets/images/map_bi/content/anquan_bg3.png";
import anquan_bg4 from "~/assets/images/map_bi/content/anquan_bg4.png";
import icobg from "~/assets/images/map_bi/content/icobg.png";
import icon27 from "~/assets/images/map_bi/content/icon27.png";
import icon28 from "~/assets/images/map_bi/content/icon28.png";
import icon29 from "~/assets/images/map_bi/content/icon29.png";
import label from "~/assets/images/map_bi/content/label.png";
import Title from "~/pages/Container/Map/components/Content/port/Title";
import { Context } from "~/pages/Container/Map/js/context";
import { initEcharts1 } from "./echarts";
import "./index.less";
const WeiXian = () => {
const { currentPort, portArea, currentBranchOffice } = useContext(Context);
const [block3List, setBlock3List] = useState([
{ WORK_TYPE: "动火作业", STATUS_NAME: "现场负责人", USER_NAME: "李长健" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "运行乙班" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "卸车部运行乙班" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "动火后", USER_NAME: "王启龙" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "装船部" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "装船队机修乙班" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "动火后", USER_NAME: "彭俊伟" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "装船队机修乙班" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "运行乙班" },
{ WORK_TYPE: "动火作业", STATUS_NAME: "延时监火", USER_NAME: "卸车队运行甲班" },
]);
const [block1OptionsList, setBlock1OptionsList] = useState([
{ img: icon27, label: "申请数", count: 0 },
{ img: icon28, label: "审批中", count: 0 },
{ img: icon29, label: "归档数", count: 0 },
]);
const main1Ref = useRef(null);
const chartInstance = useRef(null);
useMount(() => {
initEcharts1(main1Ref, chartInstance, {
clickDate: ["2025-12-31", "2026-01-01", "2026-01-02", "2026-01-03", "2026-01-04"],
date: [
["7.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
["0.0", "0.0", "0.0", "0.0", "0.0"],
],
name: ["动火作业", "盲板作业", "有限空间作业", "高处作业", "吊装作业", "临时用电", "动土作业", "断路作业"],
});
return () => {
if (chartInstance.current) {
chartInstance.current.dispose();
chartInstance.current = null;
}
};
});
import WorkRecordPanel from "./WorkRecordPanel";
import WorkStatusPanel from "./WorkStatusPanel";
import WorkTrendPanel from "./WorkTrendPanel";
/** 危险作业模块仅负责按展示顺序组合业务区块。 */
function WeiXian() {
return (
<div className="port_weixian">
<div className="block1">
<Title title="安全作业状态统计" />
<div className="options">
{block1OptionsList.map((item, index) => (
<div key={index} className="option">
<div className="circular" style={{ backgroundImage: `url(${icobg})` }}>
<img src={item.img} alt="" />
</div>
<div className="label" style={{ backgroundImage: `url(${label})` }}>
{item.label}
<CountUp end={+item.count} />
</div>
</div>
))}
</div>
</div>
<div className="block2">
<Title title="安全作业情况统计" />
<div className="content">
<div ref={main1Ref} style={{ width: "100%", height: "240px" }} />
</div>
</div>
<div className="block3">
<Title title="安全作业记录" />
<div className="content">
<div className="table">
<div className="tr">
<div className="td">序号</div>
<div className="td">作业类型</div>
<div className="td">状态</div>
<div className="td">下一步操作人</div>
</div>
{block3List && block3List.length > 0
? (
block3List.map((item, index) => (
<div key={index} className="tr">
<div className="td">
<div
className="bg"
style={{
...(index === 0 && { backgroundImage: `url(${anquan_bg1})` }),
...(index === 1 && { backgroundImage: `url(${anquan_bg2})` }),
...(index === 2 && { backgroundImage: `url(${anquan_bg3})` }),
...(index > 2 && { backgroundImage: `url(${anquan_bg4})` }),
}}
>
{index + 1}
</div>
</div>
<div className="td">{item.WORK_TYPE}</div>
<div className="td">{item.STATUS_NAME}</div>
<div className="td">{item.USER_NAME}</div>
</div>
))
)
: (
<div className="tr">
<div className="empty">暂无数据</div>
</div>
)}
</div>
</div>
</div>
<div className="port-danger-work">
<WorkStatusPanel />
<WorkTrendPanel />
<WorkRecordPanel />
</div>
);
};
}
export default WeiXian;

View File

@ -1,160 +0,0 @@
.port_weixian {
.block1 {
background-image: linear-gradient(to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8));
.options {
display: flex;
justify-content: space-between;
padding: 13px 15px;
border: 1px solid;
border-image: linear-gradient(to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)) 1;
border-top: none;
.option {
display: flex;
flex-direction: column;
align-items: center;
.circular {
background-size: 100% 100%;
background-repeat: no-repeat;
width: 70px;
height: 70px;
text-align: center;
padding-top: 13px;
img {
width: 25px;
height: 26px;
animation: weixianSlideY 2s infinite;
}
}
.label {
display: flex;
justify-content: center;
background-size: 100% 100%;
background-repeat: no-repeat;
width: 120px;
height: 24px;
margin-top: 6px;
font-size: 12px;
line-height: 25px;
text-align: center;
color: #fff;
}
}
}
}
.block2 {
margin-top: 10px;
background-image: linear-gradient(to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8));
.content {
padding: 10px 15px;
border: 1px solid;
border-image: linear-gradient(to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)) 1;
border-top: none;
}
}
.block3 {
margin-top: 10px;
background-image: linear-gradient(to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8));
.content {
border: 1px solid;
border-image: linear-gradient(to bottom,
rgba(58, 122, 149, 0),
rgba(58, 122, 149, 1)) 1;
border-top: none;
padding: 10px;
.options {
display: flex;
justify-content: flex-end;
.title {
cursor: pointer;
}
}
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
&:nth-child(1) {
flex: none;
flex-basis: 50px;
text-align: left;
}
&:nth-child(2) {
flex-basis: 20%;
}
.bg {
background-size: 100% 100%;
background-repeat: no-repeat;
width: 21px;
height: 15px;
margin: auto;
line-height: 15px;
padding-left: 4px;
}
}
&:nth-child(n + 11) {
.bg {
padding-left: 0;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes weixianSlideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
}

View File

@ -17,7 +17,7 @@ function FireDeviceListPanel(props) {
useEffect(() => {
const loadDeviceList = async () => {
setIsVisible(false);
const { data } = await props.getFirePointDeviceList({
const { data = [] } = await props.getFirePointDeviceList({
portArea,
...queryParams,
pageIndex: 1,

View File

@ -114,21 +114,23 @@ function Map(props) {
return (
<div ref={fullscreenRef}>
<Spin spinning={props.biMark.biFullLoading} delay={500} description="正在加载数据...">
<Context.Provider value={providerValues}>
<div id="cesiumContainer" />
<div id="contentContainer">
{isRenderContent && (
<Spin spinning={props.biMark.biFullLoading}>
<>
<Header />
<CenterUtils />
<RightUtils history={props.history} isFullscreen={isFullscreen} toggleFullscreen={toggleFullscreen} />
<BottomUtils />
<Content history={props.history} />
<CustomModal />
</Spin>
</>
)}
</div>
</Context.Provider>
</Spin>
<div
style={{ display: state.coverMaskVisible ? "block" : "none" }}
className="coverMaskContainer"

View File

@ -130,7 +130,7 @@ export default function useMapMethods(viewerRef, request) {
// 添加分公司点
const addBranchOfficePoint = async (portArea = 1, pointInfo = null) => {
const { data } = await request.getCorpInfoListAll({ eqPortArea: portArea, inType: [0, 1, 2, 6] });
const { data = [] } = await request.getCorpInfoListAll({ eqPortArea: portArea, inType: [0, 1, 2, 6] });
mitt.emit(changeCoverMaskVisibleMittKey, true);
let branchOfficePoint = [];
if (!pointInfo) {
@ -348,6 +348,7 @@ export default function useMapMethods(viewerRef, request) {
* @param options.markType {String} 扎点类型
* @param options.subLabel {String} 二级标题用于弹窗标题
* @param options.titleKey {String} 标题键用于从item中获取标题
* @param options.isShowModal {Boolean} 是否显示弹窗
*/
const addMarkPoint = async (pointList, options) => {
if (!options.markType)
@ -367,7 +368,7 @@ export default function useMapMethods(viewerRef, request) {
position: getPosition(item.longitude || item.lng, item.latitude || item.lat),
billboard: await getBillboard({ image: options.markIcon, name }),
monitorItems: {
data: { ...item, markType: `标记点_${options.markType}`, title: options.subLabel },
data: { ...item, markType: `标记点_${options.markType}`, title: options.subLabel, isShowModal: options.isShowModal ?? true },
},
}),
);

View File

@ -103,6 +103,7 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
};
const clickMarkPoint = (data) => {
if (data.isShowModal)
mitt.emit(clickMarkPointMittKey, data);
};