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}

View File

@@ -7,7 +7,7 @@ services:
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-gongxue_2024}
MYSQL_DATABASE: ${DB_DATABASE:-gongxue}
MYSQL_DATABASE: gongxue
MYSQL_CHARSET: utf8mb4
MYSQL_COLLATION: utf8mb4_unicode_ci
ports:
@@ -15,6 +15,42 @@ services:
volumes:
- mysql_data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
backend:
build:
context: .
dockerfile: apps/server/Dockerfile
container_name: gongxue_backend
restart: always
environment:
DB_TYPE: mysql
DB_HOST: mysql
DB_PORT: 3306
DB_USERNAME: root
DB_PASSWORD: ${MYSQL_ROOT_PASSWORD:-gongxue_2024}
DB_DATABASE: gongxue
DB_SYNCHRONIZE: "false"
JWT_SECRET: ${JWT_SECRET:-gongxue-jwt-prod-2026-k3y}
JWT_EXPIRES_IN: 24h
PORT: 3000
depends_on:
mysql:
condition: service_healthy
frontend:
build:
context: .
dockerfile: apps/admin/Dockerfile
container_name: gongxue_frontend
restart: always
ports:
- "9527:80"
depends_on:
- backend
volumes:
mysql_data: