网站内容设计要求,汕头定制网站建设,国外设计素材网站,北京市住房城乡建设部网站首页目录
一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语
一. 简述
上一篇文章我们实现登录页面和管理页面的 Layout 骨架#xff0c;并对接登录和登出接口。这篇…目录
一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语
一. 简述
上一篇文章我们实现登录页面和管理页面的 Layout 骨架并对接登录和登出接口。这篇文章我们将实现用户管理的模块和相应的接口。最后效果如下
二. 模块规划
在开发之前我们需要对 xxl-job管理系统的用户模块进行规划。
2.1. 页面规划
一般我们都是从前端页面需要使用什么组件后端接口需要哪些 前端使用的组件表格、分页、下拉框、输入框和按钮就是一个很普通的 CRUD 管理页面比较简单接口也是围绕这些功能的分页查询接口、创建用户接口、编辑用户接口和删除接口。
2.2. 模型实体定义
接着我们需要定义下前后端交互会使用的到的请求和响应实体的定义。
首先是用户分页查询接口的请求和响应
// UserPageQueryProp 用户分页查询请求参数定义
export interface UserPageQueryProp {page: number; // 页码size: number; // 页大小role: number; // 角色 IDusername?: string; // 用户名称
}// UserTableProp 用户分页查询返回参数定义
export interface UserTableProp {id: number; // 用户IDusername: string; // 用户名称role: number; // 角色permission: string; // 权限
} 这里需要注意的是虽然我们表格中只有用户名和角色名两个显示属性但是考虑到在编辑的时候需要根据角色显示权限信息这里在分页查询中返回用户的权限数据。但是如果在一些复杂的分页表格中不建议这样操作 接着是用户创建和编辑的请求的定义
// UserTableProp 用户创建表单属性
export interface UserCreateFormProp {username: string; // 用户名称password: string; // 密码role: number; // 角色permission: string[]; // 权限
}// UserUpdateFormProp 用户创建表单属性
export interface UserUpdateFormProp extends UserCreateFormProp{id: number; // 用户ID
}三. 模块实现
从这个模块我们可以分为两个大部分和三个小组件组成。 其中功能部分我们可以使用 antd 的Space 中嵌套表单组件实现表格可以使用 Table 组件这个组件自带分页功能实现最后创建和编辑按钮我们使用 Modal 组件中嵌套 Form 表单组件实现就可以了。下面我们按功能一个个实现这个用户模块。 这里我们在使用 TS 这个 Buff 的使用大部分使用需要申明类型尤其在使用不熟悉的 UI 组件库的时候大家需要多读文章多看组件定义文件或者源码。 3.1. 用户分页搜索
上面我们分析我们要使用组件这里就不赘述了直接上代码
import {Button, Divider, Input, Select, Space, Table, Tag} from antd;
import React, {useEffect, useState} from react;
import {User} from /types;
import {ColumnsType} from antd/es/table;
import {useRequest} from ahooks;
import UserApi from /api/user.ts;
import {ClearOutlined, PlusOutlined, SearchOutlined} from ant-design/icons;const UserPage () {// 定义列信息const columns: ColumnsTypeUser.UserTableProp [{title: 账号,key: username,dataIndex: username,align: center},{title: 角色,key: role,dataIndex: role,align: center,render: (_, record) record.role 1 ? Tag color#f50管理员/Tag : Tag color#2db7f5普通用户/Tag},{title: 操作,key: active,align: center,width: 200,render: (_, record) SpaceButton typeprimary onClick{() openEdit(record.id)}编辑/ButtonButton typeprimary danger onClick{() deleteUser(record.id)}删除/Button/Space,},]// 总条数const [total, setTotal] useStatenumber(0);const [selectedRowKeys, setSelectedRowKeys] useStatenumber[]([]);// 用户数据const [datasource, setDatasource] useStateUser.UserTableProp[]([]);// 分页查询属性const [pageQuery, setPageQuery] useStateUser.UserPageQueryProp(defaultUserPageQuery());return divSpaceButton typeprimary icon{PlusOutlined /}增加用户/ButtonDivider typevertical/div角色/divSelectonChange{e setPageQuery({...pageQuery, role: e})}placeholder选择状态defaultValue{-1}style{{width: 100}}options{[{value: -1, label: 全部},{value: 1, label: 管理员},{value: 0, label: 普通用户}]}/div style{{marginLeft: 20}}用户名称/divInputallowClearplaceholder请输入搜索的用户名称value{pageQuery.username}onChange{e setPageQuery({...pageQuery, username: e.target.value})} /Button danger typeprimary icon{ClearOutlined /} onClick{clearSearch}清空/ButtonButton typeprimary icon{SearchOutlined /} onClick{() loadUser.run(pageQuery)}搜索/Button/SpaceTableborderedsize{small}columns{columns}loading{loadUser.loading}dataSource{datasource}style{{ marginTop: 10 }}rowKey{(record) record.id}pagination{{onShowSizeChange: (current, size) loadUser.run({...pageQuery, page: current, size: size}),onChange: (page, pageSize) loadUser.run({...pageQuery, page: page, size: pageSize}),showTotal: () 共 ${total} 个,showQuickJumper: true,showSizeChanger: true,pageSize: pageQuery.size,current: pageQuery.page,size: default,total: total,}}rowSelection{{type: checkbox,selectedRowKeys: selectedRowKeys,onChange: (selectedRowKeys: React.Key[]) {setSelectedRowKeys([...selectedRowKeys.map(item item as number)])}}}//div
}export default UserPage;这里我们需要注意一下几点
表格每一个行都需要一个 Key默认是 React.Key但是如果我们需要自定义的时候可以使用rowKey{(record) record.id}定义自己的 rowKey这里的 record 就是定义表格属性模型User.UserTableProp关于分页属性我们可以通过pagination属性进行设置可以设置属性和方法可以在分页组件文章中看到最后一点就是关于表格行选中可以通过rowSelection属性设置
接下来我们就需要对接分页查询的接口了首先我们在 api/user.ts 中添加用户分页接口 api 定义
/*** 用户分页* param param* constructor*/
export const UserPage (param: User.UserPageQueryProp): PromisePageDataUser.UserTableProp {return https.request({url: /user/pageList,method: post,data: param})
}接着我们看一下如何使用这个api并且了解下ahooks 中的useRequest中非常好用的地方。
// 加载用户列表
const loadUser useRequest(UserApi.UserPage, {manual: true, // 手动调用onSuccess: ({records, total}) { // 成功之后执行的操作setTotal(total);setDatasource(records);}
});最后我们配合 useEffect使用加载用户列表的接口会在加载用户管理页面的时候调用这个接口。
useEffect(() {loadUser.run(pageQuery)
}, [])这里我们介绍 ahooks 中的 useRequest这个工具 hooks。 支持的功能很多这里我们现使用这里的 loading 返回值。在我们请求接口的时候如果遇到网络抖动之类的加载缓慢的情况让表格出现一个加载状态的图标是非常友好了不然用户也很懵逼。在上面antd 提供了加载属性loading{loadUser.loading}我们只需要将这个值的变化交给 useRequest 就可以完全不需要我们手动控制。
接下来我们实现上面搜索的功能。 这里一个是下拉框一个是输入框我们直接使用的是 antd 的组件我们仅需要实现清空输入和搜索两个按钮事件就可以了。对于清空搜索的点击事件我们只需要将下拉选项设置为默认值输入框清空就可以了代码如下
// 清空搜索
const clearSearch () {setPageQuery({...pageQuery, role: -1, username: })
}对于搜索我们仅需要手动调用分页接口就可以了代码如下
Button typeprimary icon{SearchOutlined /} onClick{() loadUser.run(pageQuery)}
搜索/Button3.2. Modal 配置
这个用户管理的部分需要用到创建用户和编辑用户两个功能在xxl-job中都是都通过打开弹窗进行操的我们这里也是使用相同的逻辑。这里我们使用 antd 的 Modal 组件。在使用这个组件的时候我们需要对 Modal 组件的打开和关闭进行一个统一的控制。
// UserCreateModelProp 创建用户弹窗属性
export interface UserCreateModalProp {visible: boolean;close: (isLoad: boolean) void; // 关闭模态框
}// UserUpdateFormProp 用户更新表单属性
export interface UserUpdateFormProp {id: number; // 用户IDpassword: string; // 密码role: number; // 角色permission: string[]; // 权限
}// 定义模态框的类型
export type ModalType create | update;// UserModelProp 用户模态框汇总属性
export interface UserModalProp {createVisible: boolean; // 创建用户模态框打开标识updateVisible: boolean; // 编辑用户模态框打开标识userData?: UserTableProp; // 编辑是存放被编辑用户信息
}接着我们分别定义打开和关闭模态框的事件
// 关闭模态框
const closeModal (isLoad: boolean) {// 在全局只能有一个弹窗打开所以在关闭的时候把标识变量都设为 false 就可以了setUserModelProp({createVisible: false, updateVisible: false, userData: undefined})if(isLoad) {// 如果创建和编辑成功我们需要重新加载表格数据显示最新的数据loadUser.run(pageQuery)}
}// 打开模态框
const openModal (types: User.ModalType, data?: User.UserTableProp) {switch (types) {case create:setUserModalProp({createVisible: true, updateVisible: false});break;case update:setUserModalProp({updateVisible: true, createVisible: false, userData: data});break;default:break}
}
最后我们在创建和编辑按钮上使用这些事件就可以了
Button typeprimary icon{PlusOutlined /} onClick{() openModal(create)}增加用户/ButtonButton typeprimary onClick{() openModal(update, record)}编辑/Button
接着我们定一个模态框组件在当前目录下创建 create.tsx和 update.tsx 文件这两个文件分别是创建用户和编辑用户模态框组件子组件。
import {Modal} from antd;
import React from react;
import {User} from /types;const CreateUserModal: React.FCUser.UserCreateModalProp ({visible, close}) {const submitForm () {close(true)}return Modaltitle创建用户open{visible}onOk{submitForm}onCancel{() close(false)}h1创建用户/h1/Modal
}export default CreateUserModal;编辑类似不做展示了 这两个子组件设置组件之间的传值问题我们在User.UserCreateModalProp定义了创建用户模态框组件需要的参数visible变量和 close函数。最后我们在 index.tsx 中使用这个子组件就可以了。
// 存放模态框状态值
const [userModalProp, setUserModalProp] useStateUser.UserModalProp({createVisible: false, updateVisible: false});CreateUserModalkeycreateclose{closeModal} // 模态框关闭事件visible{userModalProp.createVisible} // 创建用户模态框打开状态标识变量
/效果如下
3.3. 创建用户表单
这里我们接着实现创建用户表单和表单提交的相关部分直接上代码 推荐先看看 antd 的 Form 组件的文章。 import {Checkbox, Divider, Empty, Form, Input, message, Modal, Radio, Row, Spin, Tag} from antd;
import React, {useEffect, useState} from react;
import {Group, User} from /types;
import {useRequest} from ahooks;
import {GroupApi, UserApi} from /api/index.ts;
import styled from emotion/styled;const CreateUserModal: React.FCUser.UserCreateModalProp ({visible, close}) {// 表单const [form] Form.useFormUser.UserCreateFormProp();// 监听表单 role 的 valueconst roleValue Form.useWatch(role, form);// 执行器列表const [groups, setGroups] useStateGroup.JobGroupListProp[]([]);// 执行器请求const groupLoader useRequest(GroupApi.GroupLists, {manual: true, onSuccess: (data) {setGroups(data);}})// 创建用户请求const createLoader useRequest(UserApi.CreateUser, {manual: true, onSuccess: () {message.success(创建用户成功)close(true)}});const submitForm () {form.validateFields().then(value {// console.log(submit , value)if (value.role 1) {value.permission []}createLoader.run(value);})}// 监听 visible 打开关闭标识useEffect(() {if (visible) { // 当创建用户模态框打开请求执行器列表接口并设置角色默认值为普通用户groupLoader.run();form.setFieldValue(role, 0)} else {// 关闭模态框的时候将表单置为空并将执行器列表设置为空数组form.resetFields();setGroups([]);}}, [visible])return Controllertitle创建用户maskClosablewidth{500}open{visible}onOk{submitForm}onCancel{() close(false)}Spin tip加载中...... spinning{createLoader.loading}Form form{form} layoutvertical nameform_create_modalForm.Item nameusername label账号 rules{[{ required: true, message: 请输入账号 }]}Input placeholder请输入账号 //Form.ItemForm.Item namepassword label密码 rules{[{ required: true, message: 请输入密码 }]}Input.Password placeholder请输入密码 //Form.ItemForm.Item namerole label角色Radio.GroupRadio value{0}普通用户/RadioRadio value{1}管理员/Radio/Radio.Group/Form.Item{roleValue 0 Form.Item namepermission label权限{groups.length 0 ? Checkbox.Group classNamexxl-job-list{groups.map(item Row key{item.id}Checkbox value{item.appName}{item.title}Divider typevertical /Tag colorlime{item.appName}/Tag/Checkbox/Row)}/Checkbox.Group : Empty /}/Form.Item}/Form/Spin/Controller
}const Controller styled(Modal).ant-modal-body {padding-top: 24px;.xxl-job-list {flex-direction: column;}}
export default CreateUserModal;这里我们通过 Modal 包裹表单组件使用 useEffect监听 visible属性当前模态框打开的时候需要请求执行器列表并设置角色默认值。
还需要注意的一个点是当角色是管理员的时候是不需要选择执行器的所有在切换角色为管理员的时候需要将之前选中的执行器清空所以在最后提交用户数据的时候设置下执行器就可以了。
const submitForm () {form.validateFields().then(value {if (value.role 1) { // 当角色是管理员的时候将执行器权限设置为空数据value.permission []}createLoader.run(value);})
}此外我们还通过 styled 修改了 Modal 组件的样式主要是为了将多选框flex 布局从 row 改为 column。
// 使用 styled 包裹 Modal 组件
const Controller styled(Modal).ant-modal-body {padding-top: 24px;.xxl-job-list {flex-direction: column;}}3.4. 修改用户表单
有了上面创建用户表单部分我们在修改用户信息的时候仅需要了解表单初始化的问题了这里我们也是用使用Form.setFieldsValue方法进行初始化表单代码代码
useEffect(() {if (visible data) {groupLoader.run();form.setFieldsValue({id: data.id, username: data.username, role: data.role, permission: data.permission})} else {form.resetFields();setGroups([]);}
}, [visible])这里还有一个不一样的地方是我们会设置一个隐藏的用户主键方便我们后面执行更新的时候确定要被更新用户信息
Controllertitle更新用户maskClosablewidth{500}open{visible}onOk{submitForm}onCancel{() close(false)}Spin tip加载中...... spinning{updateLoader.loading}Form form{form} layoutvertical nameform_update_modal// 不显示主键在我们提交数据的时候会反给form.validateFields().then(value {})中Form.Item nameid label主键 style{{display: none}}Input //Form.ItemForm.Item nameusername label账号Input placeholder请输入账号 readOnly //Form.ItemForm.Item namepassword label密码Input.Password placeholder请输入新密码为空则不更新密码 //Form.ItemForm.Item namerole label角色Radio.GroupRadio value{0}普通用户/RadioRadio value{1}管理员/Radio/Radio.Group/Form.Item{roleValue 0 Form.Item namepermission label权限{groups.length 0 ? Checkbox.Group classNamexxl-job-list{groups.map(item Row key{item.id}Checkbox value{item.appName}{item.title}Divider typevertical /Tag colorlime{item.appName}/Tag/Checkbox/Row)}/Checkbox.Group : Empty /}/Form.Item}/Form/Spin/Controller3.5. 删除
终于快要搞完了现在我们就剩删除用户这个功能了。针对我们删除来说一般我都需要弹出一个提示询问用户是否确定删除这条数据。这里我们可以使用 antd 中的 删除Modal或者气泡提示就可以了。 这里功能简单只需要调用组件在其回调方法中调用删除接口就可以了。代码如下
// 移除用户
const loadRemoveUser useRequest(UserApi.RemoveUser, {manual: true,onSuccess: () {loadUser.run(pageQuery);message.success(移除用户成功);}
})// 删除用户
const deleteUser (id: number) {Modal.confirm({title: 你确认删除当前用户吗?,icon: ExclamationCircleFilled /,content: 删除用户会导致无法登录和操作任务,okText: 确认,okType: danger,cancelText: 取消,onOk() {loadRemoveUser.run(id)},onCancel() {},});
}最后在给删除按钮添加点击事件并将用户的 ID 传给接口。
Button typelink danger onClick{() deleteUser(record.id)}删除/Button四. 结束语
这篇文章我们介绍了如何利用 antd 提供的组件快速开发一个 CRUD 功能的管理模块相信大家可以从中收获很多东西了下一篇文章我们将介绍执行器管理的模块开发。