shaogen1995 2 년 전
부모
커밋
7a307c1c8d

+ 1 - 0
src/assets/styles/base.css

@@ -178,6 +178,7 @@ img {
   padding-left: 30px;
   border-radius: 10px;
   position: relative;
+  color: #333;
 }
 
 .pageTitlt::before {

+ 1 - 19
src/pages/Goods/index.tsx

@@ -45,24 +45,6 @@ function Goods() {
     setEditPageShow(true);
   }, []);
 
-  // 点击新增,新增成功之后的回调
-  const addTableListFu = useCallback(() => {
-    setTableSelect({
-      name: "",
-      num: "",
-      dictTexture: "",
-      dictAge: "",
-      dictLevel: "",
-      dictSource: "",
-      startTime: "",
-      endTime: "",
-      topic: -1,
-      display: -1,
-      pageSize: 10,
-      pageNum: 1,
-    });
-  }, []);
-
   // 从仓库获取下拉列表数据
   const dictList = useSelector((state: RootState) => state.loginStore.dictList);
 
@@ -474,7 +456,7 @@ function Goods() {
           id={editId.current}
           closePage={() => setEditPageShow(false)}
           upTableList={getList}
-          addTableList={() => addTableListFu()}
+          addTableList={resetSelectFu}
         />
       ) : null}
     </div>

+ 7 - 1
src/pages/Hot/index.module.scss

@@ -1,8 +1,14 @@
 .Hot {
-  display: flex;
   color: #696969;
 
   :global {
+
+    .hotBox {
+      margin-top: 15px;
+      display: flex;
+      height: calc(100% - 52px);
+    }
+
     .hotTitle {
       color: #696969;
       display: flex;

+ 78 - 74
src/pages/Hot/index.tsx

@@ -231,89 +231,93 @@ function Hot() {
 
   return (
     <div className={styles.Hot}>
-      <div className="hotLeft">
-        {/* 第一个盒子 */}
-        <div className="hotLeft_1">
-          {/* 标题和!提示 */}
-          <div className="hotTitle">
-            <div className="hotTitle1">万物墙使用热度 {wallNum}</div>
-            <div className="hotTitleInco">
-              <Tooltip title=" 游客通过万物墙每查看一次数据,热度值记为1">
-                <div className="hotTitleInco1">
-                  <ExclamationOutlined />
-                </div>{" "}
-              </Tooltip>
+      <div className="pageTitlt">热度管理</div>
+
+      <div className="hotBox">
+        <div className="hotLeft">
+          {/* 第一个盒子 */}
+          <div className="hotLeft_1">
+            {/* 标题和!提示 */}
+            <div className="hotTitle">
+              <div className="hotTitle1">万物墙使用热度 {wallNum}</div>
+              <div className="hotTitleInco">
+                <Tooltip title=" 游客通过万物墙每查看一次数据,热度值记为1">
+                  <div className="hotTitleInco1">
+                    <ExclamationOutlined />
+                  </div>{" "}
+                </Tooltip>
+              </div>
             </div>
+            {/* 折线图 */}
+            <div className="hotEch1"></div>
+            {/* 近十四天数据文字 */}
+            <div className="hotLeft_1Txt">近十四天数据</div>
           </div>
-          {/* 折线图 */}
-          <div className="hotEch1"></div>
-          {/* 近十四天数据文字 */}
-          <div className="hotLeft_1Txt">近十四天数据</div>
-        </div>
 
-        {/* 第二个盒子 */}
-        <div className="hotLeft_2">
-          <div className="hotTitle">
-            <div className="hotTitle1">馆藏统计</div>
-            <div className="hotTitle2">当前文物合计共 {goodNum} 件</div>
-          </div>
-          {/* 4个饼图 */}
-          <div className="hotEch2Box">
-            <div className="hotEch2BoxSon">
-              <div className="txt">类别</div>
-              <div className="hotEch2 ech2BoxCake"></div>
-            </div>
-            <div className="hotEch2BoxSon">
-              <div className="txt">年代</div>
-              <div className="hotEch3 ech2BoxCake"></div>
+          {/* 第二个盒子 */}
+          <div className="hotLeft_2">
+            <div className="hotTitle">
+              <div className="hotTitle1">馆藏统计</div>
+              <div className="hotTitle2">当前文物合计共 {goodNum} 件</div>
             </div>
-            <div className="hotEch2BoxSon">
-              <div className="txt">级别</div>
-              <div className="hotEch4 ech2BoxCake"></div>
-            </div>
-            <div className="hotEch2BoxSon">
-              <div className="txt">来源</div>
-              <div className="hotEch5 ech2BoxCake"></div>
+            {/* 4个饼图 */}
+            <div className="hotEch2Box">
+              <div className="hotEch2BoxSon">
+                <div className="txt">类别</div>
+                <div className="hotEch2 ech2BoxCake"></div>
+              </div>
+              <div className="hotEch2BoxSon">
+                <div className="txt">年代</div>
+                <div className="hotEch3 ech2BoxCake"></div>
+              </div>
+              <div className="hotEch2BoxSon">
+                <div className="txt">级别</div>
+                <div className="hotEch4 ech2BoxCake"></div>
+              </div>
+              <div className="hotEch2BoxSon">
+                <div className="txt">来源</div>
+                <div className="hotEch5 ech2BoxCake"></div>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-      <div className="hotRight">
-        <div className="hotRightTitle">
-          <div className="hotRightTitle1">馆藏点赞</div>
-          &emsp;&emsp;
-          <div>
-            <Button onClick={deriveFu}>导出数据</Button>
-            &emsp;
-            <Select
-              value={value}
-              style={{ width: 120 }}
-              onChange={(e) => setValue(e)}
-              options={[
-                { value: 1, label: "今日" },
-                { value: 7, label: "近七日" },
-                { value: 30, label: "近三十日" },
-                { value: "", label: "所有时间" },
-              ]}
-            />
+        <div className="hotRight">
+          <div className="hotRightTitle">
+            <div className="hotRightTitle1">馆藏点赞</div>
+            &emsp;&emsp;
+            <div>
+              <Button onClick={deriveFu}>导出数据</Button>
+              &emsp;
+              <Select
+                value={value}
+                style={{ width: 120 }}
+                onChange={(e) => setValue(e)}
+                options={[
+                  { value: 1, label: "今日" },
+                  { value: 7, label: "近七日" },
+                  { value: 30, label: "近三十日" },
+                  { value: "", label: "所有时间" },
+                ]}
+              />
+            </div>
           </div>
-        </div>
-        {1 + 1 === 2 ? (
-          <div className="hotRightMain">
-            {likeData.slice(0, 20).map((v, i) => (
-              <div className="hotRightMainRow" key={i}>
-                <div className="hotRightMainRow1" title="666666">
-                  {i + 1}. {v.name}
+          {1 + 1 === 2 ? (
+            <div className="hotRightMain">
+              {likeData.slice(0, 20).map((v, i) => (
+                <div className="hotRightMainRow" key={i}>
+                  <div className="hotRightMainRow1" title="666666">
+                    {i + 1}. {v.name}
+                  </div>
+                  <div className="hotRightMainRow2">{v.pcs}</div>
                 </div>
-                <div className="hotRightMainRow2">{v.pcs}</div>
-              </div>
-            ))}
-          </div>
-        ) : (
-          <div className="noneInfo">
-            <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
-          </div>
-        )}
+              ))}
+            </div>
+          ) : (
+            <div className="noneInfo">
+              <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
+            </div>
+          )}
+        </div>
       </div>
     </div>
   );

+ 19 - 1
src/pages/Log/index.module.scss

@@ -1,5 +1,23 @@
 .Log{
   :global{
-    
+    .logTop{
+      height: 100px;
+      border-radius: 10px;
+      background-color: #fff;
+      .tableSelectBox{
+        padding: 8px 24px 0;
+        display: flex;
+        align-items: center;
+        .row{
+          margin-right: 20px;
+        }
+      }
+    }
+    .tableMain{
+      border-radius: 10px;
+      margin-top: 20px;
+      height: calc(100% - 117px);
+      background-color: #fff;
+    }
   }
 }

+ 124 - 5
src/pages/Log/index.tsx

@@ -1,12 +1,131 @@
-import React from "react";
+import { RootState } from "@/store";
+import { getLogListAPI } from "@/store/action/log";
+import { Input, DatePicker, Table } from "antd";
+import React, { useEffect, useMemo, useRef, useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
+
 import styles from "./index.module.scss";
- function Log() {
-  
+
+const { RangePicker } = DatePicker;
+
+function Log() {
+  const dispatch = useDispatch();
+
+  const pageNumRef = useRef(1);
+  const pagePageRef = useRef(10);
+  // 筛选和分页
+  const [tableSelect, setTableSelect] = useState({
+    searchKey: "",
+    pageSize: 10,
+    pageNum: 1,
+    startTime: "",
+    endTime: "",
+  });
+
+  // 账号的输入
+  const nameTime = useRef(-1);
+  const nameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    clearTimeout(nameTime.current);
+    nameTime.current = window.setTimeout(() => {
+      setTableSelect({ ...tableSelect, searchKey: e.target.value, pageNum: 1 });
+    }, 500);
+  };
+  // 时间选择器改变
+  const timeChange = (date: any, dateString: any) => {
+    let startTime = "";
+    let endTime = "";
+    if (dateString[0] && dateString[1]) {
+      startTime = dateString[0] + " 00:00:00";
+      endTime = dateString[1] + " 23:59:59";
+    }
+    setTableSelect({ ...tableSelect, startTime, endTime, pageNum: 1 });
+  };
+
+  useEffect(() => {
+    pageNumRef.current = tableSelect.pageNum;
+    pagePageRef.current = tableSelect.pageSize;
+    dispatch(getLogListAPI(tableSelect));
+  }, [dispatch, tableSelect]);
+
+  // ---------关于表格
+
+  // 页码变化
+  const paginationChange = (pageNum: number, pageSize: number) => {
+    pageNumRef.current = pageNum;
+    pagePageRef.current = pageSize;
+    setTableSelect({ ...tableSelect, pageNum, pageSize });
+  };
+
+  const results = useSelector((state: RootState) => state.logReducer.tableInfo);
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "序号",
+        render: (text: any, record: any, index: any) =>
+          index + 1 + (pageNumRef.current - 1) * pagePageRef.current,
+      },
+      {
+        title: "操作者",
+        dataIndex: "userName",
+      },
+      {
+        title: "操作日期",
+        dataIndex: "createTime",
+      },
+      {
+        title: "IP记录",
+        dataIndex: "ip",
+      },
+      {
+        title: "操作记录",
+        dataIndex: "type",
+      },
+    ];
+  }, []);
+
   return (
     <div className={styles.Log}>
-      <h1>Log</h1>
+      <div className="logTop">
+        <div className="pageTitlt">操作日志</div>
+        <div className="tableSelectBox">
+          <div className="row">
+            <span>账号:</span>
+            <Input
+              maxLength={10}
+              style={{ width: 150 }}
+              placeholder="请输入"
+              allowClear
+              onChange={(e) => nameChange(e)}
+            />
+          </div>
+          <div className="row">
+            <span>操作日期:</span>
+            <RangePicker onChange={timeChange} />
+          </div>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="tableMain">
+        <Table
+          scroll={{ y: 570 }}
+          dataSource={results.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: tableSelect.pageNum,
+            pageSize: tableSelect.pageSize,
+            total: results.total,
+            onChange: paginationChange,
+          }}
+        />
+      </div>
     </div>
-  )
+  );
 }
 
 const MemoLog = React.memo(Log);

+ 13 - 0
src/pages/User/UserAdd/index.css

@@ -0,0 +1,13 @@
+.userAdd .ant-modal-close {
+  display: none;
+}
+.userAdd .userAddMain {
+  border-top: 1px solid #999999;
+  padding-top: 15px;
+  width: 100%;
+}
+.userAdd .userAddMain .passTit {
+  color: #ff4d4f;
+  font-size: 14px;
+  padding-left: 98px;
+}

+ 17 - 0
src/pages/User/UserAdd/index.less

@@ -0,0 +1,17 @@
+.userAdd {
+  .ant-modal-close {
+    display: none;
+  }
+
+  .userAddMain {
+    border-top: 1px solid #999999;
+    padding-top: 15px;
+    width: 100%;
+
+    .passTit {
+      color: #ff4d4f;
+      font-size: 14px;
+      padding-left: 98px;
+    }
+  }
+}

+ 130 - 0
src/pages/User/UserAdd/index.tsx

@@ -0,0 +1,130 @@
+import { Button, Form, Input, Modal, Popconfirm, Select } from "antd";
+import React, { useCallback, useEffect, useRef } from "react";
+import "./index.css";
+
+type Props = {
+  id: any;
+  closePage: () => void;
+  upTableList: () => void;
+  addTableList: () => void;
+};
+
+function UserAdd({ id, closePage, upTableList, addTableList }: Props) {
+  // 设置表单初始数据(区分编辑和新增)
+  const FormBoxRef = useRef<any>({});
+
+  const getInfoInAPIFu = useCallback(async (id: number) => {
+    console.log("是编辑,在这里发请求拿数据");
+  }, []);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    // return message.warning("有表单不符号规则!");
+  }, []);
+
+  useEffect(() => {
+    if (id) getInfoInAPIFu(id);
+    else {
+      FormBoxRef.current.setFieldsValue({});
+    }
+  }, [getInfoInAPIFu, id]);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(async (values: any) => {
+    // if (res.code === 0) {
+    //   message.success(id ? "编辑成功!" : "新增成功!");
+    //   if (id) upTableList();
+    //   else addTableList();
+
+    //   closePage();
+    // }
+    console.log("通过校验,点击确定");
+  }, []);
+
+  return (
+    <Modal
+      wrapClassName="userAdd"
+      destroyOnClose
+      open={true}
+      title={id ? "编辑" : "新增"}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="userAddMain">
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 5 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="账号名"
+            name="userName"
+            rules={[{ required: true, message: "请输入账号名!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={15} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="用户昵称"
+            name="nickName"
+            rules={[{ required: true, message: "请输入用户昵称!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={8} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="用户角色"
+            name="roleId"
+            rules={[{ required: true, message: "请选择角色!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              options={[
+                { label: 0, value: "1xx" },
+                { label: 1, value: "2xx" },
+              ]}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="真实姓名"
+            name="realName"
+            rules={[{ required: true, message: "请输入真实姓名!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={8} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <div className="passTit">* 默认密码 123456</div>
+
+          {/* 确定和取消按钮 */}
+          <br />
+          <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={closePage}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </Form.Item>
+        </Form>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoUserAdd = React.memo(UserAdd);
+
+export default MemoUserAdd;

+ 29 - 3
src/pages/User/index.module.scss

@@ -1,5 +1,31 @@
-.User{
-  :global{
-    
+.User {
+  :global {
+    .userTop {
+      height: 100px;
+      border-radius: 10px;
+      background-color: #fff;
+
+      .selectBox {
+        padding: 4px 24px 5px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .row {
+          margin-right: 20px;
+        }
+
+        .selectBoxL {
+          display: flex;
+          align-items: center;
+        }
+      }
+    }
+    .tableBox{
+      margin-top: 15px;
+      height: calc(100% - 110px);
+      background-color: #fff;
+      border-radius: 10px;
+    }
   }
 }

+ 350 - 5
src/pages/User/index.tsx

@@ -1,12 +1,357 @@
-import React from "react";
+import { RootState } from "@/store";
+import {
+  getUserListAPI,
+  userDisplayAPI,
+  userPassResetAPI,
+  userRemoveAPI,
+} from "@/store/action/user";
+import { UserTableAPIType, UserTableListType } from "@/types";
+import {
+  Input,
+  DatePicker,
+  Button,
+  Table,
+  Switch,
+  Popconfirm,
+  message,
+} from "antd";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import { useDispatch, useSelector } from "react-redux";
 import styles from "./index.module.scss";
- function User() {
-  
+import UserAdd from "./UserAdd";
+const { RangePicker } = DatePicker;
+
+function User() {
+  const dispatch = useDispatch();
+
+  const pageNumRef = useRef(1);
+  const pagePageRef = useRef(10);
+
+  // 顶部筛选
+  const [tableSelect, setTableSelect] = useState<UserTableAPIType>({
+    startTime: "",
+    endTime: "",
+    nickName: "",
+    pageNum: 1,
+    pageSize: 10,
+    realName: "",
+    searchKey: "",
+  });
+
+  // 封装发送请求的函数
+
+  const getList = useCallback(async () => {
+    const data = {
+      ...tableSelect,
+      pageNum: pageNumRef.current,
+    };
+    dispatch(getUserListAPI(data));
+  }, [dispatch, tableSelect]);
+
+  // 当前页码统一
+  useEffect(() => {
+    pageNumRef.current = tableSelect.pageNum;
+    pagePageRef.current = tableSelect.pageSize;
+  }, [tableSelect.pageNum, tableSelect.pageSize]);
+
+  // 防止发送了2次请求来对应页码
+
+  const getListRef = useRef(-1);
+
+  useEffect(() => {
+    clearTimeout(getListRef.current);
+    getListRef.current = window.setTimeout(() => {
+      getList();
+    }, 100);
+  }, [getList, tableSelect]);
+
+  // 用户昵称的输入
+  const nameTime = useRef(-1);
+  const nameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(nameTime.current);
+      nameTime.current = window.setTimeout(() => {
+        setTableSelect({
+          ...tableSelect,
+          nickName: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [tableSelect]
+  );
+
+  // 真实姓名的输入
+  const realNameTime = useRef(-1);
+  const realNameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(realNameTime.current);
+      realNameTime.current = window.setTimeout(() => {
+        setTableSelect({
+          ...tableSelect,
+          realName: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [tableSelect]
+  );
+
+  // 时间选择器改变
+  const timeChange = (date: any, dateString: any) => {
+    let startTime = "";
+    let endTime = "";
+    if (dateString[0] && dateString[1]) {
+      startTime = dateString[0] + " 00:00:00";
+      endTime = dateString[1] + " 23:59:59";
+    }
+    setTableSelect({ ...tableSelect, startTime, endTime, pageNum: 1 });
+  };
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1);
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now());
+    setTableSelect({
+      startTime: "",
+      endTime: "",
+      nickName: "",
+      pageNum: 1,
+      pageSize: 10,
+      realName: "",
+      searchKey: "",
+    });
+  }, []);
+
+  // 从仓库中获取表格数据
+  const tableInfo = useSelector(
+    (state: RootState) => state.userReducer.tableInfo
+  );
+
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      pageNumRef.current = pageNum;
+      pagePageRef.current = pageSize;
+      setTableSelect({ ...tableSelect, pageNum, pageSize });
+    },
+    [tableSelect]
+  );
+
+  // 切换表格中的启用停用状态
+  const isEnabledClickFu = useCallback(
+    async (val: boolean, id: number) => {
+      const isDisable = val ? 1 : 0;
+      const res: any = await userDisplayAPI(id, isDisable);
+      if (res.code === 0) getList();
+    },
+    [getList]
+  );
+
+  // 点击删除
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res: any = await userRemoveAPI(id);
+      if (res.code === 0) {
+        message.success("删除成功!");
+        getList();
+      }
+    },
+    [getList]
+  );
+
+  // 点击重置密码
+  const resetPassFu = useCallback(async (id: number) => {
+    const res: any = await userPassResetAPI(id);
+    if (res.code === 0) message.success("重置成功!");
+  }, []);
+
+  // 0------------点击新增或者编辑出来的页面
+  const [editPageShow, setEditPageShow] = useState(false);
+  const editId = useRef(0);
+
+  const openEditPageFu = useCallback(
+    (id: number) => {
+      if (id === 0 && tableInfo.list.length >= 30)
+        return message.warning("最多支持30个用户!");
+
+      editId.current = id;
+      setEditPageShow(true);
+    },
+    [tableInfo.list.length]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      // {
+      //   width: 80,
+      //   title: "序号",
+      //   render: (text: any, record: any, index: any) =>
+      //     index + 1 + (pageNumRef.current - 1) * pagePageRef.current,
+      // },
+      {
+        title: "账号名",
+        dataIndex: "userName",
+      },
+      {
+        title: "用户昵称",
+        dataIndex: "nickName",
+      },
+      {
+        title: "用户角色",
+        dataIndex: "dictTexture",
+      },
+      {
+        title: "真实姓名",
+        dataIndex: "realName",
+      },
+      {
+        title: "注册时间",
+        dataIndex: "createTime",
+      },
+
+      {
+        title: "启用状态",
+        render: (item: UserTableListType) => {
+          return item.isAdmin === 1 ? (
+            "-"
+          ) : (
+            <Switch
+              checkedChildren="启用"
+              unCheckedChildren="停用"
+              checked={item.isEnabled === 1}
+              onChange={(val) => isEnabledClickFu(val, item.id!)}
+            />
+          );
+        },
+      },
+
+      {
+        title: "操作",
+        render: (item: UserTableListType) => {
+          return item.isAdmin === 1 ? (
+            "-"
+          ) : (
+            <>
+              <Popconfirm
+                title="密码重制后为123456,是否重置?"
+                okText="重置"
+                cancelText="取消"
+                onConfirm={() => resetPassFu(item.id!)}
+              >
+                <Button
+                  size="small"
+                  type="text"
+                  onClick={() => openEditPageFu(item.id!)}
+                >
+                  重置密码
+                </Button>
+              </Popconfirm>
+
+              <Button
+                size="small"
+                type="text"
+                onClick={() => openEditPageFu(item.id!)}
+              >
+                编辑
+              </Button>
+              <Popconfirm
+                title="删除后无法恢复,是否删除?"
+                okText="删除"
+                cancelText="取消"
+                onConfirm={() => delTableFu(item.id!)}
+              >
+                <Button size="small" type="text" danger>
+                  删除
+                </Button>
+              </Popconfirm>
+            </>
+          );
+        },
+      },
+    ];
+  }, [delTableFu, isEnabledClickFu, openEditPageFu, resetPassFu]);
+
   return (
     <div className={styles.User}>
-      <h1>User</h1>
+      <div className="userTop">
+        <div className="pageTitlt">用户管理</div>
+        <div className="selectBox">
+          <div className="selectBoxL">
+            <div className="row">
+              <span>用户昵称:</span>
+              <Input
+                key={inputKey}
+                maxLength={8}
+                style={{ width: 150 }}
+                placeholder="请输入"
+                allowClear
+                onChange={(e) => nameChange(e)}
+              />
+            </div>
+
+            <div className="row">
+              <span>真实姓名:</span>
+              <Input
+                key={inputKey}
+                maxLength={8}
+                style={{ width: 150 }}
+                placeholder="请输入"
+                allowClear
+                onChange={(e) => realNameChange(e)}
+              />
+            </div>
+
+            <div className="row">
+              <span>注册日期:</span>
+              <RangePicker key={inputKey} onChange={timeChange} />
+            </div>
+          </div>
+          <div className="selectBoxR">
+            <Button onClick={resetSelectFu}>重置</Button>&emsp;&emsp;
+            <Button type="primary" onClick={() => openEditPageFu(0)}>
+              新增
+            </Button>
+          </div>
+        </div>
+      </div>
+      {/* 表格主体 */}
+      <div className="tableBox">
+        <Table
+          scroll={{ y: 575 }}
+          dataSource={tableInfo.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            // showSizeChanger: true,
+            current: tableSelect.pageNum,
+            pageSize: tableSelect.pageSize,
+            total: tableInfo.total,
+            onChange: paginationChange(),
+          }}
+        />
+      </div>
+
+      {/* 点击新增或者编辑 */}
+      {editPageShow ? (
+        <UserAdd
+          id={editId.current}
+          closePage={() => setEditPageShow(false)}
+          upTableList={getList}
+          addTableList={resetSelectFu}
+        />
+      ) : null}
     </div>
-  )
+  );
 }
 
 const MemoUser = React.memo(User);

+ 12 - 6
src/pages/Wall/WallTable/index.tsx

@@ -61,18 +61,24 @@ function WallTable() {
     [dispatch]
   );
 
+  // 从仓库中获取列表数据
+  const results = useSelector((state: RootState) => state.wallReducer.list);
+
   // 点击新增或者编辑
   const [open, setOpen] = useState(false);
 
   const editId = useRef(0);
 
-  const editTableFu = useCallback((id: number) => {
-    editId.current = id;
-    setOpen(true);
-  }, []);
+  const editTableFu = useCallback(
+    (id: number) => {
+      if (id === 0 && results.length >= 20)
+        return message.warning("最多支持上传20个内容!");
 
-  // 从仓库中获取列表数据
-  const results = useSelector((state: RootState) => state.wallReducer.list);
+      editId.current = id;
+      setOpen(true);
+    },
+    [results.length]
+  );
 
   const columns = useMemo(() => {
     return [

+ 15 - 0
src/store/action/log.ts

@@ -0,0 +1,15 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取用户管理表格列表
+ */
+export const getLogListAPI = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("sys/log/list", data);
+    const obj = {
+      list: res.data.records,
+      total: res.data.total,
+    };
+    dispatch({ type: "log/getList", payload: obj });
+  };
+};

+ 38 - 0
src/store/action/user.ts

@@ -0,0 +1,38 @@
+import { UserTableAPIType } from "@/types";
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取用户管理表格列表
+ */
+export const getUserListAPI = (data: UserTableAPIType) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("sys/user/list", data);
+    const obj = {
+      list: res.data.records,
+      total: res.data.total,
+    };
+
+    dispatch({ type: "user/getList", payload: obj });
+  };
+};
+
+/**
+ * 用户-是否显示
+ */
+export const userDisplayAPI = (id: number, display: number) => {
+  return http.get(`sys/user/editStatus/${id}/${display}`);
+};
+
+/**
+ * 删除用户
+ */
+export const userRemoveAPI = (id: number) => {
+  return http.get(`sys/user/removes/${id}`);
+};
+
+/**
+ * 重置密码
+ */
+export const userPassResetAPI = (id: number) => {
+  return http.get(`sys/user/resetPass/${id}`);
+};

+ 5 - 1
src/store/reducer/index.ts

@@ -1,16 +1,20 @@
 // 导入合并reducer的依赖
 import { combineReducers } from 'redux'
 import goodsReducer from './goods'
+import logReducer from './log'
 
 // 导入 登录 模块的 reducer
 import loginReducer from './login'
+import userReducer from './user'
 import wallReducer from './wall'
 
 // 合并 reducer
 const rootReducer = combineReducers({
   loginStore: loginReducer,
   wallReducer:wallReducer,
-  goodsReducer:goodsReducer
+  goodsReducer:goodsReducer,
+  userReducer:userReducer,
+  logReducer:logReducer
 })
 
 // 默认导出

+ 25 - 0
src/store/reducer/log.ts

@@ -0,0 +1,25 @@
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as LogTableType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type LogActionType = {
+  type: "log/getList";
+  payload: { list: LogTableType[]; total: number };
+};
+
+// 频道 reducer
+export default function logReducer(state = initState, action: LogActionType) {
+  switch (action.type) {
+    // 获取列表数据
+    case "log/getList":
+      return { ...state, tableInfo: action.payload };
+    default:
+      return state;
+  }
+}

+ 29 - 0
src/store/reducer/user.ts

@@ -0,0 +1,29 @@
+import { UserTableListType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as UserTableListType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type UserActionType = {
+  type: "user/getList";
+  payload: { list: UserTableListType[]; total: number };
+};
+
+// 频道 reducer
+export default function userReducer(state = initState, action: UserActionType) {
+  switch (action.type) {
+    // 获取列表数据
+    case "user/getList":
+      return { ...state, tableInfo: action.payload };
+    default:
+      return state;
+  }
+}
+
+

+ 11 - 0
src/types/api/log.d.ts

@@ -0,0 +1,11 @@
+type LogTableType = {
+  createTime: string;
+  creatorId: null;
+  creatorName: string;
+  description: string;
+  id: number;
+  ip: string;
+  type: string;
+  updateTime: null;
+  userName: string;
+}

+ 27 - 0
src/types/api/user.d.ts

@@ -0,0 +1,27 @@
+export type UserTableAPIType={
+  startTime:string
+  endTime:string
+  nickName:string
+  pageNum:number
+  pageSize:number
+  realName:string
+  searchKey:string
+}
+
+export type UserTableListType={
+  createTime: string;
+  creatorId: null;
+  creatorName: string;
+  id: number;
+  isAdmin: number;
+  isEnabled: number;
+  nickName: string;
+  phone: string;
+  realName: string;
+  roleId: null;
+  roleName: string;
+  sex: string;
+  thumb: string;
+  updateTime: string;
+  userName: string;
+}

+ 3 - 1
src/types/index.d.ts

@@ -1,4 +1,6 @@
 export * from './store/login'
 export * from './api/wall'
 export * from './api/goods'
-export * from './api/hot'
+export * from './api/hot'
+export * from './api/user'
+export * from './api/log'