首页 > 其他分享 >React+Ant Design实现CRUD

React+Ant Design实现CRUD

时间:2024-05-19 16:08:40浏览次数:24  
标签:function Ant const 模态 CRUD 表单 React student import

Student.ts

//学生对象
export interface Student {
    id: number,
    name: string,
    sex?: string,
    birthday?: string
}

//服务器返回的数据
export interface Result<T> {
    code: number,
    msg?: string,
    data: T
}

//分页响应
export interface PageResp<T> {
    records: T[],
    totalRow: number
}

//学生查询条件
export interface StudentQueryForm {
    name?: string,
    sex?: string
}

Table.tsx

import {Button, Input, Select, Space, Table} from 'antd'
import {ColumnsType, TablePaginationConfig} from 'antd/lib/table'
import axios from 'axios'
import React, {useEffect, useState} from 'react'
import {PageResp, Result, Student, StudentQueryForm} from '../model/Student'
import Add from './Add'
import Edit from "./Edit";
import Remove from "./Remove";
import BatchRemove from "./BatchRemove";
import styled from 'styled-components';
import {Row, Col} from 'antd'; //引入栅格系统

//创建一个样式化的div组件,设置外边距为20px
const StyledDiv = styled.div`margin: 20px`
//从Select组件中解构出Option组件,用于后续的使用
const {Option} = Select

//学生表格页面的主组件,使用Ant Design的Table组件来展示学生信息,并提供了筛选、分页、新增、编辑和删除等功能
export default function StudentTable() {
    //使用React的useState钩子来定义和初始化state
    //学生列表,初始状态为空数组
    const [students, setStudents] = useState<Student[]>([])
    //加载状态,初始值为true,表示开始加载
    const [loading, setLoading] = useState(true)
    //分页信息
    const [pagination, setPagination] = useState<TablePaginationConfig>({
        current: 1, //当前页码
        pageSize: 5, //每页显示条数
        showSizeChanger: true, //是否显示页码选择器
        pageSizeOptions: ['5', '10', '15', '20'] //设置每页显示数量选项
    })
    //查询表单数据
    const [form, setForm] = useState<StudentQueryForm>({})

    //处理分页变化事件,用于更新分页信息
    function onTableChange(newPagination: TablePaginationConfig) {
        setPagination(newPagination)
    }

    //处理姓名查询条件变化事件,用于查询表单数据
    function onNameChange(e: React.ChangeEvent<HTMLInputElement>) {
        setForm((old) => {
            return {...old, name: e.target.value} //通过e.target.value获得输入框的当前值
        })
    }

    //处理性别查询条件变化事件,用于查询表单数据
    function onSexChange(value: string) {
        setForm((old) => {
            return {...old, sex: value}
        })
    }

    //使用useEffect钩子来监听分页信息和查询表单信息的变化,并重新获取学生数据
    useEffect(() => {
        async function getStudents() {
            const resp = await axios.get<Result<PageResp<Student>>>(
                'http://localhost:8080/api/student/findByPage',
                {
                    params: {
                        pageNum: pagination.current, //当前页码
                        pageSize: pagination.pageSize, //每页显示条数
                        ...form //表单提交的数据
                    }
                }
            )
            //返回结果中:records 代表当前页集合, totalRow 代表总记录数
            setStudents(resp.data.data.records)
            setPagination((old) => {
                return {...old, total: resp.data.data.totalRow}
            })
            setLoading(false)
        }
        getStudents() //重新获取学生数据
    }, [pagination.pageSize, form, pagination]) //监听分页和表单数据的变化以重新获取数据

    //定义学生表格的列信息,包括列标题、要关联的属性名和操作按钮的渲染函数
    const columns: ColumnsType<Student> = [
        {
            title: '编号',
            dataIndex: 'id'
        },
        {
            title: '姓名',
            dataIndex: 'name'
        },
        {
            title: '性别',
            dataIndex: 'sex'
        },
        {
            title: '生日',
            dataIndex: 'birthday'
        },
        {
            title: '操作',
            dataIndex: 'operation',
            render: (_, student) => {
                //渲染操作按钮
                return (
                    <Space>
                        <Button type='default' size='small' onClick={() => {
                            onUpdateClick(student)
                        }}>修改</Button>
                        <Remove id={student.id} onSuccess={onDeleteSuccess}></Remove>
                    </Space>
                )
            }
        }
    ]

    //新增功能的相关逻辑,包括打开新增模态框、取消新增、确认新增成功和更新表单数据
    //点击新增按钮时触发的函数,用于打开新增模态框
    function onInsertClick() {
        setInsertOpen(true)
    }
    //在新增模态框取消操作时触发的函数,用于关闭新增模态框
    function onInsertCancel() {
        setInsertOpen(false)
    }
    //在新增成功操作时触发的函数,用于关闭新增模态框并重置表单数据
    function onInsertSuccess() {
        setInsertOpen(false)
        setForm((old) => {
            return {...old}
        })
    }
    //使用useState管理新增模态框的显示状态和新增表单数据
    const [insertOpen, setInsertOpen] = useState(false)
    //初始化新增表单的信息,默认为空学生对象
    const [insertForm] = useState<Student>({
        id: 0,
        name: '',
        sex: '',
        birthday: '',
    })

    //修改功能的相关逻辑,包括打开修改模态框、取消修改、确认修改成功和更新表单数据
    //点击修改按钮时触发的函数
    function onUpdateClick(student: Student) {
        setUpdateOpen(true) //打开修改模态框
        setUpdateForm(student) //设置更新表单的数据
    }
    //在修改模态框取消操作时触发的函数,用于关闭修改模态框
    function onUpdateCancel() {
        setUpdateOpen(false)
    }
    //修改成功时触发的函数,用于关闭修改模态框并重置表单数据
    function onUpdateSuccess() {
        setUpdateOpen(false)
        setForm((old) => {
            return {...old}
        })
    }
    //使用useState初始化修改模态框的显示状态和修改表单的数据
    const [updateOpen, setUpdateOpen] = useState(false)
    const [updateForm, setUpdateForm] = useState<Student>({
        id: 0,
        name: '',
        sex: '',
        birthday: ''
    })

    //删除操作成功后的回调函数,用于更新表单数据
    function onDeleteSuccess() {
        //使用setForm函数更新表单状态,保持表单状态的不变性
        setForm((old) => {
            return {...old}
        })
    }

    //删除选中功能的相关逻辑,包括保存选中学生的 ID、更新选中学生的 ID 和确认批量删除成功
    //使用状态管理器useState初始化一个空数组,用于存储键值数组
    const [ids, setIds] = useState<React.Key[]>([])
    //当需要更新ids状态时调用此函数
    function onIdsChange(ids: React.Key[]) {
        setIds(ids)
    }
    //删除选定项成功后的回调函数,用于重置表单状态和清空ids数组
    function onDeleteSelectedSuccess() {
        //重置表单状态,保持原有状态不变
        setForm((old) => {
            return {...old}
        })
        //清空ids数组
        setIds([])
    }

    //渲染组件,包含各种 Ant Design 组件的使用和布局的处理
    return (
        <div>
            {/* 添加组件,控制添加学生操作的显示与逻辑 */}
            <Add open={insertOpen} student={insertForm} onSuccess={onInsertSuccess} onCancel={onInsertCancel}></Add>
            {/* 编辑组件,控制编辑学生操作的显示与逻辑 */}
            <Edit open={updateOpen} student={updateForm} onSuccess={onUpdateSuccess} onCancel={onUpdateCancel}></Edit>
            <div>
                <StyledDiv>
                    <Space>
                        {/* 输入框,用于输入学生姓名,变更时触发姓名变更事件 */}
                        <Input placeholder='请输入姓名' value={form.name} onChange={onNameChange}></Input>
                        {/* 下拉框,用于选择学生性别,变更时触发性别变更事件 */}
                        <Select placeholder='请选择性别' value={form.sex} onChange={onSexChange} allowClear={true}>
                            <Option value='男'>男</Option>
                            <Option value='女'>女</Option>
                        </Select>
                        {/* 新增按钮:点击触发新增学生操作 */}
                        <Button type='primary' onClick={onInsertClick}>新增</Button>
                        {/* 批量删除组件,批量删除选中学生,选中的学生通过ids传递,成功删除后触发相应事件 */}
                        <BatchRemove ids={ids} onSuccess={onDeleteSelectedSuccess}></BatchRemove>
                    </Space>
                </StyledDiv>
            </div>
            <Row gutter={16}>
                <Col span={24}>
                    {/* 学生表格,展示学生信息,支持选择与批量删除 */}
                    <Table rowSelection={{selectedRowKeys: ids, onChange: onIdsChange}}
                           columns={columns} //列定义
                           dataSource={students} //数据源,一般是数组包对象
                           rowKey='id' //作为唯一标识的属性名
                           loading={loading} //显示加载图片
                           pagination={pagination} //分页信息
                           onChange={onTableChange} //分页变化
                    ></Table>
                </Col>
            </Row>
        </div>
    )
}

Add.tsx

import {DatePicker, DatePickerProps, Form, Input, message, Modal, Radio} from 'antd'
import dayjs from "dayjs";
import {Rule} from 'antd/lib/form'
import axios from 'axios'
import {Result, Student} from '../model/Student'

//新增学生信息的模态框组件
export default function Add({open, student, onSuccess, onCancel}: {
    open: boolean //模态框是否可见
    student: Student //新增学生的初始信息
    onSuccess?: () => void //添加成功时的回调函数
    onCancel?: () => void //取消添加时的回调函数
}) {
    //引入并解构Form和Radio中的Item和Group组件
    const {Item} = Form
    const {Group} = Radio
    //定义性别选项的数组
    const options = [
        {label: '男', value: '男'},
        {label: '女', value: '女'},
    ]
    //创建表单实例
    const [form] = Form.useForm()
    //定义姓名字段的校验规则
    const nameRules: Rule[] = [
        {required: true, message: '姓名不可为空'},
        {min: 2, type: 'string', message: '至少两个字符'},
    ]
    //定义生日字段的校验规则
    const birthdayRules: Rule[] = [
        {required: true, message: '生日不可为空'},
    ]

    //日期选择器的变更处理器
    const onChange: DatePickerProps['onChange'] = (date, dateString) => {
        console.log(date, dateString);
    };

    //点击模态框确定按钮时的处理函数,验证表单数据,并提交学生信息
    async function onOk() {
        //验证并获取表单数据
        try {
            const student = await form.validateFields()
            //使用dayjs格式化学生生日
            student.birthday = dayjs(student.birthday).format('YYYY-MM-DD')
            //发送新增学生的请求到后端
            const resp = await axios.post<Result<string>>(
                `http://localhost:8080/api/student/add`, student
            )
            message.success(resp.data.data) //显示成功提示消息
            onSuccess && onSuccess() //调用成功回调
            form.resetFields() //重置表单
        } catch (e) {
            console.error(e)
        }
    }

    //渲染模态框及表单组件
    return (
        <Modal
            title='新增学生' //模态框标题
            open={open} //模态框是否打开
            onOk={onOk} //确定按钮点击事件处理函数
            onCancel={onCancel} //取消按钮点击事件处理函数
            forceRender={true} //强制渲染模态框,即使父组件被卸载
        >
            <Form form={form} initialValues={student}>
                <Item label='姓名' name='name' rules={nameRules}>
                    <Input/>
                </Item>
                <Item label='性别' name='sex'>
                    <Group options={options} optionType='button' buttonStyle='solid'/>
                </Item>
                <Item label='生日' name='birthday' rules={birthdayRules}>
                    <DatePicker onChange={onChange}/>
                </Item>
            </Form>
        </Modal>
    )
}

Edit.tsx

import {DatePicker, DatePickerProps, Form, Input, message, Modal, Radio} from 'antd'
import moment from 'moment'
import {Rule} from 'antd/lib/form'
import axios from 'axios'
import {useEffect} from 'react'
import {Result, Student} from '../model/Student'

//编辑学生信息的模态框组件
export default function Edit({open, student, onSuccess, onCancel}: {
    open: boolean //模态框是否可见
    student: Student //需要编辑的学生对象
    onSuccess?: () => void //编辑成功后的回调函数
    onCancel?: () => void //取消编辑时的回调函数
}) {
    //引入并解构Form和Radio中的Item和Group组件
    const {Item} = Form
    const {Group} = Radio
    //定义性别选项的数组
    const options = [
        {label: '男', value: '男'},
        {label: '女', value: '女'},
    ]
    //创建表单实例
    const [form] = Form.useForm()
    //定义姓名字段的校验规则
    const nameRules: Rule[] = [
        {required: true, message: '姓名不可为空'},
        {min: 2, type: 'string', message: '至少两个字符'},
    ]
    //定义生日字段的校验规则
    const birthdayRules: Rule[] = [
        {required: true, message: '生日不可为空'},
    ]

    //日期选择器的变更处理器
    const onChange: DatePickerProps['onChange'] = (date, dateString) => {
        console.log(date, dateString);
    };

    const dateFormat = 'YYYY-MM-DD'; //日期格式

    //点击模态框确定按钮时的处理函数,验证表单数据,并提交学生信息
    async function onOk() {
        //验证表单字段并获取值
        try {
            const student = await form.validateFields()
            //使用moment格式化学生生日
            student.birthday = moment(student.birthday).format('YYYY-MM-DD')
            //发送修改学生的请求到后端
            const resp = await axios.put<Result<string>>(
                `http://localhost:8080/api/student/edit`, student
            )
            message.success(resp.data.data) //显示成功提示消息
            onSuccess && onSuccess() //调用成功回调
        } catch (e) {
            console.error(e)
        }
    }

    //使用useEffect初始化表单值
    useEffect(() => {
        // 修改表单数据
        // form.setFieldsValue(student) // id, name, sex, birthday
        const {birthday, ...other} = student;
        //birthday属性通过moment库格式化后再赋值,这样做可以确保表单数据与student对象保持同步
        form.setFieldsValue({birthday: moment(birthday, dateFormat)})
        form.setFieldsValue(other)
    }, [form, student])

    //渲染模态框及表单
    return (
        <Modal
            title='修改学生' //模态框标题
            open={open} //控制模态框是否显示
            onOk={onOk} //点击确定按钮时的回调函数
            onCancel={onCancel} //点击取消按钮时的回调函数
            forceRender={true} //强制渲染模态框,即使父组件被卸载
        >
            <Form form={form}>
                <Item label='编号' name='id'>
                    <Input readOnly/>
                </Item>
                <Item label='姓名' name='name' rules={nameRules}>
                    <Input/>
                </Item>
                <Item label='性别' name='sex'>
                    <Group options={options} optionType='button' buttonStyle='solid'/>
                </Item>
                <Item label='生日' name='birthday' rules={birthdayRules}>
                    <DatePicker onChange={onChange}/>
                </Item>
            </Form>
        </Modal>
    )
}

Remove.tsx

import {Button, message, Popconfirm} from 'antd'
import axios from 'axios'
import {Result} from '../model/Student'

//删除学生信息的组件
export default function Remove({id, onSuccess}: {
    id: number, //学生的唯一标识符
    onSuccess?: () => void //删除成功后执行的回调函数
}) {
    //确认删除学生的逻辑
    async function onConfirm() {
        //发送删除学生的请求到后端
        const resp = await axios.delete<Result<string>>(
            `http://localhost:8080/api/student/remove/${id}`
        )
        message.success(resp.data.data) //显示成功提示消息
        onSuccess && onSuccess() //调用成功回调
    }

    //渲染删除按钮,使用Popconfirm组件确认删除操作
    return (
        <Popconfirm title='确定要删除学生吗?' onConfirm={onConfirm}>
            <Button danger size='small'>删除</Button>
        </Popconfirm>
    )
}

BatchRemove.tsx

import {Button, message, Popconfirm} from "antd";
import axios from "axios";
import React from "react";
import {Result} from "../model/Student";

//批量删除学生信息的组件
export default function BatchRemove({ids, onSuccess}: {
    ids: React.Key[], //需要删除的学生的ids数组
    onSuccess?: () => void //删除成功后的回调函数
}) {
    //确定按钮是否禁用:如果ids数组为空,则禁用按钮
    const disabled = ids.length === 0

    //确认删除的逻辑处理
    async function onConfirm() {
        //发送批量删除学生的请求到后端
        const resp = await axios.delete<Result<string>>(
            `http://localhost:8080/api/student/batchRemove/${ids}`
        )
        message.success(resp.data.data) //显示成功提示消息
        onSuccess && onSuccess() //调用成功回调
    }

    //渲染删除选中按钮,使用Popconfirm组件确认删除操作
    return (
        <Popconfirm title='真的要删除选中的学生吗?' onConfirm={onConfirm} disabled={disabled}>
            <Button danger type='primary' disabled={disabled}>删除选中</Button>
        </Popconfirm>
    )
}

标签:function,Ant,const,模态,CRUD,表单,React,student,import
From: https://www.cnblogs.com/javasm1214/p/18200417

相关文章

  • React 中的 Hook
    React中的Hook是React16.8版本引入的一项特性,它让你在函数组件中使用状态(state)、生命周期方法、副作用等React的特性,而无需编写类组件。使用Hook的主要目的是让函数组件具备了更多类组件的功能,同时让代码更加清晰、简洁,并且更容易复用逻辑。一些常见的ReactHook......
  • react中的jsx语法
    JSX是JavaScriptXML的缩写,它是一种JavaScript的语法扩展。JSX允许在JavaScript代码中编写类似于XML或HTML的标记结构,用来描述用户界面的结构。 在React应用中,开发者通常使用JSX来定义组件的结构。这样做的好处是,JSX让代码更加直观易读,并且可以轻松地在JavaS......
  • 挑战程序设计竞赛 2.1章习题 poj 3046 Ant Counting
    https://vjudge.net.cn/problem/POJ-3046#author=GPT_zh有一天,贝西在蚂蚁山里探头探脑,看着蚂蚁们来来回回地觅食。她发现很多蚂蚁都是兄弟姐妹,彼此无法区分。她还发现,有时只有一只蚂蚁去觅食,有时几只,有时全部。这就产生了大量不同组合的蚂蚁!有点数学天赋的贝茜开始琢磨起来......
  • ctflearn-writeup(Exclusive Santa)
    https://ctflearn.com/challenge/851在完成这题前最好先下载foremost,unrar,stegsolve等工具首先拿到题目后,先解压得到两个图片文件1.png和3.png两张图片用exiftool,strings,binwalk试过后发现无解于是用关键命令foremost3.png-T(修复破损文件)发现有一个output的文件夹......
  • Games101-4 antialiasing and z-buffer
    利用中心对三角形进行采样antialiasing反走样samplingartifact--图形学中一切不好的东西空间,时间采样问题---信号的速度快导致采样跟不上如何做:在采样之前进行模糊/滤波,然后进行采样--不能反过来正弦和余弦滤波--好处:参数不同频率不同---每隔多少就重复一次......
  • antd-vue 时间选择器限制, 选择不超过七天的范围,且默认时间为当前时间往后七天
    1.template代码<a-range-picker v-model:value="conversationTime" style="margin-right:20px" :disabledDate="disabledDate" @calendarChange="onCalendarChange" @change="onChange" @openChange......
  • WindowsBaselineAssistant Windows安全基线核查加固助手,WindowsBaselineAssistant Wi
    GitHub-DeEpinGh0st/WindowsBaselineAssistant:Windows安全基线核查加固助手WindowsBaselineAssistantWindows安全基线核查加固助手,WindowsBaselineAssistantWindowsBaselineAssistant(WBA)是一个用于检测和加固Windows安全基线的辅助工具,借助此工具你可以免去繁琐的......
  • AoPS - Chapter 24 Diophantine Equations
    这一节主要讲解了二元一次丢番图方程、本原勾股数、佩尔方程(ThePellEquation)。丢番图方程(Diophantineequation)是指未知数为整数的整数系数多项式等式。(丢番图方程-维基百科)二元一次丢番图方程关于\(x,y\)的形如\(ax+by=c\)的丢番图方程称为二元一次丢番图方程。求解......
  • Java-并发-ReentrantLock
    0.是什么ReentrantLock是java.util.concurrent.locks包中的一个类,提供了比synchronized关键字更灵活和强大的锁机制。ReentrantLock实现了Lock接口,它允许显式地加锁和解锁,并提供了一些高级功能,如中断锁请求、超时锁请求、公平锁和非公平锁选择等。1.为什么在Java诞生......
  • vue-cli项目处理vant自适应问题
    原因vant自带的样式,用的单位是px,无法自适应。一般有两种处理思路。一、写媒体查询安装插件postcss-pxtorem:用于将单位px转化为rem//安装命令npmi-Dpostcss-pxtoremlib-flexible:给html标签设置font-size,作为rem基准值(因为我的项目已经脚本处理了,所以我是没有......