feat: add useCampus hook and CampusSwitcher component
This commit is contained in:
36
apps/admin/src/components/CampusSwitcher.tsx
Normal file
36
apps/admin/src/components/CampusSwitcher.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Select, Typography } from 'antd';
|
||||||
|
import { EnvironmentOutlined } from '@ant-design/icons';
|
||||||
|
import { useCampus } from '../hooks/useCampus';
|
||||||
|
|
||||||
|
const CampusSwitcher: React.FC = () => {
|
||||||
|
const { campuses, currentId, switchCampus, loading } = useCampus();
|
||||||
|
|
||||||
|
if (campuses.length <= 1) {
|
||||||
|
return (
|
||||||
|
<Typography.Text style={{ color: '#fff', marginRight: 24 }}>
|
||||||
|
<EnvironmentOutlined style={{ marginRight: 4 }} />
|
||||||
|
{campuses[0]?.name || '主校区'}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
...campuses.map((c) => ({ value: String(c.id), label: c.name })),
|
||||||
|
{ value: '', label: '全部校区' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
value={currentId || undefined}
|
||||||
|
onChange={switchCampus}
|
||||||
|
options={options}
|
||||||
|
loading={loading}
|
||||||
|
style={{ minWidth: 140, marginRight: 24 }}
|
||||||
|
variant="borderless"
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CampusSwitcher;
|
||||||
40
apps/admin/src/hooks/useCampus.ts
Normal file
40
apps/admin/src/hooks/useCampus.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
interface Department {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
parentId: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCampus() {
|
||||||
|
const [campuses, setCampuses] = useState<Department[]>([]);
|
||||||
|
const [currentId, setCurrentId] = useState<string>(
|
||||||
|
() => localStorage.getItem('currentCampusId') || ''
|
||||||
|
);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
const fetchCampuses = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const data = await api.get('/departments') as unknown as Department[];
|
||||||
|
const campusList = data.filter((d) => d.type === 'campus');
|
||||||
|
setCampuses(campusList);
|
||||||
|
if (!currentId && campusList.length > 0) {
|
||||||
|
setCurrentId(String(campusList[0].id));
|
||||||
|
localStorage.setItem('currentCampusId', String(campusList[0].id));
|
||||||
|
}
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
finally { setLoading(false); }
|
||||||
|
}, [currentId]);
|
||||||
|
|
||||||
|
useEffect(() => { fetchCampuses(); }, []);
|
||||||
|
|
||||||
|
const switchCampus = useCallback((id: string) => {
|
||||||
|
setCurrentId(id);
|
||||||
|
localStorage.setItem('currentCampusId', id);
|
||||||
|
window.dispatchEvent(new CustomEvent('campus-changed', { detail: id }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { campuses, currentId, switchCampus, loading };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user