diff --git a/apps/admin/src/pages/Bills/index.tsx b/apps/admin/src/pages/Bills/index.tsx index 9d65c08..a5f14b7 100644 --- a/apps/admin/src/pages/Bills/index.tsx +++ b/apps/admin/src/pages/Bills/index.tsx @@ -13,6 +13,7 @@ import { Select, Tooltip, Spin, + Empty, } from 'antd'; import { FileTextOutlined, @@ -54,6 +55,7 @@ const BillsPage: React.FC = () => { const [generateForm] = Form.useForm(); const [saving, setSaving] = useState(false); const [detailLoading, setDetailLoading] = useState(false); + const [batchLoading, setBatchLoading] = useState(false); const fetchData = useCallback(async () => { setLoading(true); @@ -63,8 +65,8 @@ const BillsPage: React.FC = () => { if (filterExpenseType) params.expenseType = filterExpenseType; const res = await api.get('/bills', { params }) as unknown[]; setBills(res); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载失败,请稍后重试'); } setLoading(false); }, [filterStatus, filterExpenseType]); @@ -110,8 +112,9 @@ const BillsPage: React.FC = () => { try { const res = await api.get(`/bills/${id}`); setDetailModal(res); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载详情失败'); + } } finally { setDetailLoading(false); } @@ -132,6 +135,7 @@ const BillsPage: React.FC = () => { const batchUpdateStatus = async (status: string) => { if (selectedRows.length === 0) return message.warning('请先选择账单'); + setBatchLoading(true); try { await api.put('/bills/batch/status', { ids: selectedRows, status }); message.success(`已批量更新 ${selectedRows.length} 条账单`); @@ -139,6 +143,8 @@ const BillsPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '操作失败'); + } finally { + setBatchLoading(false); } }; @@ -151,9 +157,9 @@ const BillsPage: React.FC = () => { message.error(e?.message || '删除失败'); } }; - const batchDelete = async () => { if (selectedRows.length === 0) return message.warning('请先选择账单'); + setBatchLoading(true); try { await api.post('/bills/batch/delete', { ids: selectedRows }); message.success(`已删除 ${selectedRows.length} 条账单`); @@ -161,6 +167,8 @@ const BillsPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '操作失败'); + } finally { + setBatchLoading(false); } }; @@ -334,6 +342,7 @@ const BillsPage: React.FC = () => { permission="bill:confirm" onClick={() => batchUpdateStatus('confirmed')} disabled={selectedRows.length === 0} + loading={batchLoading} > 批量确认 @@ -342,6 +351,7 @@ const BillsPage: React.FC = () => { type="primary" onClick={() => batchUpdateStatus('paid')} disabled={selectedRows.length === 0} + loading={batchLoading} > 批量标记已付 @@ -357,6 +367,7 @@ const BillsPage: React.FC = () => { danger disabled={selectedRows.length === 0} icon={} + loading={batchLoading} > 批量删除 @@ -389,6 +400,7 @@ const BillsPage: React.FC = () => { dataSource={filteredBills} rowKey="id" loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} rowSelection={{ selectedRowKeys: selectedRows, diff --git a/apps/admin/src/pages/Classes/index.tsx b/apps/admin/src/pages/Classes/index.tsx index d77bcb0..c5930b3 100644 --- a/apps/admin/src/pages/Classes/index.tsx +++ b/apps/admin/src/pages/Classes/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState, useMemo, useCallback } from 'react'; import { Table, Button, Input, Select, Space, Tag, Modal, Form, InputNumber, - DatePicker, Popconfirm, message, Card, Switch, + DatePicker, Popconfirm, message, Card, Switch, Empty, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { PlusOutlined, SearchOutlined, TeamOutlined, InboxOutlined } from '@ant-design/icons'; @@ -98,8 +98,9 @@ const ClassesPage: React.FC = () => { params.isArchived = showArchived; const res = await api.get('/classes', { params } as Record); setData(res); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载失败,请稍后重试'); + } } finally { setLoading(false); } @@ -266,6 +267,7 @@ const ClassesPage: React.FC = () => { dataSource={filtered} rowKey="id" loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 20 }} scroll={{ x: 1100 }} /> diff --git a/apps/admin/src/pages/ClassroomRentals/index.tsx b/apps/admin/src/pages/ClassroomRentals/index.tsx index 272e409..de2d3cf 100644 --- a/apps/admin/src/pages/ClassroomRentals/index.tsx +++ b/apps/admin/src/pages/ClassroomRentals/index.tsx @@ -14,6 +14,7 @@ import { Popconfirm, Upload, Tooltip, + Empty, } from 'antd'; import { PlusOutlined, UploadOutlined, DeleteOutlined, FileTextOutlined } from '@ant-design/icons'; import dayjs, { Dayjs } from 'dayjs'; @@ -50,8 +51,8 @@ const ClassroomRentalsPage: React.FC = () => { if (filterMonth) params.month = filterMonth.format('YYYY-MM'); const res: any = await api.get('/classroom-rentals', { params }); setData(res); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载失败,请稍后重试'); } setLoading(false); }; @@ -61,8 +62,8 @@ const ClassroomRentalsPage: React.FC = () => { const [cr, tn]: any = await Promise.all([api.get('/classrooms'), api.get('/tenants')]); setClassrooms(cr); setTenants(tn); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载教室列表失败'); } }; @@ -311,10 +312,10 @@ const ClassroomRentalsPage: React.FC = () => { dataSource={filteredData} rowKey="id" loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} scroll={{ x: 1200 }} /> - { params: { year: month.year(), month: month.month() + 1 }, }); setData(res); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, [month]); @@ -85,8 +87,9 @@ const ClassroomSchedulePage: React.FC = () => { try { const res: any = await api.get(`/classroom-rentals/${rentalId}`); setDetailModal(res); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载详情失败'); } }; diff --git a/apps/admin/src/pages/Classrooms/index.tsx b/apps/admin/src/pages/Classrooms/index.tsx index c819eaf..e0e7f32 100644 --- a/apps/admin/src/pages/Classrooms/index.tsx +++ b/apps/admin/src/pages/Classrooms/index.tsx @@ -13,6 +13,7 @@ import { Popconfirm, Upload, Tooltip, + Empty, } from 'antd'; import { PlusOutlined, @@ -69,8 +70,8 @@ const ClassroomsPage: React.FC = () => { try { const res: any = await api.get('/classrooms', { params: { includeArchived: showArchived } }); setData(res); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载失败,请稍后重试'); } setLoading(false); }; @@ -287,9 +288,9 @@ const ClassroomsPage: React.FC = () => { dataSource={filteredData} rowKey="id" loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 20, showTotal: (total) => `共 ${total} 条` }} /> - { const [roomRanking, setRoomRanking] = useState>([]); const [classroomUtil, setClassroomUtil] = useState(null); const [loading, setLoading] = useState(true); + const [refreshLoading, setRefreshLoading] = useState(false); const [period, setPeriod] = useState<[string, string]>([ dayjs().startOf('month').format('YYYY-MM-DD'), dayjs().endOf('month').format('YYYY-MM-DD'), ]); const fetchData = useCallback(async () => { - setLoading(true); + const isRefresh = stats !== null; + if (isRefresh) { + setRefreshLoading(true); + } else { + setLoading(true); + } try { const [s, rr, cr, g] = await Promise.all([ api.get('/dashboard/stats'), @@ -114,7 +120,8 @@ const DashboardPage: React.FC = () => { message.error('数据加载失败,请稍后重试'); } setLoading(false); - }, [period]); + setRefreshLoading(false); + }, [period, stats]); useEffect(() => { fetchData(); @@ -321,7 +328,7 @@ const DashboardPage: React.FC = () => { gap: 12, }} > -

数据面板

+

数据面板{refreshLoading && }

{ const [d, s]: any[] = await Promise.all([api.get('/deposits'), api.get('/students')]); setData(d); setStudents(s); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载失败,请稍后重试'); } setLoading(false); }; @@ -86,8 +87,8 @@ const DepositsPage: React.FC = () => { try { const res = await api.get('/deposits/pending-refunds'); setPendingRefunds(res || []); - } catch (e) { - console.error(e); + } catch (e: any) { + message.error(e?.message || '加载待退款列表失败'); } setPendingLoading(false); }; @@ -436,10 +437,10 @@ const DepositsPage: React.FC = () => { dataSource={filteredData} rowKey="id" loading={loading} + locale={{ emptyText: }} scroll={{ x: 1200 }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} /> - ), }, { diff --git a/apps/admin/src/pages/Expenses/index.tsx b/apps/admin/src/pages/Expenses/index.tsx index 96d5e7f..8438bd2 100644 --- a/apps/admin/src/pages/Expenses/index.tsx +++ b/apps/admin/src/pages/Expenses/index.tsx @@ -14,6 +14,7 @@ import { Tabs, Popconfirm, Upload, + Empty, } from 'antd'; import { PlusOutlined, @@ -51,6 +52,7 @@ const ExpensesPage: React.FC = () => { const [selectedRoomKeys, setSelectedRoomKeys] = useState([]); const [selectedPersonalKeys, setSelectedPersonalKeys] = useState([]); const [saving, setSaving] = useState(false); + const [batchLoading, setBatchLoading] = useState(false); // Dynamic expense type options from API const [typeOptions, setTypeOptions] = useState<{ value: string; label: string }[]>([]); @@ -78,6 +80,7 @@ const ExpensesPage: React.FC = () => { }, []); const handleBatchDeleteRoom = async () => { + setBatchLoading(true); try { const res: any = await api.post('/expenses/room/batch-delete', { ids: selectedRoomKeys }); message.success(res?.message || `已删除 ${selectedRoomKeys.length} 条`); @@ -85,10 +88,13 @@ const ExpensesPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量删除失败'); + } finally { + setBatchLoading(false); } }; const handleBatchDeletePersonal = async () => { + setBatchLoading(true); try { const res: any = await api.post('/expenses/personal/batch-delete', { ids: selectedPersonalKeys, @@ -98,6 +104,8 @@ const ExpensesPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量删除失败'); + } finally { + setBatchLoading(false); } }; @@ -114,8 +122,9 @@ const ExpensesPage: React.FC = () => { setPersonalExpenses(pe); setRooms(rm); setStudents(st); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, []); @@ -410,6 +419,7 @@ const ExpensesPage: React.FC = () => { danger icon={} disabled={selectedRoomKeys.length === 0} + loading={batchLoading} > 批量删除 @@ -433,6 +443,7 @@ const ExpensesPage: React.FC = () => { dataSource={filteredRoomExpenses} rowKey="id" loading={loading} + locale={{ emptyText: }} scroll={{ x: 1200 }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} rowSelection={{ @@ -440,7 +451,6 @@ const ExpensesPage: React.FC = () => { onChange: (keys) => setSelectedRoomKeys(keys as number[]), }} /> - ), }, { @@ -532,6 +542,7 @@ const ExpensesPage: React.FC = () => { danger icon={} disabled={selectedPersonalKeys.length === 0} + loading={batchLoading} > 批量删除 @@ -549,12 +560,12 @@ const ExpensesPage: React.FC = () => { 录入个人费用 - }} scroll={{ x: 1200 }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} rowSelection={{ diff --git a/apps/admin/src/pages/Occupancies/index.tsx b/apps/admin/src/pages/Occupancies/index.tsx index d0adc2a..8f86cc5 100644 --- a/apps/admin/src/pages/Occupancies/index.tsx +++ b/apps/admin/src/pages/Occupancies/index.tsx @@ -14,8 +14,8 @@ import { Popconfirm, Upload, Switch, - Alert, Tooltip, + Empty, } from 'antd'; import { PlusOutlined, @@ -50,6 +50,7 @@ const OccupanciesPage: React.FC = () => { const [batchCheckOutModal, setBatchCheckOutModal] = useState(false); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [saving, setSaving] = useState(false); + const [batchLoading, setBatchLoading] = useState(false); const [checkInForm] = Form.useForm(); const [checkOutForm] = Form.useForm(); const [transferForm] = Form.useForm(); @@ -187,6 +188,7 @@ const OccupanciesPage: React.FC = () => { const handleBatchCheckOut = async () => { const values = await batchCheckOutForm.validateFields(); + setBatchLoading(true); try { const res: any = await api.post('/occupancies/batch-check-out', { ids: selectedRowKeys, @@ -201,10 +203,13 @@ const OccupanciesPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量退宿失败'); + } finally { + setBatchLoading(false); } }; const handleBatchDelete = async () => { + setBatchLoading(true); try { const res: any = await api.post('/occupancies/batch-delete', { ids: selectedRowKeys }); message.success(res?.message || `已删除 ${selectedRowKeys.length} 条`); @@ -212,6 +217,8 @@ const OccupanciesPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量删除失败'); + } finally { + setBatchLoading(false); } }; @@ -447,6 +454,7 @@ const OccupanciesPage: React.FC = () => { setBatchCheckOutModal(true); }} style={{ marginLeft: 12 }} + loading={batchLoading} > 批量退宿 @@ -463,6 +471,7 @@ const OccupanciesPage: React.FC = () => { size="small" icon={} style={{ marginLeft: 12 }} + loading={batchLoading} > 批量删除 @@ -482,12 +491,11 @@ const OccupanciesPage: React.FC = () => { dataSource={filteredData} rowKey="id" loading={loading} + locale={{ emptyText: }} scroll={{ x: 1300 }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} rowSelection={rowSelection} /> - - {/* 入住登记弹窗 */} { const res: any = await api.get('/operation-logs', { params }); setData(res.data); setTotal(res.total); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, [page, filterModule, dateRange]); diff --git a/apps/admin/src/pages/Permissions/index.tsx b/apps/admin/src/pages/Permissions/index.tsx index 1d2f644..de742bb 100644 --- a/apps/admin/src/pages/Permissions/index.tsx +++ b/apps/admin/src/pages/Permissions/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Card, Tag, Input, Space, Spin, Empty } from 'antd'; +import { Card, Tag, Input, Space, Spin, Empty, message } from 'antd'; import api from '../../api'; interface PermissionItem { @@ -36,7 +36,10 @@ const PermissionsPage: React.FC = () => { api .get('/rbac/permissions/tree') .then((res: any) => setPermTree(res)) - .catch(console.error) + .catch((e: unknown) => { + const err = e as { message?: string }; + message.error(err?.message || '加载权限失败'); + }) .finally(() => setLoading(false)); }, []); diff --git a/apps/admin/src/pages/Roles/index.tsx b/apps/admin/src/pages/Roles/index.tsx index 41e08db..596ff24 100644 --- a/apps/admin/src/pages/Roles/index.tsx +++ b/apps/admin/src/pages/Roles/index.tsx @@ -10,6 +10,7 @@ import { message, Card, Checkbox, + Empty, } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; import api from '../../api'; @@ -52,8 +53,9 @@ const RolesPage: React.FC = () => { ]); setData(roles); setAllPerms(permTree); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, []); @@ -224,10 +226,10 @@ const RolesPage: React.FC = () => {
}} scroll={{ x: 900 }} pagination={false} /> diff --git a/apps/admin/src/pages/RoomVisual/index.tsx b/apps/admin/src/pages/RoomVisual/index.tsx index 4844bb1..b2f2e1a 100644 --- a/apps/admin/src/pages/RoomVisual/index.tsx +++ b/apps/admin/src/pages/RoomVisual/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useCallback } from 'react'; -import { Row, Col, Card, Tag, Select, Statistic, Modal, Spin, Badge, Tooltip, DatePicker, Alert, Button } from 'antd'; +import { Row, Col, Card, Tag, Select, Statistic, Modal, Spin, Badge, Tooltip, DatePicker, Alert, Button, message } from 'antd'; import { HomeOutlined, UserOutlined, CalendarOutlined, BankOutlined, HistoryOutlined, ShopOutlined } from '@ant-design/icons'; import dayjs, { Dayjs } from 'dayjs'; import api from '../../api'; @@ -64,8 +64,9 @@ const RoomVisualPage: React.FC = () => { const params = isHistorical ? { asOf: asOf!.format('YYYY-MM-DD') } : undefined; const res: any = await api.get('/rooms/visual', { params }); setData(res); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, [isHistorical, asOf]); diff --git a/apps/admin/src/pages/Rooms/index.tsx b/apps/admin/src/pages/Rooms/index.tsx index 2fc7278..1896f97 100644 --- a/apps/admin/src/pages/Rooms/index.tsx +++ b/apps/admin/src/pages/Rooms/index.tsx @@ -15,6 +15,7 @@ import { Upload, Drawer, Tabs, + Empty, } from 'antd'; import type { UploadRequestError, UploadRequestOption } from '@rc-component/upload/lib/interface'; import { @@ -88,8 +89,10 @@ const RoomsPage: React.FC = () => { const [lockerForm] = Form.useForm(); const [savingBed, setSavingBed] = useState(false); const [savingLocker, setSavingLocker] = useState(false); + const [batchLoading, setBatchLoading] = useState(false); const handleBatchDelete = async () => { + setBatchLoading(true); try { const res: any = await api.post('/rooms/batch-delete', { ids: selectedRowKeys }); message.success(res?.message || `已批量归档 ${selectedRowKeys.length} 间`); @@ -97,6 +100,8 @@ const RoomsPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量归档失败'); + } finally { + setBatchLoading(false); } }; @@ -109,8 +114,9 @@ const RoomsPage: React.FC = () => { setArchivedCount(archived.length); const filtered = showArchived ? res : res.filter((r: any) => r.status !== 'archived'); setData(filtered); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }; @@ -162,14 +168,20 @@ const RoomsPage: React.FC = () => { try { const res = await api.get(`/rooms/${roomId}/beds`); setBeds(res); - } catch (e) { console.error(e); } + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载床位失败'); + } }, []); const fetchLockers = useCallback(async (roomId: number) => { try { const res = await api.get(`/rooms/${roomId}/lockers`); setLockers(res); - } catch (e) { console.error(e); } + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载柜子失败'); + } }, []); const handleSaveBed = async () => { @@ -425,7 +437,13 @@ const RoomsPage: React.FC = () => { cancelText="取消" disabled={selectedRowKeys.length === 0} > - } disabled={selectedRowKeys.length === 0}> + } + disabled={selectedRowKeys.length === 0} + loading={batchLoading} + > 批量归档 @@ -486,6 +504,7 @@ const RoomsPage: React.FC = () => { rowKey="id" scroll={{ x: 1200 }} loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 20, showTotal: (total) => `共 ${total} 间` }} rowClassName={(record) => (record.status === 'archived' ? 'archived-row' : '')} rowSelection={{ diff --git a/apps/admin/src/pages/Students/index.tsx b/apps/admin/src/pages/Students/index.tsx index a96cba6..752bd89 100644 --- a/apps/admin/src/pages/Students/index.tsx +++ b/apps/admin/src/pages/Students/index.tsx @@ -17,6 +17,7 @@ import { Card, Drawer, Descriptions, + Empty, } from 'antd'; import { PlusOutlined, @@ -72,6 +73,7 @@ const StudentsPage: React.FC = () => { const [showArchived, setShowArchived] = useState(false); const [archivedCount, setArchivedCount] = useState(0); const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [batchLoading, setBatchLoading] = useState(false); const [enrollmentData, setEnrollmentData] = useState>({}); const [drawerOpen, setDrawerOpen] = useState(false); const [drawerStudentId, setDrawerStudentId] = useState(undefined); @@ -111,6 +113,7 @@ const StudentsPage: React.FC = () => { }; const handleBatchDelete = async () => { + setBatchLoading(true); try { const res: any = await api.post('/students/batch-delete', { ids: selectedRowKeys }); message.success(res?.message || `已批量归档 ${selectedRowKeys.length} 人`); @@ -118,6 +121,8 @@ const StudentsPage: React.FC = () => { fetchData(); } catch (e: any) { message.error(e?.message || '批量归档失败'); + } finally { + setBatchLoading(false); } }; @@ -132,8 +137,9 @@ const StudentsPage: React.FC = () => { const archived = list.filter((r) => r.status === 'archived'); setArchivedCount(archived.length); setData(showArchived ? list : list.filter((r) => r.status !== 'archived')); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, [searchName, showArchived, filterStatus, filterTenantId]); @@ -383,6 +389,7 @@ const StudentsPage: React.FC = () => { danger icon={} disabled={selectedRowKeys.length === 0} + loading={batchLoading} > 批量归档 @@ -441,6 +448,7 @@ const StudentsPage: React.FC = () => { dataSource={data} rowKey="id" loading={loading} + locale={{ emptyText: }} scroll={{ x: 1410 }} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 人` }} rowClassName={(record: any) => (record.status === 'archived' ? 'archived-row' : '')} diff --git a/apps/admin/src/pages/Tenants/index.tsx b/apps/admin/src/pages/Tenants/index.tsx index 80595c0..f460f88 100644 --- a/apps/admin/src/pages/Tenants/index.tsx +++ b/apps/admin/src/pages/Tenants/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useMemo } from 'react'; -import { Table, Modal, Form, Input, Select, Space, message, Tag, Popconfirm } from 'antd'; +import { Table, Modal, Form, Input, Select, Space, message, Tag, Popconfirm, Empty } from 'antd'; import { PlusOutlined, InboxOutlined } from '@ant-design/icons'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; @@ -44,8 +44,9 @@ const TenantsPage: React.FC = () => { try { const res: any = await api.get('/tenants'); setData(res); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }; @@ -195,9 +196,9 @@ const TenantsPage: React.FC = () => { dataSource={filteredData} rowKey="id" loading={loading} + locale={{ emptyText: }} pagination={{ pageSize: 20, showTotal: (total) => `共 ${total} 条` }} /> - { ]); setData(users); setRoles(rolesRes); - } catch (e) { - console.error(e); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '加载失败,请稍后重试'); } setLoading(false); }, [showArchived]);