joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::

列表代码

import React, { useState, useMemo } from "react";
import { Space, Table, Tag, Form, Input, Button, Pagination } from "antd";
import type { TableProps, FormProps } from "antd";
import EditModal from "./components/EditModal";

interface DataType {
  key: string;
  name: string;
  age: number;
  address: string;
  tags: string[];
}

// 扩展 data 数据
const generateData = (): DataType[] => {
  const names = [
    "John Brown",
    "Jim Green",
    "Joe Black",
    "Alice Smith",
    "Bob Johnson",
    "Eva Williams",
  ];
  const addresses = [
    "New York No. 1 Lake Park",
    "London No. 1 Lake Park",
    "Sydney No. 1 Lake Park",
    "Tokyo No. 1 Lake Park",
    "Paris No. 1 Lake Park",
    "Berlin No. 1 Lake Park",
  ];
  const tagsList = [
    ["nice", "developer"],
    ["loser"],
    ["cool", "teacher"],
    ["coder"],
    ["designer"],
    ["manager"],
  ];

  const result: DataType[] = [];
  for (let i = 1; i <= 50; i++) {
    const name = names[i % names.length];
    const address = addresses[i % addresses.length];
    const tags = tagsList[i % tagsList.length];
    result.push({
      key: `${i}`,
      name,
      age: 25 + (i % 20),
      address,
      tags,
    });
  }
  return result;
};

const data: DataType[] = generateData();

// 新增 SearchForm 组件
interface SearchFormProps {
  onFinish: FormProps["onFinish"];
  onReset: () => void;
}

const SearchForm: React.FC<SearchFormProps> = ({ onFinish, onReset }) => {
  const [form] = Form.useForm();

  return (
    <Form
      form={form}
      name="search"
      layout="inline"
      onFinish={onFinish}
      style={{ marginBottom: 16 }}
    >
      <Form.Item label="Name" name="name">
        <Input placeholder="Search by name" />
      </Form.Item>

      <Form.Item label="Tag" name="tag">
        <Input placeholder="Search by tag" />
      </Form.Item>

      <Form.Item>
        <Button type="primary" htmlType="submit">
          Search
        </Button>
      </Form.Item>

      <Form.Item>
        <Button htmlType="button" onClick={onReset}>
          Reset
        </Button>
      </Form.Item>
    </Form>
  );
};

const App: React.FC = () => {
  const [filteredData, setFilteredData] = useState<DataType[]>(data);
  const [searchParams, setSearchParams] = useState({
    name: "",
    tag: "",
  });
  const [currentPage, setCurrentPage] = useState(1);
  const pageSize = 10;
  const [editingItem, setEditingItem] = useState<DataType | null>(null);
  const [isModalVisible, setIsModalVisible] = useState(false);

  const handleAdd = () => {
    setIsModalVisible(true);
    setEditingItem({
      key: `${filteredData.length + 1}`,
      name: "",
      age: 20,
      address: "New Address",
      tags: ["new"],
    });
  };

  const handleEdit = (record: DataType) => {
    setEditingItem(record);
    setIsModalVisible(true);
  };

  const handleModalOk = (values: {
    name: string;
    age: number;
    address: string;
    tags: string[];
  }) => {
    if (editingItem) {
      setFilteredData((prev) =>
        prev.map((item) =>
          item.key === editingItem.key ? { ...item, ...values } : item
        )
      );
    }
  };

  const handleModalCancel = () => {
    setIsModalVisible(false);
    setEditingItem(null);
  };

  const handleFinish = (values: any) => {
    setSearchParams(values);

    const filtered = data.filter((item) => {
      return (
        (!values.name ||
          item.name.toLowerCase().includes(values.name.toLowerCase())) &&
        (!values.tag ||
          item.tags.some((t) =>
            t.toLowerCase().includes(values.tag.toLowerCase())
          ))
      );
    });

    setFilteredData(filtered);
    setCurrentPage(1); // 重置为第一页
  };

  const handleReset = () => {
    setSearchParams({
      name: "",
      tag: "",
    });
    setFilteredData(data);
    setCurrentPage(1);
  };

  const handleDelete = (key: string) => {
    if (window.confirm("确定要删除该条目吗?")) {
      setFilteredData((prev) => prev.filter((item) => item.key !== key));
    }
  };

  // 分页数据切片
  const paginatedData = useMemo(() => {
    return filteredData.slice(
      (currentPage - 1) * pageSize,
      currentPage * pageSize
    );
  }, [filteredData, currentPage, pageSize]);

  const columns = [
    {
      title: "Name",
      dataIndex: "name",
      key: "name",
      render: (text: string) => <a>{text}</a>,
    },
    {
      title: "Age",
      dataIndex: "age",
      key: "age",
    },
    {
      title: "Address",
      dataIndex: "address",
      key: "address",
    },
    {
      title: "Tags",
      key: "tags",
      dataIndex: "tags",
      render: (_: any, { tags }: { tags: string[] }) => (
        <>
          {tags.map((tag) => {
            let color = tag.length > 5 ? "geekblue" : "green";
            if (tag === "loser") {
              color = "volcano";
            }
            return (
              <Tag color={color} key={tag}>
                {tag.toUpperCase()}
              </Tag>
            );
          })}
        </>
      ),
    },
    {
      title: "Action",
      key: "action",
      render: (_, record: DataType) => (
        <Space size="middle">
          <Button type="link" onClick={() => handleEdit(record)}>
            Edit
          </Button>
          <Button type="link" danger onClick={() => handleDelete(record.key)}>
            Delete
          </Button>
        </Space>
      ),
    },
  ];

  return (
    <div style={{ padding: 24 }}>
      <SearchForm onFinish={handleFinish} onReset={handleReset} />
      <div style={{ marginBottom: 16 }}>
        <Button type="primary" onClick={handleAdd}>
          新增
        </Button>
      </div>
      <Table<DataType>
        columns={columns}
        dataSource={paginatedData}
        pagination={false}
      />
      <EditModal
        visible={isModalVisible}
        onCancel={handleModalCancel}
        onOk={handleModalOk}
        initialValues={editingItem || undefined}
      />
      <Pagination
        current={currentPage}
        pageSize={pageSize}
        total={filteredData.length}
        onChange={(page) => setCurrentPage(page)}
        style={{ marginTop: 16, textAlign: "right" }}
      />
    </div>
  );
};

export default App;

弹窗代码

import React, { useEffect, useState } from "react";
import { Modal, Form, Input, Select, Tag } from "antd";

interface EditModalProps {
  visible: boolean;
  onCancel: () => void;
  onOk: (values: {
    name: string;
    age: number;
    address: string;
    tags: string[];
  }) => void;
  initialValues?: {
    name: string;
    age: number;
    address: string;
    tags: string[];
  };
}

const { Option } = Select;

const EditModal: React.FC<EditModalProps> = ({
  visible,
  onCancel,
  onOk,
  initialValues,
}) => {
  const [form] = Form.useForm();

  // 新增 useEffect 强制更新表单字段
  useEffect(() => {
    if (visible && initialValues) {
      form.setFieldsValue(initialValues);
    }
  }, [initialValues, visible, form]);

  const handleOk = () => {
    form.validateFields().then((values) => {
      onOk(values);
      form.resetFields();
    });
  };

  useEffect(() => {
    console.log(initialValues, "initialValues");
  }, [visible]);

  return (
    <Modal
      title="编辑数据"
      visible={visible}
      onCancel={() => {
        form.resetFields();
        onCancel();
      }}
      onOk={handleOk}
    >
      <Form form={form} layout="vertical" initialValues={initialValues}>
        <Form.Item label="Name" name="name" rules={[{ required: true }]}>
          <Input />
        </Form.Item>

        <Form.Item
          label="Age"
          name="age"
          rules={[{ required: true, type: "number", min: 0 }]}
        >
          <Input type="number" />
        </Form.Item>

        <Form.Item label="Address" name="address" rules={[{ required: true }]}>
          <Input />
        </Form.Item>

        <Form.Item label="Tags" name="tags" rules={[{ required: true }]}>
          <Select mode="tags" style={{ width: "100%" }} tokenSeparators={[","]}>
            {[
              "nice",
              "developer",
              "loser",
              "cool",
              "teacher",
              "coder",
              "designer",
              "manager",
            ].map((tag) => (
              <Option key={tag} value={tag}>
                {tag}
              </Option>
            ))}
          </Select>
        </Form.Item>
      </Form>
    </Modal>
  );
};

export default EditModal;
posted on 2025-05-17 12:33  joken1310  阅读(29)  评论(0)    收藏  举报