feat(admin): 管理端 UI/UX 深度优化——错误/加载/空状态、表单快捷键、移动端适配与无障碍

This commit is contained in:
2026-08-08 15:05:33 +08:00
parent 57639a3869
commit a0829f17ce
54 changed files with 702 additions and 369 deletions

View File

@@ -7,12 +7,13 @@ import api from '../../api';
import PermissionButton from '../../components/PermissionButton';
import EditableCell from '../../components/EditableCell';
import { message } from '../../ui/app-message';
import { RefreshButton } from '../../components/RefreshButton';
import { usePermission } from '../../hooks/usePermission';
import { useApiMutation } from '../../hooks/useApiMutation';
import { validateResponse } from '../../utils/validate';
import { organizationsSchema } from '../../api/schemas';
import { useDirtyGuard } from '../../hooks/useDirtyGuard';
import { QueryEmpty } from '../../components/QueryState';
import { QueryEmpty, QueryErrorState } from '../../components/QueryState';
const PRESET_COLORS = [
'#ff7875',
@@ -59,21 +60,15 @@ const OrganizationsPage: React.FC = () => {
const [searchText, setSearchText] = useState('');
const [filterStatus, setFilterStatus] = useState<string>();
const { data = [], isLoading, isFetching } = useQuery({
const { data = [], isLoading, isFetching, isError, refetch } = useQuery({
queryKey: ['organizations'],
queryFn: async () => {
try {
return validateResponse<OrganizationItem[]>(
organizationsSchema,
await api.get<OrganizationItem[]>('/organizations', {
params: { includeArchived: true },
}),
);
} catch (error: any) {
message.error(error?.message || '机构数据加载失败');
return [];
}
},
queryFn: async () =>
validateResponse<OrganizationItem[]>(
organizationsSchema,
await api.get<OrganizationItem[]>('/organizations', {
params: { includeArchived: true },
}),
),
});
const loading = isLoading || isFetching;
@@ -385,6 +380,7 @@ const OrganizationsPage: React.FC = () => {
]}
/>
</Space>
<RefreshButton loading={isFetching} onRefresh={() => void refetch()} />
<PermissionButton
permission="organization:create"
type="primary"
@@ -394,31 +390,39 @@ const OrganizationsPage: React.FC = () => {
</PermissionButton>
</div>
<Table
columns={columns}
dataSource={filteredData}
rowKey="id"
loading={loading}
locale={{
emptyText: (
<QueryEmpty
description="暂无机构"
action={
hasPermission('organization:create')
? { label: '添加机构', icon: <PlusOutlined />, onClick: () => openEditor() }
: undefined
}
/>
),
}}
scroll={{ x: 1100 }}
pagination={{
defaultPageSize: 20,
showSizeChanger: true,
pageSizeOptions: [20, 50, 100],
showTotal: (total) => `${total} 个机构`,
}}
/>
{isError ? (
<QueryErrorState
title="机构数据加载失败"
description="请检查网络后重试。"
onRetry={() => void refetch()}
/>
) : (
<Table
columns={columns}
dataSource={filteredData}
rowKey="id"
loading={loading}
locale={{
emptyText: (
<QueryEmpty
description="暂无机构"
action={
hasPermission('organization:create')
? { label: '添加机构', icon: <PlusOutlined />, onClick: () => openEditor() }
: undefined
}
/>
),
}}
scroll={{ x: 1100 }}
pagination={{
defaultPageSize: 20,
showSizeChanger: true,
pageSizeOptions: [20, 50, 100],
showTotal: (total) => `${total} 个机构`,
}}
/>
)}
<Modal
title={editing ? `编辑机构 · ${editing.name}` : '添加外部机构'}
open={modalOpen}