feat: 支持表格单元格快捷编辑
Some checks failed
CI 检查 / lint (pull_request) Has been cancelled
CI 检查 / typecheck (pull_request) Has been cancelled
CI 检查 / test (pull_request) Has been cancelled

This commit is contained in:
2026-07-21 14:17:08 +08:00
parent fe0b71a0a9
commit a585fd42d5
17 changed files with 2197 additions and 303 deletions

View File

@@ -23,6 +23,7 @@ import {
} from '@ant-design/icons';
import api from '../../api';
import PermissionButton from '../../components/PermissionButton';
import EditableCell from '../../components/EditableCell';
import { message } from '../../ui/app-message';
const statusMap: Record<string, { text: string; color: string }> = {
@@ -110,6 +111,12 @@ const ClassroomsPage: React.FC = () => {
}
};
const saveCell = async (record: any, field: string, value: unknown) => {
await api.put(`/classrooms/${record.id}`, { [field]: value });
message.success('已保存');
await fetchData();
};
const handleArchive = async (id: number) => {
try {
await api.delete(`/classrooms/${id}`);
@@ -155,16 +162,83 @@ const ClassroomsPage: React.FC = () => {
width: 120,
dataIndex: 'name',
sorter: (a: any, b: any) => a.name.localeCompare(b.name),
render: (v: string, r: any) => (
<EditableCell
value={v}
required
permission="classroom:edit"
disabled={r.status === 'archived'}
onSave={(next) => saveCell(r, 'name', next)}
>
{v}
</EditableCell>
),
},
{
title: '楼栋',
dataIndex: 'building',
width: 80,
render: (v: string, r: any) => (
<EditableCell
value={v}
permission="classroom:edit"
disabled={r.status === 'archived'}
onSave={(next) => saveCell(r, 'building', next)}
>
{v || '-'}
</EditableCell>
),
},
{
title: '楼层',
dataIndex: 'floor',
width: 80,
render: (v: number, r: any) => (
<EditableCell
value={v}
editor="number"
permission="classroom:edit"
disabled={r.status === 'archived'}
onSave={(next) => saveCell(r, 'floor', next)}
>
{v ?? '-'}
</EditableCell>
),
},
{ title: '楼栋', dataIndex: 'building', width: 80 },
{ title: '楼层', dataIndex: 'floor', width: 80 },
{
title: '类型',
width: 90,
dataIndex: 'roomType',
render: (v: string) => <Tag color={typeColor[v] || 'default'}>{v || '-'}</Tag>,
render: (v: string, r: any) => (
<EditableCell
value={v}
editor="select"
options={['大', '次大', '小'].map((value) => ({ value, label: value }))}
permission="classroom:edit"
disabled={r.status === 'archived'}
onSave={(next) => saveCell(r, 'roomType', next)}
>
<Tag color={typeColor[v] || 'default'}>{v || '-'}</Tag>
</EditableCell>
),
},
{
title: '容量',
dataIndex: 'capacity',
width: 80,
render: (v: number, r: any) => (
<EditableCell
value={v}
editor="number"
min={0}
permission="classroom:edit"
disabled={r.status === 'archived'}
onSave={(next) => saveCell(r, 'capacity', next)}
>
{v ?? '-'}
</EditableCell>
),
},
{ title: '容量', dataIndex: 'capacity', width: 80 },
{
title: '状态',
width: 100,
@@ -175,17 +249,29 @@ const ClassroomsPage: React.FC = () => {
) => {
const effectiveStatus = record.effectiveStatus || record.status;
return (
<Tooltip
title={
record.currentUsage
? `${record.currentUsage.title} (${record.currentUsage.startTime}-${record.currentUsage.endTime})`
: undefined
}
<EditableCell
value={record.status}
editor="select"
options={[
{ value: 'available', label: '可用' },
{ value: 'maintenance', label: '维护中' },
]}
permission="classroom:edit"
disabled={record.status === 'archived'}
onSave={(next) => saveCell(record, 'status', next)}
>
<Tag color={statusMap[effectiveStatus]?.color}>
{statusMap[effectiveStatus]?.text || effectiveStatus}
</Tag>
</Tooltip>
<Tooltip
title={
record.currentUsage
? `${record.currentUsage.title} (${record.currentUsage.startTime}-${record.currentUsage.endTime})`
: undefined
}
>
<Tag color={statusMap[effectiveStatus]?.color}>
{statusMap[effectiveStatus]?.text || effectiveStatus}
</Tag>
</Tooltip>
</EditableCell>
);
},
},