You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloudspace Design表格过滤与数据总数显示异常问题求助

Cloudscape Design表格数据总数统计与搜索功能冲突问题

问题背景

  • 技术栈:后端NodeJS,前端React + Cloudscape Design
  • 核心矛盾:
    • 后端使用filter方法过滤数据时,前端搜索功能正常,但表格数据总数统计异常
    • 移除filter方法后,总数显示正常,但搜索栏无法实现自由文本搜索
  • 当前状态:数据可正常获取并渲染,仅总数统计与搜索功能无法同时正常工作

后端现有代码

const takeAllUsers = async ()=>{
    const res = await getUsers();
    const users = res.data.getAllUsers.result.map((item: any) => {
        if (item.enabled)
            return {id: item.email,
                firstName: item.givenName,
                lastName: item.familyName,
                email: item.email,
                mobileNumber: item.phoneNumber,
                role: item.userRoles.toString(),
                profilePicture: item.profilePicture,
                status: item.enabled ? 'OK' : 'ERROR',
                customerId: item.customerId
            };
    }).filter((i:any) => i);
    setUserLoading(false);
    setAllUsers(users);
};

前端现有代码

import * as React from 'react';
import Layout from '../Layout/layout';
import Table from '../Customers/components/CustomTable';
import { SpaceBetween,TableProps, Link, StatusIndicator, StatusIndicatorProps, 
  CollectionPreferencesProps} from '@cloudscape-design/components';
import UpdateUser from './components/UpdateUser';
import DeleteUser from './components/DeleteUser';
import InviteNewUser from './components/InviteNewUser';
import UsersType from '../../configs/types/Users';
import { userContext } from '../../UserContext/UserContext';
import { UserContextType } from '../../configs/types/UserContextType';

type InstanceState = 'OK' | 'ERROR';
const columnLabel = (column: string) => (sortState: TableProps.LabelData) => {
  const ascending = !sortState.descending;
  return `${column}, ${sortState.sorted ? `sorted ${ascending ? 'ascending' : 'descending'}` : 'not sorted'}.`;
};

const stateToStatusIndicator: Record<InstanceState, StatusIndicatorProps> = {
  OK: { type: 'success', children: 'Active' },
  ERROR: { type: 'error', children: 'Disabled' },
};

const visibleContentOptions: 
ReadonlyArray<CollectionPreferencesProps.VisibleContentOptionsGroup> = [
{
    label: 'Instance properties',
    options: [
        {
            id: 'id',
            label: 'ID',
            editable: false,
        },
        {
            id: 'firstName',
            label: 'First Name',
        },
        { id: 'type', label: 'Type' },
        {
            id: 'lastName',
            label: 'Last Name',
        },
        {
            id: 'email',
            label: 'Email',
        },
        {
            id: 'mobileNumber',
            label: 'Mobile Number',
        },
        {
            id: 'officeAddress',
            label: 'Office Address',
        },
        {
            id: 'role',
            label: 'Role',
        },
        {
            id: 'profilePicture',
            label: 'Profile Picture',
        }
    ],
  },
];

const Users: React.FC = () => {    
  const { takeAllUsers,allUsers } = React.useContext(userContext) as UserContextType;
  const columnsConfig: TableProps.ColumnDefinition<UsersType>[] = [
    {
        id: 'id',
        header: 'ID',
        cell: item => <Link href={`#${item.id}`}>{item.id}</Link>,
        ariaLabel: columnLabel('id'),
        sortingField: 'id',
    },
    
    {
        id: 'firstName',
        header: 'Name',
        cell: item => item.firstName || '-',
        ariaLabel: columnLabel('Name'),
        sortingField: 'name',
    },
    { id: 'lastName', header: 'Last Name', cell: item => item.lastName, ariaLabel: columnLabel('lastName'), sortingField: 'lastName' },
    { id: 'email', header: 'Email', cell: item => item.email, ariaLabel: columnLabel('email'), sortingField: 'email' },
    { id: 'mobileNumber', header: 'Mobile Number', cell: item => item.mobileNumber, ariaLabel: columnLabel('mobileNumber'), sortingField: 'mobileNumber' },
    { id: 'officeAddress', header: 'Office Address', cell: item => item.officeAdress, ariaLabel: columnLabel('officeAdress'), sortingField: 'officeAdress' },
    { id: 'role', header: 'Roles', cell: item => item.role, ariaLabel: columnLabel('role'), sortingField: 'role' },
    {
        id: 'status',
        header: 'Status',
        cell: item => <StatusIndicator {...stateToStatusIndicator[item.status]} />,
        ariaLabel: columnLabel('state'),
        sortingField: 'status',
    },
    {
        id: 'profilePicture',
        header: 'Image ID',
        cell: item => item.profilePicture,
        ariaLabel: columnLabel('imageId'),
        sortingField: 'imageId',
    }
];

const visibleContent=['id','firstName','lastName','email','mobileNumber','officeAddress','role','status','profilePicture'];
const renderCustomerPage = () => {
    return (

        <React.Fragment>
            <Table 
                TableHeader={
                    <SpaceBetween direction="horizontal" size="xs">
                        <UpdateUser/>
                        <DeleteUser/>
                        <InviteNewUser/>
                    </SpaceBetween>
                }
                columnsConfig={columnsConfig}
                data={allUsers}
                header="User"
                visibleContentOptions={visibleContentOptions}
                takeCustomerList={takeAllUsers}
                visibleContent={visibleContent}
            />
        </React.Fragment>
    );
};

return (
    <>
        <Layout
            header="Users"
            mainContent={renderCustomerPage()}
            items={[
                { text: 'Home', href: '/admin' },
                { text: 'Users', href: '/user'}
            ]}
        />
    </>
  );
};

export default Users;

解决方案

1. 后端调整:分离全量原始数据与过滤后数据

修改takeAllUsers函数,同时保存全量用户数据和过滤后的有效用户数据,既满足搜索需求,又保证表格渲染的是过滤后的列表:

const takeAllUsers = async ()=>{
    const res = await getUsers();
    // 处理所有用户数据,保留原始字段用于后续搜索和过滤
    const allRawUsers = res.data.getAllUsers.result.map((item: any) => ({
        id: item.email,
        firstName: item.givenName,
        lastName: item.familyName,
        email: item.email,
        mobileNumber: item.phoneNumber,
        role: item.userRoles.toString(),
        profilePicture: item.profilePicture,
        status: item.enabled ? 'OK' : 'ERROR',
        customerId: item.customerId,
        enabled: item.enabled // 保留enabled字段用于前端过滤
    }));
    // 过滤出启用状态的用户
    const filteredUsers = allRawUsers.filter(user => user.enabled);
    setUserLoading(false);
    setAllUsers(filteredUsers); // 给表格渲染使用
    setAllRawUsers(allRawUsers); // 保存全量数据用于搜索
};

注意:需要在你的userContext中新增allRawUsers状态以及对应的setAllRawUsers方法。

2. 前端调整:基于全量数据实现搜索过滤

在Users组件中添加搜索状态和过滤逻辑,将搜索结果传递给表格:

const Users: React.FC = () => {    
  const { takeAllUsers, allUsers, allRawUsers } = React.useContext(userContext) as UserContextType;
  const [searchQuery, setSearchQuery] = React.useState('');

  // 基于搜索词过滤全量数据
  const filteredData = React.useMemo(() => {
    if (!searchQuery.trim()) return allUsers;
    const lowerQuery = searchQuery.toLowerCase();
    return allRawUsers.filter(user => 
      user.firstName?.toLowerCase().includes(lowerQuery) ||
      user.lastName?.toLowerCase().includes(lowerQuery) ||
      user.email.toLowerCase().includes(lowerQuery) ||
      user.mobileNumber?.includes(lowerQuery) ||
      user.role.toLowerCase().includes(lowerQuery)
    );
  }, [searchQuery, allRawUsers, allUsers]);

  // ... 保留原有columnsConfig、visibleContent等代码

  const renderCustomerPage = () => {
    return (
        <React.Fragment>
            {/* 添加搜索输入框 */}
            <input 
              type="text" 
              placeholder="搜索用户..." 
              value={searchQuery}
              onChange={(e) => setSearchQuery(e.target.value)}
              style={{ marginBottom: '16px', padding: '8px' }}
            />
            <Table 
                TableHeader={
                    <SpaceBetween direction="horizontal" size="xs">
                        <UpdateUser/>
                        <DeleteUser/>
                        <InviteNewUser/>
                    </SpaceBetween>
                }
                columnsConfig={columnsConfig}
                data={filteredData} // 传入过滤后的搜索结果
                header="User"
                visibleContentOptions={visibleContentOptions}
                takeCustomerList={takeAllUsers}
                visibleContent={visibleContent}
            />
        </React.Fragment>
    );
  };

  // ... 保留原有return代码
};

3. 验证效果

  • 初始状态下,表格显示过滤后的启用用户,总数正确对应allUsers的长度
  • 输入搜索词时,表格会基于全量原始数据过滤,显示匹配结果,总数自动更新为当前搜索结果的数量
  • 搜索功能和总数统计可同时正常工作

内容的提问来源于stack exchange,提问作者Onur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:05:54