feat: add bed/locker selection to check-in form and occupancy table
This commit is contained in:
@@ -54,6 +54,8 @@ const OccupanciesPage: React.FC = () => {
|
||||
const [checkOutForm] = Form.useForm();
|
||||
const [transferForm] = Form.useForm();
|
||||
const [batchCheckOutForm] = Form.useForm();
|
||||
const [availableBeds, setAvailableBeds] = useState<any[]>([]);
|
||||
const [availableLockers, setAvailableLockers] = useState<any[]>([]);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -86,6 +88,25 @@ const OccupanciesPage: React.FC = () => {
|
||||
setSelectedRowKeys([]);
|
||||
}, [fetchData]);
|
||||
|
||||
const handleRoomChange = async (roomId: number) => {
|
||||
checkInForm.setFieldValue('bedId', undefined);
|
||||
checkInForm.setFieldValue('lockerId', undefined);
|
||||
if (!roomId) {
|
||||
setAvailableBeds([]);
|
||||
setAvailableLockers([]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const [beds, lockers] = await Promise.all([
|
||||
api.get(`/rooms/${roomId}/beds/available`),
|
||||
api.get(`/rooms/${roomId}/lockers/available`),
|
||||
]);
|
||||
setAvailableBeds(beds);
|
||||
setAvailableLockers(lockers);
|
||||
if (beds.length === 1) checkInForm.setFieldValue('bedId', beds[0].id);
|
||||
} catch (e) { console.error(e); }
|
||||
};
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!searchText) return data;
|
||||
const keyword = searchText.toLowerCase();
|
||||
@@ -108,6 +129,8 @@ const OccupanciesPage: React.FC = () => {
|
||||
rentalType: values.rentalType,
|
||||
tenantId: values.tenantId,
|
||||
notes: values.notes,
|
||||
bedId: values.bedId,
|
||||
lockerId: values.lockerId || undefined,
|
||||
});
|
||||
message.success('入住登记成功');
|
||||
setCheckInModal(false);
|
||||
@@ -195,6 +218,8 @@ const OccupanciesPage: React.FC = () => {
|
||||
const columns = useMemo(() => [
|
||||
{ title: '学生', width: 120, render: (_: any, r: any) => r.student?.name || '-' },
|
||||
{ title: '宿舍', width: 120, render: (_: any, r: any) => r.room?.roomNumber || '-' },
|
||||
{ title: '床位', width: 80, render: (_: unknown, r: Record<string, unknown>) => (r.bed as Record<string, string> | undefined)?.bedNumber || '-' },
|
||||
{ title: '柜子', width: 80, render: (_: unknown, r: Record<string, unknown>) => (r.locker as Record<string, string> | undefined)?.lockerNumber || '-' },
|
||||
{ title: '入住日期', dataIndex: 'checkInDate', width: 110 },
|
||||
{ title: '计费起始', dataIndex: 'billingStartDate', width: 110 },
|
||||
{
|
||||
@@ -494,18 +519,17 @@ const OccupanciesPage: React.FC = () => {
|
||||
name="roomId"
|
||||
label="选择宿舍"
|
||||
rules={[{ required: true, message: '请选择宿舍' }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
placeholder="搜索并选择宿舍"
|
||||
options={rooms.map((r: any) => ({
|
||||
onChange={handleRoomChange}
|
||||
options={rooms.map((r) => ({
|
||||
value: r.id,
|
||||
label: `${r.roomNumber} (${r.building || ''}) [${r.currentCount}/${r.capacity}]`,
|
||||
disabled: r.currentCount >= r.capacity,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="checkInDate" label="入住日期" rules={[{ required: true }]}>
|
||||
<DatePicker style={{ width: '100%' }} placeholder="选择入住日期" format="YYYY-MM-DD" />
|
||||
</Form.Item>
|
||||
@@ -542,6 +566,37 @@ const OccupanciesPage: React.FC = () => {
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="bedId"
|
||||
label="床位"
|
||||
rules={[{ required: true, message: '请选择床位' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请先选择房间"
|
||||
disabled={availableBeds.length === 0}
|
||||
options={availableBeds.map((b) => ({
|
||||
value: b.id,
|
||||
label: b.bedNumber,
|
||||
}))}
|
||||
notFoundContent="该房间暂无可用床位"
|
||||
/>
|
||||
</Form.Item>
|
||||
{availableBeds.length > 0 && (
|
||||
<div style={{ marginTop: -16, marginBottom: 16, color: '#888', fontSize: 12 }}>
|
||||
空闲 {availableBeds.length} 张床位
|
||||
</div>
|
||||
)}
|
||||
<Form.Item name="lockerId" label="柜子(可选)">
|
||||
<Select
|
||||
allowClear
|
||||
placeholder="可选分配柜子"
|
||||
disabled={availableLockers.length === 0}
|
||||
options={availableLockers.map((l) => ({
|
||||
value: l.id,
|
||||
label: l.lockerNumber,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="notes" label="备注">
|
||||
<Input.TextArea rows={2} />
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user