|
@@ -0,0 +1,407 @@
|
|
|
|
+import React, {
|
|
|
|
+ useCallback,
|
|
|
|
+ useEffect,
|
|
|
|
+ useMemo,
|
|
|
|
+ useRef,
|
|
|
|
+ useState,
|
|
|
|
+} from "react";
|
|
|
|
+import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons";
|
|
|
|
+import styles from "./index.module.scss";
|
|
|
|
+import SpinLoding from "@/components/SpinLoding";
|
|
|
|
+import { Route, Switch, useLocation } from "react-router-dom";
|
|
|
|
+import AuthRoute from "@/components/AuthRoute";
|
|
|
|
+import NotFound from "@/components/NotFound";
|
|
|
|
+import classNames from "classnames";
|
|
|
|
+import history from "@/utils/history";
|
|
|
|
+import { Button, Form, Input, Modal, Popconfirm } from "antd";
|
|
|
|
+import { Base64 } from "js-base64";
|
|
|
|
+import encodeStr from "@/utils/pass";
|
|
|
|
+import { getDictListAPI, passWordEditAPI } from "@/store/action/login";
|
|
|
|
+import { getTokenInfo, removeTokenInfo } from "@/utils/storage";
|
|
|
|
+import { useDispatch } from "react-redux";
|
|
|
|
+import inco1 from "@/assets/img/inco1.png";
|
|
|
|
+import inco2 from "@/assets/img/inco2.png";
|
|
|
|
+import inco3 from "@/assets/img/inco3.png";
|
|
|
|
+import inco4 from "@/assets/img/inco4.png";
|
|
|
|
+import inco1Ac from "@/assets/img/inco1Ac.png";
|
|
|
|
+import inco2Ac from "@/assets/img/inco2Ac.png";
|
|
|
|
+import inco3Ac from "@/assets/img/inco3Ac.png";
|
|
|
|
+import inco4Ac from "@/assets/img/inco4Ac.png";
|
|
|
|
+import { MessageFu } from "@/utils/message";
|
|
|
|
+
|
|
|
|
+function Layout() {
|
|
|
|
+ const dispatch = useDispatch();
|
|
|
|
+
|
|
|
|
+ type ListTempType = {
|
|
|
|
+ title: string;
|
|
|
|
+ inco: any;
|
|
|
|
+ son: {
|
|
|
|
+ id: number;
|
|
|
|
+ name: string;
|
|
|
|
+ path: string;
|
|
|
|
+ done: boolean;
|
|
|
|
+ Com: React.LazyExoticComponent<
|
|
|
|
+ React.MemoExoticComponent<() => JSX.Element>
|
|
|
|
+ >;
|
|
|
|
+ inco: any;
|
|
|
|
+ incoAc: any;
|
|
|
|
+ num?: number;
|
|
|
|
+ }[];
|
|
|
|
+ }[];
|
|
|
|
+
|
|
|
|
+ const listTemp = useMemo(() => {
|
|
|
|
+ const arr: ListTempType = [
|
|
|
|
+ {
|
|
|
|
+ title: "数据统计",
|
|
|
|
+ inco: inco1,
|
|
|
|
+ son: [
|
|
|
|
+ {
|
|
|
|
+ id: 100,
|
|
|
|
+ name: "热度统计",
|
|
|
|
+ path: "/",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../A1Hot")),
|
|
|
|
+ inco: inco1,
|
|
|
|
+ incoAc: inco1Ac,
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: "内容管理",
|
|
|
|
+ inco: inco2,
|
|
|
|
+ son: [
|
|
|
|
+ {
|
|
|
|
+ id: 200,
|
|
|
|
+ name: "场景管理",
|
|
|
|
+ path: "/scene",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B1Scene")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 300,
|
|
|
|
+ name: "馆藏管理",
|
|
|
|
+ path: "/goods",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B2Goods")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 400,
|
|
|
|
+ name: "万物墙管理",
|
|
|
|
+ path: "/wall",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B3Wall")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 500,
|
|
|
|
+ name: "弹幕管理",
|
|
|
|
+ path: "/barrage",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B4Barrage")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ num: 0,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 600,
|
|
|
|
+ name: "题库管理",
|
|
|
|
+ path: "/topic",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B5Topic")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 700,
|
|
|
|
+ name: "智能导览管理",
|
|
|
|
+ path: "/smart",
|
|
|
|
+ done: false,
|
|
|
|
+ Com: React.lazy(() => import("../B6Smart")),
|
|
|
|
+ inco: inco2,
|
|
|
|
+ incoAc: inco2Ac,
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ return arr;
|
|
|
|
+ }, []);
|
|
|
|
+
|
|
|
|
+ // 是超级管理员
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const userInfo = getTokenInfo().user;
|
|
|
|
+ if (userInfo.isAdmin === 1) {
|
|
|
|
+ listTemp.push({
|
|
|
|
+ title: "系统管理",
|
|
|
|
+ inco: inco4,
|
|
|
|
+ son: [
|
|
|
|
+ {
|
|
|
|
+ id: 800,
|
|
|
|
+ name: "用户管理",
|
|
|
|
+ path: "/user",
|
|
|
|
+ done: true,
|
|
|
|
+ Com: React.lazy(() => import("../C1User")),
|
|
|
|
+ inco: inco3,
|
|
|
|
+ incoAc: inco3Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 900,
|
|
|
|
+ name: "角色管理",
|
|
|
|
+ path: "/role",
|
|
|
|
+ done: true,
|
|
|
|
+ Com: React.lazy(() => import("../C2Role")),
|
|
|
|
+ inco: inco3,
|
|
|
|
+ incoAc: inco3Ac,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 1000,
|
|
|
|
+ name: "操作日志",
|
|
|
|
+ path: "/log",
|
|
|
|
+ done: true,
|
|
|
|
+ Com: React.lazy(() => import("../C3Log")),
|
|
|
|
+ inco: inco4,
|
|
|
|
+ incoAc: inco4Ac,
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }, [listTemp]);
|
|
|
|
+
|
|
|
|
+ // 权限的数据和页面判断
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ // authPageArr.forEach((v) => {
|
|
|
|
+ // if (v.authority) {
|
|
|
|
+ // listTemp.forEach((v2) => {
|
|
|
|
+ // if (v.id === v2.id) v2.done = true;
|
|
|
|
+ // });
|
|
|
|
+ // }
|
|
|
|
+ // });
|
|
|
|
+ // const newList = listTemp.filter((v) => v.done);
|
|
|
|
+ // setList(listTemp.filter((v) => v.done));
|
|
|
|
+ }, [listTemp]);
|
|
|
|
+
|
|
|
|
+ const [list, setList] = useState(listTemp);
|
|
|
|
+
|
|
|
|
+ // 进页面看看第一个页面有权限的是哪一个
|
|
|
|
+ // useEffect(() => {
|
|
|
|
+ // const userInfo = getTokenInfo().user;
|
|
|
|
+ // if (userInfo.isAdmin !== 1) {
|
|
|
|
+ // if (list[0] && list[0].id !== 100) history.replace(list[0].path);
|
|
|
|
+ // }
|
|
|
|
+ // }, [list]);
|
|
|
|
+
|
|
|
|
+ // 进页面获取所有下拉信息和权限信息
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ dispatch(getDictListAPI());
|
|
|
|
+ // dispatch(getPermissionsAPI());
|
|
|
|
+ }, [dispatch]);
|
|
|
|
+
|
|
|
|
+ // 点击跳转
|
|
|
|
+ const pathCutFu = useCallback((path: string) => {
|
|
|
|
+ history.push(path);
|
|
|
|
+ }, []);
|
|
|
|
+
|
|
|
|
+ // 当前路径选中的左侧菜单
|
|
|
|
+ const location = useLocation();
|
|
|
|
+ const [path, setPath] = useState("");
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const arr = location.pathname.split("/");
|
|
|
|
+ let pathTemp = "/";
|
|
|
|
+ if (arr[1]) pathTemp = "/" + arr[1];
|
|
|
|
+
|
|
|
|
+ setPath(pathTemp);
|
|
|
|
+ }, [location]);
|
|
|
|
+
|
|
|
|
+ const userInfo = useMemo(() => {
|
|
|
|
+ return getTokenInfo().user;
|
|
|
|
+ }, []);
|
|
|
|
+
|
|
|
|
+ // 修改密码相关
|
|
|
|
+ const [open, setOpen] = useState(false);
|
|
|
|
+
|
|
|
|
+ // 拿到新密码的输入框的值
|
|
|
|
+ const oldPasswordValue = useRef("");
|
|
|
|
+
|
|
|
|
+ const checkPassWord = (rule: any, value: any = "") => {
|
|
|
|
+ if (value !== oldPasswordValue.current)
|
|
|
|
+ return Promise.reject("新旧密码不一致!");
|
|
|
|
+ else return Promise.resolve(value);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const onFinish = async (values: any) => {
|
|
|
|
+ // 通过校验之后发送请求
|
|
|
|
+ if (values.oldPassword === values.newPassword)
|
|
|
|
+ return MessageFu.warning("新旧密码不能相同!");
|
|
|
|
+ const obj = {
|
|
|
|
+ oldPassword: encodeStr(Base64.encode(values.oldPassword)),
|
|
|
|
+ newPassword: encodeStr(Base64.encode(values.newPassword)),
|
|
|
|
+ };
|
|
|
|
+ const res: any = await passWordEditAPI(obj);
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
+ MessageFu.success("修改成功!");
|
|
|
|
+ loginExit();
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 点击退出登录
|
|
|
|
+ const loginExit = () => {
|
|
|
|
+ removeTokenInfo();
|
|
|
|
+ history.push("/login");
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <div className={styles.Layout}>
|
|
|
|
+ {/* 左边 */}
|
|
|
|
+ <div className="layoutLeft">
|
|
|
|
+ <div className="layoutLeftTop">
|
|
|
|
+ <h3>
|
|
|
|
+ 中医药文化宣传教育基地
|
|
|
|
+ <br />
|
|
|
|
+ 线上展馆管理后台
|
|
|
|
+ </h3>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 左边主体 */}
|
|
|
|
+ <div className="layoutLeftMain">
|
|
|
|
+ {list.map((v1) => (
|
|
|
|
+ <div className="mainBoxL2RowBox" key={v1.title}>
|
|
|
|
+ <div className="mainBoxL2RowBoxTit">
|
|
|
|
+ <img className="tabImg" src={v1.inco} alt="" />
|
|
|
|
+ <div className="txt">{v1.title}</div>
|
|
|
|
+ </div>
|
|
|
|
+ {v1.son.map((v2) => (
|
|
|
|
+ <div
|
|
|
|
+ key={v2.id}
|
|
|
|
+ onClick={() => pathCutFu(v2.path)}
|
|
|
|
+ className={classNames(
|
|
|
|
+ "mainBoxL2Row",
|
|
|
|
+ v2.path === path ? "active" : ""
|
|
|
|
+ )}
|
|
|
|
+ >
|
|
|
|
+ <img className="tabImg" src={v2.inco} alt="" />
|
|
|
|
+ <img className="tabImgAc" src={v2.incoAc} alt="" />
|
|
|
|
+ {v2.id === 500 ? (
|
|
|
|
+ <div className="rowTip">{v2.num}</div>
|
|
|
|
+ ) : null}
|
|
|
|
+ <div className="txt">{v2.name}</div>
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 右边 */}
|
|
|
|
+ <div className="layoutRight">
|
|
|
|
+ <div className="layoutRightTop">
|
|
|
|
+ {/* 用户相关 */}
|
|
|
|
+ <div className="user">
|
|
|
|
+ {userInfo.realName}
|
|
|
|
+ <div className="userInco userInco1">
|
|
|
|
+ <CaretUpOutlined />
|
|
|
|
+ </div>
|
|
|
|
+ <div className="userInco userInco2">
|
|
|
|
+ <CaretDownOutlined />
|
|
|
|
+ </div>
|
|
|
|
+ <div className="userSet">
|
|
|
|
+ <span onClick={() => setOpen(true)}>修改密码</span>
|
|
|
|
+ <Popconfirm
|
|
|
|
+ placement="bottom"
|
|
|
|
+ title="确定退出吗?"
|
|
|
|
+ okText="确定"
|
|
|
|
+ cancelText="取消"
|
|
|
|
+ onConfirm={loginExit}
|
|
|
|
+ >
|
|
|
|
+ 退出登录
|
|
|
|
+ </Popconfirm>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 右边主体 */}
|
|
|
|
+ <div className="layoutRightMain">
|
|
|
|
+ {/* 二级路由页面 */}
|
|
|
|
+ <div className="mainBoxR">
|
|
|
|
+ <React.Suspense fallback={<SpinLoding />}>
|
|
|
|
+ <Switch>
|
|
|
|
+ {list.map((v1) => {
|
|
|
|
+ return v1.son.map((v2) => (
|
|
|
|
+ <AuthRoute
|
|
|
|
+ key={v2.id}
|
|
|
|
+ exact
|
|
|
|
+ path={v2.path}
|
|
|
|
+ component={v2.Com}
|
|
|
|
+ />
|
|
|
|
+ ));
|
|
|
|
+ })}
|
|
|
|
+
|
|
|
|
+ <Route path="*" component={NotFound} />
|
|
|
|
+ </Switch>
|
|
|
|
+ </React.Suspense>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ {/* 点击修改密码打开的对话框 */}
|
|
|
|
+ <Modal
|
|
|
|
+ destroyOnClose
|
|
|
|
+ open={open}
|
|
|
|
+ title="修改密码"
|
|
|
|
+ onCancel={() => setOpen(false)}
|
|
|
|
+ footer={
|
|
|
|
+ [] // 设置footer为空,去掉 取消 确定默认按钮
|
|
|
|
+ }
|
|
|
|
+ >
|
|
|
|
+ <Form
|
|
|
|
+ name="basic"
|
|
|
|
+ labelCol={{ span: 5 }}
|
|
|
|
+ wrapperCol={{ span: 16 }}
|
|
|
|
+ onFinish={onFinish}
|
|
|
|
+ autoComplete="off"
|
|
|
|
+ >
|
|
|
|
+ <Form.Item
|
|
|
|
+ label="旧密码"
|
|
|
|
+ name="oldPassword"
|
|
|
|
+ rules={[{ required: true, message: "不能为空!" }]}
|
|
|
|
+ >
|
|
|
|
+ <Input.Password maxLength={15} />
|
|
|
|
+ </Form.Item>
|
|
|
|
+
|
|
|
|
+ <Form.Item
|
|
|
|
+ label="新密码"
|
|
|
|
+ name="newPassword"
|
|
|
|
+ rules={[{ required: true, message: "不能为空!" }]}
|
|
|
|
+ >
|
|
|
|
+ <Input.Password
|
|
|
|
+ maxLength={15}
|
|
|
|
+ onChange={(e) => (oldPasswordValue.current = e.target.value)}
|
|
|
|
+ />
|
|
|
|
+ </Form.Item>
|
|
|
|
+
|
|
|
|
+ <Form.Item
|
|
|
|
+ label="确定新密码"
|
|
|
|
+ name="checkPass"
|
|
|
|
+ rules={[{ validator: checkPassWord }]}
|
|
|
|
+ >
|
|
|
|
+ <Input.Password maxLength={15} />
|
|
|
|
+ </Form.Item>
|
|
|
|
+
|
|
|
|
+ <Form.Item wrapperCol={{ offset: 14, span: 16 }}>
|
|
|
|
+ <Button onClick={() => setOpen(false)}>取消</Button>
|
|
|
|
+  
|
|
|
|
+ <Button type="primary" htmlType="submit">
|
|
|
|
+ 确定
|
|
|
|
+ </Button>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ </Form>
|
|
|
|
+ </Modal>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
|
|
|
|
+const MemoLayout = React.memo(Layout);
|
|
|
|
+export default MemoLayout;
|