User操作

Tutorial: ReactTS案例 Category: React Published: 2026-04-07 13:58:26 Views: 20 Likes: 0 Comments: 0

用户操作

一、新增用户
  1. 新增组件 src\pages\user\components\AddUser.tsx
import React, { useEffect } from "react";
import { Form, Input, message, Modal } from "antd";
import { doAddUser } from "../../../api/user";

interface IProps {
  open: boolean;
  onCancel(refresh?: boolean): void;
}

function AddUser({ open, onCancel }: IProps) {
  const [form] = Form.useForm();

  useEffect(() => {
    if (open) {
      form.resetFields();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open]);

  const addUser = async (u: User) => {
    const res = await doAddUser(u);
    if (res.success) {
      message.success("添加成功");
      onCancel(true);
    } else {
      message.error(res.errorMessage);
    }
  };

  return (
    <Modal
      title="新增用户"
      open={open}
      onCancel={() => {
        onCancel();
      }}
      onOk={() => {
        form.submit();
      }}
    >
      <Form
        labelCol={{ span: 5 }}
        wrapperCol={{ span: 16 }}
        form={form}
        onFinish={addUser}
      >
        <Form.Item
          label="用户名"
          name={"username"}
          rules={[
            {
              required: true,
              type: "string",
              message: "用户名不可以为空",
            },
          ]}
        >
          <Input />
        </Form.Item>
        <Form.Item
          label="邮箱"
          name={"email"}
          rules={[
            {
              required: true,
              type: "email",
              message: "邮箱格式不合法",
            },
          ]}
        >
          <Input />
        </Form.Item>
        <Form.Item
          label="密码"
          name={"password"}
          rules={[
            {
              required: true,
              type: "string",
              min: 6,
              message: "密码至少要6位",
            },
          ]}
        >
          <Input />
        </Form.Item>
      </Form>
    </Modal>
  );
}

export default AddUser;
  1. User 引入组件
// etc...
import AddUser from "./components/AddUser";
const Index = () => {
  const [open, setOpen] = useState(false);
  // 新增用户
  const onCancel = async (status?: boolean) => {
    setOpen(false);
    if (status) {
      getListByPage();
    }
  };
  const addUserWrapper = <AddUser open={open} onCancel={onCancel} />;
  // etc...

  return (
    <div className={styles.userContainer}>
      <Button
        type="primary"
        onClick={() => {
          setOpen(true);
        }}
      >
        新增
      </Button>
      <Table
        rowKey={"id"}
        dataSource={list}
        columns={columns}
        scroll={{ x: 1500, y: 500 }}
        pagination={pagination}
        onChange={changePage}
      />
      {/* 新增用户 */}
      {addUserWrapper}
    </div>
  );
};
二、删除用户
  1. src\pages\user\components\DeleteUser.tsx
import React from "react";
import { Button, message, Popconfirm } from "antd";
import { deleteUserById } from "../../../api/user";

interface Props {
  id: number;
  onDelete(id: number): void;
}

const DeleteUser = ({ id, onDelete }: Props) => {
  const delUser = async () => {
    const res = await deleteUserById(id);
    if (res.success) {
      onDelete(id);
    } else {
      message.error(res.errorMessage);
    }
  };
  return (
    <>
      <Popconfirm title="删除用户" onConfirm={delUser}>
        <Button type="primary" danger>
          删除
        </Button>
      </Popconfirm>
    </>
  );
};

export default DeleteUser;
  1. User 引入
import DeleteUser from "./components/DeleteUser";
const Index = () => {
  // 删除用户
  const deleteUser = async (id: number) => {
    message.success(id);
    await getListByPage(); // 刷新页面
  };
  // etc...
  const columns: ColumnsType<User> = [
    // etc...
    {
      title: "操作",
      key: "operation",
      fixed: "right",
      width: 200,
      align: "center",
      render(value, record, index) {
        return (
          <Space>
            <Button type="primary">编辑</Button>
            <DeleteUser id={record.id} onDelete={deleteUser} />
          </Space>
        );
      },
    },
  ];
};
三、编辑用户
  1. src\pages\user\components\EditUser.tsx
import React, { useEffect } from "react";
import { Form, Input, message, Modal } from "antd";
import { updateUser } from "../../../api/user";

interface IProps {
  user: User;
  open: boolean;
  onCancel(refresh?: boolean): void;
}

export default function EditUser({ user, open, onCancel }: IProps) {
  const [form] = Form.useForm();

  useEffect(() => {
    if (open) {
      form.resetFields();
    }
  }, [open]);

  const saveUser = async (u: User) => {
    const res = await updateUser(user.id, u);
    if (res.success) {
      message.success("更新成功");
      onCancel(true);
    } else {
      message.error(res.errorMessage);
    }
  };

  return (
    <Modal
      title="编辑用户"
      open={open}
      onCancel={() => {
        onCancel();
      }}
      onOk={() => {
        form.submit();
      }}
    >
      <Form
        labelCol={{ span: 5 }}
        wrapperCol={{ span: 16 }}
        form={form}
        initialValues={{
          ...user,
          password: "",
        }}
        onFinish={saveUser}
      >
        <Form.Item label="id" name={"id"} hidden>
          <Input />
        </Form.Item>
        <Form.Item label="用户名" name={"username"}>
          <Input />
        </Form.Item>
        <Form.Item label="邮箱" name={"email"}>
          <Input />
        </Form.Item>
        <Form.Item label="密码" name={"password"}>
          <Input />
        </Form.Item>
      </Form>
    </Modal>
  );
}
  1. User 页面
import EditUser from "./components/EditUser";
const Index = () => {
  const [currentUser, setCurrentUser] = useState<User>({} as User);
  const [editWrapper, setEditWrapper] = useState(false);
  // 编辑用户
  const cancelEditUser = async (status?: boolean) => {
    setEditWrapper(false);
    if (status) {
      getListByPage();
    }
  };

  const editUserWrapper = (
    <EditUser user={currentUser} open={editWrapper} onCancel={cancelEditUser} />
  );

  const columns: ColumnsType<User> = [
    {
      title: "操作",
      key: "operation",
      fixed: "right",
      width: 200,
      align: "center",
      render(value, record, index) {
        return (
          <Space>
            <Button
              type="primary"
              onClick={() => {
                setCurrentUser(record);
                setEditWrapper(true);
              }}
            >
              编辑
            </Button>
            <DeleteUser id={record.id} onDelete={deleteUser} />
          </Space>
        );
      },
    },
  ];

  return (
    <div className={styles.userContainer}>
      {/* 新增用户 */}
      {addUserWrapper}
      {/* 编辑用户 */}
      {editUserWrapper}
    </div>
  );
};
  1. 完成的 User 页面
import React, { useRef, useState, useEffect } from "react";
import { Table, Button, Space, Input, message } from "antd";
import type { InputRef } from "antd";
import { SearchOutlined, SyncOutlined } from "@ant-design/icons";
import type {
  ColumnsType,
  ColumnType,
  TablePaginationConfig,
} from "antd/es/table";
import type { FilterConfirmProps } from "antd/es/table/interface";
import Highlighter from "react-highlight-words";

import AddUser from "./components/AddUser";
import DeleteUser from "./components/DeleteUser";
import EditUser from "./components/EditUser";

// API
import { getUserList } from "../../api/user";
// 样式
import styles from "./user.module.scss";

type DataIndex = keyof User;

const Index = () => {
  const [searchText, setSearchText] = useState("");
  const [searchedColumn, setSearchedColumn] = useState("");
  const searchInput = useRef<InputRef>(null);
  const [list, setList] = useState<User[]>([]);
  const [pagination, setPagination] = useState<TablePaginationConfig>({
    position: ["bottomCenter"],
    showSizeChanger: true,
  });
  const [open, setOpen] = useState(false);
  const [currentUser, setCurrentUser] = useState<User>({} as User);
  const [editWrapper, setEditWrapper] = useState(false);

  useEffect(() => {
    getListByPage();
  }, []);

  // 获取用户
  const getListByPage = async (current: number = 1) => {
    const res = await getUserList(current);
    setList(res.data.list);
    setPagination({
      ...pagination,
      ...res.data,
    });
  };

  // 新增用户
  const onCancel = async (status?: boolean) => {
    setOpen(false);
    if (status) {
      getListByPage();
    }
  };

  const addUserWrapper = <AddUser open={open} onCancel={onCancel} />;

  // 删除用户
  const deleteUser = async (id: number) => {
    message.success(id);
    await getListByPage(); // 刷新页面
  };

  // 编辑用户
  const cancelEditUser = async (status?: boolean) => {
    setEditWrapper(false);
    if (status) {
      getListByPage();
    }
  };

  const editUserWrapper = (
    <EditUser user={currentUser} open={editWrapper} onCancel={cancelEditUser} />
  );

  const changePage = (p: TablePaginationConfig) => {
    console.log(p.current);
    getListByPage(p.current);
  };

  const handleSearch = (
    selectedKeys: string[],
    confirm: (param?: FilterConfirmProps) => void,
    dataIndex: DataIndex
  ) => {
    confirm();
    setSearchText(selectedKeys[0]);
    setSearchedColumn(dataIndex);
  };

  const handleReset = (clearFilters: () => void) => {
    clearFilters();
    setSearchText("");
  };

  const getColumnSearchProps = (dataIndex: DataIndex): ColumnType<User> => ({
    filterDropdown: ({
      setSelectedKeys,
      selectedKeys,
      confirm,
      clearFilters,
      close,
    }) => (
      <div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
        <Input
          ref={searchInput}
          placeholder={`Search ${dataIndex}`}
          value={selectedKeys[0]}
          onChange={(e) =>
            setSelectedKeys(e.target.value ? [e.target.value] : [])
          }
          onPressEnter={() =>
            handleSearch(selectedKeys as string[], confirm, dataIndex)
          }
          style={{ marginBottom: 8, display: "block" }}
        />
        <Space>
          <Button
            type="primary"
            size="small"
            onClick={() =>
              handleSearch(selectedKeys as string[], confirm, dataIndex)
            }
            icon={<SearchOutlined />}
          >
            搜索
          </Button>
          <Button
            type="primary"
            size="small"
            onClick={() => {
              clearFilters && handleReset(clearFilters);
              confirm({ closeDropdown: true });
              close();
            }}
            icon={<SyncOutlined />}
          >
            还原
          </Button>
        </Space>
      </div>
    ),
    filterIcon: (filtered: boolean) => (
      <SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
    ),
    onFilter: (value, record) =>
      record[dataIndex]
        .toString()
        .toLowerCase()
        .includes((value as string).toLowerCase()),
    onFilterDropdownOpenChange: (visible) => {
      if (visible) {
        setTimeout(() => searchInput.current?.select(), 100);
      }
    },
    render: (text) =>
      searchedColumn === dataIndex ? (
        <Highlighter
          highlightStyle={{ backgroundColor: "#ffc069", padding: 0 }}
          searchWords={[searchText]}
          autoEscape
          textToHighlight={text ? text.toString() : ""}
        />
      ) : (
        text
      ),
  });

  const columns: ColumnsType<User> = [
    {
      title: "ID",
      width: 100,
      dataIndex: "id",
      key: "id",
      align: "center",
      fixed: "left",
    },
    {
      title: "姓名",
      dataIndex: "username",
      key: "username",
      ...getColumnSearchProps("username"),
    },
    {
      title: "email",
      dataIndex: "email",
      key: "email",
    },
    {
      title: "操作",
      key: "operation",
      fixed: "right",
      width: 200,
      align: "center",
      render(value, record, index) {
        return (
          <Space>
            <Button
              type="primary"
              onClick={() => {
                console.log(1111111, record);
                setCurrentUser(record);
                setEditWrapper(true);
              }}
            >
              编辑
            </Button>
            <DeleteUser id={record.id} onDelete={deleteUser} />
          </Space>
        );
      },
    },
  ];

  return (
    <div className={styles.userContainer}>
      <Button
        type="primary"
        onClick={() => {
          setOpen(true);
        }}
      >
        新增
      </Button>
      <Table
        rowKey={"id"}
        dataSource={list}
        columns={columns}
        scroll={{ x: 1500, y: 500 }}
        pagination={pagination}
        onChange={changePage}
      />
      {/* 新增用户 */}
      {addUserWrapper}
      {/* 编辑用户 */}
      {editUserWrapper}
    </div>
  );
};

export default Index;