上一章节我们完成了前端菜单和用户列表的功能,以及后端通过中间件来封装响应结果、通过封装DRF分页组件来实现分页的功能。
这一章节将实现页面头部用户头像展示和下拉退出系统的功能、用户管理模块的增删改功能。
由于博主本身也才开始使用ts,很多类型都是用any
来定义的,后续会逐渐完善。
实现效果如下:
在线演示地址:http://121.43.43.59/ (帐号:admin 密码:123456)
为了实现上述图片中的效果(头像中为用户的姓名),我们需要在登录接口成功时返回用户姓名的数据,所以需要修改登录接口来增加返回字段,如下图红框所示(增加了用户姓名、用户名的返回):
接口调整完成后,我们需要修改前端的登录完成后的代码,将用户信息保存起来备用,在登录方法中加入红框中的代码即可:
然后为了代码结构分类清晰,因为头像这个功能实际上后面每个页面都会用到,它不属于任何一个页面,所以这里我在src
文件夹下新建了文件夹components
,以后类似这样的公共组件我们都可以存放在这里。
然后在components
下面新建RightContent
文件夹,这就是我们的右侧头部(头像)组件了,再在它下面新建index.tsx
文件用于开发我们的代码,目录结果如下:
index.tsx
代码为:
import {message, Dropdown, Menu, Avatar } from 'antd';
import { history } from 'umi';
import React from 'react';
const menu = (
<Menu>
<Menu.Item key="1" onClick={() => message.warning('待实现!')}>个人中心</Menu.Item>
<Menu.Item key="2" onClick={() => { localStorage.setItem('token', ''); history.push('/login'); }}>退出</Menu.Item>
</Menu >
);
const GlobalHeaderRight: React.FC = () => {
const userInfo = localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo') as any) : {}
return (
<Dropdown
placement="bottomRight"
overlay={menu}
>
<Avatar style={{ backgroundColor: '#7265e6' }} size={36}>{userInfo.name}</Avatar>
</Dropdown>
);
};
export default GlobalHeaderRight;
最后在layouts\index.tsx
中的ProLayout
指定我们的右侧头部组件即可(ProLayout中增加下面的代码):
rightContentRender={() => <RightContent />}
记得在文件头部import该组件:
import RightContent from '@/components/RightContent';
有疑问可查看ProLayout文档学习,也可以在演示地址联系博主进行解答。
这样我们就完成了头像和下拉菜单的功能:
删除功能除了删除对应的数据外,还需要重新刷新列表,刚好ProTalbe
提供了对应的方法,所以在我们的用户模块代码中(pages/user/index.tsx
文件)里的columns
的操作
里修改对应的代码即可
1)首先头部新增引入userRef
:
import React, { useState, useRef } from 'react';
2)定义格式:
interface ActionType {
reload: () => void;
fetchMore: () => void;
reset: () => void;
}
3)在User
组件中声明:
const ref = useRef<ActionType | any>();
4)在ProTable
组件中增加如下配置:
actionRef={ref}
5)修改操作
中的删除请求代码,完整的操作
代码如下:
{
title: '操作',
key: 'option',
dataIndex: 'option',
width: 120,
valueType: 'option',
render: (v: any, record: any) => [
<a key={record.id}>修改</a>,
<a key={record.id} onClick={() => {
services.UserAll(record.id, reqDelete).then(res => {
ref.current.reload(); //刷新代码
})
}}> 删除</a >
],
}
虽然这样实现了删除功能并且刷新了列表,但在删除非第一页数据的最后一条时(比如存在两页数据,删除第二页最后一条)会保持第二页的参数进行请求,会导致列表数据为空:
所以在非首页的最后一条数据被删除时,我们应该改变页码为前一页进行请求。
1)声明获取数据的长度字段:
const [dataLength, setDataLength] = useState<number>(0);
2)修改请求ProTable
中的request
方法,为了获取返回数据的长度,完整的request
代码如下:
request={(...tableParams) => {
var filters: object = tableParams[2];
for (let key in filters) {
//删除查询条件为空的
if (!filters[key]) {
delete filters[key];
}
}
setParams({ ...params, ...filters });
return UserAll({ ...params, ...filters }, reqList).then((res) => {
setDataLength(res.data.length);
return res;
});
}}
3)修改操作
中删除请求代码如下:
<a key={record.id} onClick={() => {
UserAll(record.id, reqDelete).then(
res => {
if (params.page > 1 && dataLength <= 1) {//在非首页的最后一条数据被删除时,改变页码为前一页进行请求
setParams({ ...params, ...{ page: params.page - 1 } })
}
ref.current.reload();
})
}}> 删除</a >
这样我们的删除功能就大功告成了!
对于修改和创建功能我们通过弹窗的来做,因为需要有地方填写用户的信息。
这里我们使用的弹窗是ProForm
这个组件,官方文档:https://procomponents.ant.design/components/form
首先要在user
文件夹下新建form.tsx
文件,并编写弹窗页面的代码,代码为具体的弹窗样式和逻辑交互,使用proForm
组件能省不少事。
然后在入口index.tsx
文件增加控制弹窗显示、弹窗数据管理的代码;
最后就是控制弹窗请求接口进行数据保存的方法封装了。
1.user/form.tsx
弹窗完整代码:
import React from 'react';
import ProForm, {
ModalForm,
ProFormText,
ProFormRadio,
} from '@ant-design/pro-form';
const Form: React.FC<any> = ({ visible, cancel, formData, onFinish }) => {
return (
<ModalForm
title={formData.formType === 'create' ? "创建用户" : "修改用户"}
initialValues={{
username: formData.username || null,
first_name: formData.first_name || null,
last_name: formData.last_name || null,
email: formData.email || null,
is_active: formData.is_active || false,
is_superuser: formData.is_superuser || false
}}
visible={visible}
autoFocusFirstInput
modalProps={{
destroyOnClose: true,
onCancel: () => cancel()
}}
onFinish={async (values) => {
onFinish(values, formData.formType).then(() => { //成功保存则返回true
return true;
}, () => { //保存失败则返回false
return false;
})
}}
>
<ProFormText
width="md"
name="username"
rules={[{ required: true, message: "用户名必填" }, { type: 'string' }, { max: 18, message: '最多18个字' }]}
label="用户名"
placeholder="请输入用户名" />
<ProForm.Group>
<ProFormText
width="md"
name="first_name"
rules={[{ required: true, message: "必填!" }, { type: 'string' }, { max: 18, message: '最多18个字' }]}
label="用户名字"
placeholder="请输入名称"
/>
<ProFormText
width="md"
name="last_name"
rules={[{ required: true, message: "必填!" }, { type: 'string' }, { max: 18, message: '最多18个字' }]}
label="用户姓氏"
placeholder="请输入名称"
/>
</ProForm.Group>
<ProFormText width="md" name="email" label="邮箱号" placeholder="请输入邮箱号" />
<ProFormRadio.Group
name="is_active"
label="用户状态"
options={[
{
label: '启用',
value: true,
},
{
label: '禁用',
value: false,
}
]}
/>
<ProFormRadio.Group
name="is_superuser"
label="是否为管理员"
options={[
{
label: '是',
value: true,
},
{
label: '否',
value: false,
}
]}
/>
</ModalForm>
);
};
export default React.memo<any>(Form);
2.user/index.tsx
相关代码:
1)User
组件类定义控制弹窗的属性:
const [formData, setFormData] = useState<any>({});//传递给弹窗显示的数据
const [formVisible, setFormVisible] = useState<boolean>(false); //控制弹窗显示还是隐藏
2)点击列表的新建/修改按钮以及弹窗确认按钮后执行的方法代码:
//点击新建/修改,执行的代码
const showModal = (type: string, values = {}) => {
values['formType'] = type
setFormData(values)
setFormVisible(true)
};
// 弹窗点确认按钮执行的方法
const onFormFinish = async (values: any, formType: string) => {
var reqType: string
if (formType === 'create') {
reqType = reqCreate
}
else {
reqType = reqUpdate
values.id = formData.id
}
return await UserAll(values, reqType).then((res) => {
message.success('操作成功!')
setFormVisible(false)
formType === 'create' ? ref.current.reloadAndRest() : ref.current.reload();
});
};
3)return中弹窗Form
组件的代码:
<Form
formData={formData}
onFinish={(values: object, formType: string) => onFormFinish(values, formType)}
cancel={() => setFormVisible(false)}
visible={formVisible}
/>
4)列表columns
中,操作栏的代码:
{
title: '操作',
key: 'option',
dataIndex: 'option',
width: 120,
valueType: 'option',
render: (v: any, record: any) => [
<a key={record.id} onClick={() => showModal('update', record)}>
修改
</a>,
<a
key={record.id}
onClick={() => {
UserAll(record.id, reqDelete).then((res) => {
if (params.page > 1 && dataLength <= 1) {
//在非首页的最后一条数据被删除时,改变页码为前一页进行请求
setParams({ ...params, ...{ page: params.page - 1 } });
}
ref.current.reload();
});
}}
>
删除
</a>,
],
},
这一章用到了ProForm
这个组件,可以结合下面两个官方文档进行学习:
当然这个过程中会存在不少疑问,可以点击下方在线演示地址进行反馈。
在线演示地址:http://121.43.43.59/ (帐号:admin 密码:123456)
欢迎在文章头部右上角订阅本专栏,及时获取最新教程分享!
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/momoda118/article/details/121904987
内容来源于网络,如有侵权,请联系作者删除!