2026-07-21 11:49:03 +08:00
|
|
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
2026-03-02 16:35:37 +08:00
|
|
|
import { produce } from "immer";
|
2026-01-15 18:01:40 +08:00
|
|
|
import { AnimatePresence, motion } from "motion/react";
|
2026-01-07 13:51:33 +08:00
|
|
|
import { useContext, useEffect, useState } from "react";
|
|
|
|
|
import bg7 from "~/assets/images/map_bi/bottom_utils/bg7.png";
|
|
|
|
|
import bg8 from "~/assets/images/map_bi/bottom_utils/bg8.png";
|
2026-01-05 14:53:49 +08:00
|
|
|
import titleImg from "~/assets/images/map_bi/bottom_utils/title.png";
|
|
|
|
|
import titleOnImg from "~/assets/images/map_bi/bottom_utils/title_on.png";
|
2026-07-21 11:49:03 +08:00
|
|
|
import { NS_BI_MARK } from "~/enumerate/namespace";
|
2026-01-07 13:51:33 +08:00
|
|
|
import { branchOfficeUtilsList } from "~/pages/Container/Map/components/BottomUtils/branchOfficeUtilsList";
|
2026-01-05 14:53:49 +08:00
|
|
|
import { Context } from "~/pages/Container/Map/js/context";
|
|
|
|
|
import { portUtilsList } from "./portUtilsList";
|
2026-01-15 18:01:40 +08:00
|
|
|
import { usePortUtilsAnimation } from "./usePortUtilsAnimation";
|
2026-01-05 14:53:49 +08:00
|
|
|
import "./index.less";
|
|
|
|
|
|
2026-07-22 10:38:03 +08:00
|
|
|
const dangerWorkTypes = [
|
|
|
|
|
"hot_work",
|
|
|
|
|
"confinedspace_work",
|
|
|
|
|
"electricity_work",
|
|
|
|
|
"high_work",
|
|
|
|
|
"cutroad_work",
|
|
|
|
|
"breakground_work",
|
|
|
|
|
"hoisting_work",
|
|
|
|
|
"blindboard_work",
|
|
|
|
|
];
|
2026-07-24 13:59:10 +08:00
|
|
|
const gateTypes = [
|
|
|
|
|
"HGKM_MKMJ_GATE_TYPE_PERSON",
|
|
|
|
|
"HGKM_MKMJ_GATE_TYPE_CAR",
|
|
|
|
|
];
|
2026-07-22 10:38:03 +08:00
|
|
|
|
2026-07-15 10:17:00 +08:00
|
|
|
const bottomUtilsAnimation = {
|
|
|
|
|
initial: { y: 100, opacity: 0 },
|
|
|
|
|
animate: { y: 0, opacity: 1, transition: { duration: 0.5, ease: "easeOut" } },
|
|
|
|
|
exit: { y: 100, opacity: 0, transition: { duration: 0.3, ease: "easeIn" } },
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-21 11:49:03 +08:00
|
|
|
// 分公司子项按顺序进入、反向退出,波浪式效果。
|
2026-07-15 10:17:00 +08:00
|
|
|
const branchOfficeContainerAnimation = {
|
|
|
|
|
hidden: {
|
|
|
|
|
y: 200,
|
|
|
|
|
opacity: 0,
|
|
|
|
|
transition: { duration: 0.2, ease: "easeIn", staggerChildren: 0.03, staggerDirection: -1 },
|
|
|
|
|
},
|
|
|
|
|
visible: {
|
|
|
|
|
y: 0,
|
|
|
|
|
opacity: 1,
|
|
|
|
|
transition: { duration: 0.3, ease: "easeOut", staggerChildren: 0.05, staggerDirection: 1 },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const branchOfficeItemAnimation = {
|
|
|
|
|
hidden: { y: 50, opacity: 0 },
|
|
|
|
|
visible: { y: 0, opacity: 1, transition: { duration: 0.3, ease: "easeOut" } },
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-21 11:49:03 +08:00
|
|
|
function BottomUtils(props) {
|
2026-07-16 10:38:54 +08:00
|
|
|
const {
|
2026-07-21 11:49:03 +08:00
|
|
|
mapMethods,
|
2026-07-16 10:38:54 +08:00
|
|
|
currentPort,
|
|
|
|
|
pureMap,
|
|
|
|
|
currentBranchOffice,
|
|
|
|
|
bottomUtilsCurrentIndex,
|
|
|
|
|
bottomUtilsResetVersion,
|
|
|
|
|
actions,
|
2026-07-21 11:49:03 +08:00
|
|
|
portArea,
|
2026-07-16 10:38:54 +08:00
|
|
|
} = useContext(Context);
|
2026-01-05 14:53:49 +08:00
|
|
|
|
2026-07-15 10:17:00 +08:00
|
|
|
const bottomUtilsMode = !pureMap && currentPort && !currentBranchOffice
|
|
|
|
|
? "port"
|
|
|
|
|
: !pureMap && currentPort && currentBranchOffice ? "branchOffice" : null;
|
|
|
|
|
const [list, setList] = useState(() => bottomUtilsMode === "port"
|
|
|
|
|
? portUtilsList
|
|
|
|
|
: bottomUtilsMode === "branchOffice" ? branchOfficeUtilsList : []);
|
|
|
|
|
const [listMode, setListMode] = useState(bottomUtilsMode);
|
2026-01-15 18:01:40 +08:00
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
parentControls: portUtilsParentControls,
|
|
|
|
|
childControls: portUtilsChildControls,
|
|
|
|
|
optionRefs: portUtilsOptionRefs,
|
|
|
|
|
isAnimating: portUtilsIsAnimating,
|
|
|
|
|
hasInteracted: portUtilsHasInteracted,
|
|
|
|
|
shouldHideInactive: portUtilsShouldHideInactive,
|
|
|
|
|
animationConfig: portUtilsAnimationConfig,
|
|
|
|
|
} = usePortUtilsAnimation(
|
|
|
|
|
portUtilsList.length,
|
|
|
|
|
bottomUtilsCurrentIndex,
|
2026-07-15 10:17:00 +08:00
|
|
|
bottomUtilsMode === "port",
|
2026-01-15 18:01:40 +08:00
|
|
|
);
|
2026-01-05 14:53:49 +08:00
|
|
|
|
|
|
|
|
const resetAllCheck = () => {
|
2026-03-02 16:35:37 +08:00
|
|
|
setList(produce((draft) => {
|
|
|
|
|
draft.forEach((item) => {
|
|
|
|
|
item.list.forEach((item1) => {
|
|
|
|
|
item1.check = false;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}));
|
2026-01-05 14:53:49 +08:00
|
|
|
};
|
|
|
|
|
|
2026-01-07 13:51:33 +08:00
|
|
|
useEffect(() => {
|
2026-07-15 10:17:00 +08:00
|
|
|
if (bottomUtilsMode === "port") {
|
2026-01-15 18:01:40 +08:00
|
|
|
setList(portUtilsList);
|
|
|
|
|
}
|
2026-07-15 10:17:00 +08:00
|
|
|
else if (bottomUtilsMode === "branchOffice") {
|
2026-01-15 18:01:40 +08:00
|
|
|
setList(branchOfficeUtilsList);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
setList([]);
|
|
|
|
|
}
|
2026-07-15 10:17:00 +08:00
|
|
|
setListMode(bottomUtilsMode);
|
|
|
|
|
}, [bottomUtilsMode]);
|
2026-01-05 14:53:49 +08:00
|
|
|
|
2026-01-07 13:51:33 +08:00
|
|
|
useEffect(() => {
|
2026-07-16 10:38:54 +08:00
|
|
|
resetAllCheck();
|
|
|
|
|
}, [bottomUtilsResetVersion]);
|
2026-01-05 14:53:49 +08:00
|
|
|
|
|
|
|
|
const optionsClick = (index) => {
|
2026-07-16 10:38:54 +08:00
|
|
|
actions.setBottomUtilsIndex(bottomUtilsCurrentIndex === index ? -1 : index);
|
2026-01-05 14:53:49 +08:00
|
|
|
};
|
|
|
|
|
|
2026-07-21 11:49:03 +08:00
|
|
|
const optionsItemsClick = async (index, index1, item, item1) => {
|
|
|
|
|
const check = !list[index].list[index1].check;
|
|
|
|
|
if (check) {
|
|
|
|
|
if (item1.request) {
|
2026-07-22 14:43:31 +08:00
|
|
|
let pointData = [];
|
2026-07-22 10:38:03 +08:00
|
|
|
const requestParams = { portArea, corpinfoId: currentBranchOffice, pageIndex: 1, pageSize: 9999 };
|
|
|
|
|
if (dangerWorkTypes.includes(item1.type)) {
|
|
|
|
|
requestParams.workType = item1.type;
|
|
|
|
|
}
|
2026-07-24 13:59:10 +08:00
|
|
|
if (gateTypes.includes(item1.type)) {
|
|
|
|
|
requestParams.gateType = item1.type;
|
|
|
|
|
}
|
2026-07-22 10:38:03 +08:00
|
|
|
const { data = [] } = await props[item1.request](requestParams);
|
2026-07-22 14:43:31 +08:00
|
|
|
pointData = [...data];
|
2026-07-22 10:38:03 +08:00
|
|
|
if (dangerWorkTypes.includes(item1.type)) {
|
2026-07-22 14:43:31 +08:00
|
|
|
for (let i = 0; i < pointData.length; i++) {
|
|
|
|
|
pointData[i].latitude = pointData[i].info.latitude;
|
|
|
|
|
pointData[i].longitude = pointData[i].info.longitude;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mapMethods.current.addMarkPoint(pointData, {
|
2026-07-21 11:49:03 +08:00
|
|
|
markType: item1.type,
|
|
|
|
|
markIcon: item1.markIcon,
|
|
|
|
|
subLabel: item1.label,
|
|
|
|
|
titleKey: item1.titleKey,
|
2026-07-22 08:52:47 +08:00
|
|
|
isShowModal: item1.isShowModal,
|
2026-07-21 11:49:03 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mapMethods.current.removeMarkPoint(item1.type);
|
|
|
|
|
}
|
2026-03-02 16:35:37 +08:00
|
|
|
setList(produce((draft) => {
|
2026-07-21 11:49:03 +08:00
|
|
|
draft[index].list[index1].check = check;
|
2026-03-02 16:35:37 +08:00
|
|
|
}));
|
2026-01-05 14:53:49 +08:00
|
|
|
};
|
|
|
|
|
|
2026-01-15 18:01:40 +08:00
|
|
|
const renderPortUtils = () => {
|
2026-07-15 10:17:00 +08:00
|
|
|
if (bottomUtilsMode === "port" && listMode === bottomUtilsMode) {
|
2026-01-15 18:01:40 +08:00
|
|
|
return list.map((item, index) => {
|
|
|
|
|
const isCurrentActive = bottomUtilsCurrentIndex === index;
|
|
|
|
|
const hasActiveChildren = bottomUtilsCurrentIndex !== -1;
|
|
|
|
|
const isAllowClick = hasActiveChildren && !isCurrentActive && portUtilsShouldHideInactive;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<motion.div
|
|
|
|
|
key={index}
|
|
|
|
|
ref={el => (portUtilsOptionRefs.current[index] = el)}
|
|
|
|
|
className="option"
|
|
|
|
|
animate={portUtilsHasInteracted ? portUtilsParentControls[index] : false}
|
|
|
|
|
onClick={() => !portUtilsIsAnimating && !isAllowClick && optionsClick(index)}
|
|
|
|
|
style={{
|
|
|
|
|
cursor: isAllowClick ? "default" : "pointer",
|
2026-03-02 16:35:37 +08:00
|
|
|
zIndex: isAllowClick ? -1 : 0,
|
2026-01-15 18:01:40 +08:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<img src={isCurrentActive ? item.checkImg : item.img} alt="" className="img" />
|
|
|
|
|
<div className="label" style={{ backgroundImage: `url(${isCurrentActive ? titleOnImg : titleImg})` }}>
|
|
|
|
|
{item.label}
|
|
|
|
|
</div>
|
|
|
|
|
{isCurrentActive && (
|
|
|
|
|
<motion.div
|
|
|
|
|
className="child_items"
|
|
|
|
|
animate={portUtilsChildControls}
|
|
|
|
|
initial={{ opacity: 0 }}
|
2026-01-12 16:51:34 +08:00
|
|
|
>
|
2026-01-15 18:01:40 +08:00
|
|
|
{item.list?.map((item1, index1) => {
|
|
|
|
|
return (
|
|
|
|
|
<motion.div
|
2026-01-07 13:51:33 +08:00
|
|
|
key={index1}
|
2026-01-15 18:01:40 +08:00
|
|
|
className="child_item"
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
transition={{ delay: index1 * portUtilsAnimationConfig.staggerDelay }}
|
2026-01-07 13:51:33 +08:00
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
optionsItemsClick(index, index1, item, item1);
|
|
|
|
|
}}
|
|
|
|
|
>
|
2026-01-15 18:01:40 +08:00
|
|
|
<img src={item1.check ? item1.checkImg : item1.img} alt="" className="child_img" />
|
2026-01-07 13:51:33 +08:00
|
|
|
<div className="child_label">{item1.label}</div>
|
2026-01-15 18:01:40 +08:00
|
|
|
</motion.div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
</motion.div>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-01-07 13:51:33 +08:00
|
|
|
};
|
2026-01-05 14:53:49 +08:00
|
|
|
|
2026-01-15 18:01:40 +08:00
|
|
|
const renderBranchOfficeUtils = () => {
|
2026-07-15 10:17:00 +08:00
|
|
|
if (bottomUtilsMode === "branchOffice" && listMode === bottomUtilsMode) {
|
2026-01-15 18:01:40 +08:00
|
|
|
return (
|
|
|
|
|
list.map((item, index) => {
|
2026-01-07 13:51:33 +08:00
|
|
|
const isCurrentActive = bottomUtilsCurrentIndex === index;
|
|
|
|
|
return (
|
2026-01-15 18:01:40 +08:00
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className="option"
|
|
|
|
|
style={{ backgroundImage: `url(${isCurrentActive ? bg7 : bg8})` }}
|
|
|
|
|
onClick={() => optionsClick(index)}
|
|
|
|
|
>
|
|
|
|
|
<div className="label">{item.label}</div>
|
|
|
|
|
<AnimatePresence>
|
|
|
|
|
{(isCurrentActive && item.list?.length > 0) && (
|
2026-07-21 11:49:03 +08:00
|
|
|
<motion.div
|
|
|
|
|
className="items"
|
|
|
|
|
initial="hidden"
|
|
|
|
|
animate="visible"
|
|
|
|
|
exit="hidden"
|
|
|
|
|
variants={branchOfficeContainerAnimation}
|
|
|
|
|
>
|
2026-01-15 18:01:40 +08:00
|
|
|
{item.list?.map((item1, index1) => {
|
|
|
|
|
return (
|
|
|
|
|
<motion.div
|
|
|
|
|
key={index1}
|
|
|
|
|
className={`item ${item1.check ? "active" : ""}`}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
optionsItemsClick(index, index1, item, item1);
|
|
|
|
|
}}
|
2026-07-15 10:17:00 +08:00
|
|
|
variants={branchOfficeItemAnimation}
|
2026-01-15 18:01:40 +08:00
|
|
|
>
|
|
|
|
|
<div className="child_label">{item1.label}</div>
|
|
|
|
|
</motion.div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
</AnimatePresence>
|
2026-01-07 13:51:33 +08:00
|
|
|
</div>
|
|
|
|
|
);
|
2026-01-15 18:01:40 +08:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-01-07 13:51:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
2026-01-08 11:27:19 +08:00
|
|
|
<div className="map_content_bottom_utils_container">
|
2026-07-15 10:17:00 +08:00
|
|
|
<AnimatePresence mode="wait">
|
|
|
|
|
{bottomUtilsMode && (
|
|
|
|
|
<motion.div
|
|
|
|
|
key={bottomUtilsMode}
|
|
|
|
|
className={bottomUtilsMode === "port" ? "bottom_utils port" : "bottom_utils branch_office"}
|
|
|
|
|
{...bottomUtilsAnimation}
|
|
|
|
|
>
|
2026-01-15 18:01:40 +08:00
|
|
|
{renderPortUtils()}
|
|
|
|
|
{renderBranchOfficeUtils()}
|
2026-07-15 10:17:00 +08:00
|
|
|
</motion.div>
|
2026-01-15 18:01:40 +08:00
|
|
|
)}
|
2026-07-15 10:17:00 +08:00
|
|
|
</AnimatePresence>
|
2026-01-05 14:53:49 +08:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-21 11:49:03 +08:00
|
|
|
export default Connect([NS_BI_MARK], true)(BottomUtils);
|