zcloud-gbs-bi-react/src/pages/Container/Map/components/BottomUtils/index.js

248 lines
8.3 KiB
JavaScript
Raw Normal View History

2026-07-21 11:49:03 +08:00
import { Connect } from "@cqsjjb/jjb-dva-runtime";
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";
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
// 分公司子项按顺序进入、反向退出,波浪式效果。
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) {
const {
2026-07-21 11:49:03 +08:00
mapMethods,
currentPort,
pureMap,
currentBranchOffice,
bottomUtilsCurrentIndex,
bottomUtilsResetVersion,
actions,
2026-07-21 11:49:03 +08:00
portArea,
} = useContext(Context);
2026-01-05 14:53:49 +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,
bottomUtilsMode === "port",
2026-01-15 18:01:40 +08:00
);
2026-01-05 14:53:49 +08:00
const resetAllCheck = () => {
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(() => {
if (bottomUtilsMode === "port") {
2026-01-15 18:01:40 +08:00
setList(portUtilsList);
}
else if (bottomUtilsMode === "branchOffice") {
2026-01-15 18:01:40 +08:00
setList(branchOfficeUtilsList);
}
else {
setList([]);
}
setListMode(bottomUtilsMode);
}, [bottomUtilsMode]);
2026-01-05 14:53:49 +08:00
2026-01-07 13:51:33 +08:00
useEffect(() => {
resetAllCheck();
}, [bottomUtilsResetVersion]);
2026-01-05 14:53:49 +08:00
const optionsClick = (index) => {
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) {
const { data } = await props[item1.request]({ portArea, corpinfoId: currentBranchOffice });
mapMethods.current.addMarkPoint(data, {
markType: item1.type,
markIcon: item1.markIcon,
subLabel: item1.label,
titleKey: item1.titleKey,
});
}
}
else {
mapMethods.current.removeMarkPoint(item1.type);
}
setList(produce((draft) => {
2026-07-21 11:49:03 +08:00
draft[index].list[index1].check = check;
}));
2026-01-05 14:53:49 +08:00
};
2026-01-15 18:01:40 +08:00
const renderPortUtils = () => {
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",
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 = () => {
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);
}}
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">
<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()}
</motion.div>
2026-01-15 18:01:40 +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);