Files
new-api/web/src/components/table/users/UsersTable.jsx
t0ng7u 301909e3e5 📱 feat(ui): Introduce responsive CardTable with mobile card view, dynamic skeletons & pagination
1. Add `web/src/components/common/ui/CardTable.js`
   • Renders Semi-UI `Table` on desktop; on mobile, transforms each row into a rounded `Card`.
   • Supports all standard `Table` props, including `rowSelection`, `scroll`, `pagination`, etc.
   • Adds mobile pagination via Semi-UI `Pagination`.
   • Implements a 500 ms minimum, active Skeleton loader that mimics real column layout (including operation-button row).

2. Replace legacy `Table` with `CardTable`
   • Updated all major data pages: Channels, MJ-Logs, Redemptions, Tokens, Task-Logs, Usage-Logs and Users.
   • Removed unused `Table` imports; kept behaviour on desktop unchanged.

3. UI polish
   • Right-aligned operation buttons and sensitive fields (e.g., token keys) inside mobile cards.
   • Improved Skeleton placeholders to better reflect actual UI hierarchy and preserve the active animation.

These changes dramatically improve the mobile experience while retaining full functionality on larger screens.
2025-07-19 02:27:57 +08:00

175 lines
4.7 KiB
JavaScript

import React, { useMemo, useState } from 'react';
import { Empty } from '@douyinfe/semi-ui';
import CardTable from '../../common/ui/CardTable.js';
import {
IllustrationNoResult,
IllustrationNoResultDark
} from '@douyinfe/semi-illustrations';
import { getUsersColumns } from './UsersColumnDefs';
import PromoteUserModal from './modals/PromoteUserModal';
import DemoteUserModal from './modals/DemoteUserModal';
import EnableDisableUserModal from './modals/EnableDisableUserModal';
import DeleteUserModal from './modals/DeleteUserModal';
const UsersTable = (usersData) => {
const {
users,
loading,
activePage,
pageSize,
userCount,
compactMode,
handlePageChange,
handlePageSizeChange,
handleRow,
setEditingUser,
setShowEditUser,
manageUser,
refresh,
t,
} = usersData;
// Modal states
const [showPromoteModal, setShowPromoteModal] = useState(false);
const [showDemoteModal, setShowDemoteModal] = useState(false);
const [showEnableDisableModal, setShowEnableDisableModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [modalUser, setModalUser] = useState(null);
const [enableDisableAction, setEnableDisableAction] = useState('');
// Modal handlers
const showPromoteUserModal = (user) => {
setModalUser(user);
setShowPromoteModal(true);
};
const showDemoteUserModal = (user) => {
setModalUser(user);
setShowDemoteModal(true);
};
const showEnableDisableUserModal = (user, action) => {
setModalUser(user);
setEnableDisableAction(action);
setShowEnableDisableModal(true);
};
const showDeleteUserModal = (user) => {
setModalUser(user);
setShowDeleteModal(true);
};
// Modal confirm handlers
const handlePromoteConfirm = () => {
manageUser(modalUser.id, 'promote', modalUser);
setShowPromoteModal(false);
};
const handleDemoteConfirm = () => {
manageUser(modalUser.id, 'demote', modalUser);
setShowDemoteModal(false);
};
const handleEnableDisableConfirm = () => {
manageUser(modalUser.id, enableDisableAction, modalUser);
setShowEnableDisableModal(false);
};
// Get all columns
const columns = useMemo(() => {
return getUsersColumns({
t,
setEditingUser,
setShowEditUser,
showPromoteModal: showPromoteUserModal,
showDemoteModal: showDemoteUserModal,
showEnableDisableModal: showEnableDisableUserModal,
showDeleteModal: showDeleteUserModal
});
}, [
t,
setEditingUser,
setShowEditUser,
]);
// Handle compact mode by removing fixed positioning
const tableColumns = useMemo(() => {
return compactMode ? columns.map(col => {
if (col.dataIndex === 'operate') {
const { fixed, ...rest } = col;
return rest;
}
return col;
}) : columns;
}, [compactMode, columns]);
return (
<>
<CardTable
columns={tableColumns}
dataSource={users}
scroll={compactMode ? undefined : { x: 'max-content' }}
pagination={{
currentPage: activePage,
pageSize: pageSize,
total: userCount,
pageSizeOpts: [10, 20, 50, 100],
showSizeChanger: true,
onPageSizeChange: handlePageSizeChange,
onPageChange: handlePageChange,
}}
loading={loading}
onRow={handleRow}
empty={
<Empty
image={<IllustrationNoResult style={{ width: 150, height: 150 }} />}
darkModeImage={<IllustrationNoResultDark style={{ width: 150, height: 150 }} />}
description={t('搜索无结果')}
style={{ padding: 30 }}
/>
}
className="overflow-hidden"
size="middle"
/>
{/* Modal components */}
<PromoteUserModal
visible={showPromoteModal}
onCancel={() => setShowPromoteModal(false)}
onConfirm={handlePromoteConfirm}
user={modalUser}
t={t}
/>
<DemoteUserModal
visible={showDemoteModal}
onCancel={() => setShowDemoteModal(false)}
onConfirm={handleDemoteConfirm}
user={modalUser}
t={t}
/>
<EnableDisableUserModal
visible={showEnableDisableModal}
onCancel={() => setShowEnableDisableModal(false)}
onConfirm={handleEnableDisableConfirm}
user={modalUser}
action={enableDisableAction}
t={t}
/>
<DeleteUserModal
visible={showDeleteModal}
onCancel={() => setShowDeleteModal(false)}
user={modalUser}
users={users}
activePage={activePage}
refresh={refresh}
manageUser={manageUser}
t={t}
/>
</>
);
};
export default UsersTable;