feat: 支持表格单元格快捷编辑
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
import api from '../../api';
|
||||
import { downloadBlob } from '../../utils/download';
|
||||
import PermissionButton from '../../components/PermissionButton';
|
||||
import EditableCell from '../../components/EditableCell';
|
||||
import { message } from '../../ui/app-message';
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
@@ -199,6 +200,26 @@ const RoomsPage: React.FC = () => {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveRoomCell = async (record: any, field: string, value: unknown) => {
|
||||
await api.put(`/rooms/${record.id}`, { [field]: value });
|
||||
message.success('已保存');
|
||||
await fetchData();
|
||||
};
|
||||
|
||||
const saveBedCell = async (record: BedItem, field: string, value: unknown) => {
|
||||
if (!drawerRoom) return;
|
||||
await api.put(`/rooms/${drawerRoom.id}/beds/${record.id}`, { [field]: value });
|
||||
message.success('已保存');
|
||||
await fetchBeds(drawerRoom.id);
|
||||
};
|
||||
|
||||
const saveLockerCell = async (record: LockerItem, field: string, value: unknown) => {
|
||||
if (!drawerRoom) return;
|
||||
await api.put(`/rooms/${drawerRoom.id}/lockers/${record.id}`, { [field]: value });
|
||||
message.success('已保存');
|
||||
await fetchLockers(drawerRoom.id);
|
||||
};
|
||||
const fetchBeds = useCallback(async (roomId: number) => {
|
||||
try {
|
||||
const res = await api.get<BedItem[]>(`/rooms/${roomId}/beds`);
|
||||
@@ -337,27 +358,123 @@ const RoomsPage: React.FC = () => {
|
||||
dataIndex: 'roomNumber',
|
||||
width: 100,
|
||||
sorter: (a: any, b: any) => a.roomNumber.localeCompare(b.roomNumber),
|
||||
render: (v: string, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
required
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'roomNumber', next)}
|
||||
>
|
||||
{v}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '楼栋',
|
||||
dataIndex: 'building',
|
||||
width: 80,
|
||||
render: (v: string, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'building', next)}
|
||||
>
|
||||
{v || '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '楼层',
|
||||
dataIndex: 'floor',
|
||||
width: 80,
|
||||
render: (v: number, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="number"
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'floor', next)}
|
||||
>
|
||||
{v ?? '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'roomType',
|
||||
width: 90,
|
||||
render: (v: any, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'roomType', next)}
|
||||
>
|
||||
{v || '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{ title: '楼栋', dataIndex: 'building', width: 80 },
|
||||
{ title: '楼层', dataIndex: 'floor', width: 80 },
|
||||
{ title: '类型', dataIndex: 'roomType', width: 90, render: (v: any) => v || '-' },
|
||||
{
|
||||
title: '租赁类型',
|
||||
dataIndex: 'rentalCategory',
|
||||
width: 100,
|
||||
render: (v: string) => {
|
||||
if (v === 'long') return <Tag color="blue">长租</Tag>;
|
||||
if (v === 'short') return <Tag color="green">短租</Tag>;
|
||||
return '-';
|
||||
},
|
||||
render: (v: string, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="select"
|
||||
options={[
|
||||
{ value: 'long', label: '长租' },
|
||||
{ value: 'short', label: '短租' },
|
||||
]}
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'rentalCategory', next)}
|
||||
>
|
||||
{(() => {
|
||||
if (v === 'long') return <Tag color="blue">长租</Tag>;
|
||||
if (v === 'short') return <Tag color="green">短租</Tag>;
|
||||
return '-';
|
||||
})()}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '月租金',
|
||||
dataIndex: 'monthlyRate',
|
||||
width: 100,
|
||||
render: (v: number) => (v ? `¥${v}` : '-'),
|
||||
render: (v: number, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="money"
|
||||
min={0}
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'monthlyRate', next)}
|
||||
>
|
||||
{v ? `¥${v}` : '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '额定人数',
|
||||
dataIndex: 'capacity',
|
||||
width: 80,
|
||||
render: (v: number, r: any) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="number"
|
||||
min={1}
|
||||
required
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'capacity', next)}
|
||||
>
|
||||
{v}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{ title: '额定人数', dataIndex: 'capacity', width: 80 },
|
||||
{
|
||||
title: '当前入住',
|
||||
width: 80,
|
||||
@@ -377,7 +494,22 @@ const RoomsPage: React.FC = () => {
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
render: (s: string) => <Tag color={statusMap[s]?.color}>{statusMap[s]?.text || s}</Tag>,
|
||||
render: (s: string, r: any) => (
|
||||
<EditableCell
|
||||
value={s}
|
||||
editor="select"
|
||||
options={[
|
||||
{ value: 'available', label: '可入住' },
|
||||
{ value: 'full', label: '已满' },
|
||||
{ value: 'maintenance', label: '维修中' },
|
||||
]}
|
||||
permission="room:edit"
|
||||
disabled={r.status === 'archived'}
|
||||
onSave={(next) => saveRoomCell(r, 'status', next)}
|
||||
>
|
||||
<Tag color={statusMap[s]?.color}>{statusMap[s]?.text || s}</Tag>
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
@@ -778,21 +910,65 @@ const RoomsPage: React.FC = () => {
|
||||
pagination={false}
|
||||
size="small"
|
||||
columns={[
|
||||
{ title: '编号', dataIndex: 'bedNumber', width: 80 },
|
||||
{
|
||||
title: '编号',
|
||||
dataIndex: 'bedNumber',
|
||||
width: 80,
|
||||
render: (v: string, r: BedItem) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
required
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveBedCell(r, 'bedNumber', next)}
|
||||
>
|
||||
{v}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
render: (s: string) => {
|
||||
const map: Record<string, { text: string; color: string }> = {
|
||||
available: { text: '空闲', color: 'green' },
|
||||
occupied: { text: '占用', color: 'blue' },
|
||||
maintenance: { text: '维修', color: 'orange' },
|
||||
};
|
||||
return <Tag color={map[s]?.color}>{map[s]?.text || s}</Tag>;
|
||||
},
|
||||
render: (s: string, r: BedItem) => (
|
||||
<EditableCell
|
||||
value={s}
|
||||
editor="select"
|
||||
options={[
|
||||
{ value: 'available', label: '空闲' },
|
||||
{ value: 'occupied', label: '占用' },
|
||||
{ value: 'maintenance', label: '维修' },
|
||||
]}
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveBedCell(r, 'status', next)}
|
||||
>
|
||||
{(() => {
|
||||
const map: Record<string, { text: string; color: string }> = {
|
||||
available: { text: '空闲', color: 'green' },
|
||||
occupied: { text: '占用', color: 'blue' },
|
||||
maintenance: { text: '维修', color: 'orange' },
|
||||
};
|
||||
return <Tag color={map[s]?.color}>{map[s]?.text || s}</Tag>;
|
||||
})()}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'notes',
|
||||
render: (v: string, r: BedItem) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="textarea"
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveBedCell(r, 'notes', next)}
|
||||
>
|
||||
{v || '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{ title: '备注', dataIndex: 'notes', render: (v: string) => v || '-' },
|
||||
{
|
||||
title: '操作',
|
||||
width: 120,
|
||||
@@ -885,21 +1061,65 @@ const RoomsPage: React.FC = () => {
|
||||
pagination={false}
|
||||
size="small"
|
||||
columns={[
|
||||
{ title: '编号', dataIndex: 'lockerNumber', width: 80 },
|
||||
{
|
||||
title: '编号',
|
||||
dataIndex: 'lockerNumber',
|
||||
width: 80,
|
||||
render: (v: string, r: LockerItem) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
required
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveLockerCell(r, 'lockerNumber', next)}
|
||||
>
|
||||
{v}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
render: (s: string) => {
|
||||
const map: Record<string, { text: string; color: string }> = {
|
||||
available: { text: '空闲', color: 'green' },
|
||||
occupied: { text: '占用', color: 'blue' },
|
||||
maintenance: { text: '维修', color: 'orange' },
|
||||
};
|
||||
return <Tag color={map[s]?.color}>{map[s]?.text || s}</Tag>;
|
||||
},
|
||||
render: (s: string, r: LockerItem) => (
|
||||
<EditableCell
|
||||
value={s}
|
||||
editor="select"
|
||||
options={[
|
||||
{ value: 'available', label: '空闲' },
|
||||
{ value: 'occupied', label: '占用' },
|
||||
{ value: 'maintenance', label: '维修' },
|
||||
]}
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveLockerCell(r, 'status', next)}
|
||||
>
|
||||
{(() => {
|
||||
const map: Record<string, { text: string; color: string }> = {
|
||||
available: { text: '空闲', color: 'green' },
|
||||
occupied: { text: '占用', color: 'blue' },
|
||||
maintenance: { text: '维修', color: 'orange' },
|
||||
};
|
||||
return <Tag color={map[s]?.color}>{map[s]?.text || s}</Tag>;
|
||||
})()}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'notes',
|
||||
render: (v: string, r: LockerItem) => (
|
||||
<EditableCell
|
||||
value={v}
|
||||
editor="textarea"
|
||||
permission="room:edit"
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
onSave={(next) => saveLockerCell(r, 'notes', next)}
|
||||
>
|
||||
{v || '-'}
|
||||
</EditableCell>
|
||||
),
|
||||
},
|
||||
{ title: '备注', dataIndex: 'notes', render: (v: string) => v || '-' },
|
||||
{
|
||||
title: '操作',
|
||||
width: 120,
|
||||
|
||||
Reference in New Issue
Block a user