import React, { useState, useEffect, useReducer, useRef } from "react"; import Qmmap from "../../qmmap/index"; import { useHistory, useLocation } from "react-router-dom"; import { getMallInfo, post } from "../../js/helpers/data-helper"; import "./Index.scss"; import Floors from "../../components/Floors/Floors"; import HeadBar from "../../components/HeadBar/HeadBar"; import Popup from "../../components/Popup/Popup"; import pos from "./pos.png"; import offline from "./offline.png"; import compass from "./compass.png"; import Shops from "../Shops/Shops"; import NavBottom from "../../components/NavBottom/NavBottom"; import Modal from "react-modal"; import DefaultPopup, { DefaultPopupStates, } from "../../components/DefaultPopup/DefaultPopup"; import More from "../../components/More/More"; import arpng from "./ar.png"; import Car from "../Car/Car"; import axios from "axios"; import Activities from "../Activities/Activities"; import Coupons from "../Coupons/Coupons"; import TabMap from "./tabs/Tabs"; import ShopCoupons from "../ShopCoupons/ShopCoupons"; export const MallCode = React.createContext(null); // const vConsole = new window.VConsole(); let focusdDevice; let memberID; let isShop; const Index = () => { const history = useHistory(); const [mapId] = useState("id" + new Date().getTime()); const [shop, setShop] = useState(null); const [mallInfo, setMallInfo] = useState(null); const mall = mallInfo ? mallInfo.mall : null; const config = mallInfo ? mallInfo.config : null; const images = mallInfo ? mallInfo.images : null; const [map, setMap] = useState(null); const [sceneIndex, setSceneIndex] = useState(null); const params = new URLSearchParams(useLocation().search); const [mallCode, setMallCode] = useState(null); const startParams = params.get("s"); let endId = params.get("e"); const openid = params.get("openid"); if (params.get("memberID")) memberID = params.get("memberID"); if (params.get("isShop")) isShop = params.get("isShop"); const plate = params.get("plate"); const [navigation, setNavigation] = useState(false); const [inAnimation, setInAnimation] = useState(false); const [displayMode, setDisplayMode] = useState(1); const [searchType, setSearchType] = useState(0); const [showOptions, setShowOptions] = useState(false); const [showShops, setShowShops] = useState(false); const [routeSearchText, setRouteSearchText] = useState(""); const [percent, setPercent] = useState(0); const [elevations, setElevations] = useState([]); const [paused, setPaused] = useState(false); const [playAudio, setPlayAudio] = useState(false); const [online, setOnline] = useState(true); const [azimuthAngle, setAzimuthAngle] = useState(0); const [follow, setFollow] = useState(false); const [facilities, setFacilities] = useState(null); const [defaultPopupState, setDefaultPopupState] = useState( DefaultPopupStates.init ); const [start, _setStart] = useState(null); const [end, _setEnd] = useState(null); const [isPick, _setIsPick] = useState(false); const [doFocus, _setDoFocus] = useState(0); const [showARPrompt, setShowARPrompt] = useState(false); const [ARshop, setARShop] = useState(null); const [isTyping, setIsTyping] = useState(null); const [showFindCar, setShowFindCar] = useState(false); const [showActivities, setShowActivities] = useState(false); const [showCoupon, setShowCoupon] = useState(false); const [tab, setTab] = useState("地图"); const [couponShop, setCouponShop] = useState(null); const [initActivity, setInitActivity] = useState(null); const showShopCoupons = !!couponShop; const hasTab = mall && mall.menu.length > 1; const setStatistics = mall ? ({ userId, navType, pointType, objectCode, objectName, floorName }) => userId && userId !== "null" && axios.post(mall.baseUrl + "/api/ar/v1/applet/AddGuideRecord", { mallCode: mall.code, userId, navType, pointType, objectCode, objectName, floorName, }) : undefined; useEffect(() => { if (shop) { const e = shop.houseNum ? shop.houseNum : shop.isDevice ? `${shop.floorOrder}_${shop.navPoint}_${shop.name}` : encodeURIComponent(shop.id); history.replace( `/?openid=${openid}&e=${e}&name=${shop.name}${ shop.floorName ? "(" + shop.floorName + ")" : "" }` ); } }, [shop]); useEffect(() => { if (!map) return; let start; let end; if (startParams) { const startParamList = startParams.split("_"); if (startParamList.length === 3) { let [sfloororder, spoint, sname] = startParamList; sfloororder = Number(sfloororder); spoint = Number(spoint); start = { isDevice: true, name: sname, navPoint: spoint, yaxis: spoint, floorOrder: sfloororder, }; setStart(start); } } if (!endId) return; if (endId === "findcar") return setShowFindCar(true); if (endId === "me") return setTab("我的"); if (endId.startsWith && endId.startsWith("activities")) { setTab("活动"); if (endId === "activities") return; else { const code = endId.replace("activities", ""); const activity = mall.activities.find((act) => act.code === code); if (activity) setInitActivity(activity); return; } } if (mall.mcShopIDHouseNumMap && mall.mcShopIDHouseNumMap[endId]) endId = mall.mcShopIDHouseNumMap[endId]; const shop = map.getShopByHouseNum(endId); const p = map.getPByHouseNum(endId) ? map.getPByHouseNum(endId).data : null; const fac = map.getFacilityById(endId) ? map.getFacilityById(endId) : null; const endParamList = endId.split("_"); let endPoint = null; if (endParamList.length === 3) { let [efloororder, epoint, ename] = endParamList; efloororder = Number(efloororder); epoint = Number(epoint); endPoint = { isDevice: true, name: ename, navPoint: epoint, yaxis: epoint, floorOrder: efloororder, }; } end = shop ? shop : p ? p : fac ? fac : endPoint; if (!start) { setDoFocus(2); shop ? map.focusShopByHouseNum(endId) : p ? map.focusPByHouseNum(endId) : fac ? map.focusFacilityById(endId) : map.addDeviceAndFocus(end).then((device) => { focusdDevice = device; setShop(end); }); return; } if (start && end) { setEnd(end); map.startNavigate({ start, end, }); } }, [map]); useEffect(() => { map && map.setStart(start); }, [start]); useEffect(() => { map && map.setEnd(end); }, [end]); const doFocusRef = useRef(doFocus); const setDoFocus = (data) => { doFocusRef.current = data; _setDoFocus(data); }; const startRef = useRef(start); const setStart = (data) => { startRef.current = data; _setStart(data); }; const endRef = useRef(end); const setEnd = (data) => { endRef.current = data; _setEnd(data); }; const isPickRef = useRef(isPick); const setIsPick = (data) => { isPickRef.current = data; _setIsPick(data); }; useEffect(() => { let offlineListener = () => setOnline(false); let onlineListener = () => setOnline(true); window.addEventListener("offline", offlineListener); window.addEventListener("online", onlineListener); return () => { window.removeEventListener("online", onlineListener); window.removeEventListener("offline", offlineListener); }; }); const [_, dispatchLS] = useReducer( ({ lastSearch }, { type, data }) => { switch (type) { case "set": return { lastSearch: data }; case "addLine": lastSearch && lastSearch.forEach(({ floorOrder, addLine }) => { Number(floorOrder) === data && addLine(); }); return { lastSearch }; default: throw new Error(); } }, { lastSearch: null, } ); const handleFocus = ({ data, preventDefault }) => { const start = startRef.current; const end = endRef.current; const isPick = isPickRef.current; const doFocus = doFocusRef.current; if (doFocus === 2) { setDoFocus(1); setShop(data); return; } if (start && end) { preventDefault(); } else if (((start && !end) || (!start && end)) && !isPick) { preventDefault(); } else { if (follow) { map.setFollow(false); setFollow(false); } setShop(data); } setDoFocus(0); }; const swap = async () => { if (navigation && start && end) await navigation.stop(); if (start && end) map.startNavigate({ start: end, end: start }); setStart(end); setEnd(start); }; const handleBlur = () => { if (focusdDevice) { focusdDevice.blur(); focusdDevice = null; } const doFocus = doFocusRef.current; if (doFocus === 1) return; history.replace(`/?openid=${openid}`); setShop(null); }; const loadMap = () => { let img = new Image(100, 200); img.src = offline; const { scale, needSpotLight } = mall; new Qmmap({ container: document.querySelector(`#${mapId}`), config: { ...(config ? config : {}), focusStyle: ["scale", "showText"], focusColor: 0xff0000, controller: "MapControls", routeSearchAnimationType: 2, routeSearchZoom: 2, maxZoom: 4, playAudio, needSpotLight, scale, floorHeights: { 0: 10, 1: 10, 2: 10, 3: 10, 4: 10, 5: 10, 6: 10, 7: 10, 8: 10, 9: 10, 10: 10, 11: 10, }, backgroundColor: null, navIconTopColor: 0xffffff, navIconMiddleColor: 0x437af7, navIconBottomColor: 0xffffff, pathMainColor: 0x437af7, pathBorderColor: 0x5ea4f9, pathArrowColor: 0xffffff, addtionalFacilityCodeMap: mall.addtionalFacilityCodeMap, autoRotate: false, customTitleFacilityTypeMap: { 116: true }, wrapperWindowRatio: 0.9, showShopLabel: false, useFormatColor: false, floorDiffMap: { "3_5": 1, "5_3": 1, }, elevatorWaitCost: 7000, elevatorCostPerFloor: 1000, escalatorCostPerFloor: 7000, }, mall, onFocusShop: (data, stop) => { handleFocus({ data, preventDefault: stop }); }, onBlurShop: handleBlur, onFocusFacility: (data, stop) => { handleFocus({ data, preventDefault: stop }); }, onBlurFacility: handleBlur, onTapP(data, stop) { handleFocus({ data, preventDefault: stop }); }, onBlurP: handleBlur, onSearchStart: (navigation) => { const { pathsByFloor } = navigation; if (pathsByFloor.length === 1) setElevations([]); else { let result = []; let acc = 0; for (let i = 0; i < pathsByFloor.length - 1; i++) { let { floorOrder: floorOrder1, distanceSum } = pathsByFloor[i]; let { floorOrder: floorOrder2 } = pathsByFloor[i + 1]; acc += distanceSum; result.push({ isUp: Number(floorOrder2) > Number(floorOrder1), floorOrder: floorOrder2, percent: acc / navigation.totalDistance, name: mall.floors[floorOrder2][1], }); } setElevations(result); } navigation.handleText = setRouteSearchText; navigation.onPercentChange = setPercent; navigation.onPausedChanged = setPaused; setNavigation(navigation); setInAnimation(true); dispatchLS({ type: "set", data: pathsByFloor }); }, onSearchComplete: () => { setInAnimation(false); }, images, onFloorChange: (floorOrder) => { setDoFocus(0); setSceneIndex(floorOrder); dispatchLS({ type: "addLine", data: floorOrder }); }, onLoad: (map) => { setDisplayMode(1); setMap(map); }, onAzimuthAngleChange: (angle) => setAzimuthAngle(Math.floor((angle / Math.PI) * 180)), }); }; useEffect(() => { if (!mallCode) { getMallInfo({ memberID }).then((result) => { if (!mallCode) setMallCode(result.mall.code); setMallInfo(result); }); } }, [mallCode]); const showPopup = shop !== null && !isPick && defaultPopupState !== DefaultPopupStates.facList; const hasCoupon = showPopup && shop && shop.hasCoupon; const showHeadBar = (start || end) && !inAnimation; const showHeadBarSearchType = showHeadBar && start && end; const showNav = inAnimation && start && end; const showDefaultPopup = !showPopup && !showHeadBar && !showNav && facilities; const isNavEnd = showHeadBar && start && end; const exitFromNav = () => { map.setStart(null); map.setEnd(null); map.recycle(); setIsPick(false); navigation && navigation.stop && navigation.stop(); dispatchLS({ type: "set", data: null }); setStart(null); setEnd(null); }; useEffect(() => { if (navigation) { if (openid) { const isShop = "intro" in end; const isP = end.isP; const isDevice = end.isDevice; setStatistics({ userId: openid, navType: 2, pointType: isShop || isDevice ? "1" : isP ? "3" : "2", objectCode: isShop ? end.code : isP ? end.houseNum : end.Type, objectName: end.name, floorName: end.floorName || mall.floors[end.floorOrder][1], }); } } }, [navigation]); useEffect(() => { if (mallInfo) { setTab(mall.menu[0].name); loadMap(); } }, [mallInfo]); useEffect(() => { if (map) { let facs = map.getAllFacilities(); facs = facs .filter(({ url, typeName }) => url && typeName) .reduce( (acc, nxt) => acc[nxt.typeName] ? { ...acc, [nxt.typeName]: [...acc[nxt.typeName], nxt] } : { ...acc, [nxt.typeName]: [nxt] }, {} ); setFacilities(facs); } }, [map]); useEffect(() => { switch (tab) { case "活动": setShowFindCar(false); setShowCoupon(false); setShowActivities(true); break; case "地图": setShowFindCar(false); setShowCoupon(false); setShowActivities(false); break; case "寻车": setShowCoupon(false); setShowActivities(false); setShowFindCar(true); break; case "我的": setShowActivities(false); setShowFindCar(false); setShowCoupon(true); break; default: break; } }, [tab]); return (
{showShopCoupons && ( setCouponShop(null)} shop={couponShop} > )} {showActivities && ( setTab("地图")} facilities={facilities} onGo={(fac) => { setTab("地图"); map && map.focusFacilityById(fac.id); }} > )} {showFindCar && mall && ( name === "寻车")?.specialType === 1 } plate={plate} lots={mall.lots} onBack={() => setTab("地图")} onLot={(e) => { setDoFocus(2); map.focusPByHouseNum(e); setTab("地图"); }} > )} {showARPrompt && (
即将离开模拟导航 进入AR导航
是否要继续?
setShowARPrompt(false)}> 取消
{ if (openid && openid !== "null") { const isShop = "intro" in ARshop; const isP = ARshop.isP; const isDevice = ARshop.isDevice; setStatistics({ userId: openid, navType: 1, pointType: isShop || isDevice ? "1" : isP ? "3" : "2", objectCode: isShop ? ARshop.code : isP ? ARshop.houseNum : ARshop.Type, objectName: ARshop.name, floorName: ARshop.floorName || mall.floors[ARshop.floorOrder][1], }); } setShowARPrompt(false); window.wx.miniProgram.redirectTo({ url: `/pages/index/index?e=${ ARshop.houseNum ? ARshop.houseNum : ARshop.isDevice ? `${ARshop.floorOrder}_${ARshop.navPoint}_${ARshop.name}` : encodeURIComponent(ARshop.id) }&searchType=${searchType}`, }); }} > 确定
)} {!online && ( )}
{!(start || end) && (
{ const { msg } = await post("/api/ar/v1/applet/GetUserAward", { memberID, poiCode: "97be8faa6ab34e08864bf2b1c231e6ab", }); window.weui.toast(msg, { className: "toast", }); }} > 图左 {mall && mall.city}
{mall && mall.name}
)} {showHeadBar && ( { setStart(shop); map.startNavigate({ start: shop, end }); }} onSetEnd={(shop) => { setEnd(shop); map.startNavigate({ start, end: shop }); }} blurMap={() => { map.blurShop(); map.blurFacility(); }} searchType={searchType} onClickSearchType={(id) => { if (id === searchType) return; setSearchType(id); map && map.changeSearchType(id); }} showSearchType={start && end} onIsTypingChange={setIsTyping} > )} {((!(start && end) && !isTyping) || showHeadBarSearchType) && ( { if (id === displayMode) return; setDisplayMode(id); map && map.changeDisplayMode(id); }} onClickSearchType={(id) => { if (id === searchType) return; setSearchType(id); map && map.changeSearchType(id); }} > )} {!isTyping && !showHeadBar && ( <> map && !showNav && map.changeFloor(sceneIndex, true) } /> )}
setShowShops(false)} onClick={({ houseNum }) => { setShowShops(false); setDoFocus(2); map.focusShopByHouseNum(houseNum); }} onClose={() => setShowShops(false)} > { setShowShops(true); }} onClickFac={(id) => { setDoFocus(2); map && map.focusFacilityById(id); }} setEnd={(fac) => { setEnd(fac); setShop(null); }} blurMap={() => { setShop(null); map.blurShop(); map.blurFacility(); }} mall={mall} onClick={({ houseNum }) => { setShowShops(false); setDoFocus(2); map.focusShopByHouseNum(houseNum); }} > ) } floors={ mall && sceneIndex !== null && (defaultPopupState !== DefaultPopupStates.moreFac || !showDefaultPopup) && ( { setShowActivities(true); }} mall={mall} hasCoupon={hasCoupon} > ) } shop={shop} closePopup={() => { setShop(null); history.replace(`/?openid=${openid}`); map.blurShop(); map.blurFacility(); }} showDetail={() => setShop({ ...shop, showDetail: true })} setEnd={() => { setEnd(shop); setShop(null); }} handleAR={(shop) => { setARShop(shop); setShowARPrompt(true); }} onClickCoupon={() => { setCouponShop(shop); }} > {showNav && ( map.changeRouteSearchAnimationType( map.routeSearchAnimationType() === 1 ? 2 : 1 ) } onExit={exitFromNav} end={end} meters={Math.floor(navigation.totalDistanceInMeter * (1 - percent))} minutes={Math.floor( (navigation.totalDistanceInMeter * (1 - percent)) / 1.4 / 60 )} puaseOrResume={() => { if (paused) navigation.resume(); else navigation.pause(); }} paused={paused} startText={mall.floors[start.floorOrder][1]} routeSearchText={routeSearchText} percent={percent} elevations={elevations} handleAR={(shop) => { setARShop(shop); setShowARPrompt(true); }} > )} {isNavEnd && (
{ map.startNavigate({ start, end }); }} > 开始导航
)} {mall && mall.menu.length > 1 && (
{mall.menu.map(({ name, alias }) => { const isActive = tab === name; return (
setTab(name)} > {alias || name}
); })}
)}
); }; export default Index;