feat: classroom status filter + export button + menu (departments/notifications)

This commit is contained in:
2026-07-06 14:43:13 +08:00
parent fb6d99266e
commit 4b02012634
3 changed files with 48 additions and 7 deletions

View File

@@ -24,6 +24,7 @@ import {
KeyOutlined,
CheckCircleOutlined,
LaptopOutlined,
BellOutlined,
} from '@ant-design/icons';
import { usePermission } from '../hooks/usePermission';
import NotificationBell from '../components/NotificationBell';
@@ -107,6 +108,8 @@ const allMenuItems: MenuItemType[] = [
label: '系统管理',
permission: 'log:view',
children: [
{ key: '/departments', icon: <HomeOutlined />, label: '校区/部门', permission: 'department:view' },
{ key: '/notifications', icon: <BellOutlined />, label: '通知中心', permission: 'notification:view' },
{ key: '/operation-logs', icon: <AuditOutlined />, label: '操作日志', permission: 'log:view' },
{ key: '/roles', icon: <SafetyOutlined />, label: '角色管理', permission: 'role:view' },
{ key: '/permissions', icon: <KeyOutlined />, label: '权限一览', permission: 'role:view' },

View File

@@ -52,14 +52,14 @@ const ClassroomsPage: React.FC = () => {
const [showArchived, setShowArchived] = useState(false);
const [form] = Form.useForm();
const [searchText, setSearchText] = useState('');
const [filterStatus, setFilterStatus] = useState<string | undefined>(undefined);
const filteredData = useMemo(() => {
if (!searchText) return data;
const s = searchText.toLowerCase();
return data.filter(
(d: any) => d.name?.toLowerCase().includes(s) || d.building?.toLowerCase().includes(s),
);
}, [data, searchText]);
let result = data;
if (searchText) { const s = searchText.toLowerCase(); result = result.filter((d: Record<string, unknown>) => (typeof d.name === 'string' && d.name.toLowerCase().includes(s)) || (typeof d.building === 'string' && d.building.toLowerCase().includes(s))); }
if (filterStatus) result = result.filter((d: Record<string, unknown>) => d.status === filterStatus);
return result;
}, [data, searchText, filterStatus]);
const fetchData = async () => {
setLoading(true);
@@ -223,6 +223,7 @@ const ClassroomsPage: React.FC = () => {
if (!e.target.value) setSearchText('');
}}
/>
<Select placeholder="状态" allowClear style={{ width: 110 }} value={filterStatus} onChange={setFilterStatus} options={[{value:'available',label:'可用'},{value:'in_use',label:'使用中'},{value:'maintenance',label:'维护中'}]} />
<Button
type={showArchived ? 'primary' : 'default'}
onClick={() => setShowArchived(!showArchived)}
@@ -243,6 +244,7 @@ const ClassroomsPage: React.FC = () => {
>
</PermissionButton>
<PermissionButton permission="classroom:view" icon={<DownloadOutlined />} onClick={() => { const baseURL = '/api'; const token = localStorage.getItem('token'); fetch(`${baseURL}/classrooms/export`, { headers: { Authorization: `Bearer ${token}` } }).then(r => r.blob()).then(b => { const a = document.createElement('a'); a.href = URL.createObjectURL(b); a.download = '教室使用报表.xlsx'; a.click(); }); }}></PermissionButton>
<Upload
accept=".xlsx,.xls"
showUploadList={false}