index.tsx 8.5 KB

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