|
|
@@ -0,0 +1,316 @@
|
|
|
+import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
+import { CaretRightOutlined } from '@ant-design/icons'
|
|
|
+import styles from './index.module.scss'
|
|
|
+import { Route, Switch, useLocation } from 'react-router-dom'
|
|
|
+import AuthRoute from '@/components/AuthRoute'
|
|
|
+import history from '@/utils/history'
|
|
|
+import { getTokenInfo } from '@/utils/storage'
|
|
|
+import NotFound from '@/components/NotFound'
|
|
|
+import classNames from 'classnames'
|
|
|
+import tabLeftArr, { loginExit, routerSon, RouterType, RouterTypeRow } from './data'
|
|
|
+import MyPopconfirm from '@/components/MyPopconfirm'
|
|
|
+import store, { RootState } from '@/store'
|
|
|
+import SpinLodingSon from '@/components/SpinLodingSon'
|
|
|
+import { DownOutlined, RightOutlined } from '@ant-design/icons'
|
|
|
+import { useSelector } from 'react-redux'
|
|
|
+import { baseURL } from '@/utils/http'
|
|
|
+import baseTouXiangImg from '@/assets/img/user.png'
|
|
|
+import PassEdit from './PassEdit'
|
|
|
+
|
|
|
+function Layout() {
|
|
|
+ const [loding, setLoding] = useState(false)
|
|
|
+
|
|
|
+ // 获取字典值 // 获取标签
|
|
|
+ // const dispatch = useDispatch()
|
|
|
+
|
|
|
+ const getListFu = useCallback(() => {
|
|
|
+ // 待完善
|
|
|
+ setLoding(true)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ // 用户信息存到仓库
|
|
|
+ store.dispatch({ type: 'layout/userInfo', payload: (getTokenInfo() || {}).user })
|
|
|
+ getListFu()
|
|
|
+ }, [getListFu])
|
|
|
+ // 获取用户信息
|
|
|
+ const { userInfo, passEditShow } = useSelector((state: RootState) => state.A0Layout)
|
|
|
+
|
|
|
+ // 当前路径选中的左侧菜单
|
|
|
+ const location = useLocation()
|
|
|
+ const sroolRef = useRef<HTMLDivElement>(null)
|
|
|
+ const sroolTimeRef = useRef(-1)
|
|
|
+
|
|
|
+ const [acPageName, setAcPageName] = useState(['', ''])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (loding) {
|
|
|
+ const arr = location.pathname.split('/')
|
|
|
+ let pathTemp = '/'
|
|
|
+ if (arr[1]) pathTemp = '/' + arr[1]
|
|
|
+
|
|
|
+ // 滚动到中间
|
|
|
+ clearTimeout(sroolTimeRef.current)
|
|
|
+ if (pathTemp !== '/goodsLook') {
|
|
|
+ sroolTimeRef.current = window.setTimeout(() => {
|
|
|
+ if (sroolRef.current) {
|
|
|
+ const dom = document.querySelector('.layoutLeftMain') as HTMLDivElement
|
|
|
+ if (dom) {
|
|
|
+ dom.scrollTo({
|
|
|
+ top: sroolRef.current.offsetTop - 350,
|
|
|
+ behavior: 'smooth'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 200)
|
|
|
+ }
|
|
|
+ const pathRes = pathTemp.split('_')[0]
|
|
|
+
|
|
|
+ tabLeftArr.forEach(v1 => {
|
|
|
+ v1.son.forEach(v2 => {
|
|
|
+ if (v2.path === pathRes) setAcPageName([v1.name, v2.name])
|
|
|
+ else if (pathRes === '/goodsLook') setAcPageName(['', ''])
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }, [location, loding])
|
|
|
+
|
|
|
+ const [routerSonRes, setRouterSonRes] = useState<RouterTypeRow[]>([])
|
|
|
+
|
|
|
+ // 获取用户权限信息
|
|
|
+ const getUserAuthFu = useCallback(async () => {
|
|
|
+ const userInfo = getTokenInfo().user
|
|
|
+
|
|
|
+ // 待完善
|
|
|
+ let isOkIdArr: number[] = [9901, 709, 710, 720, 730, 740, 750, 760, 770]
|
|
|
+
|
|
|
+ const roleArr: any[] = []
|
|
|
+
|
|
|
+ roleArr.forEach(v1 => {
|
|
|
+ if (v1.children) {
|
|
|
+ v1.children.forEach((v2: any) => {
|
|
|
+ if (v2.authority) isOkIdArr.push(v2.id)
|
|
|
+ if (v2.children) {
|
|
|
+ v2.children.forEach((v3: any) => {
|
|
|
+ if (v3.authority) isOkIdArr.push(v3.id)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 详情页,也需要看下有没有页面权限
|
|
|
+ setRouterSonRes(routerSon.filter(v => isOkIdArr.includes(v.id)))
|
|
|
+
|
|
|
+ // 是管理员
|
|
|
+ if (userInfo.isAdmin === 1) {
|
|
|
+ ;[750].forEach(v => {
|
|
|
+ isOkIdArr.push(v)
|
|
|
+ })
|
|
|
+ } else if (isOkIdArr.includes(750)) isOkIdArr = isOkIdArr.filter(v => v !== 750)
|
|
|
+
|
|
|
+ // 页面权限id,存到仓库
|
|
|
+ store.dispatch({ type: 'layout/authorityIds', payload: isOkIdArr })
|
|
|
+
|
|
|
+ const tempArr: RouterTypeRow[] = []
|
|
|
+
|
|
|
+ // 权限数据存到仓库
|
|
|
+ const roleArrStoreArr: RouterType = []
|
|
|
+
|
|
|
+ tabLeftArr.forEach(v1 => {
|
|
|
+ if (v1.son && v1.son[0]) {
|
|
|
+ const obj = {
|
|
|
+ ...v1,
|
|
|
+ son: [] as RouterTypeRow[]
|
|
|
+ }
|
|
|
+
|
|
|
+ v1.son.forEach(v2 => {
|
|
|
+ if (isOkIdArr.includes(v2.id)) {
|
|
|
+ tempArr.push(v2)
|
|
|
+ // 过滤掉 藏品详情 页
|
|
|
+ if (v2.id < 9901) obj.son.push({ ...v2, authority: true })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ roleArrStoreArr.push(obj)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 权限数据存到仓库
|
|
|
+ store.dispatch({ type: 'layout/userRolePermissions', payload: roleArrStoreArr })
|
|
|
+
|
|
|
+ setRouterCom(tempArr)
|
|
|
+
|
|
|
+ // 如果当前页面没有权限了,跳转有权限的第一个页面
|
|
|
+ const urlAll = window.location.hash
|
|
|
+ const isNowPath = urlAll.replace('#', '')
|
|
|
+ const pathArr = tempArr.map(v => v.pathLast || v.path)
|
|
|
+
|
|
|
+ const routerSonArr = routerSon.map(v => v.path)
|
|
|
+
|
|
|
+ const lastArr = [...pathArr, ...routerSonArr]
|
|
|
+
|
|
|
+ let flagPush = true
|
|
|
+
|
|
|
+ lastArr.forEach(v => {
|
|
|
+ if (v === '/') {
|
|
|
+ if (isNowPath === '/') flagPush = false
|
|
|
+ } else {
|
|
|
+ if (isNowPath.includes(v)) flagPush = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (flagPush) history.push(pathArr[0])
|
|
|
+
|
|
|
+ const pathRes = isNowPath.split('_')[0]
|
|
|
+
|
|
|
+ const resList = tabLeftArr.map(v => ({
|
|
|
+ ...v,
|
|
|
+ show: v.son.some(v => v.path === (flagPush ? pathArr[0] : pathRes)),
|
|
|
+ son: v.son.filter(c => isOkIdArr.includes(c.id))
|
|
|
+ }))
|
|
|
+
|
|
|
+ setList(resList)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getUserAuthFu()
|
|
|
+ }, [getUserAuthFu])
|
|
|
+
|
|
|
+ // 左侧菜单 信息
|
|
|
+ const [list, setList] = useState([] as RouterType)
|
|
|
+
|
|
|
+ // 路由信息(过滤之后的)
|
|
|
+ const [RouterCom, setRouterCom] = useState<RouterTypeRow[]>([])
|
|
|
+
|
|
|
+ // useEffect(() => {
|
|
|
+ // console.log(123, list);
|
|
|
+ // }, [list]);
|
|
|
+
|
|
|
+ // 点击跳转
|
|
|
+ const pathCutFu = useCallback((item: RouterTypeRow) => {
|
|
|
+ history.push(item.path)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ // 点击用户 出来 退出登录 修改密码
|
|
|
+ const [isUserBtnShow, setIsUserBtnShow] = useState(false)
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className={styles.Layout}>
|
|
|
+ {/* 左边 */}
|
|
|
+ <div className='layoutLeft'>
|
|
|
+ <div className='layoutLeftTop'>
|
|
|
+ <img className='logo' src={require('@/assets/img/logo.png')} alt='' />
|
|
|
+ </div>
|
|
|
+ {/* 左边主体 */}
|
|
|
+ <div className='layoutLeftMain mySorrl'>
|
|
|
+ {list.map(v => (
|
|
|
+ <div
|
|
|
+ className={classNames('layoutLRowBox')}
|
|
|
+ key={v.id}
|
|
|
+ hidden={!v.son.length || (v.son.length === 1 && v.son[0].name === '藏品详情')}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ className={classNames(
|
|
|
+ 'layoutLRowBoxTxt',
|
|
|
+ v.show ? 'layoutLRowBoxTxtShow' : '',
|
|
|
+ acPageName[0] === v.name ? 'layoutLRowBoxTxtShowAc' : ''
|
|
|
+ )}
|
|
|
+ onClick={() => {
|
|
|
+ setList(
|
|
|
+ list.map(c => ({
|
|
|
+ ...c,
|
|
|
+ show: c.id === v.id ? !c.show : c.show
|
|
|
+ }))
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {v.name}
|
|
|
+ <span className={classNames(v.show ? 'layoutLRowBoxTxtIcon' : '')}>
|
|
|
+ <DownOutlined />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ {v.son.map(v2 => (
|
|
|
+ <div
|
|
|
+ key={v2.id}
|
|
|
+ hidden={v2.id >= 9901}
|
|
|
+ className={classNames(
|
|
|
+ 'layoutLRowBoxRow',
|
|
|
+ acPageName[1] === v2.name ? 'active' : '',
|
|
|
+ v.show ? '' : 'layoutLRowBoxRowHide'
|
|
|
+ )}
|
|
|
+ ref={acPageName[1] === v2.name ? sroolRef : null}
|
|
|
+ onClick={() => pathCutFu(v2)}
|
|
|
+ >
|
|
|
+ {v2.name}
|
|
|
+ <span>
|
|
|
+ <RightOutlined />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {/* 右边 */}
|
|
|
+ <div className='layoutRight'>
|
|
|
+ <div className='layoutRightTop'>
|
|
|
+ {/* 用户相关 */}
|
|
|
+ <div
|
|
|
+ className={classNames('user', isUserBtnShow ? 'userShow' : '')}
|
|
|
+ onMouseLeave={() => setIsUserBtnShow(false)}
|
|
|
+ >
|
|
|
+ <div className='userNameBox' onClick={() => setIsUserBtnShow(true)}>
|
|
|
+ <img src={userInfo.thumb ? baseURL + userInfo.thumb : baseTouXiangImg} alt='' />
|
|
|
+
|
|
|
+ {userInfo.realName || userInfo.userName || '匿名'}
|
|
|
+
|
|
|
+ <div className='userInco userInco2'>
|
|
|
+ <CaretRightOutlined />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className='userSet'>
|
|
|
+ <div>
|
|
|
+ <span
|
|
|
+ onClick={() => store.dispatch({ type: 'layout/passEditShow', payload: true })}
|
|
|
+ >
|
|
|
+ 修改密码
|
|
|
+ </span>
|
|
|
+ <MyPopconfirm txtK='退出登录' onConfirm={loginExit} Dom='退出登录' loc='bottom' />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {/* 右边主体 */}
|
|
|
+ <div className='layoutRightMain'>
|
|
|
+ {/* 二级路由页面 */}
|
|
|
+ {loding ? (
|
|
|
+ <div className='mainBoxR'>
|
|
|
+ <React.Suspense fallback={<SpinLodingSon />}>
|
|
|
+ <Switch>
|
|
|
+ {RouterCom.map(v => (
|
|
|
+ <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
|
|
|
+ ))}
|
|
|
+
|
|
|
+ {/* 非tab栏页面 */}
|
|
|
+ {routerSonRes.map(v => (
|
|
|
+ <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
|
|
|
+ ))}
|
|
|
+
|
|
|
+ <Route path='*' component={NotFound} />
|
|
|
+ </Switch>
|
|
|
+ </React.Suspense>
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 点击修改密码打开的对话框 */}
|
|
|
+ {passEditShow ? <PassEdit /> : null}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
|
|
|
+const MemoLayout = React.memo(Layout)
|
|
|
+export default MemoLayout
|