import React, { useEffect, useRef, useState, Suspense } from 'react'; import { Anchor, Popover, Radio, Spin } from 'antd'; import Icon, { LoadingOutlined } from '@ant-design/icons'; import { store, helpers } from '@wisdom-utils/utils'; import classNames from 'classnames'; import Cookies from 'js-cookie'; import { connect } from 'react-redux'; import { useHistory } from '@wisdom-utils/runtime'; import KeepAlive from 'react-activation'; import AMapLoader from '@amap/amap-jsapi-loader'; import RightContent from '@/components/GlobalHeader/HNRightContent'; import defaultSetting from '@wisdom-utils/components/lib/AppLayout/layouts/defaultSettings'; import { actionCreators } from '@/containers/App/store'; import BasicLayout from './AppLayout/layouts/BasicLayout'; import { WEB_GIS_TYPE } from '../constants'; import SecurityLayout from './SecurityLayout'; import Site from './Site'; import layoutStyles from './BasicLayout.less'; import styls from './HN.less'; const ArcgisMap = React.lazy(() => import('../pages/map/arcgis')); const AMap = React.lazy(() => import('../pages/map/amap')); const CesiumMap = React.lazy(() => import('../pages/map/cesiumMap')); const { params } = helpers; const { getParamsV1 } = params; const antIcon = <LoadingOutlined style={{ fontSize: 12 }} spin />; const arrowSvg = ({ fillColor = '#fff' }) => ( <svg t="1543324489942" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/1999/xlink" width="16" height="16" > <path d="M511.700683 639.423111 191.917496 319.596945 319.830771 319.596945 511.700683 511.715521 703.570595 319.596945 831.48387 319.596945Z" p-id="8626" fill={fillColor} /> </svg> ); const ArrowIcon = props => <Icon component={arrowSvg} {...props} />; const optionsWith = [{ label: '按站点', value: 'site' }, { label: '按城市', value: 'city' }]; const HOT = ['HOT', '县', '市', 'New']; const StationsItem = (item, action, onChangeVisible) => { const changeGroup = (event, data) => { action.changeGroup && action.changeGroup(event, data, onChangeVisible); }; return ( <li key={item.groupID} style={{ marginRight: `${item.style.marginRight}px` }}> <a className={classNames(layoutStyles.city_select, layoutStyles.showTip)} title={item.city} index={item.promoteIndex} style={{ fontSize: '13px' }} onClick={event => changeGroup(event, item)} > {item.groupName} {item.promoteTip && HOT.includes(item.promoteTip) && <div title={`${item.promoteTip}`}>{item.promoteTip}</div>} </a> </li> ); }; const Stations = props => { const data = props.data.stations; const [targetOffset, setTargetOffset] = useState(undefined); const cityPane = useRef(null); const cityContent = useRef(null); const [defaultTab, setDefaultTab] = useState('site'); useEffect(() => { setTargetOffset(cityPane.current.clientHeight / 2); }, []); const handleClick = (event, link) => { event.preventDefault(); }; const handleTabChange = event => { setDefaultTab(event.target.value); }; return ( <> <div className={layoutStyles.focusStations}> <ul>{Array.isArray(data) ? data.map(item => StationsItem(item, props.action, props.setVisible)) : null}</ul> </div> <Radio.Group options={optionsWith} optionType="button" buttonStyle="solid" size="small" value={defaultTab} onChange={handleTabChange} style={{ marginTop: '6px' }} /> <div style={{ maxWidth: '520px', position: 'relative' }}> {defaultTab === 'site' ? ( <div className={classNames(layoutStyles.city_pane, layoutStyles.station_container)} ref={cityPane}> <Anchor affix={false} onClick={handleClick} targetOffset={targetOffset} getContainer={() => cityContent.current} > <ul className={layoutStyles.py}> {props.data && props.data.siteCityList && props.data.siteCityList.letters} </ul> <div className={layoutStyles.cityContent} style={{ height: '335px' }} ref={cityContent}> {props.data && props.data.siteCityList && props.data.siteCityList.content} </div> </Anchor> </div> ) : ( <div className="city_pane city_container">{props.data.citySelector}</div> )} <Spin spinning={props.loading} tip="加载中" /> </div> </> ); }; const renderSite = ({ data, config, loading, setLoading, action }) => { const [visible, setVisible] = useState(false); let loaded = !!((data && !data.stations) || (Array.isArray(data.weathers) && data.weathers.length === 0)); if (config && config.userInfo && config.userInfo.site === '') { loaded = false; } return ( <> <Spin indicator={antIcon} spinning={loaded} size="small" style={{ marginLeft: '10px' }} tip="" wrapperClassName={layoutStyles.spinLoadding} > <> <Popover placement="bottomLeft" trigger="click" visible={visible} content={ <Stations data={data} loading={loading} setLoading={setLoading} setVisible={setVisible} action={action} /> } arrowPointAtCenter overlayClassName={classNames(layoutStyles.stationsWrapper, layoutStyles.stationsTop)} onVisibleChange={visible => setVisible(visible)} > {Array.isArray(data.stations) ? ( <div className={layoutStyles.toggleSite}> <img src={require('../assets/basic/site.png')} className={layoutStyles.site} /> <span className={layoutStyles.name}>{data.currentStationName}</span> <ArrowIcon className={layoutStyles.arrow} fillColor="#fff" style={{ transform: !visible ? `rotate(0deg)` : `rotate(180deg)`, }} /> </div> ) : null} </Popover> </> </Spin> {data.weathers && Object.keys(data.weathers).length > 0 ? ( <span className={layoutStyles.weatcher} style={{ borderLeft: data.stations.length === 0 ? '0px' : '1px solid rgba(256, 256, 256, 0.3)', }} > <img src={data.weathers && data.weathers.icon} className={layoutStyles.icon} /> <span className={layoutStyles.text}>{data.weathers && data.weathers.text}</span> </span> ) : null} </> ); }; const Layout = props => { const [collapse, setCollapse] = useState(false); const [cityData, setCityData] = useState({}); const [siteLoading, setSiteLoading] = useState(false); const [mapMode, setMapMode] = useState(WEB_GIS_TYPE.ARCGIS); const [siteAction, setSiteAction] = useState(() => new Site(props, setSiteLoading)); // const basename = getBaseName(); const history = useHistory(); useEffect(() => { siteAction.setGlobalConfig(props.global); const tk = Cookies.get('token') || props.global.token; const isLogin = tk !== null && tk !== 'undefined' && tk !== (void 0); if (!isLogin) { let client = props.global && props.global.hasOwnProperty('client') ? props.global.get('client') : null; client = client !== 'undefined' && !_.isNull(client) && !_.isUndefined(client) ? client : 'city'; let generateType = props.global && props.global.hasOwnProperty('get') ? props.global.get('generateType') : null; generateType = !_.isNull(generateType) && !_.isUndefined(generateType) && generateType !== 'undefined' ? `&generateType=${generateType}` : ''; history.replace(`/user/login?client=${client}${generateType}`); props.logout(); return; } if ( props.global && props.global.userInfo && props.global.userInfo.token !== null && props.global.userInfo.loginName && Object.keys(cityData).length === 0 ) { siteAction.getCityStationsForUser().then(res => { setCityData(res); }); } }, [cityData, history, props, props.global, siteAction]); const handlerPageChange = () => { const params = getParamsV1(props.location.pathname); if (params.hasOwnProperty('mapType') && params.mapType === WEB_GIS_TYPE.AMAP) { AMapLoader.reset(); setMapMode(WEB_GIS_TYPE.AMAP); } else if (!/civweb4/.test(location.pathname)) { AMapLoader.reset(); setMapMode(WEB_GIS_TYPE.ARCGIS); } }; useEffect(() => { window.share.event.on('updateSite', res => setCityData(res)); return () => { window.share.event.removeAllListeners('updateSite'); }; }, []); const handleUpdateCurrentIndex = index => { props.updateCurrentIndex(index); window.share && window.share.event.emit('trigger:updateMenuIndex', index); store.set('updateMenuIndex', index); }; const handlerIndustry = event => { props.global.get('userInfo.site') ? history.push(`/industry`) : void 0; }; const handlerCollapsed = () => { setCollapse(!collapse); }; const logo = props.global && _.isFunction(props.global.get) && props.global.get('bannerLogo') ? props.global && _.isFunction(props.global.transformDevAssetsBaseURL) && props.global.transformDevAssetsBaseURL(props.global.get('bannerLogo')) : defaultSetting.logo; return ( <SecurityLayout loading {...props}> <div className={styls.hnlayout}> <BasicLayout route={props.route} title={props.global.title} siderWidth={140} logo={logo} // logo={require('@/assets/basic/HN-logo.png')} config={props.global} currentMenuIndex={props.currentMenuIndex} onHeaderLogo={handlerIndustry} onPageChange={handlerPageChange} onMenuPanelItemClick={handleUpdateCurrentIndex} // subMenuItemRender={()=> <RightContent />} headerContentRender={() => <RightContent />} headerSiteRender={() => renderSite({ data: cityData, config: props.global, loading: siteLoading, setLoading: setSiteLoading, action: siteAction, }) } > <> <Suspense fallback={<></>}> {window.location.pathname.startsWith('/civbase/civ_3d') ? ( <KeepAlive> <CesiumMap /> </KeepAlive> ) : window.location.pathname.startsWith('/civbase/civ_webgis') ? ( mapMode === 'AMap' ? ( <AMap /> ) : ( <ArcgisMap options={{ type: 'ArcgisMap' }} /> ) ) : null} </Suspense> <div id="micro-container" className="subapp-container"> {props.children} </div> </> </BasicLayout> </div> </SecurityLayout> ); }; const mapStateToProps = state => ({ global: state.getIn(['global', 'globalConfig']), settings: state.getIn(['global', 'defaultSetting']), collapsed: state.getIn(['global', 'collapsed']), menu: state.getIn(['global', 'menu']), currentMenuIndex: state.getIn(['global', 'currentMenuIndex']), flatMenu: state.getIn(['global', 'flatMenu']), authValidate: state.getIn(['global', 'authValidate']), pathname: state.getIn(['global', 'pathname']), selectedKeys: state.getIn(['global', 'selectedKeys']), openKeys: state.getIn(['global', 'openKeys']), complexConfig: state.getIn(['global', 'complexConfig']), complexPathName: state.getIn(['global', 'complexPathName']), microMounted: state.getIn(['global', 'microMounted']), }); const mapDispatchToProps = dispatch => ({ updageSetting(setting) { dispatch(actionCreators.updageSetting(setting)); }, updateConfig(config) { dispatch(actionCreators.getConfig(config)); }, updateCurrentIndex(index) { dispatch(actionCreators.updateCurrentIndex(index)); }, updateCollapsed(collapsed) { dispatch(actionCreators.updateCollapsed(collapsed)); }, updateAuthValidate(auth) { dispatch(actionCreators.updateAuthValidate(auth)); }, updatePathname(pathname) { dispatch(actionCreators.updatePathname(pathname)); }, updateSelectedKeys(keys) { dispatch(actionCreators.updateSelectedKeys(keys)); }, updateOpenKeys(keys) { dispatch(actionCreators.updateOpenKeys(keys)); }, updateComplexConfig(config) { dispatch(actionCreators.updateComplexConfig(config)); }, updateComplexPathName(pathname) { dispatch(actionCreators.updateComplexPathName(pathname)); }, logout() { dispatch(actionCreators.logout()); }, }); export default connect( mapStateToProps, mapDispatchToProps, )(Layout);