feat(map): 新增标记点点击弹窗及气象监测模块

master
LiuJiaNan 2026-07-20 14:23:04 +08:00
parent 266f7c3394
commit a5d0f2588b
14 changed files with 128 additions and 32 deletions

View File

@ -24,8 +24,7 @@ module.exports = {
contextInject: {
// 应用Key
appKey: "",
fileUrl: "https://jpfz.qhdsafety.com/gbsFileTest/",
// fileUrl: "http://192.168.20.240:9787/mnt/",
fileUrl: "",
},
// public/index.html注入全局变量
windowInject: {
@ -45,7 +44,7 @@ module.exports = {
// 开发服务
server: {
// 监听端口号
port: "8080",
port: "8956",
// 服务地址
host: "127.0.0.1",
// 是否自动打开浏览器

View File

@ -2,6 +2,7 @@ import { setJJBCommonAntdMessage } from "@cqsjjb/jjb-common-lib";
import { setup } from "@cqsjjb/jjb-dva-runtime";
import { message } from "antd";
import dayjs from "dayjs";
import { getFileUrlFromServer } from "zy-react-library/utils";
import "dayjs/locale/zh-cn";
import "../blessed_by_buddha";
@ -12,6 +13,10 @@ dayjs.locale("zh-cn");
setJJBCommonAntdMessage(message);
const app = setup();
getFileUrlFromServer();
window.mapLongitude = "119.69457721306945";
window.mapLatitude = "39.940504336846665";
window.mapBaiDuKey = "OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr";
// 非底座环境运行
if (!window.__POWERED_BY_QIANKUN__) {

View File

@ -17,7 +17,7 @@ function VideoPatrolPanel(props) {
const { data, success } = await props.getFixedCameraPlayUrl({
indexCode: cameraNumber,
});
if (success)
if (success && data)
setPlayUrl(data.url);
};
const selectCorp = (item) => {

View File

@ -54,7 +54,7 @@ function Camera() {
width={1500}
onCancel={setFalse}
title="视频巡屏"
wrapClassName="map_content_branch_office_camera_modal"
wrapClassName="map_content_branch_office_camera_modal map_bi_model"
>
<div className="container">
<div className="parent_tabs">

View File

@ -1,24 +1,4 @@
.map_content_branch_office_camera_modal {
.@{ant-prefix}-modal {
.@{ant-prefix}-modal-header {
background-color: #06103b;
padding: 16px 20px;
.@{ant-prefix}-modal-title {
color: #fff;
}
}
.@{ant-prefix}-modal-content {
padding: 0;
background-color: #020828;
}
.@{ant-prefix}-modal-close {
color: #fff;
}
}
.container {
padding: 27px 14px;

View File

@ -0,0 +1,15 @@
const MeteorologicalMonitoring = () => {
return (
<div>
<iframe
sandbox=""
src="http://192.168.42.57:8080/QinHuangDao"
style={{ width: "100%", height: "80vh" }}
frameBorder="0"
allowFullScreen
/>
</div>
);
};
export default MeteorologicalMonitoring;

View File

@ -0,0 +1,26 @@
import { Modal } from "antd";
import { useContext } from "react";
import { Context } from "~/pages/Container/Map/js/context";
import MeteorologicalMonitoring from "./MeteorologicalMonitoring";
const CustomModal = () => {
const { modalVisible, modalData, actions } = useContext(Context);
return (
<Modal
open={modalVisible}
mask={{ closable: false }}
footer={null}
width={1500}
onCancel={() => {
actions.resetMark();
}}
title={modalData.title || ""}
wrapClassName="map_bi_model"
>
<MeteorologicalMonitoring />
</Modal>
);
};
export default CustomModal;

View File

@ -106,6 +106,9 @@ function RightUtils(props) {
case "pureMap":
actions.setPureMap(!pureMap);
break;
case "weather":
actions.selectMark({ title: "气象监测" });
break;
case "fourColor":
if (!currentPort) {
message.warning("请选择要查看的港口");

View File

@ -1,11 +1,12 @@
import { useFullscreen, useMount } from "ahooks";
import { message } from "antd";
import autoFit from "autofit.js";
import { useEffect, useMemo, useReducer, useRef } from "react";
import { useEffect, useMemo, useReducer, useRef, useState } from "react";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import BottomUtils from "./components/BottomUtils";
import CenterUtils from "./components/CenterUtils";
import Content from "./components/Content";
import CustomModal from "./components/Content/modal";
import Header from "./components/Header";
import RightUtils from "./components/RightUtils";
import { Context, initialMapState, MAP_ACTION, mapReducer } from "./js/context";
@ -14,6 +15,7 @@ import mitt from "./js/mitt";
import {
changeCoverMaskVisibleMittKey,
clickBranchOfficePointMittKey,
clickMarkPointMittKey,
clickPortPointMittKey,
resetBottomUtilsMittKey,
} from "./js/mittKey";
@ -23,6 +25,7 @@ function Map(props) {
const query = useGetUrlQuery();
const { viewer, mapMethods, initMap, externalEntryPort } = useInitMap();
const [isRenderContent, setIsRenderContent] = useState(false);
const fullscreenRef = useRef(null); // 全屏容器的ref
const [isFullscreen, { toggleFullscreen }] = useFullscreen(fullscreenRef);
const [state, dispatch] = useReducer(mapReducer, initialMapState);
@ -31,6 +34,8 @@ function Map(props) {
const actions = useMemo(() => ({
selectPort: data => dispatch({ type: MAP_ACTION.SELECT_PORT, payload: data }),
selectBranchOffice: data => dispatch({ type: MAP_ACTION.SELECT_BRANCH_OFFICE, payload: data }),
selectMark: data => dispatch({ type: MAP_ACTION.SELECT_MARK, payload: data }),
resetMark: () => dispatch({ type: MAP_ACTION.RESET_MARK }),
setArea: area => dispatch({ type: MAP_ACTION.SET_AREA, payload: area }),
setBottomUtilsIndex: index => dispatch({ type: MAP_ACTION.SET_BOTTOM_UTILS_INDEX, payload: index }),
resetBottomUtils: () => dispatch({ type: MAP_ACTION.RESET_BOTTOM_UTILS }),
@ -61,6 +66,7 @@ function Map(props) {
// Cesium 工具层暂时通过 mitt 通知;所有事件在根组件统一转成 reducer action。
const handlePortClick = data => actions.selectPort(data);
const handleBranchOfficeClick = data => actions.selectBranchOffice(data);
const handleMarkClick = data => actions.selectMark(data);
const handleCoverMaskVisible = (visible) => {
actions.setCoverMaskVisible(visible);
if (!visible) {
@ -70,6 +76,7 @@ function Map(props) {
const handleResetBottomUtils = () => actions.resetBottomUtils();
mitt.on(clickPortPointMittKey, handlePortClick);
mitt.on(clickBranchOfficePointMittKey, handleBranchOfficeClick);
mitt.on(clickMarkPointMittKey, handleMarkClick);
mitt.on(changeCoverMaskVisibleMittKey, handleCoverMaskVisible);
mitt.on(resetBottomUtilsMittKey, handleResetBottomUtils);
@ -77,6 +84,7 @@ function Map(props) {
autoFit.off();
mitt.off(clickPortPointMittKey, handlePortClick);
mitt.off(clickBranchOfficePointMittKey, handleBranchOfficeClick);
mitt.off(clickMarkPointMittKey, handleMarkClick);
mitt.off(changeCoverMaskVisibleMittKey, handleCoverMaskVisible);
mitt.off(resetBottomUtilsMittKey, handleResetBottomUtils);
};
@ -87,6 +95,10 @@ function Map(props) {
query.clientId && window.sessionStorage.setItem("clientId", query.clientId);
query.orgId && window.sessionStorage.setItem("orgId", query.orgId);
query.token && window.sessionStorage.setItem("token", query.token);
setTimeout(() => {
if (window.sessionStorage.getItem("token"))
setIsRenderContent(true);
});
}, []);
const providerValues = useMemo(
@ -99,11 +111,16 @@ function Map(props) {
<Context.Provider value={providerValues}>
<div id="cesiumContainer" />
<div id="contentContainer">
<Header />
<CenterUtils />
<RightUtils history={props.history} isFullscreen={isFullscreen} toggleFullscreen={toggleFullscreen} />
<BottomUtils />
<Content history={props.history} />
{isRenderContent && (
<>
<Header />
<CenterUtils />
<RightUtils history={props.history} isFullscreen={isFullscreen} toggleFullscreen={toggleFullscreen} />
<BottomUtils />
<Content history={props.history} />
<CustomModal />
</>
)}
</div>
</Context.Provider>
<div

View File

@ -33,3 +33,26 @@
pointer-events: auto;
}
}
.map_bi_model{
.@{ant-prefix}-modal {
.@{ant-prefix}-modal-header {
background-color: #06103b;
padding: 16px 20px;
.@{ant-prefix}-modal-title {
color: #fff;
}
}
.@{ant-prefix}-modal-body,.@{ant-prefix}-modal-container {
padding: 0;
background-color: #020828;
}
.@{ant-prefix}-modal-close {
color: #fff;
}
}
}

View File

@ -13,11 +13,15 @@ export const initialMapState = {
headerTitle: "秦港股份安全监管平台",
bottomUtilsResetVersion: 0,
rightUtilsResetVersion: 0,
modalVisible: false,
modalData: {},
};
export const MAP_ACTION = {
SELECT_PORT: "selectPort",
SELECT_BRANCH_OFFICE: "selectBranchOffice",
SELECT_MARK: "selectMark",
RESET_MARK: "resetMark",
SET_AREA: "setArea",
SET_BOTTOM_UTILS_INDEX: "setBottomUtilsIndex",
RESET_BOTTOM_UTILS: "resetBottomUtils",
@ -47,6 +51,21 @@ export function mapReducer(state, action) {
headerTitle: `${data.corpName || data.name}安全监管平台`,
};
}
case MAP_ACTION.SELECT_MARK: {
const data = action.payload;
return {
...state,
modalVisible: true,
modalData: data,
};
}
case MAP_ACTION.RESET_MARK: {
return {
...state,
modalVisible: false,
modalData: {},
};
}
case MAP_ACTION.SET_AREA:
return { ...state, area: action.payload };
case MAP_ACTION.SET_BOTTOM_UTILS_INDEX:

View File

@ -703,7 +703,7 @@ export default function useMapMethods(viewerRef) {
position: getPosition(item.LONGITUDE, item.LATITUDE),
billboard: await getBillboard({ image: options.mapIcon, name }),
monitorItems: {
data: { ...item, mapType: `标记点_${options.mapType}`, subLabel: options.subLabel },
data: { ...item, mapType: `标记点_${options.mapType}`, title: options.subLabel },
},
}),
);

View File

@ -2,6 +2,8 @@
export const clickPortPointMittKey = "clickPortPoint";
// 点击分公司点位
export const clickBranchOfficePointMittKey = "clickBranchOfficePoint";
// 点击标记点位
export const clickMarkPointMittKey = "clickMarkPoint";
// Cesium 点位层通知 React 重置底部工具栏
export const resetBottomUtilsMittKey = "resetBottomUtils";
// 改变覆盖蒙版显隐

View File

@ -6,6 +6,7 @@ import { getPosition } from "./mapUtils";
import mitt from "./mitt";
import {
clickBranchOfficePointMittKey,
clickMarkPointMittKey,
clickPortPointMittKey,
resetBottomUtilsMittKey,
} from "./mittKey";
@ -102,6 +103,10 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
});
};
const clickMarkPoint = (data) => {
mitt.emit(clickMarkPointMittKey, data);
};
// 点位点击
const pointClickEvent = (pick) => {
const data = pick.monitorItems.data;
@ -114,6 +119,8 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
clickPortPoint(data);
if (data.mapType === "分公司")
clickBranchOfficePoint(data);
if (data.mapType.includes("标记点"))
clickMarkPoint(data);
};
return {