ant design pro 用户列表渲实践
用户页面:
src\pages\Admin\User\index.tsx
import { PlusOutlined } from '@ant-design/icons';
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components';
import {
PageContainer,
ProDescriptions,
ProTable,
} from '@ant-design/pro-components';
import { Button, Drawer, Modal, message,Spin } from 'antd';
import React, { useEffect, useRef, useState,useCallback } from 'react';
import CreateModal from "./components/CreateModal";
import UpdateModal from "./components/UpdateModal";
import ReadModal from "./components/ReadModal";
import {
addUserByUsingPOST,
deleteUserByUsingPOST,
updateUserByUsingPOST,
listUserVOByPageUsingGET,
} from "@/services/user/userController";
import { useModel } from "@umijs/max";
import { BASEENTITYCOLUMN, UPDATEUSERCOLUMN, USERPAGESIZE,USERENTITYCOLUMN } from "@/constant/user";
/**
* 用户管理
* @returns
*/
const UserManager: React.FC = () => {
/**
* @en-US Pop-up window of new window
* @zh-CN 新建窗口的弹窗
* */
const [createModalOpen, handleModalOpen] = useState<boolean>(false);
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [showDetail, setShowDetail] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<UserEntityAPI.UserVO>();
const [readModalOpen, handleReadModalOpen] = useState<boolean>(false);
//分页
const [formValue, setFormValue] = useState<UserEntityAPI.UserVO[]>([]);
const [total, setTotal] = useState<number>(0)
const [isLoading, setIsLoading] = useState(true);
//获取用户信息
const getFormInfo = async (pageNum = 1, pageSize = USERPAGESIZE) => {
const res = await listUserVOByPageUsingGET({
pageNum: pageNum,
pageSize: pageSize,
// userId: "userId",
// userType: 'sys_user',
})
setTotal(res?.total || 0)
// console.log(res?.data);
setFormValue(res?.data || []);
setIsLoading(false);
}
//点击详情
const readClickStatus = useCallback((record:UserEntityAPI.UserVO) => {
handleReadModalOpen(true);
setCurrentRow(record);
}, [handleReadModalOpen, setCurrentRow]);
//点击修改
const updateClickStatus = useCallback((record:UserEntityAPI.UserVO) => {
handleUpdateModalOpen(true);
setCurrentRow(record);
}, [handleUpdateModalOpen, setCurrentRow]);
//点击添加
const handleAdd = async (fields: UserEntityAPI.userAddRquestParams) => {
const hide = message.loading('正在添加');
try {
await addUserByUsingPOST({
...fields,
userType: 'sys_user',
});
hide();
await getFormInfo();
actionRef?.current?.reload()
message.success('添加成功');
if (createModalOpen) handleModalOpen(false);
return true;
} catch (error: any) {
hide();
message.error("添加失败", error?.message);
return false;
}
};
/**
* Delete node
* @zh-CN 删除用户
*
* @param selectedRow
*/
const handleRemove = async (selectedRow: UserEntityAPI.DeleteRequestParams) => {
const hide = message.loading('正在删除');
if (!selectedRow) return true;
try {
await deleteUserByUsingPOST({
userId: selectedRow.userId,
});
hide();
await getFormInfo();
actionRef?.current?.reload()
message.success('删除成功');
return true;
} catch (error: any) {
hide();
message.error("删除失败", error?.message);
return false;
}
};
//初始化
useEffect(() => {
// console.log("useEffect");
getFormInfo();
// console.log("构造函数执行完,formValue状态变化后:", formValue)
}, []);
//如果网络请求数据还没拿到,就先 加载中 转圈
if (isLoading) {
return <Spin />
}
/**
* @en-US Update node
* @zh-CN 更新用户
*
* @param fields
*/
const handleUpdate = async (fields: UserEntityAPI.UserUpdateRequestParams) => {
if (!currentRow) {
return;
}
const hide = message.loading('更新中');
try {
await updateUserByUsingPOST({
userId: currentRow.userId,
...fields,
});
hide();
message.success('更新成功');
handleUpdateModalOpen(false);
await getFormInfo();
actionRef?.current?.reload()
return true;
} catch (error) {
hide();
message.error('更新失败');
return false;
}
};
const columns: ProColumns<UserEntityAPI.UserVO>[] = [
...BASEENTITYCOLUMN,
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<Button
color={"blue"}
type={"link"}
key="detail"
onClick={() => {
// handleModalOpen(true);
// setCurrentRow(record);
readClickStatus(record);
// history.push(`/receive/record?childrenId=${record?.id}`)
}}
>
详情
</Button>,
<a
key="modify"
onClick={() => {
// handleUpdateModalOpen(true);
// setCurrentRow(record);
updateClickStatus(record);
}}
>
修改
</a>,
<Button
type={"text"}
danger={true}
key="config"
onClick={() => {
//提示是否删除
Modal.confirm({
title: '删除',
content: '确定删除吗?',
onOk: () => {
handleRemove(record)
}
})
}}
>
删除
</Button>,
],
},
];
//UPDATEUSERCOLUMN
const updateColumn: ProColumns<UserEntityAPI.UserUpdateRequestParams>[] = [
...UPDATEUSERCOLUMN,
];
return (
<PageContainer>
<ProTable<UserEntityAPI.UserVO, UserEntityAPI.PageParams>
key="main"
pagination={{
total,
pageSize: USERPAGESIZE,
onChange: async (pageNum, pageSize) => {
await getFormInfo(pageNum, pageSize);
},
}}
headerTitle={'用户信息'}
actionRef={actionRef}
rowKey="key"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
type="primary"
key="primary"
onClick={() => {
handleModalOpen(true);
}}
>
<PlusOutlined /> 新建用户
</Button>,
]}
request={async () => ({
data: formValue || {},
})}
columns={columns}
rowSelection={{
onChange: (e) => {
console.log("rowSelection")
// setSelectedRows(selectedRowKeys);
console.log(e);
},
}}
/>
<UpdateModal
columns={updateColumn}
onSubmit={async (values: UserEntityAPI.UserUpdateRequestParams) => { handleUpdate(values) }}
onCancel={() => {
handleUpdateModalOpen(false);
if (!showDetail) {
setCurrentRow(undefined);
}
}}
visible={updateModalOpen}
values={currentRow || {}}
/>
<Drawer
key="drawer"
width={600}
open={showDetail}
onClose={() => {
setCurrentRow(undefined);
setShowDetail(false);
}}
closable={false}
>
{currentRow?.userName && (
<ProDescriptions<UserEntityAPI.UserVO>
column={2}
title={currentRow?.userName}
request={async () => ({
data: currentRow || {},
})}
params={{
id: currentRow?.userName,
}}
columns={columns as ProDescriptionsItemProps<UserEntityAPI.UserVO>[]}
/>
)}
</Drawer>
<CreateModal columns={updateColumn} onCancel={() => { handleModalOpen(false) }}
onSubmit={async (values: UserEntityAPI.UserUpdateRequestParams) => {
await handleAdd(values)
}} visible={createModalOpen} file={false} />
<Drawer width={640}
placement="right"
closable={false}
onClose={ ()=> {
setCurrentRow(undefined);
handleReadModalOpen(false)}
}
open={readModalOpen}>
<ReadModal EntityItem={currentRow} EntityColumns={USERENTITYCOLUMN}/>
</Drawer>
</PageContainer>
);
}
export default UserManager;
组件
src\pages\Admin\User\components\ReadModal.tsx
import React, { useState } from 'react';
import type { DescriptionsProps } from 'antd';
import {ProColumns} from "@ant-design/pro-components";
import {ProDescriptions} from "@ant-design/pro-descriptions";
import { Avatar, Col, Divider, Drawer, List, Row,Descriptions} from 'antd';
import { USERENTITYCOLUMN } from '@/constant/user';
export type Props = {
EntityItem: UserEntityAPI.UserVO;
EntityColumns: ProColumns<UserEntityAPI.UserVO>[];
visible: boolean;
};
/**
* 用户详情组件
* @param props 用户详情组件
* @returns
*/
const ReadModal: React.FC<Props> = (props) => {
const {EntityItem,EntityColumns} = props;
//描述组件:用于展示用户信息
let items: DescriptionsProps['items'] = [];
// if(userEntityItem){
// items = [
// {
// key: '1',
// label: 'UserName',
// children: userEntityItem.userName,
// },
// {
// key: '2',
// label: '手机号码',
// children: userEntityItem.photoNumber,
// },
// {
// key: '2',
// label: '性别',
// children: userEntityItem.sex,
// },
// {
// key: '2',
// label: 'nickName',
// children: userEntityItem.nickName,
// },
// ];
// }
//描述列表组件
return (
<>
<ProDescriptions dataSource={EntityItem} columns={EntityColumns}/>
</>
);
};
export default ReadModal;
src\pages\Admin\User\components\CreateModal.tsx
import '@umijs/max';
import React from 'react';
import {Form,Modal} from "antd";
import {ProColumns, ProTable} from "@ant-design/pro-table/lib";
import MyUploadFile from "@/components/UploadFile";
export type Props = {
columns: ProColumns<UserEntityAPI.UserUpdateRequestParams>[];
onCancel: () => void;
onSubmit: (values: UserEntityAPI.UserUpdateRequestParams) => Promise<void>;
visible: boolean;
file?: boolean;
};
const CreateModal: React.FC<Props> = (props) => {
const {columns, visible, onSubmit, onCancel, file} = props;
return (
<Modal open={visible} onCancel={()=> onCancel?.()} footer={null}>
{/* <div style={{ marginLeft: "20px", marginRight: "10px"}}>
{file ? (
<Form requiredMark={true}>
上传附件: <MyUploadFile />
</Form>
) : null}
</div> */}
<br/>
<ProTable
type={"form"}
columns={columns}
onSubmit={async (value: UserEntityAPI.UserUpdateRequestParams) => {
onSubmit?.(value);
}}
/>
</Modal>
);
};
export default CreateModal;
src\pages\Admin\User\components\UpdateModal.tsx
import '@umijs/max';
import React, {useEffect, useRef} from 'react';
import {Modal} from "antd";
import {ProColumns, ProTable} from "@ant-design/pro-table/lib";
import {ProFormInstance} from "@ant-design/pro-form";
export type Props = {
values: UserEntityAPI.UserUpdateRequestParams;
columns: ProColumns<UserEntityAPI.UserUpdateRequestParams>[];
onCancel: () => void;
onSubmit: (values: UserEntityAPI.UserUpdateRequestParams) => Promise<void>;
visible: boolean;
};
const UpdateModal: React.FC<Props> = (props) => {
const {columns, visible, onSubmit, onCancel,values} = props;
const formRef = useRef<ProFormInstance>();
useEffect(()=>{
formRef.current?.setFieldsValue(values)
})
return (
<Modal open={visible} onCancel={()=> onCancel?.()} footer={null}>
<ProTable
type={"form"}
columns={columns}
formRef={formRef}
onSubmit={async (value: UserEntityAPI.UserUpdateRequestParams)=>{
onSubmit?.(value)
}}
/>
</Modal>
);
};
export default UpdateModal;
常量
src\constant\user.tsx
import { ProColumns } from "@ant-design/pro-components";
import type { DescriptionsProps } from 'antd';
export const SYSTEM_LOGO = "https://avatars.githubusercontent.com/u/103118339?v=4";
export const PAGESIZE = 3;
export const USERPAGESIZE = 6;
export const NEWSAVATAR = "https://hzh-1318734603.cos.ap-shanghai.myqcloud.com/%E6%96%B0%E9%97%BB.jpg";
export const BASEENTITYCOLUMN: ProColumns<UserEntityAPI.UserVO>[] = [
{
title: 'id',
dataIndex: 'userId',
valueType: 'index',
},
{
title: '用户名',
dataIndex: 'userName',
valueType: 'text',
formItemProps: {
rules: [{
required: true,
message: "请输入用户名",
}]
}
},
// {
// title: '密码(8位以上不包含特殊字符)',
// hideInTable:true,
// hideInSearch:true,
// dataIndex: 'password',
// valueType: 'text',
// formItemProps: {
// rules: [{
// required: true,
// message: "请输入密码",
// },{
// type: "string",
// min: 8,
// message: "密码小于8位",
// },
// {
// pattern: /^[a-zA-Z0-9]+$/,
// message: "不允许包含特殊字符",
// }]
// }
// },
{
title: '昵称',
dataIndex: 'nickName',
valueType: 'text',
formItemProps: {
rules: [{
required: true,
message: "请输入姓名",
}]
}
},
{
title: '用户类型',
dataIndex: 'userType',
valueType: 'text',
valueEnum: {
'sys_user': {
text: '系统用户',
status: 'Success',
},
'general_user': {
text: '普通用户',
status: 'Success',
},
},
},
{
title: '性别',
dataIndex: 'sex',
hideInTable: false,
valueType: 'text',
valueEnum: {
'0': {
text: '男',
status: 'Success',
},
'1': {
text: '女',
status: 'Success',
},
},
},
{
title: '角色',
dataIndex: 'userRole',
hideInForm: true,
valueEnum: {
'admin': {
text: '管理员',
status: 'Success',
},
'children': {
text: '用户',
status: 'Success',
},
},
},
{
title: '状态',
dataIndex: 'status',
hideInTable: true,
valueType: 'text',
valueEnum: {
'0': {
text: '正常',
status: 'Success',
},
'1': {
text: '禁用',
status: 'Success',
},
},
},
{
title: '手机号码',
dataIndex: 'phoneNumber',
hideInTable: true,
valueType: 'text',
},
{
title: '最后登录ip',
dataIndex: 'loginIp',
hideInTable: true,
valueType: 'text',
},
{
title: '最后登录时间',
dataIndex: 'loginTime',
hideInTable: true,
valueType: 'text',
sorter: (a, b) => a.loginTime - b.loginTime,
},
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateTime',
hideInForm: true,
sorter: (a, b) => a.createTime - b.createTime,
},
{
title: '备注',
dataIndex: 'remark',
hideInTable: true,
valueType: 'textarea',
},
]
export const UPDATEUSERCOLUMN: ProColumns<UserEntityAPI.UserUpdateRequestParams>[] = [
{
title: 'id',
dataIndex: 'userId',
valueType: 'index',
},
{
title: '用户名',
dataIndex: 'userName',
valueType: 'text',
formItemProps: {
rules: [{
required: true,
message: "请输入用户名",
}]
}
},
{
title: '昵称',
dataIndex: 'nickName',
valueType: 'text',
formItemProps: {
rules: [{
required: true,
message: "请输入姓名",
}]
}
},
{
title: '性别',
dataIndex: 'sex',
hideInTable: false,
valueType: 'text',
valueEnum: {
'0': {
text: '男',
status: 'Success',
},
'1': {
text: '女',
status: 'Success',
},
},
},
{
title: '角色',
dataIndex: 'admin',
hideInForm: true,
valueEnum: {
'true': {
text: '超级管理员',
status: 'Success',
},
'false': {
text: '用户',
status: 'Success',
},
},
},
{
title: '手机号码',
dataIndex: 'phoneNumber',
hideInTable: true,
valueType: 'text',
},
{
title: '邮箱',
dataIndex: 'email',
hideInTable: true,
valueType: 'text',
},
{
title: '状态',
dataIndex: 'status',
hideInTable: true,
valueType: 'text',
valueEnum: {
'0': {
text: '正常',
status: 'Success',
},
'1': {
text: '禁用',
status: 'Success',
},
},
},
{
title: '备注',
dataIndex: 'remark',
hideInTable: true,
valueType: 'textarea',
},
]
/**
* title: '文本',
key: 'text',
dataIndex: 'id',
ellipsis: true,
copyable: true,
*/
export const USERENTITYCOLUMN: ProColumns<UserEntityAPI.UserVO>[] = [
{
title: '用户id',
key: "text",
dataIndex: 'userId',
ellipsis: true,
copyable: true,
},
{
title: '用户名',
dataIndex: 'userName',
valueType: 'text',
},
{
title: '昵称',
dataIndex: 'nickName',
valueType: 'text',
},
{
title: '性别',
dataIndex: 'sex',
hideInTable: false,
valueType: 'text',
valueEnum: {
'0': {
text: '男',
status: 'Success',
},
'1': {
text: '女',
status: 'Success',
},
},
},
{
title: '角色',
key: 'userRole',
dataIndex: 'admin',
valueType: 'select',
valueEnum: {
'true': {
text: '管理员',
status: 'Success',
},
'children': {
text: '用户',
status: 'Success',
},
},
},
{
title: '手机号码',
dataIndex: 'phoneNumber',
hideInTable: false,
valueType: 'text',
},
{
title: '邮箱',
dataIndex: 'email',
hideInTable: false,
valueType: 'text',
},
{
title: '状态',
dataIndex: 'status',
hideInTable: false,
valueType: 'text',
valueEnum: {
'0': {
text: '正常',
status: 'Success',
},
'1': {
text: '禁用',
status: 'Success',
},
},
},
{
title: '创建时间',
dataIndex: 'createTime',
hideInTable: false,
valueType: 'date',
fieldProps: {
format: 'YYYY.MM.DD',
},
},
{
title: '创建人',
dataIndex: 'createBy',
hideInTable: false,
valueType: 'text',
},
{
title: '修改时间',
dataIndex: 'updateTime',
hideInTable: false,
valueType: 'text',
},
{
title: '修改人',
dataIndex: 'updateBy',
hideInTable: false,
valueType: 'text',
},
{
title: '最后登录ip',
dataIndex: 'loginIp',
hideInTable: false,
valueType: 'text',
},
{
title: '最后登录时间',
dataIndex: 'loginTime',
hideInTable: false,
valueType: 'date',
fieldProps: {
format: 'YYYY.MM.DD',
},
},
{
title: '备注',
dataIndex: 'remark',
hideInTable: false,
valueType: 'textarea',
},
]
API接口
用户接口
src\services\user\userController.ts
import { request } from '@umijs/max';
/** listUserVOByPage POST /api/user/list */
export async function listUserVOByPageUsingGET(
params: UserEntityAPI.BaseUserRequestPageParams,
options?: { [key: string]: any },
): Promise<UserEntityAPI.BaseResponsePageUserVO> {
return request<UserEntityAPI.BaseResponsePageUserVO>('/api/user/list', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: params,
...(options || {}),
});
}
/** addUser POST /api/user/add */
export async function addUserByUsingPOST(
body: UserEntityAPI.userAddRquestParams,
options?: { [key: string]: any }) {
return request<UserEntityAPI.BaseResponse>('/api/user/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** deleteUser POST /api/user/delete */
export async function deleteUserByUsingPOST(
body: UserEntityAPI.DeleteRequestParams,
options?: { [key: string]: any },
) {
return request<UserEntityAPI.BaseResponse>('/api/user/del', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** updateUser POST /api/user/update */
export async function updateUserByUsingPOST(
body: UserEntityAPI.UserUpdateRequestParams,
options?: { [key: string]: any },
) {
return request<UserEntityAPI.BaseResponse>('/api/user/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** updateUser POST /api/user/update */
export async function updateUserPasswordByUsingPOST(
body: UserEntityAPI.UpdatePasswordRequestParams,
options?: { [key: string]: any },
) {
return request<UserEntityAPI.BaseResponse>('/api/profile/updatePwd', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
export async function updateProfileByUsingPOST(
body: UserEntityAPI.UserUpdateRequestParams,
options?: { [key: string]: any },
) {
return request<UserEntityAPI.BaseResponse>('/api/profile/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
类型
src\services\user\typings.d.ts
/**
* @description 用户管理
*/
declare namespace UserEntityAPI {
/**
* 基本请求响应参数
*/
type BaseResponse = {
code?: number;
data?: any;
msg?: string;
};
/**
* 用户分页请求参数
* @name BaseUserRequestPageParams
* @description 用户分页请求参数
* @typedef BaseUserRequestPageParams
* @property {Integer} id - 用户ID
* @property {string} userId - 用户ID
*/
type BaseUserRequestPageParams = {
pageSize?: number;
pageNum?: number;
orderByColumn?: string;
isAsc?: string;
id?: number;
userId?: string;
userName?: string;
userType?: string;
nickName?: string;
phoneNumber?: string;
email?: string;
}
/**
* userList
* @name userList
* @description 获取用户列表
* @request GET:/api/user/list
* @response `200` `userList`
* @throws 400
* @throws 500
* @throws default
*/
export type BaseResponsePageUserVO = {
data?: UserVO[];
total?: number;
code?: number;
msg?: string;
}
/**
* 分页查询参数
* @name PageParams
* @description 分页查询参数
* @typedef PageParams
* @property {Integer} pageSize - 分页大小
* @property {Integer} pageNum - 当前页数
* @property {string} orderByColumn - 排序列
* @property {string} isAsc - 排序的方向desc或者asc
*/
type PageParams = {
pageSize?: Integer;
pageNum?: Integer;
// orderByColumn?: string;
// isAsc?: string;
};
/**
* 查询用户个人信息
* @name userInfo
* @description 查询用户个人信息
*/
type UserVO = {
avatar?: string;
createBy?: string;
createTime?: Date;
delFlag?: string;
email?: string;
loginIp?: string;
loginTime?: Date;
nickName?: string;
phoneNumber?: string;
remark?: string;
sex?: string;
status?: string;
updateBy?: string;
updateTime?: string;
userId?: number;
userName?: string;
userType?: string;
roles: any;
roleIds: string[];
roleId: string;
admin: boolean;
};
/**
* 用户添加参数
* @name userAddParams
* @description 用户添加参数
* @typedef userAddParams
* @property {Integer} userId - 用户ID
* @property {string} userName - 用户名
* @property {string} userType - 用户类型
* @property {string} nickName - 昵称
* @property {string} phoneNumber - 手机号
* @property {string} email - 邮箱
* @property {string} avatar - 头像
* @property {string} createBy - 创建者
* @property {Date} createTime - 创建时间
*/
export type userAddRquestParams = {
userId?: number;
userName?: string;
userType?: string;
nickName?: string;
phoneNumber?: string;
email?: string;
avatar?: string;
// createBy?: string;
// createTime?: string;
delFlag?: string;
// loginIp?: string;
// loginTime?: Date;
remark?: string;
sex?: string;
status?: string;
// updateBy?: string;
// updateTime?: string;
}
/**
* 删除用户请求参数
* @name DeleteRequest
* @description 删除用户请求参数
* @typedef DeleteRequest
* @property {Integer} id - 用户ID
*/
type DeleteRequestParams = {
userId?: number;
};
// type DeleteRequestParams = {
// userIds?: number[];
// };
/**
* 更新用户请求参数
* @name UserUpdateRequestParams
* @description 更新用户请求参数
*/
type UserUpdateRequestParams = {
userId?: number;
userName?: string;
userType?: string;
nickName?: string;
phoneNumber?: string;
email?: string;
avatar?: string;
// createBy?: string;
// createTime?: Date;
delFlag?: string;
// loginIp?: string;
// loginTime?: Date;
remark?: string;
sex?: string;
};
/**
* 修改密码请求参数
* @name UpdatePasswordRequestParams
* @description 修改密码请求参数
* @typedef UpdatePasswordRequestParams
* @property {string} oldPassword - 旧密码
* @property {string} newPassword - 新密码
*/
type UpdatePasswordRequestParams = {
oldPassword?: string;
newPassword?: string;
newPasswordAgain?: string;
};
/**
* --------------------------------------example----------------------------------------------------
*/
}
src\services\user\index.ts
import * as userController from './userController';
export default {
userController,
};
效果图
查看详情:
新增:
修改: