refactor(map): 人员定位 二级 三级 对接接口

master
LiuJiaNan 2026-07-28 17:36:24 +08:00
parent 854fbeff50
commit 07aea5d5fc
10 changed files with 174 additions and 260 deletions

View File

@ -148,3 +148,19 @@ export const getAlarmType = declareRequest(
"getAlarmTypeLoading", "getAlarmTypeLoading",
"Post > @/personnelPosition/alarmRecord/bi/alarmType", "Post > @/personnelPosition/alarmRecord/bi/alarmType",
); );
export const getPersonStat = declareRequest(
"getPersonStatLoading",
"Post > @/personnelPosition/area/personStat",
);
export const getPersonLocationPositioning = declareRequest(
"getPersonLocationPositioningLoading",
"Post > @/personnelPosition/bi/personLocation/positioning",
);
export const getAlarmRecordList = declareRequest(
"getAlarmRecordListLoading",
"Post > @/personnelPosition/alarmRecord/bi/list",
);
export const getPersonLocationCompanyOnlineStat = declareRequest(
"getPersonLocationCompanyOnlineStatLoading",
"Post > @/personnelPosition/bi/personLocation/companyOnlineStat",
);

View File

@ -1,24 +1,29 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useContext, useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll"; import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel"; import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less"; import "./index.less";
const records = [ const dispositionText = { INIT: "未处置", CLOSE: "已处置" };
{ alarmContent: "SOS紧急告警", personnelInvolved: "张三", dispositionStatus: 1 },
{ alarmContent: "静止/滞留告警", personnelInvolved: "李四", dispositionStatus: 2 },
{ alarmContent: "电子围栏越界", personnelInvolved: "王五", dispositionStatus: 1 },
{ alarmContent: "非授权区域停留", personnelInvolved: "赵六", dispositionStatus: 3 },
{ alarmContent: "设备及信号类告警", personnelInvolved: "钱七", dispositionStatus: 1 },
{ alarmContent: "聚集告警", personnelInvolved: "孙八", dispositionStatus: 2 },
{ alarmContent: "单独作业告警", personnelInvolved: "周九", dispositionStatus: 1 },
{ alarmContent: "超员/缺员告警", personnelInvolved: "吴十", dispositionStatus: 3 },
{ alarmContent: "SOS紧急告警", personnelInvolved: "郑一", dispositionStatus: 1 },
{ alarmContent: "静止/滞留告警", personnelInvolved: "王二", dispositionStatus: 2 },
];
const dispositionText = { 1: "已处置", 2: "未处置", 3: "处置中" };
/** 负责展示人员告警处置状态列表。 */ /** 负责展示人员告警处置状态列表。 */
function AlarmHandlingPanel() { function AlarmHandlingPanel(props) {
const { portArea, currentBranchOffice } = useContext(Context);
const [data, setData] = useState([]);
useEffect(() => {
const loadData = async () => {
const { data } = await props.getAlarmRecordList({ portArea, corpinfoId: currentBranchOffice });
setData(data || []);
};
loadData();
}, []);
return ( return (
<Panel title="告警处置情况" className="branch-office-personnel__alarm-handling"> <Panel title="告警处置情况" className="branch-office-personnel__alarm-handling">
<div className="branch-office-alarm-handling__content"> <div className="branch-office-alarm-handling__content">
@ -29,19 +34,17 @@ function AlarmHandlingPanel() {
<div>处置情况</div> <div>处置情况</div>
</div> </div>
<div className="branch-office-alarm-handling__body"> <div className="branch-office-alarm-handling__body">
<SeamlessScroll list={records} step={0.5}> <Spin spinning={props.biStatistics.getAlarmRecordListLoading}>
{records.map((item, index) => ( <SeamlessScroll list={data} step={0.5}>
{data.map((item, index) => (
<div className="branch-office-alarm-handling__row" key={index}> <div className="branch-office-alarm-handling__row" key={index}>
<div>{item.alarmContent}</div> <div>{item.description}</div>
<div>{item.personnelInvolved}</div> <div>{item.firstStaffNameSnapshot}</div>
<div <div className="branch-office-alarm-handling__status">{dispositionText[item.disposeStatus]}</div>
className={`branch-office-alarm-handling__status branch-office-alarm-handling__status--${item.dispositionStatus}`}
>
{dispositionText[item.dispositionStatus]}
</div>
</div> </div>
))} ))}
</SeamlessScroll> </SeamlessScroll>
</Spin>
</div> </div>
</div> </div>
</div> </div>
@ -49,4 +52,4 @@ function AlarmHandlingPanel() {
); );
} }
export default AlarmHandlingPanel; export default Connect([NS_BI_STATISTICS], true)(AlarmHandlingPanel);

View File

@ -28,15 +28,3 @@
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
} }
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--1 {
color: #1db924;
}
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--2 {
color: #ff611c;
}
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--3 {
color: #258ff1;
}

View File

@ -49,7 +49,7 @@ function AlarmTypeChartPanel(props) {
useMount(() => { useMount(() => {
const loadData = async () => { const loadData = async () => {
const { data } = await props.getAlarmType({ portArea, corpinfoId: currentBranchOffice }); const { data } = await props.getAlarmType({ portArea, corpinfoId: currentBranchOffice });
initEcharts(chartRef, chartInstance, data); initEcharts(chartRef, chartInstance, data || []);
}; };
loadData(); loadData();

View File

@ -1,33 +1,26 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { useMount } from "ahooks"; import { useMount } from "ahooks";
import { Spin } from "antd";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { useRef } from "react"; import { useContext, useRef } from "react";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel"; import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less"; import "./index.less";
const records = [
{ name: "A区", unitPersonnelCount: 120, relatedPartyPersonnelCount: 85 },
{ name: "B区", unitPersonnelCount: 95, relatedPartyPersonnelCount: 70 },
{ name: "C区", unitPersonnelCount: 80, relatedPartyPersonnelCount: 60 },
{ name: "D区", unitPersonnelCount: 150, relatedPartyPersonnelCount: 110 },
{ name: "E区", unitPersonnelCount: 75, relatedPartyPersonnelCount: 55 },
{ name: "F区", unitPersonnelCount: 110, relatedPartyPersonnelCount: 80 },
{ name: "G区", unitPersonnelCount: 65, relatedPartyPersonnelCount: 45 },
{ name: "H区", unitPersonnelCount: 140, relatedPartyPersonnelCount: 100 },
{ name: "I区", unitPersonnelCount: 90, relatedPartyPersonnelCount: 65 },
{ name: "J区", unitPersonnelCount: 125, relatedPartyPersonnelCount: 90 },
];
/** 负责展示封闭区域人员统计图,并管理图表实例生命周期。 */ /** 负责展示封闭区域人员统计图,并管理图表实例生命周期。 */
function ClosedAreaPersonnelPanel() { function ClosedAreaPersonnelPanel(props) {
const { portArea, currentBranchOffice } = useContext(Context);
const chartInstance = useRef(null); const chartInstance = useRef(null);
const chartRef = useRef(null); const chartRef = useRef(null);
const initEcharts = (mainRef, chartInstance, data) => { const initEcharts = (mainRef, chartInstance, data) => {
chartInstance.current = echarts.init(mainRef.current); chartInstance.current = echarts.init(mainRef.current);
const unitPersonnelData = data.map(item => Number.parseInt(item.unitPersonnelCount)); const unitPersonnelData = data.map(item => Number.parseInt(item.unitCount));
const relatedPartyPersonnelData = data.map(item => Number.parseInt(item.relatedPartyPersonnelCount)); const relatedPartyPersonnelData = data.map(item => Number.parseInt(item.relatedCount));
const names = data.map(item => item.name); const names = data.map(item => item.areaName);
const option = { const option = {
tooltip: { tooltip: {
@ -162,7 +155,12 @@ function ClosedAreaPersonnelPanel() {
}; };
useMount(() => { useMount(() => {
initEcharts(chartRef, chartInstance, records); const loadData = async () => {
const { data } = await props.getPersonStat({ portArea, corpinfoId: currentBranchOffice });
initEcharts(chartRef, chartInstance, data || []);
};
loadData();
return () => { return () => {
if (chartInstance.current) { if (chartInstance.current) {
@ -177,11 +175,13 @@ function ClosedAreaPersonnelPanel() {
title="封闭区域人员统计情况" title="封闭区域人员统计情况"
className="branch-office-personnel__area-statistics" className="branch-office-personnel__area-statistics"
> >
<Spin spinning={props.biStatistics.getPersonStatLoading}>
<div className="branch-office-area-personnel__content"> <div className="branch-office-area-personnel__content">
<div ref={chartRef} className="branch-office-area-personnel__chart" /> <div ref={chartRef} className="branch-office-area-personnel__chart" />
</div> </div>
</Spin>
</Panel> </Panel>
); );
} }
export default ClosedAreaPersonnelPanel; export default Connect([NS_BI_STATISTICS], true)(ClosedAreaPersonnelPanel);

View File

@ -1,22 +1,27 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useContext, useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll"; import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel"; import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less"; import "./index.less";
const records = [
{ name: "张三", area: "A区", onlineStatus: 1 },
{ name: "李四", area: "B区", onlineStatus: 1 },
{ name: "王五", area: "C区", onlineStatus: 2 },
{ name: "赵六", area: "D区", onlineStatus: 1 },
{ name: "钱七", area: "E区", onlineStatus: 1 },
{ name: "孙八", area: "F区", onlineStatus: 2 },
{ name: "周九", area: "G区", onlineStatus: 1 },
{ name: "吴十", area: "H区", onlineStatus: 1 },
{ name: "郑一", area: "I区", onlineStatus: 2 },
{ name: "王二", area: "J区", onlineStatus: 1 },
];
/** 负责展示人员定位与在线状态列表。 */ /** 负责展示人员定位与在线状态列表。 */
function PersonnelLocationPanel() { function PersonnelLocationPanel(props) {
const { portArea, currentBranchOffice } = useContext(Context);
const [data, setData] = useState([]);
useEffect(() => {
const loadData = async () => {
const { data } = await props.getPersonLocationPositioning({ portArea, corpinfoId: currentBranchOffice });
setData(data || []);
};
loadData();
}, []);
return ( return (
<Panel title="人员定位列表" className="branch-office-personnel__location"> <Panel title="人员定位列表" className="branch-office-personnel__location">
<div className="branch-office-personnel-location__content"> <div className="branch-office-personnel-location__content">
@ -27,19 +32,17 @@ function PersonnelLocationPanel() {
<div>在线状态</div> <div>在线状态</div>
</div> </div>
<div className="branch-office-personnel-location__body"> <div className="branch-office-personnel-location__body">
<SeamlessScroll list={records} step={0.5}> <Spin spinning={props.biStatistics.getPersonLocationPositioningLoading}>
{records.map((item, index) => ( <SeamlessScroll list={data} step={0.5}>
{data.map((item, index) => (
<div className="branch-office-personnel-location__row" key={index}> <div className="branch-office-personnel-location__row" key={index}>
<div>{item.name}</div> <div>{item.personName}</div>
<div>{item.area}</div> <div>{item.areaName}</div>
<div <div className="branch-office-personnel-location__status">{item.onlineStatusName}</div>
className={`branch-office-personnel-location__status branch-office-personnel-location__status--${item.onlineStatus}`}
>
{item.onlineStatus === 1 ? "在线" : "离线"}
</div>
</div> </div>
))} ))}
</SeamlessScroll> </SeamlessScroll>
</Spin>
</div> </div>
</div> </div>
</div> </div>
@ -47,4 +50,4 @@ function PersonnelLocationPanel() {
); );
} }
export default PersonnelLocationPanel; export default Connect([NS_BI_STATISTICS], true)(PersonnelLocationPanel);

View File

@ -28,7 +28,3 @@
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
} }
.branch-office-personnel-location__row .branch-office-personnel-location__status--1 {
color: #1db924;
}

View File

@ -1,132 +1,27 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useContext, useEffect, useState } from "react";
import SeamlessScroll from "zy-react-library/components/SeamlessScroll"; 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 Panel from "~/pages/Container/Map/components/Content/port/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less"; import "./index.less";
const records = [
{
alarmName: "安全帽佩戴异常",
alarmTime: "2024-12-19 10:30:25",
foulUserName: "张三",
place: "二号码头作业区",
},
{
alarmName: "进入危险区域",
alarmTime: "2024-12-19 09:45:12",
foulUserName: "李四",
place: "化学品仓库",
},
{
alarmName: "高空作业未系安全带",
alarmTime: "2024-12-19 08:20:48",
foulUserName: "王五",
place: "装卸平台",
},
{
alarmName: "违规操作设备",
alarmTime: "2024-12-19 07:15:33",
foulUserName: "赵六",
place: "维修车间",
},
{
alarmName: "烟火报警",
alarmTime: "2024-12-19 06:50:17",
foulUserName: "钱七",
place: "物料堆放区",
},
{
alarmName: "超时作业",
alarmTime: "2024-12-19 05:42:09",
foulUserName: "孙八",
place: "集装箱堆场",
},
{
alarmName: "违规吸烟",
alarmTime: "2024-12-19 04:18:34",
foulUserName: "周九",
place: "油料储存区",
},
{
alarmName: "人员聚集超限",
alarmTime: "2024-12-19 03:25:41",
foulUserName: "吴十",
place: "登船通道",
},
{
alarmName: "车辆超速",
alarmTime: "2024-12-19 02:33:16",
foulUserName: "郑十一",
place: "港内道路",
},
{
alarmName: "未佩戴防护用品",
alarmTime: "2024-12-19 01:45:28",
foulUserName: "王十二",
place: "散货码头",
},
{
alarmName: "进入限制区域",
alarmTime: "2024-12-18 23:12:55",
foulUserName: "冯十三",
place: "控制中心",
},
{
alarmName: "违规动火作业",
alarmTime: "2024-12-18 22:05:43",
foulUserName: "陈十四",
place: "维修平台",
},
{
alarmName: "人员滞留超时",
alarmTime: "2024-12-18 21:38:19",
foulUserName: "褚十五",
place: "危险品堆场",
},
{
alarmName: "设备异常操作",
alarmTime: "2024-12-18 20:27:06",
foulUserName: "卫十六",
place: "装卸设备区",
},
{
alarmName: "违规携带危险品",
alarmTime: "2024-12-18 19:44:52",
foulUserName: "蒋十七",
place: "安检通道",
},
{
alarmName: "安全距离不足",
alarmTime: "2024-12-18 18:15:37",
foulUserName: "沈十八",
place: "龙门吊作业区",
},
{
alarmName: "违规使用手机",
alarmTime: "2024-12-18 17:29:44",
foulUserName: "韩十九",
place: "易燃品仓库",
},
{
alarmName: "人员跌倒",
alarmTime: "2024-12-18 16:36:21",
foulUserName: "杨二十",
place: "栈桥区域",
},
{
alarmName: "违规跨越护栏",
alarmTime: "2024-12-18 15:51:08",
foulUserName: "朱二十一",
place: "码头边缘",
},
{
alarmName: "未按指定路线行走",
alarmTime: "2024-12-18 14:42:35",
foulUserName: "秦二十二",
place: "作业通道",
},
];
/** 展示人员定位相关的报警列表。 */ /** 展示人员定位相关的报警列表。 */
function AlarmListPanel() { function AlarmListPanel(props) {
const { portArea } = useContext(Context);
const [data, setData] = useState([]);
useEffect(() => {
const loadData = async () => {
const { data } = await props.getAlarmRecordList({ portArea });
setData(data || []);
};
loadData();
}, []);
return ( return (
<Panel title="报警列表" className="port-personnel__alarm-list"> <Panel title="报警列表" className="port-personnel__alarm-list">
<div className="port-personnel-alarm-list__content"> <div className="port-personnel-alarm-list__content">
@ -138,24 +33,18 @@ function AlarmListPanel() {
<div className="port-personnel-alarm-list__cell">报警地点</div> <div className="port-personnel-alarm-list__cell">报警地点</div>
</div> </div>
<div className="port-personnel-alarm-list__table-body"> <div className="port-personnel-alarm-list__table-body">
<SeamlessScroll list={records} step={0.5}> <Spin spinning={props.biStatistics.getAlarmRecordListLoading}>
{records.map((item, index) => ( <SeamlessScroll list={data} step={0.5}>
{data.map((item, index) => (
<div key={index} className="port-personnel-alarm-list__row"> <div key={index} className="port-personnel-alarm-list__row">
<div className="port-personnel-alarm-list__cell"> <div className="port-personnel-alarm-list__cell">{item.alarmTypeName}</div>
{item.alarmName} <div className="port-personnel-alarm-list__cell">{item.startTime}</div>
</div> <div className="port-personnel-alarm-list__cell">{item.firstStaffNameSnapshot}</div>
<div className="port-personnel-alarm-list__cell"> <div className="port-personnel-alarm-list__cell">{item.alarmName?.split("-")[0]}</div>
{item.alarmTime}
</div>
<div className="port-personnel-alarm-list__cell">
{item.foulUserName}
</div>
<div className="port-personnel-alarm-list__cell">
{item.place}
</div>
</div> </div>
))} ))}
</SeamlessScroll> </SeamlessScroll>
</Spin>
</div> </div>
</div> </div>
</div> </div>
@ -163,4 +52,4 @@ function AlarmListPanel() {
); );
} }
export default AlarmListPanel; export default Connect([NS_BI_STATISTICS], true)(AlarmListPanel);

View File

@ -1,26 +1,44 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Spin } from "antd";
import { useContext, useEffect, useState } from "react";
import employeeIcon from "~/assets/images/map_bi/content/img1ico1.png"; import employeeIcon from "~/assets/images/map_bi/content/img1ico1.png";
import vehicleIcon from "~/assets/images/map_bi/content/img1ico2.png"; import vehicleIcon from "~/assets/images/map_bi/content/img1ico2.png";
import internalIcon from "~/assets/images/map_bi/content/img1ico3.png"; import internalIcon from "~/assets/images/map_bi/content/img1ico3.png";
import contractorIcon from "~/assets/images/map_bi/content/img1ico4.png"; import contractorIcon from "~/assets/images/map_bi/content/img1ico4.png";
import temporaryIcon from "~/assets/images/map_bi/content/img1ico5.png"; import temporaryIcon from "~/assets/images/map_bi/content/img1ico5.png";
import iconBackground from "~/assets/images/map_bi/content/img2.png"; import iconBackground from "~/assets/images/map_bi/content/img2.png";
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
import Panel from "~/pages/Container/Map/components/Content/port/Panel"; import Panel from "~/pages/Container/Map/components/Content/port/Panel";
import { Context } from "~/pages/Container/Map/js/context";
import "./index.less"; import "./index.less";
const statistics = [ const statistics = [
{ title: "在线员工", image: employeeIcon, count: "-" }, { title: "在线员工", image: employeeIcon, count: "0", key: "onlineCount" },
{ title: "在线车辆", image: vehicleIcon, count: "-" }, { title: "在线车辆", image: vehicleIcon, count: "0" },
{ title: "内部人员", image: internalIcon, count: "-" }, { title: "内部人员", image: internalIcon, count: "0", key: "internalCount" },
{ title: "外协人员", image: contractorIcon, count: "-" }, { title: "外协人员", image: contractorIcon, count: "0" },
{ title: "临时人员", image: temporaryIcon, count: "-" }, { title: "临时人员", image: temporaryIcon, count: "0", key: "temporaryCount" },
]; ];
/** 展示人员定位相关的基础统计信息。 */ /** 展示人员定位相关的基础统计信息。 */
function LocationInfoPanel() { function LocationInfoPanel(props) {
const { portArea } = useContext(Context);
const [data, setData] = useState(statistics);
useEffect(() => {
const loadData = async () => {
const { data } = await props.getPersonLocationCompanyOnlineStat({ portArea });
setData(statistics.map(item => ({ ...item, count: (data || {})[item.key] || 0 })));
};
loadData();
}, []);
return ( return (
<Panel title="定位基础信息"> <Panel title="定位基础信息">
<Spin spinning={props.biStatistics.getPersonLocationCompanyOnlineStatLoading}>
<div className="port-location-info__options"> <div className="port-location-info__options">
{statistics.map(item => ( {data.map(item => (
<div key={item.title} className="port-location-info__option"> <div key={item.title} className="port-location-info__option">
<div <div
className="port-location-info__icon" className="port-location-info__icon"
@ -35,8 +53,9 @@ function LocationInfoPanel() {
</div> </div>
))} ))}
</div> </div>
</Spin>
</Panel> </Panel>
); );
} }
export default LocationInfoPanel; export default Connect([NS_BI_STATISTICS], true)(LocationInfoPanel);

View File

@ -83,7 +83,7 @@ function Map(props) {
setTimeout(() => { setTimeout(() => {
if (window.sessionStorage.getItem("token")) { if (window.sessionStorage.getItem("token")) {
props.getCorpInfo().then(({ data }) => { props.getCorpInfo().then(({ data }) => {
if ([0, 1, 6].includes(data.type)) { if ([0, 1, 6].includes(data?.type)) {
const id = data.id; const id = data.id;
const name = data.corpName; const name = data.corpName;
const longitude = data.longitude; const longitude = data.longitude;