上一节 【图文并茂】ant design pro 如何统一封装好 ProFormSelect 的查询请求
这一节的内容会利用上一篇文章的内容的。
我们经常会实现一个远程数据调用的 select 框,不过有时候这个 select 是有层级的。
就像我们这个分类一样,有父分类,子分类的。
多层级。
怎么处理呢?
还是先实现后端。
后端
数据结构:
c
const permissionGroupSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
parent: { type: mongoose.Schema.Types.ObjectId, ref: 'PermissionGroup' },
},
{ timestamps: true },
);
我这里只存了一个 parent ,就是上一级
这样就能找到所有关联关系,比如当前的所有的 children
你要存 children 也行,但是操作起来会复杂,但查询变得简单。
我的数据量很小,只存 parent 就够用的。
controller
c
onst getPermissionGroups = handleAsync(async (req: Request, res: Response) => {
const { current = '1', pageSize = '10' } = req.query;
const query = buildQuery(req.query);
// 执行查询
const permissionGroups = await PermissionGroup.find(query)
.populate('parent') // Assuming you want to populate parent
.sort('-createdAt') // Sort by creation time in descending order
.skip((+current - 1) * +pageSize)
.limit(+pageSize)
.exec();
const total = await PermissionGroup.countDocuments(query).exec();
const getChildren = async (parentId: string | null): Promise<any[]> => {
const children = await PermissionGroup.find({ parent: parentId })
.populate('parent')
.exec();
return Promise.all(
children.map(async (child) => ({
...child.toObject(),
children: await getChildren(child._id),
})),
);
};
const getPermissionGroupsWithChildren = async (
permissionGroups: any[],
): Promise<any[]> => {
return Promise.all(
permissionGroups.map(async (permissionGroup) => ({
...permissionGroup.toObject(),
children: await getChildren(permissionGroup._id),
})),
);
};
const permissionGroupsWithChildren =
await getPermissionGroupsWithChildren(permissionGroups);
res.json({
success: true,
data: permissionGroupsWithChildren,
total,
current: +current,
pageSize: +pageSize,
});
});
接下来我去遍历循环 children ,把它的内容填充好就行。
响应的数据是这样的:
c
{
"success": true,
"data": [
{
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0,
"children": [
{
"_id": "66b1b00bb5d937a0aef34034",
"name": "权限",
"createdAt": "2024-08-06T05:09:31.292Z",
"updatedAt": "2024-08-10T02:24:41.759Z",
"__v": 0,
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"children": []
},
{
"_id": "66b6d2c9b9ad87dfa985f34f",
"name": "用户",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-10T02:39:05.563Z",
"updatedAt": "2024-08-10T02:39:05.563Z",
"__v": 0,
"children": []
},
{
"_id": "66b6d2ddb9ad87dfa985f362",
"name": "菜单",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-10T02:39:25.628Z",
"updatedAt": "2024-08-10T02:39:25.628Z",
"__v": 0,
"children": []
},
{
"_id": "66b6d2e9b9ad87dfa985f377",
"name": "角色",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-10T02:39:37.339Z",
"updatedAt": "2024-08-10T02:39:37.339Z",
"__v": 0,
"children": []
},
{
"_id": "66b6d2fdb9ad87dfa985f38e",
"name": "数据权限",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-10T02:39:57.756Z",
"updatedAt": "2024-08-10T02:39:57.756Z",
"__v": 0,
"children": []
},
{
"_id": "66b6d314b9ad87dfa985f3a7",
"name": "权限组",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-10T02:40:20.528Z",
"updatedAt": "2024-08-10T02:40:20.528Z",
"__v": 0,
"children": []
},
{
"_id": "66b9ad348554e602536acc67",
"name": "认证管理菜单",
"parent": {
"_id": "66b1b54ef8871ea52a7e3de9",
"name": "认证管理",
"createdAt": "2024-08-06T05:31:58.495Z",
"updatedAt": "2024-08-10T02:24:31.070Z",
"__v": 0
},
"createdAt": "2024-08-12T06:35:32.560Z",
"updatedAt": "2024-08-12T06:35:32.560Z",
"__v": 0,
"children": []
}
]
},
{
"_id": "66adec30d647a4fde5546b1c",
"name": "材料类目",
"createdAt": "2024-08-03T08:37:04.433Z",
"updatedAt": "2024-08-10T02:24:51.188Z",
"__v": 0,
"children": []
}
],
"total": 2,
"current": 1,
"pageSize": 10000
}
name 和 children 是关键。
最后提交给后端的数据肯定是 _id, 因为它才是唯一的。
name 是给用户看的,children 是一个层级关系。
前端
后端搞定了,就要搞前端。
c
import React from 'react';
import { ProFormTreeSelect } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import useQueryList from '@/hooks/useQueryList';
import { Spin } from 'antd';
const PermissionGroupSelect = ({ name, label }: { name: string; label: string }) => {
const intl = useIntl();
const { items: permissionGroups, loading } = useQueryList('/permission-groups');
return (
<Spin spinning={loading}>
<ProFormTreeSelect
name={name}
rules={[{ required: false }]}
width="md"
label={intl.formatMessage({ id: label })}
allowClear
secondary
fieldProps={{
showArrow: false,
treeDefaultExpandAll: true,
filterTreeNode: true,
showSearch: true,
dropdownMatchSelectWidth: false,
autoClearSearchValue: true,
treeNodeFilterProp: 'name',
fieldNames: {
label: 'name',
value: '_id',
children: 'children',
},
treeData: permissionGroups,
}}
/>
</Spin>
);
};
export default PermissionGroupSelect;
主要是有两个东西,一个是 loading
我用的是 Spin 组件
然后是这里:
c
fieldNames: {
label: 'name',
value: '_id',
children: 'children',
},
要跟我的后端响应数据对上的。
其它的没啥,编辑的时候要填充好数据,才能选中。
c
<ProForm
initialValues={{
...values,
parent: values?.parent?._id,
}}
onFinish={async (values) => {
await onFinish({
...values,
});
}}
>
这个地方,跟之前是一样的
完结
- ant design pro 如何去保存颜色
- ant design pro v6 如何做好角色管理
- ant design 的 tree 如何作为角色中的权限选择之一
- ant design 的 tree 如何作为角色中的权限选择之二
- ant design pro access.ts 是如何控制多角色的权限的
- ant design pro 中用户的表单如何控制多个角色
- ant design pro 如何实现动态菜单带上 icon 的
- ant design pro 的表分层级如何处理
- ant design pro 如何处理权限管理
- ant design pro 技巧之自制复制到剪贴板组件
- ant design pro 技巧之实现列表页多标签
- 【图文并茂】ant design pro 如何对接登录接口
- 【图文并茂】ant design pro 如何对接后端个人信息接口
- 【图文并茂】ant design pro 如何给后端发送 json web token - 请求拦截器的使用
- 【图文并茂】ant design pro 如何使用 refresh token 可续期 token 来提高用户体验
- 【图文并茂】ant design pro 如何统一封装好 ProFormSelect 的查询请求