index.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import React, { useCallback, useEffect, useRef, useState } from 'react'
  2. import { CaretRightOutlined } from '@ant-design/icons'
  3. import styles from './index.module.scss'
  4. import SpinLoding from '@/components/SpinLoding'
  5. import { Route, Switch, useLocation } from 'react-router-dom'
  6. import AuthRoute from '@/components/AuthRoute'
  7. import classNames from 'classnames'
  8. import history from '@/utils/history'
  9. import { Button, Form, Input, Modal } from 'antd'
  10. import { Base64 } from 'js-base64'
  11. import encodeStr from '@/utils/pass'
  12. import { passWordEditAPI } from '@/store/action/layout'
  13. import { getTokenInfo, removeTokenInfo } from '@/utils/storage'
  14. import { MessageFu } from '@/utils/message'
  15. import logoImg from '@/assets/img/logo.png'
  16. import NotFound from '@/components/NotFound'
  17. import { RouterType, RouterTypeRow } from '@/types'
  18. import tabLeftArr from './data'
  19. import MyPopconfirm from '@/components/MyPopconfirm'
  20. // import { Z1_APIgetAuthByUserId } from "@/store/action/Z1user";
  21. function Layout() {
  22. // 当前路径选中的左侧菜单
  23. const location = useLocation()
  24. const [path, setPath] = useState('')
  25. useEffect(() => {
  26. const arr = location.pathname.split('/')
  27. let pathTemp = '/'
  28. if (arr[1]) pathTemp = '/' + arr[1]
  29. setPath(pathTemp)
  30. }, [location])
  31. // 获取用户权限信息
  32. const getUserAuthFu = useCallback(async () => {
  33. const userInfo = getTokenInfo().user
  34. // const res = await Z1_APIgetAuthByUserId(userInfo.id);
  35. // if (res.code === 0) {
  36. // 这里后台返回的一层的数据。懒得改逻辑,手动修改成2级的数据
  37. // res.data = [
  38. // {
  39. // id: Date.now(),
  40. // name: "",
  41. // children: res.data,
  42. // },
  43. // ];
  44. const isOkIdArr: number[] = [101, 102, 103, 104, 105]
  45. // const tempList: UserListType[] = res.data || [];
  46. // console.log(123, tempList);
  47. // tempList.forEach((v) => {
  48. // if (v.children) {
  49. // v.children.forEach((c) => {
  50. // if (c.authority) isOkIdArr.push(c.id);
  51. // });
  52. // }
  53. // });
  54. // 是管理员
  55. if (userInfo.isAdmin === 1) {
  56. isOkIdArr.push(2100)
  57. isOkIdArr.push(2200)
  58. }
  59. const tempArr: RouterTypeRow = []
  60. tabLeftArr.forEach(v1 => {
  61. if (v1.son && v1.son[0]) {
  62. v1.son.forEach(v2 => {
  63. if (isOkIdArr.includes(v2.id)) {
  64. tempArr.push(v2)
  65. }
  66. })
  67. }
  68. })
  69. setRouterCom(tempArr)
  70. // 如果当前页面没有权限了,跳转有权限的第一个页面
  71. const urlAll = window.location.hash
  72. const isNowPath = urlAll.replace('#', '')
  73. const pathArr = tempArr.map(v => v.path)
  74. if (!pathArr.includes(isNowPath)) {
  75. history.push(pathArr[0])
  76. }
  77. const resList = tabLeftArr.map(v => ({
  78. ...v,
  79. son: v.son.filter(c => isOkIdArr.includes(c.id))
  80. }))
  81. setList(resList)
  82. // }
  83. }, [])
  84. useEffect(() => {
  85. getUserAuthFu()
  86. }, [getUserAuthFu])
  87. // 左侧菜单 信息
  88. const [list, setList] = useState([] as RouterType)
  89. // 路由信息(过滤之后的)
  90. const [RouterCom, setRouterCom] = useState<RouterTypeRow>([])
  91. // useEffect(() => {
  92. // console.log(123, list);
  93. // }, [list]);
  94. // 点击跳转
  95. const pathCutFu = useCallback((path: string) => {
  96. history.push(path)
  97. }, [])
  98. // 修改密码相关
  99. const [open, setOpen] = useState(false)
  100. // 拿到新密码的输入框的值
  101. const oldPasswordValue = useRef('')
  102. const checkPassWord = (rule: any, value: any = '') => {
  103. if (value !== oldPasswordValue.current) return Promise.reject('新密码不一致!')
  104. else return Promise.resolve(value)
  105. }
  106. const onFinish = async (values: any) => {
  107. // 通过校验之后发送请求
  108. if (values.oldPassword === values.newPassword) return MessageFu.warning('新旧密码不能相同!')
  109. const obj = {
  110. oldPassword: encodeStr(Base64.encode(values.oldPassword)),
  111. newPassword: encodeStr(Base64.encode(values.newPassword))
  112. }
  113. const res: any = await passWordEditAPI(obj)
  114. if (res.code === 0) {
  115. MessageFu.success('修改成功!')
  116. loginExit()
  117. }
  118. }
  119. // 点击退出登录
  120. const loginExit = () => {
  121. removeTokenInfo()
  122. history.push('/login')
  123. }
  124. // 点击用户 出来 退出登录 修改密码
  125. const [isUserBtnShow, setIsUserBtnShow] = useState(false)
  126. return (
  127. <div className={styles.Layout}>
  128. {/* 左边 */}
  129. <div className='layoutLeft'>
  130. <div className='layoutLeftTop'>
  131. <img src={logoImg} alt='' />
  132. </div>
  133. {/* 左边主体 */}
  134. <div className='layoutLeftMain'>
  135. {list.map(v => (
  136. <div className={classNames('layoutLRowBox')} key={v.id} hidden={!v.son.length}>
  137. {/* 这个项目没有一级目录 */}
  138. <div className='layoutLRowBoxTxt'>{v.name}</div>
  139. {v.son.map(v2 => (
  140. <div
  141. key={v2.id}
  142. className={classNames('layoutLRowBoxRow', path === v2.path ? 'active' : '')}
  143. onClick={() => pathCutFu(v2.path)}
  144. >
  145. {v2.name}
  146. </div>
  147. ))}
  148. </div>
  149. ))}
  150. </div>
  151. </div>
  152. {/* 右边 */}
  153. <div className='layoutRight'>
  154. <div className='layoutRightTop'>
  155. {/* 用户相关 */}
  156. <div
  157. className={classNames('user', isUserBtnShow ? 'userShow' : '')}
  158. onMouseLeave={() => setIsUserBtnShow(false)}
  159. >
  160. <div className='userNameBox' onClick={() => setIsUserBtnShow(true)}>
  161. {getTokenInfo().user.realName || getTokenInfo().user.userName || '匿名'}
  162. <div className='userInco userInco2'>
  163. <CaretRightOutlined />
  164. </div>
  165. </div>
  166. <div className='userSet'>
  167. <div>
  168. <span onClick={() => setOpen(true)}>修改密码</span>
  169. <MyPopconfirm txtK='退出登录' onConfirm={loginExit} Dom='退出登录' loc='bottom' />
  170. </div>
  171. </div>
  172. </div>
  173. </div>
  174. {/* 右边主体 */}
  175. <div className='layoutRightMain'>
  176. {/* 二级路由页面 */}
  177. <div className='mainBoxR'>
  178. <React.Suspense fallback={<SpinLoding />}>
  179. <Switch>
  180. {RouterCom.map(v => (
  181. <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
  182. ))}
  183. <Route path='*' component={NotFound} />
  184. </Switch>
  185. </React.Suspense>
  186. </div>
  187. </div>
  188. </div>
  189. {/* 点击修改密码打开的对话框 */}
  190. <Modal
  191. destroyOnClose
  192. open={open}
  193. title='修改密码'
  194. onCancel={() => setOpen(false)}
  195. footer={
  196. [] // 设置footer为空,去掉 取消 确定默认按钮
  197. }
  198. >
  199. <Form
  200. scrollToFirstError={true}
  201. name='basic'
  202. labelCol={{ span: 5 }}
  203. wrapperCol={{ span: 16 }}
  204. onFinish={onFinish}
  205. autoComplete='off'
  206. >
  207. <Form.Item
  208. label='旧密码'
  209. name='oldPassword'
  210. rules={[{ required: true, message: '不能为空!' }]}
  211. getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
  212. >
  213. <Input.Password maxLength={20} />
  214. </Form.Item>
  215. <Form.Item
  216. label='新密码'
  217. name='newPassword'
  218. rules={[
  219. { required: true, message: '不能为空!' },
  220. { min: 6, max: 15, message: '密码长度为6-15个字符!' }
  221. ]}
  222. getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
  223. >
  224. <Input.Password
  225. maxLength={15}
  226. onChange={e => (oldPasswordValue.current = e.target.value)}
  227. />
  228. </Form.Item>
  229. <Form.Item
  230. label='确定新密码'
  231. name='checkPass'
  232. rules={[{ validator: checkPassWord }]}
  233. getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
  234. >
  235. <Input.Password maxLength={15} />
  236. </Form.Item>
  237. <Form.Item wrapperCol={{ offset: 14, span: 16 }}>
  238. <Button onClick={() => setOpen(false)}>取消</Button>
  239. &emsp;
  240. <Button type='primary' htmlType='submit'>
  241. 确定
  242. </Button>
  243. </Form.Item>
  244. </Form>
  245. </Modal>
  246. </div>
  247. )
  248. }
  249. // 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
  250. const MemoLayout = React.memo(Layout)
  251. export default MemoLayout