refactor: 统一地图页面状态通信

master
LiuJiaNan 2026-07-16 10:38:54 +08:00
parent 30d17a21b0
commit 1328d6767c
8 changed files with 155 additions and 158 deletions

View File

@ -7,12 +7,6 @@ import titleImg from "~/assets/images/map_bi/bottom_utils/title.png";
import titleOnImg from "~/assets/images/map_bi/bottom_utils/title_on.png";
import { branchOfficeUtilsList } from "~/pages/Container/Map/components/BottomUtils/branchOfficeUtilsList";
import { Context } from "~/pages/Container/Map/js/context";
import mitt from "~/pages/Container/Map/js/mitt";
import {
deletePeoplePositionPointMittKey,
resetAllBottomUtilsCheckMittKey,
resetBottomCurrentIndexMittKey,
} from "~/pages/Container/Map/js/mittKey";
import { portUtilsList } from "./portUtilsList";
import { usePortUtilsAnimation } from "./usePortUtilsAnimation";
import "./index.less";
@ -42,8 +36,15 @@ const branchOfficeItemAnimation = {
visible: { y: 0, opacity: 1, transition: { duration: 0.3, ease: "easeOut" } },
};
function BottomUtils(props) {
const { currentPort, pureMap, currentBranchOffice, bottomUtilsCurrentIndex } = useContext(Context);
function BottomUtils() {
const {
currentPort,
pureMap,
currentBranchOffice,
bottomUtilsCurrentIndex,
bottomUtilsResetVersion,
actions,
} = useContext(Context);
const bottomUtilsMode = !pureMap && currentPort && !currentBranchOffice
? "port"
@ -90,25 +91,13 @@ function BottomUtils(props) {
setListMode(bottomUtilsMode);
}, [bottomUtilsMode]);
// reducer 递增版本号时重置本组件维护的子项勾选状态,不再依赖全局事件订阅。
useEffect(() => {
mitt.on(resetBottomCurrentIndexMittKey, () => {
props.setBottomUtilsCurrentIndex(-1);
});
mitt.on(resetAllBottomUtilsCheckMittKey, () => {
resetAllCheck();
});
mitt.on(deletePeoplePositionPointMittKey, () => {
});
return () => {
mitt.off(resetBottomCurrentIndexMittKey);
mitt.off(resetAllBottomUtilsCheckMittKey);
mitt.off(deletePeoplePositionPointMittKey);
};
}, []);
}, [bottomUtilsResetVersion]);
const optionsClick = (index) => {
props.setBottomUtilsCurrentIndex(bottomUtilsCurrentIndex === index ? -1 : index);
actions.setBottomUtilsIndex(bottomUtilsCurrentIndex === index ? -1 : index);
};
const optionsItemsClick = (index, index1, item, item1) => {

View File

@ -9,12 +9,6 @@ import tabMidOnImg from "~/assets/images/map_bi/center_utils/tabmid_on.png";
import tabRightImg from "~/assets/images/map_bi/center_utils/tabright.png";
import tabRightOnImg from "~/assets/images/map_bi/center_utils/tabright_on.png";
import { Context } from "~/pages/Container/Map/js/context";
import mitt from "~/pages/Container/Map/js/mitt";
import {
deletePeoplePositionPointMittKey,
resetAllBottomUtilsCheckMittKey,
resetBottomCurrentIndexMittKey,
} from "~/pages/Container/Map/js/mittKey";
import "./index.less";
// 港区选择区从上方弹入;统计卡片保持原有缩放回弹效果。
@ -48,8 +42,8 @@ const statisticAnimation = {
},
};
function CenterUtils(props) {
const { currentPort, currentBranchOffice, pureMap, mapMethods } = useContext(Context);
function CenterUtils() {
const { currentPort, currentBranchOffice, pureMap, mapMethods, actions } = useContext(Context);
const list = [
{ label: "秦皇岛西", area: "2" },
@ -64,12 +58,10 @@ function CenterUtils(props) {
if (index === activeIndex)
return;
setActiveIndex(index);
props.setArea(list[index].area);
actions.setArea(list[index].area);
mapMethods.current.removeBranchOfficePoint();
mapMethods.current.addBranchOfficePoint(list[index].area);
mitt.emit(resetBottomCurrentIndexMittKey);
mitt.emit(resetAllBottomUtilsCheckMittKey);
mitt.emit(deletePeoplePositionPointMittKey);
actions.resetBottomUtils();
};
return (

View File

@ -6,16 +6,6 @@ import guangImg from "~/assets/images/map_bi/guang.png";
import topImg1 from "~/assets/images/map_bi/top1.png";
import topImg2 from "~/assets/images/map_bi/top2.png";
import { Context } from "~/pages/Container/Map/js/context";
import mitt from "~/pages/Container/Map/js/mitt";
import {
changePeopleTrajectorySelectVisibleMittKey,
clickBackMittKey,
clickBranchOfficePointMittKey,
clickPortPointMittKey,
deletePeoplePositionPointMittKey,
resetAllBottomUtilsCheckMittKey,
resetBottomCurrentIndexMittKey,
} from "~/pages/Container/Map/js/mittKey";
import "./index.less";
// 标题切换时先让旧标题离开,再让新标题进入,保留原来的上下滑动和淡入淡出效果。
@ -25,14 +15,13 @@ const headerAnimation = {
exit: { y: -100, opacity: 0, transition: { duration: 0.3, ease: "easeIn" } },
};
function Header(props) {
const { currentPort, currentBranchOffice, mapMethods, area } = useContext(Context);
function Header() {
const { currentPort, currentBranchOffice, mapMethods, area, headerTitle, actions } = useContext(Context);
const isPortTitle = props.headerTitle === "秦港股份安全监管平台";
const isPortTitle = headerTitle === "秦港股份安全监管平台";
const onBack = () => {
sessionStorage.removeItem("mapCurrentBranchOfficeId");
mitt.emit(deletePeoplePositionPointMittKey);
if (!currentPort) {
window.close();
setTimeout(() => {
@ -42,8 +31,8 @@ function Header(props) {
}, 500);
}
else if (currentPort !== "00003" && currentBranchOffice) {
mitt.emit(clickPortPointMittKey, { id: "", name: "秦港股份" });
mitt.emit(clickBranchOfficePointMittKey, { id: "", corpName: "秦港股份" });
actions.selectPort({ id: "", name: "秦港股份" });
actions.selectBranchOffice({ id: "", corpName: "秦港股份" });
mapMethods.current.removeWall();
mapMethods.current.removeFourColorDiagram();
mapMethods.current.removeBranchOfficePoint();
@ -52,7 +41,7 @@ function Header(props) {
mapMethods.current.addPortPoint();
}
else if (currentBranchOffice) {
mitt.emit(clickBranchOfficePointMittKey, { id: "", corpName: "秦港股份" });
actions.selectBranchOffice({ id: "", corpName: "秦港股份" });
mapMethods.current.removeBranchOfficePoint();
mapMethods.current.removeMarkPoint();
mapMethods.current.returnPreviousCenterPoint();
@ -63,7 +52,7 @@ function Header(props) {
// }, 2000);
}
else if (currentPort) {
mitt.emit(clickPortPointMittKey, { id: "", name: "秦港股份" });
actions.selectPort({ id: "", name: "秦港股份" });
mapMethods.current.removeWall();
mapMethods.current.removeFourColorDiagram();
mapMethods.current.removeBranchOfficePoint();
@ -71,17 +60,15 @@ function Header(props) {
mapMethods.current.flyTo();
mapMethods.current.addPortPoint();
}
mitt.emit(resetBottomCurrentIndexMittKey);
mitt.emit(resetAllBottomUtilsCheckMittKey);
mitt.emit(clickBackMittKey);
mitt.emit(changePeopleTrajectorySelectVisibleMittKey, false);
actions.resetBottomUtils();
actions.resetRightUtils();
};
return (
<div className="map_content_header_container">
<AnimatePresence mode="wait">
<motion.header
key={props.headerTitle}
key={headerTitle}
{...headerAnimation}
className={isPortTitle ? "port" : "branch_office"}
style={{ backgroundImage: `url(${isPortTitle ? topImg1 : topImg2})` }}
@ -94,7 +81,7 @@ function Header(props) {
<div>返回</div>
</div>
)}
<div className="title">{props.headerTitle}</div>
<div className="title">{headerTitle}</div>
<div style={{ backgroundImage: `url(${guangImg})` }} className="guang" />
</motion.header>
</AnimatePresence>

View File

@ -6,14 +6,6 @@ import tooltipImg2 from "~/assets/images/map_bi/right_utils/branch_office/bg11.p
import buttonBg from "~/assets/images/map_bi/right_utils/branch_office/button.png";
import tooltipImg1 from "~/assets/images/map_bi/right_utils/port/tooltip.png";
import { Context } from "~/pages/Container/Map/js/context";
import mitt from "~/pages/Container/Map/js/mitt";
import {
changePeopleTrajectorySelectVisibleMittKey,
clickBackMittKey,
clickMarkPointMittKey,
deletePeoplePositionPointMittKey,
resetAllBottomUtilsCheckMittKey,
} from "~/pages/Container/Map/js/mittKey";
import { utilsList } from "./utilsList";
import "./index.less";
@ -39,7 +31,15 @@ const childMenuAnimation = {
};
function RightUtils(props) {
const { currentPort, mapMethods, pureMap, currentBranchOffice, bottomUtilsCurrentIndex } = useContext(Context);
const {
currentPort,
mapMethods,
pureMap,
currentBranchOffice,
bottomUtilsCurrentIndex,
rightUtilsResetVersion,
actions,
} = useContext(Context);
const [list, setList] = useState(utilsList);
const [isShowChildLevel, setIsShowChildLevel] = useState(true);
@ -55,19 +55,13 @@ function RightUtils(props) {
}, [bottomUtilsCurrentIndex]);
useEffect(() => {
mitt.on(clickBackMittKey, () => {
setList(produce((draft) => {
draft.forEach((item) => {
if (item.type === "fourColor" || item.type === "wall")
item.check = false;
});
}));
});
return () => {
mitt.off(clickBackMittKey);
};
}, []);
}, [rightUtilsResetVersion]);
useEffect(() => {
setList(produce((draft) => {
@ -107,17 +101,10 @@ function RightUtils(props) {
break;
case "del":
mapMethods.current.removeMarkPoint();
mitt.emit(resetAllBottomUtilsCheckMittKey);
mitt.emit(deletePeoplePositionPointMittKey);
mitt.emit(changePeopleTrajectorySelectVisibleMittKey, false);
actions.resetBottomUtils();
break;
case "pureMap":
props.setPureMap(!pureMap);
break;
case "weather":
mitt.emit(clickMarkPointMittKey, {
mapType: "_右侧_METEOROLOGICAL",
});
actions.setPureMap(!pureMap);
break;
case "fourColor":
if (!currentPort) {

View File

@ -1,20 +1,21 @@
import { useFullscreen, useMount } from "ahooks";
import { message } from "antd";
import autoFit from "autofit.js";
import { useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useReducer, useRef } 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 Header from "./components/Header";
import RightUtils from "./components/RightUtils";
import { Context } from "./js/context";
import { Context, initialMapState, MAP_ACTION, mapReducer } from "./js/context";
import useInitMap from "./js/initMap";
import mitt from "./js/mitt";
import {
changeCoverMaskVisibleMittKey,
clickBranchOfficePointMittKey,
clickPortPointMittKey,
resetBottomUtilsMittKey,
} from "./js/mittKey";
import "./index.less";
@ -24,14 +25,19 @@ function Map(props) {
const fullscreenRef = useRef(null); // 全屏容器的ref
const [isFullscreen, { toggleFullscreen }] = useFullscreen(fullscreenRef);
const [state, dispatch] = useReducer(mapReducer, initialMapState);
const [coverMaskVisible, setCoverMaskVisible] = useState(false); // 是否显示透明遮罩,用于分片加载点位时阻止点击事件
const [currentPort, setCurrentPort] = useState(""); // 当前选中的港口
const [currentBranchOffice, setCurrentBranchOffice] = useState(""); // 当前选中的分公司
const [area, setArea] = useState(""); // 当前选中的港口为秦皇岛港时的区域
const [bottomUtilsCurrentIndex, setBottomUtilsCurrentIndex] = useState(""); // 当前选中的下方按钮的索引
const [pureMap, setPureMap] = useState(false); // 是否选中了右侧的纯净地图
const [headerTitle, setHeaderTitle] = useState("秦港股份安全监管平台"); // 当前头部的标题
// 页面组件只调用语义化 actions不直接感知 reducer action 或 mitt 事件名。
const actions = useMemo(() => ({
selectPort: data => dispatch({ type: MAP_ACTION.SELECT_PORT, payload: data }),
selectBranchOffice: data => dispatch({ type: MAP_ACTION.SELECT_BRANCH_OFFICE, payload: data }),
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 }),
resetRightUtils: () => dispatch({ type: MAP_ACTION.RESET_RIGHT_UTILS }),
setPureMap: visible => dispatch({ type: MAP_ACTION.SET_PURE_MAP, payload: visible }),
setCoverMaskVisible: visible => dispatch({ type: MAP_ACTION.SET_COVER_MASK_VISIBLE, payload: visible }),
}), []);
useMount(() => {
autoFit.init({ dw: 1920, dh: 1080, el: "#contentContainer", resize: true });
@ -52,32 +58,27 @@ function Map(props) {
}, 500);
}
mitt.on(clickPortPointMittKey, (data) => {
setCurrentPort(data.id);
if (data.id === "00003") {
setHeaderTitle("秦港股份安全监管平台");
}
else {
setCurrentBranchOffice(data.corpinfoId);
setHeaderTitle(`${data.name}安全监管平台`);
}
});
mitt.on(clickBranchOfficePointMittKey, (data) => {
setCurrentBranchOffice(data.id);
setHeaderTitle(`${data.corpName || data.name}安全监管平台`);
});
mitt.on(changeCoverMaskVisibleMittKey, (data) => {
setCoverMaskVisible(data);
if (!data) {
// Cesium 工具层暂时通过 mitt 通知;所有事件在根组件统一转成 reducer action。
const handlePortClick = data => actions.selectPort(data);
const handleBranchOfficeClick = data => actions.selectBranchOffice(data);
const handleCoverMaskVisible = (visible) => {
actions.setCoverMaskVisible(visible);
if (!visible) {
message.success("地图绘制完成");
}
});
};
const handleResetBottomUtils = () => actions.resetBottomUtils();
mitt.on(clickPortPointMittKey, handlePortClick);
mitt.on(clickBranchOfficePointMittKey, handleBranchOfficeClick);
mitt.on(changeCoverMaskVisibleMittKey, handleCoverMaskVisible);
mitt.on(resetBottomUtilsMittKey, handleResetBottomUtils);
return () => {
autoFit.off();
mitt.off(clickPortPointMittKey);
mitt.off(clickBranchOfficePointMittKey);
mitt.off(changeCoverMaskVisibleMittKey);
mitt.off(clickPortPointMittKey, handlePortClick);
mitt.off(clickBranchOfficePointMittKey, handleBranchOfficeClick);
mitt.off(changeCoverMaskVisibleMittKey, handleCoverMaskVisible);
mitt.off(resetBottomUtilsMittKey, handleResetBottomUtils);
};
});
@ -89,8 +90,8 @@ function Map(props) {
}, []);
const providerValues = useMemo(
() => ({ viewer, mapMethods, currentPort, currentBranchOffice, area, bottomUtilsCurrentIndex, pureMap }),
[viewer, mapMethods, currentPort, currentBranchOffice, area, bottomUtilsCurrentIndex, pureMap],
() => ({ viewer, mapMethods, ...state, actions }),
[viewer, mapMethods, state, actions],
);
return (
@ -98,15 +99,15 @@ function Map(props) {
<Context.Provider value={providerValues}>
<div id="cesiumContainer" />
<div id="contentContainer">
<Header headerTitle={headerTitle} />
<CenterUtils setArea={setArea} />
<RightUtils history={props.history} isFullscreen={isFullscreen} toggleFullscreen={toggleFullscreen} setPureMap={setPureMap} />
<BottomUtils setBottomUtilsCurrentIndex={setBottomUtilsCurrentIndex} />
<Header />
<CenterUtils />
<RightUtils history={props.history} isFullscreen={isFullscreen} toggleFullscreen={toggleFullscreen} />
<BottomUtils />
<Content history={props.history} />
</div>
</Context.Provider>
<div
style={{ display: coverMaskVisible ? "block" : "none" }}
style={{ display: state.coverMaskVisible ? "block" : "none" }}
className="coverMaskContainer"
onClick={() => message.warning("正在绘制地图,请等待绘制完成在进行操作")}
/>

View File

@ -1,3 +1,69 @@
import { createContext } from "react";
export const Context = createContext({});
// Map 页面唯一状态源:页面组件只读取这些状态,通过 actions 修改,避免再用 mitt 同步 React 状态。
export const initialMapState = {
coverMaskVisible: false,
currentPort: "",
currentBranchOffice: "",
area: "",
bottomUtilsCurrentIndex: "",
pureMap: false,
headerTitle: "秦港股份安全监管平台",
bottomUtilsResetVersion: 0,
rightUtilsResetVersion: 0,
};
export const MAP_ACTION = {
SELECT_PORT: "selectPort",
SELECT_BRANCH_OFFICE: "selectBranchOffice",
SET_AREA: "setArea",
SET_BOTTOM_UTILS_INDEX: "setBottomUtilsIndex",
RESET_BOTTOM_UTILS: "resetBottomUtils",
RESET_RIGHT_UTILS: "resetRightUtils",
SET_PURE_MAP: "setPureMap",
SET_COVER_MASK_VISIBLE: "setCoverMaskVisible",
};
export function mapReducer(state, action) {
switch (action.type) {
case MAP_ACTION.SELECT_PORT: {
const data = action.payload;
return {
...state,
currentPort: data.id,
currentBranchOffice: data.id === "00003" ? "" : data.corpinfoId || state.currentBranchOffice,
headerTitle: data.id === "00003"
? "秦港股份安全监管平台"
: `${data.name}安全监管平台`,
};
}
case MAP_ACTION.SELECT_BRANCH_OFFICE: {
const data = action.payload;
return {
...state,
currentBranchOffice: data.id,
headerTitle: `${data.corpName || data.name}安全监管平台`,
};
}
case MAP_ACTION.SET_AREA:
return { ...state, area: action.payload };
case MAP_ACTION.SET_BOTTOM_UTILS_INDEX:
return { ...state, bottomUtilsCurrentIndex: action.payload };
case MAP_ACTION.RESET_BOTTOM_UTILS:
return {
...state,
bottomUtilsCurrentIndex: state.bottomUtilsCurrentIndex || -1,
bottomUtilsResetVersion: state.bottomUtilsResetVersion + 1,
};
case MAP_ACTION.RESET_RIGHT_UTILS:
return { ...state, rightUtilsResetVersion: state.rightUtilsResetVersion + 1 };
case MAP_ACTION.SET_PURE_MAP:
return { ...state, pureMap: action.payload };
case MAP_ACTION.SET_COVER_MASK_VISIBLE:
return { ...state, coverMaskVisible: action.payload };
default:
return state;
}
}

View File

@ -2,19 +2,7 @@
export const clickPortPointMittKey = "clickPortPoint";
// 点击分公司点位
export const clickBranchOfficePointMittKey = "clickBranchOfficePoint";
// 点击标记点位
export const clickMarkPointMittKey = "clickMarkPoint";
// 点击左上角返回
export const clickBackMittKey = "clickBack";
// 重置底部工具栏当前索引
export const resetBottomCurrentIndexMittKey = "resetBottomCurrentIndex";
// 重置所有底部工具栏选中状态
export const resetAllBottomUtilsCheckMittKey = "resetAllBottomUtilsCheck";
// Cesium 点位层通知 React 重置底部工具栏
export const resetBottomUtilsMittKey = "resetBottomUtils";
// 改变覆盖蒙版显隐
export const changeCoverMaskVisibleMittKey = "changeCoverMaskVisible";
// 改变人员轨迹选择窗口显隐
export const changePeopleTrajectorySelectVisibleMittKey = "changePeopleTrajectorySelectVisible";
// 将人员定位列表提供给人员轨迹选择窗口
export const providePeoplePositionListMittKey = "providePeoplePositionList";
// 删除人员轨迹点位
export const deletePeoplePositionPointMittKey = "deletePeoplePositionPoint";

View File

@ -6,11 +6,8 @@ import { getPosition } from "./mapUtils";
import mitt from "./mitt";
import {
clickBranchOfficePointMittKey,
clickMarkPointMittKey,
clickPortPointMittKey,
deletePeoplePositionPointMittKey,
resetAllBottomUtilsCheckMittKey,
resetBottomCurrentIndexMittKey,
resetBottomUtilsMittKey,
} from "./mittKey";
export default function usePointClickEvent(viewerRef, mapMethods) {
@ -52,8 +49,7 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
sessionStorage.setItem("mapCurrentBranchOfficeId", data.corpinfoId);
}
// }, 2000);
mitt.emit(resetBottomCurrentIndexMittKey);
mitt.emit(resetAllBottomUtilsCheckMittKey);
mitt.emit(resetBottomUtilsMittKey);
};
// 港口点位点击
@ -81,11 +77,9 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
mapMethods.removeFourColorDiagram();
mapMethods.removeWall();
mapMethods.flyTo({ longitude: data.longitude, latitude: data.latitude, height: 2000 });
mitt.emit(deletePeoplePositionPointMittKey);
mitt.emit(clickBranchOfficePointMittKey, data);
sessionStorage.setItem("mapCurrentBranchOfficeId", data.corpinfoId);
mitt.emit(resetBottomCurrentIndexMittKey);
mitt.emit(resetAllBottomUtilsCheckMittKey);
mitt.emit(resetBottomUtilsMittKey);
};
// 分公司点位点击
@ -108,11 +102,6 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
});
};
// 标记点位点击
const clickMarkPoint = (data) => {
mitt.emit(clickMarkPointMittKey, data);
};
// 点位点击
const pointClickEvent = (pick) => {
const data = pick.monitorItems.data;
@ -125,8 +114,6 @@ export default function usePointClickEvent(viewerRef, mapMethods) {
clickPortPoint(data);
if (data.mapType === "分公司")
clickBranchOfficePoint(data);
if (data.mapType.includes("标记点"))
clickMarkPoint(data);
};
return {