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