【图文并茂】ant design pro 如何优雅地实现查询列表功能

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图所示,这种查询如何去实现好呢?

前端

首先,在 index.tsx 中,只要不禁用查询,一般都会有

 const columns: ProColumns<API.ItemData>[] = [
    {
      title: intl.formatMessage({ id: 'email' }),
      dataIndex: 'email',
      copyable: true,
      renderFormItem: (item, { ...rest }) => {
        return <ProFormText {...rest} placeholder={intl.formatMessage({ id: 'enter_email' })} />;
      },
      render: (dom, entity) => {
        return (
          <a
            onClick={() => {
              setCurrentRow(entity);
              setShowDetail(true);
            }}
          >
            {dom}
          </a>
        );
      },
    },
    {
      title: intl.formatMessage({ id: 'name' }),
      dataIndex: 'name',
      renderFormItem: (item, { ...rest }) => {
        return <ProFormText {...rest} placeholder={intl.formatMessage({ id: 'enter_name' })} />;
      },
    },
    {
      title: intl.formatMessage({ id: 'isAdmin' }),
      dataIndex: 'isAdmin',
      hideInSearch: true,
      render: (text) => (
        <span>{text ? intl.formatMessage({ id: 'yes' }) : intl.formatMessage({ id: 'no' })}</span>
      ),
    },
    {
      title: intl.formatMessage({ id: 'role' }),
      dataIndex: 'roles',
      hideInSearch: true,
      renderText: (_, record: any) => {
        return record.roles?.map((role: Role) => role.name)?.join(', ');
      },
    },
    {
      title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="Operating" />,
      dataIndex: 'option',
      valueType: 'option',
      render: (_, record) => [
        access.canSuperAdmin && (
          <a
            key="edit"
            onClick={() => {
              // Replace `handleUpdateModalOpen` and `setCurrentRow` with your actual functions
              handleUpdateModalOpen(true);
              setCurrentRow(record);
            }}
          >
            {intl.formatMessage({ id: 'edit' })}
          </a>
        ),
        access.canSuperAdmin && (
          <DeleteLink
            onOk={async () => {
              await handleRemove([record._id!]);
              setSelectedRows([]);
              actionRef.current?.reloadAndRest?.();
            }}
          />
        ),
      ],
    },
  ];

只要不使用 hideInSearch: true, 一般都会出现搜索框

这是其一

第二,是以 dataIndex: ‘email’, 这个作为搜索的 key

在这里插入图片描述
其三,是跟默认进来的列表页用的是同一个接口,无外乎多加了一点查询参数

   request={async (params, sort, filter) => queryList('/users', params, sort, filter)}

请求地址对了,参数对了,请求方法对了。

就来关注下后端

后端

const getUsers = handleAsync(async (req: Request, res: Response) => {
  const { email, name, live, current = '1', pageSize = '10' } = req.query;

  const query: any = {};

  if (email) {
    query.email = email;
  }

  if (name) {
    query.name = { $regex: name, $options: 'i' };
  }

  if (live) {
    query.live = live === 'true';
  }

  // 执行查询
  const users = await User.find({
    ...query,
  })
    .populate('roles')
    .sort('-createdAt') // Sort by creation time in descending order
    .skip((+current - 1) * +pageSize)
    .limit(+pageSize)
    .exec();

  const total = await User.countDocuments({
    ...query,
  }).exec();

  res.json({
    success: true,
    data: users.map((user) => exclude(user.toObject(), 'password')),
    total,
    current: +current,
    pageSize: +pageSize,
  });
});

后端主要从 req.query 拿到请求参数即可

去数据库查一下就好。

优雅实现

但是一般这个地方,查询这里,以我的经验,有时候会多次利用

比如做导出功能,做删除功能时

所以要重构一下

类似这个:

const getMenus = handleAsync(async (req: Request, res: Response) => {
  const { current = '1', pageSize = '10' } = req.query;

  const query = buildQuery(req.query);

  // 执行查询
  const menus = await Menu.find(query)
    .populate('permission')
    .populate('parent') // 填充 parent 字段
    .sort('-createdAt') // Sort by creation time in descending order
    .skip((+current - 1) * +pageSize)
    .limit(+pageSize)
    .exec();

  const total = await Menu.countDocuments(query).exec();

  // 获取所有菜单及其子菜单
  const menusWithChildren = await Promise.all(
    menus.map(async (menu) => {
      const menuWithChildren = menu.toObject();
      menuWithChildren.children = await getChildren(menu._id);
      return menuWithChildren;
    }),
  );

  res.json({
    success: true,
    data: menusWithChildren,
    total,
    current: +current,
    pageSize: +pageSize,
  });
});

我用 buildQuery 抽出来所有的查询逻辑

const buildQuery = (queryParams: any): any => {
  const query: any = {};

  if (queryParams.name) {
    query.name = { $regex: queryParams.name, $options: 'i' };
  }

  if (queryParams.path) {
    query.path = { $regex: queryParams.path, $options: 'i' };
  }

  if (queryParams.parent) {
    query.parent = queryParams.parent;
  } else {
    query.parent = null;
  }

  return query;
};

其它地方我就可以调用:

// @desc Get permission menus
// @route GET /api/menus/fetch
// @access Private
const fetchMenus = handleAsync(async (req: RequestCustom, res: Response) => {
  const query = buildQuery(req.query);

  const menus = await Menu.find(query)
    .populate('parent')
    .populate('permission');

  const menusWithChildren = await Promise.all(
    menus.map(async (menu) => {
      const menuWithChildren = menu.toObject();
      menuWithChildren.children = await getChildren(menu._id);
      return menuWithChildren;
    }),
  );

  res.json({
    success: true,
    data: checkMenu(menusWithChildren, req.user),
  });
});

这样是比较好的

获取 ant design pro & nodejs & typescript 多角色权限动态菜单管理系统源码
我正在做的程序员赚钱副业 - Shopify 真实案例技术赚钱营销课视频教程

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员随风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值