UsersListPage.tsx 2.98 KB
import { useEffect, useState, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Alert, Button, Space } from 'antd';
import { usersApi } from '../../api/users';
import type { UserListItem, UsersListQuery } from '../../api/users';
import { BizError, isBizError } from '../../api/errors';
import { ERROR_MESSAGES } from './usersConstants';
import UsersToolbar from './UsersToolbar';
import UsersFilterBar from './UsersFilterBar';
import type { UsersFilterValues } from './UsersFilterBar';
import UsersTable from './UsersTable';

export default function UsersListPage() {
  const navigate = useNavigate();
  const [query, setQuery] = useState<UsersListQuery>({
    page: 1,
    size: 20,
    sortField: 'tCreateDate',
    sortOrder: 'desc',
  });
  const [records, setRecords] = useState<UserListItem[]>([]);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  const fetchList = useCallback(async (q: UsersListQuery) => {
    setLoading(true);
    setErrorMessage(null);
    try {
      const result = await usersApi.list(q);
      setRecords(result.records);
      setTotal(result.total);
    } catch (e) {
      if (isBizError(e)) {
        if (e.code === -1) setErrorMessage(ERROR_MESSAGES.NETWORK as string);
        else setErrorMessage(e.message || (ERROR_MESSAGES.UNKNOWN as string));
      } else {
        setErrorMessage(ERROR_MESSAGES.UNKNOWN as string);
      }
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    fetchList(query);
  }, [query, fetchList]);

  const handleSearch = (filterValues: UsersFilterValues) => {
    setQuery((prev) => ({
      ...prev,
      page: 1,
      queryField: filterValues.queryField,
      matchMode: filterValues.matchMode,
      queryValue: filterValues.queryValue,
    }));
  };

  const handleReset = () => {
    setQuery({ page: 1, size: query.size });
  };

  const handleRefresh = () => fetchList(query);

  return (
    <div data-testid="users-list-page" style={{ padding: 16, background: 'var(--color-bg-page)' }}>
      <UsersToolbar onRefresh={handleRefresh} onAdd={() => navigate('/users/new')} />
      <UsersFilterBar onSearch={handleSearch} onReset={handleReset} disabled={loading} />
      {errorMessage && (
        <Alert
          type="error"
          message={errorMessage}
          showIcon
          style={{ margin: '12px 0' }}
          action={
            <Space>
              <Button size="small" onClick={handleRefresh}>
                重试
              </Button>
            </Space>
          }
          data-testid="users-list-error"
        />
      )}
      <UsersTable
        records={records}
        loading={loading}
        total={total}
        page={query.page ?? 1}
        size={query.size ?? 20}
        onRowClick={(row) => navigate(`/users/${row.userId}`)}
        onPageChange={(page, size) => setQuery((prev) => ({ ...prev, page, size }))}
      />
    </div>
  );
}