【图文并茂】ant design pro 如何实战使用 ProFormTreeSelect


上一节 【图文并茂】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,
        });
      }}
    >

这个地方,跟之前是一样的

完结

相关推荐
程序员爱技术1 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会2 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子2 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、2 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜2 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师2 小时前
CSS的三个重点
前端·css
耶啵奶膘4 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^5 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie6 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic6 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js