fix: 归档删除改为软删除
This commit is contained in:
@@ -25,7 +25,7 @@ import type { ColumnsType } from 'antd/es/table';
|
||||
import {
|
||||
PlusOutlined,
|
||||
UploadOutlined,
|
||||
DeleteOutlined,
|
||||
InboxOutlined,
|
||||
EyeOutlined,
|
||||
CloseOutlined,
|
||||
FileTextOutlined,
|
||||
@@ -747,11 +747,11 @@ const AttachmentsTab: React.FC<TabProps & { data: AttachmentRecord[] }> = ({ dat
|
||||
const handleDelete = async (attachmentId: number) => {
|
||||
try {
|
||||
await api.delete(`/archive/attachments/${attachmentId}`);
|
||||
message.success('已删除');
|
||||
message.success('已归档');
|
||||
onRefresh();
|
||||
} catch (e: unknown) {
|
||||
const err = e as { message?: string };
|
||||
message.error(err?.message || '删除失败');
|
||||
message.error(err?.message || '归档失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -786,9 +786,9 @@ const AttachmentsTab: React.FC<TabProps & { data: AttachmentRecord[] }> = ({ dat
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
<Popconfirm title="确定删除该附件?" onConfirm={() => handleDelete(record.id)}>
|
||||
<Button size="small" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
<Popconfirm title="确定归档该附件?" onConfirm={() => handleDelete(record.id)}>
|
||||
<Button size="small" danger icon={<InboxOutlined />}>
|
||||
归档
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
CheckCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
KeyOutlined,
|
||||
DeleteOutlined,
|
||||
WarningOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import api from '../../api';
|
||||
@@ -418,7 +417,7 @@ const AiConfigPage: React.FC = () => {
|
||||
|
||||
{config?.hasDatabaseKey && canWrite && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Button danger size="small" icon={<DeleteOutlined />} onClick={handleClearKey}>
|
||||
<Button danger size="small" onClick={handleClearKey}>
|
||||
清除服务器保存密钥
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -122,10 +122,10 @@ const AttendanceDevicesPage: React.FC = () => {
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/attendance-devices/${id}`);
|
||||
message.success('已删除绑定');
|
||||
message.success('已停用绑定');
|
||||
await loadData();
|
||||
} catch (error: any) {
|
||||
message.error(error?.message || '删除失败');
|
||||
message.error(error?.message || '停用失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,9 +144,9 @@ const AttendanceDevicesPage: React.FC = () => {
|
||||
<PermissionButton permission="classroom:edit" size="small" type="link" onClick={() => openEdit(record)}>
|
||||
编辑
|
||||
</PermissionButton>
|
||||
<Popconfirm title="确定删除此考勤机绑定?" onConfirm={() => handleDelete(record.id)}>
|
||||
<Popconfirm title="确定停用此考勤机绑定?" onConfirm={() => handleDelete(record.id)}>
|
||||
<PermissionButton permission="classroom:edit" size="small" danger>
|
||||
删除
|
||||
停用
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from 'antd';
|
||||
import {
|
||||
FileTextOutlined,
|
||||
DeleteOutlined,
|
||||
InboxOutlined,
|
||||
DownloadOutlined,
|
||||
FilePdfOutlined,
|
||||
} from '@ant-design/icons';
|
||||
@@ -135,21 +135,21 @@ const BillsPage: React.FC = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
const handleArchive = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/bills/${id}`);
|
||||
message.success('删除成功');
|
||||
message.success('账单已归档');
|
||||
fetchData();
|
||||
} catch (error: any) { message.error(error?.message || '删除失败'); }
|
||||
} catch (error: any) { message.error(error?.message || '归档失败'); }
|
||||
};
|
||||
|
||||
const batchDelete = async () => {
|
||||
const batchArchive = async () => {
|
||||
if (selectedRows.length === 0) return message.warning('请先选择账单');
|
||||
if (batchLoading) return;
|
||||
setBatchLoading(true);
|
||||
try {
|
||||
await api.post('/bills/batch/delete', { ids: selectedRows });
|
||||
message.success(`已删除 ${selectedRows.length} 条账单`);
|
||||
message.success(`已归档 ${selectedRows.length} 条账单`);
|
||||
setSelectedRows([]);
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
@@ -260,14 +260,14 @@ const BillsPage: React.FC = () => {
|
||||
</PermissionButton>
|
||||
)}
|
||||
{Number(record.paidAmount || 0) === 0 && record.status !== 'cancelled' && (
|
||||
<Popconfirm title="确定删除此未支付账单?" onConfirm={() => handleDelete(record.id)} okText="删除" cancelText="取消">
|
||||
<PermissionButton permission="bill:delete" size="small" danger icon={<DeleteOutlined />}>删除</PermissionButton>
|
||||
<Popconfirm title="确定归档此未支付账单?" onConfirm={() => handleArchive(record.id)} okText="归档" cancelText="取消">
|
||||
<PermissionButton permission="bill:delete" size="small" danger icon={<InboxOutlined />}>归档</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
], [showDetail, handleDelete, handleCancel, handleExportPdf]);
|
||||
], [showDetail, handleArchive, handleCancel, handleExportPdf]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -298,9 +298,9 @@ const BillsPage: React.FC = () => {
|
||||
<Select placeholder="费用类型" allowClear style={{ width: 120 }} value={filterExpenseType} onChange={setFilterExpenseType}
|
||||
options={[{value:'water',label:'水费'},{value:'electricity',label:'电费'},{value:'cleaning',label:'保洁费'},{value:'rent',label:'租金'},{value:'other',label:'其他'}]} />
|
||||
<Popconfirm
|
||||
title={`确定删除选中的 ${selectedRows.length} 条账单?`}
|
||||
onConfirm={batchDelete}
|
||||
okText="删除"
|
||||
title={`确定归档选中的 ${selectedRows.length} 条账单?`}
|
||||
onConfirm={batchArchive}
|
||||
okText="归档"
|
||||
cancelText="取消"
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
@@ -308,9 +308,9 @@ const BillsPage: React.FC = () => {
|
||||
permission="bill:delete"
|
||||
danger
|
||||
disabled={selectedRows.length === 0}
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
>
|
||||
批量删除
|
||||
批量归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
Tooltip,
|
||||
Empty,
|
||||
} from 'antd';
|
||||
import { PlusOutlined, UploadOutlined, DeleteOutlined, FileTextOutlined, StopOutlined, CheckOutlined } from '@ant-design/icons';
|
||||
import { PlusOutlined, UploadOutlined, FileTextOutlined, StopOutlined, CheckOutlined } from '@ant-design/icons';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import api from '../../api';
|
||||
import { downloadBlob } from '../../utils/download';
|
||||
@@ -211,10 +211,10 @@ const ClassroomRentalsPage: React.FC = () => {
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/classroom-rentals/${id}`);
|
||||
message.success('已删除');
|
||||
message.success('已归档');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
message.error(e?.message || '归档失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -239,10 +239,10 @@ const ClassroomRentalsPage: React.FC = () => {
|
||||
const handleDeleteContract = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/classroom-rentals/${id}/contract`);
|
||||
message.success('合同已删除');
|
||||
message.success('合同已移除');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
message.error(e?.message || '移除失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -350,8 +350,8 @@ const ClassroomRentalsPage: React.FC = () => {
|
||||
下载
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Popconfirm title="删除合同文件?" onConfirm={() => handleDeleteContract(r.id)}>
|
||||
<Button size="small" danger icon={<DeleteOutlined />} aria-label="删除合同文件" />
|
||||
<Popconfirm title="移除合同文件?" onConfirm={() => handleDeleteContract(r.id)}>
|
||||
<Button size="small" danger icon={<StopOutlined />} aria-label="移除合同文件" />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
) : (
|
||||
@@ -410,8 +410,8 @@ const ClassroomRentalsPage: React.FC = () => {
|
||||
</>
|
||||
)}
|
||||
{record.effectiveStatus !== 'active' && (
|
||||
<Popconfirm title="确定删除该租赁订单?合同文件将一并删除。" onConfirm={() => handleDelete(record.id)}>
|
||||
<PermissionButton permission="rental:delete" size="small" danger>删除</PermissionButton>
|
||||
<Popconfirm title="确定归档该租赁订单?合同文件会保留。" onConfirm={() => handleDelete(record.id)}>
|
||||
<PermissionButton permission="rental:delete" size="small" danger>归档</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
Card,
|
||||
Empty,
|
||||
} from 'antd';
|
||||
import { PlusOutlined, DeleteOutlined, DollarOutlined } from '@ant-design/icons';
|
||||
import { PlusOutlined, InboxOutlined, DollarOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import api from '../../api';
|
||||
import PermissionButton from '../../components/PermissionButton';
|
||||
@@ -168,7 +168,7 @@ const DepositsPage: React.FC = () => {
|
||||
const handleDeleteInstallment = async (installmentId: number) => {
|
||||
try {
|
||||
await api.delete(`/deposits/installments/${installmentId}`);
|
||||
message.success('分期已删除');
|
||||
message.success('分期已归档');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
@@ -216,14 +216,14 @@ const DepositsPage: React.FC = () => {
|
||||
</>
|
||||
)}
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
title="确定归档?"
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
await api.delete(`/deposits/${record.id}`);
|
||||
message.success('删除成功');
|
||||
message.success('归档成功');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
message.error(e?.message || '归档失败');
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -231,9 +231,9 @@ const DepositsPage: React.FC = () => {
|
||||
permission="deposit:delete"
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
>
|
||||
删除
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
@@ -418,11 +418,11 @@ const DepositsPage: React.FC = () => {
|
||||
</PermissionButton>
|
||||
),
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
title="确定归档?"
|
||||
onConfirm={() => handleDeleteInstallment(item.id)}
|
||||
>
|
||||
<PermissionButton key="del" permission="deposit:delete" size="small" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
<PermissionButton key="del" permission="deposit:delete" size="small" danger icon={<InboxOutlined />}>
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
].filter(Boolean)}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from 'antd';
|
||||
import {
|
||||
PlusOutlined,
|
||||
DeleteOutlined,
|
||||
InboxOutlined,
|
||||
EditOutlined,
|
||||
UploadOutlined,
|
||||
DownloadOutlined,
|
||||
@@ -91,11 +91,11 @@ const ExpensesPage: React.FC = () => {
|
||||
setBatchLoading(true);
|
||||
try {
|
||||
const res: any = await api.post('/expenses/room/batch-delete', { ids: selectedRoomKeys });
|
||||
message.success(res?.message || `已删除 ${selectedRoomKeys.length} 条`);
|
||||
message.success(res?.message || `已归档 ${selectedRoomKeys.length} 条`);
|
||||
setSelectedRoomKeys([]);
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '批量删除失败');
|
||||
message.error(e?.message || '批量归档失败');
|
||||
} finally {
|
||||
setBatchLoading(false);
|
||||
}
|
||||
@@ -108,11 +108,11 @@ const ExpensesPage: React.FC = () => {
|
||||
const res: any = await api.post('/expenses/personal/batch-delete', {
|
||||
ids: selectedPersonalKeys,
|
||||
});
|
||||
message.success(res?.message || `已删除 ${selectedPersonalKeys.length} 条`);
|
||||
message.success(res?.message || `已归档 ${selectedPersonalKeys.length} 条`);
|
||||
setSelectedPersonalKeys([]);
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '批量删除失败');
|
||||
message.error(e?.message || '批量归档失败');
|
||||
} finally {
|
||||
setBatchLoading(false);
|
||||
}
|
||||
@@ -286,10 +286,10 @@ const ExpensesPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
title="确定归档?"
|
||||
onConfirm={async () => {
|
||||
await api.delete(`/expenses/room/${record.id}`);
|
||||
message.success('删除成功');
|
||||
message.success('归档成功');
|
||||
fetchData();
|
||||
}}
|
||||
>
|
||||
@@ -297,9 +297,9 @@ const ExpensesPage: React.FC = () => {
|
||||
permission="expense:delete"
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
>
|
||||
删除
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
@@ -342,10 +342,10 @@ const ExpensesPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
title="确定归档?"
|
||||
onConfirm={async () => {
|
||||
await api.delete(`/expenses/personal/${record.id}`);
|
||||
message.success('删除成功');
|
||||
message.success('归档成功');
|
||||
fetchData();
|
||||
}}
|
||||
>
|
||||
@@ -353,9 +353,9 @@ const ExpensesPage: React.FC = () => {
|
||||
permission="expense:delete"
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
>
|
||||
删除
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
@@ -440,19 +440,19 @@ const ExpensesPage: React.FC = () => {
|
||||
</Space>
|
||||
<Space>
|
||||
<Popconfirm
|
||||
title={`确定删除选中的 ${selectedRoomKeys.length} 条费用?`}
|
||||
title={`确定归档选中的 ${selectedRoomKeys.length} 条费用?`}
|
||||
onConfirm={handleBatchDeleteRoom}
|
||||
okText="删除"
|
||||
okText="归档"
|
||||
cancelText="取消"
|
||||
disabled={selectedRoomKeys.length === 0}
|
||||
>
|
||||
<PermissionButton
|
||||
permission="expense:delete"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
disabled={selectedRoomKeys.length === 0}
|
||||
>
|
||||
批量删除
|
||||
批量归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
<PermissionButton
|
||||
@@ -568,19 +568,19 @@ const ExpensesPage: React.FC = () => {
|
||||
</Space>
|
||||
<Space>
|
||||
<Popconfirm
|
||||
title={`确定删除选中的 ${selectedPersonalKeys.length} 条个人费用?`}
|
||||
title={`确定归档选中的 ${selectedPersonalKeys.length} 条个人费用?`}
|
||||
onConfirm={handleBatchDeletePersonal}
|
||||
okText="删除"
|
||||
okText="归档"
|
||||
cancelText="取消"
|
||||
disabled={selectedPersonalKeys.length === 0}
|
||||
>
|
||||
<PermissionButton
|
||||
permission="expense:delete"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
disabled={selectedPersonalKeys.length === 0}
|
||||
>
|
||||
批量删除
|
||||
批量归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
<PermissionButton
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import {
|
||||
SaveOutlined, ApiOutlined, CheckCircleOutlined, CloseCircleOutlined,
|
||||
SyncOutlined, BankOutlined, UserOutlined,
|
||||
DeleteOutlined,
|
||||
StopOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { DataNode } from 'antd/es/tree';
|
||||
import type { TreeSelectProps } from 'antd/es/tree-select';
|
||||
@@ -337,13 +337,13 @@ const IntegrationConfigPage: React.FC = () => {
|
||||
setAttendanceGroups([]);
|
||||
if (response.data.failed.length > 0) {
|
||||
message.warning(
|
||||
`已删除 ${response.data.deleted.length} 个,失败 ${response.data.failed.length} 个`,
|
||||
`已清空 ${response.data.deleted.length} 个,失败 ${response.data.failed.length} 个`,
|
||||
);
|
||||
} else {
|
||||
message.success(`已删除钉钉全部 ${response.data.deleted.length} 个考勤组`);
|
||||
message.success(`已清空钉钉全部 ${response.data.deleted.length} 个考勤组`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
message.error(error instanceof Error ? error.message : '删除钉钉考勤组失败');
|
||||
message.error(error instanceof Error ? error.message : '清空钉钉考勤组失败');
|
||||
} finally {
|
||||
setDeletingGroups(false);
|
||||
}
|
||||
@@ -380,11 +380,11 @@ const IntegrationConfigPage: React.FC = () => {
|
||||
<PermissionButton
|
||||
permission="sync:trigger"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<StopOutlined />}
|
||||
loading={loadingGroups}
|
||||
onClick={openDeleteAllGroups}
|
||||
>
|
||||
删除钉钉全部考勤组
|
||||
清空钉钉全部考勤组
|
||||
</PermissionButton>
|
||||
</Space>
|
||||
|
||||
@@ -484,9 +484,9 @@ const IntegrationConfigPage: React.FC = () => {
|
||||
</Drawer>
|
||||
)}
|
||||
<Modal
|
||||
title="确认删除钉钉全部考勤组"
|
||||
title="确认清空钉钉全部考勤组"
|
||||
open={deleteGroupsOpen}
|
||||
okText="确认全部删除"
|
||||
okText="确认全部清空"
|
||||
okButtonProps={{ danger: true, disabled: attendanceGroups.length === 0 }}
|
||||
cancelText="取消"
|
||||
confirmLoading={deletingGroups}
|
||||
@@ -496,8 +496,8 @@ const IntegrationConfigPage: React.FC = () => {
|
||||
<Alert
|
||||
type="error"
|
||||
showIcon
|
||||
message={`将永久删除钉钉上的 ${attendanceGroups.length} 个考勤组`}
|
||||
description="本地班级和排课不会删除。删除后需在排课管理中重新同步,才能重建考勤组。"
|
||||
message={`将永久清空钉钉上的 ${attendanceGroups.length} 个考勤组`}
|
||||
description="本地班级和排课不会清空。清空后需在排课管理中重新同步,才能重建考勤组。"
|
||||
style={{ marginBottom: 12 }}
|
||||
/>
|
||||
<List
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
PlusOutlined,
|
||||
SwapOutlined,
|
||||
LogoutOutlined,
|
||||
DeleteOutlined,
|
||||
InboxOutlined,
|
||||
UploadOutlined,
|
||||
DownloadOutlined,
|
||||
ExportOutlined,
|
||||
@@ -236,11 +236,11 @@ const OccupanciesPage: React.FC = () => {
|
||||
setBatchLoading(true);
|
||||
try {
|
||||
const res: any = await api.post('/occupancies/batch-delete', { ids: selectedRowKeys });
|
||||
message.success(res?.message || `已删除 ${selectedRowKeys.length} 条`);
|
||||
message.success(res?.message || `已归档 ${selectedRowKeys.length} 条`);
|
||||
setSelectedRowKeys([]);
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '批量删除失败');
|
||||
message.error(e?.message || '批量归档失败');
|
||||
} finally {
|
||||
setBatchLoading(false);
|
||||
}
|
||||
@@ -297,19 +297,19 @@ const OccupanciesPage: React.FC = () => {
|
||||
<Space>
|
||||
<Tag>已退宿</Tag>
|
||||
<Popconfirm
|
||||
title="确定删除此记录?"
|
||||
title="确定归档此记录?"
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
await api.delete(`/occupancies/${record.id}`);
|
||||
message.success('删除成功');
|
||||
message.success('归档成功');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
message.error(e?.message || '归档失败');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<PermissionButton permission="occupancy:delete" size="small" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
<PermissionButton permission="occupancy:delete" size="small" danger icon={<InboxOutlined />}>
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
@@ -320,7 +320,7 @@ const OccupanciesPage: React.FC = () => {
|
||||
const rowSelection = useMemo(() => ({
|
||||
selectedRowKeys,
|
||||
onChange: (keys: any[]) => setSelectedRowKeys(keys),
|
||||
// 「在住记录」Tab:禁用已退宿(防止误选用于批量退宿);「全部记录」Tab:均可选用于批量删除
|
||||
// 「在住记录」Tab:禁用已退宿(防止误选用于批量退宿);「全部记录」Tab:均可选用于批量归档
|
||||
getCheckboxProps: (record: any) => (showActive ? { disabled: !!record.checkOutDate } : {}),
|
||||
}), [selectedRowKeys, showActive]);
|
||||
|
||||
@@ -479,20 +479,20 @@ const OccupanciesPage: React.FC = () => {
|
||||
</PermissionButton>
|
||||
) : (
|
||||
<Popconfirm
|
||||
title={`确定删除选中的 ${selectedRowKeys.length} 条入住记录?在住记录会自动跳过`}
|
||||
title={`确定归档选中的 ${selectedRowKeys.length} 条入住记录?在住记录会自动跳过`}
|
||||
onConfirm={handleBatchDelete}
|
||||
okText="删除"
|
||||
okText="归档"
|
||||
cancelText="取消"
|
||||
>
|
||||
<PermissionButton
|
||||
permission="occupancy:delete"
|
||||
danger
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
style={{ marginLeft: 12 }}
|
||||
loading={batchLoading}
|
||||
>
|
||||
批量删除
|
||||
批量归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Checkbox,
|
||||
Empty,
|
||||
} from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { PlusOutlined, EditOutlined, StopOutlined } from '@ant-design/icons';
|
||||
import api from '../../api';
|
||||
import PermissionButton from '../../components/PermissionButton';
|
||||
import { message } from '../../ui/app-message';
|
||||
@@ -106,13 +106,13 @@ const RolesPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
const handleDisable = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/rbac/roles/${id}`);
|
||||
message.success('角色已删除');
|
||||
message.success('角色已停用');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e.message || '删除失败');
|
||||
message.error(e.message || '停用失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -169,9 +169,9 @@ const RolesPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
{!record.isSystem && (
|
||||
<Popconfirm title="确认删除该角色?" onConfirm={() => handleDelete(record.id)}>
|
||||
<PermissionButton permission="role:delete" type="link" size="small" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
<Popconfirm title="确认停用该角色?" onConfirm={() => handleDisable(record.id)}>
|
||||
<PermissionButton permission="role:delete" type="link" size="small" icon={<StopOutlined />}>
|
||||
停用
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
InboxOutlined,
|
||||
SearchOutlined,
|
||||
ExportOutlined,
|
||||
DeleteOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import api from '../../api';
|
||||
import { downloadBlob } from '../../utils/download';
|
||||
@@ -229,9 +228,9 @@ const RoomsPage: React.FC = () => {
|
||||
const handleDeleteBed = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/rooms/${drawerRoom.id}/beds/${id}`);
|
||||
message.success('已删除');
|
||||
message.success('已归档');
|
||||
fetchBeds(drawerRoom.id);
|
||||
} catch (e: any) { message.error(e?.message || '删除失败'); }
|
||||
} catch (e: any) { message.error(e?.message || '归档失败'); }
|
||||
};
|
||||
|
||||
const handleBatchBeds = async (count: number) => {
|
||||
@@ -263,9 +262,9 @@ const RoomsPage: React.FC = () => {
|
||||
const handleDeleteLocker = async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/rooms/${drawerRoom.id}/lockers/${id}`);
|
||||
message.success('已删除');
|
||||
message.success('已归档');
|
||||
fetchLockers(drawerRoom.id);
|
||||
} catch (e: any) { message.error(e?.message || '删除失败'); }
|
||||
} catch (e: any) { message.error(e?.message || '归档失败'); }
|
||||
};
|
||||
|
||||
const handleBatchLockers = async (count: number) => {
|
||||
@@ -461,7 +460,7 @@ const RoomsPage: React.FC = () => {
|
||||
<PermissionButton
|
||||
permission="room:delete"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
disabled={selectedRowKeys.length === 0}
|
||||
loading={batchLoading}
|
||||
>
|
||||
@@ -701,7 +700,7 @@ const RoomsPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
{r.status !== 'occupied' && (
|
||||
<Popconfirm title="确定删除?" onConfirm={() => handleDeleteBed(r.id)}>
|
||||
<Popconfirm title="确定归档?" onConfirm={() => handleDeleteBed(r.id)}>
|
||||
<PermissionButton
|
||||
permission="room:edit"
|
||||
size="small"
|
||||
@@ -709,7 +708,7 @@ const RoomsPage: React.FC = () => {
|
||||
danger
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
>
|
||||
删除
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
@@ -784,7 +783,7 @@ const RoomsPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
{r.status !== 'occupied' && (
|
||||
<Popconfirm title="确定删除?" onConfirm={() => handleDeleteLocker(r.id)}>
|
||||
<Popconfirm title="确定归档?" onConfirm={() => handleDeleteLocker(r.id)}>
|
||||
<PermissionButton
|
||||
permission="room:edit"
|
||||
size="small"
|
||||
@@ -792,7 +791,7 @@ const RoomsPage: React.FC = () => {
|
||||
danger
|
||||
disabled={drawerRoom?.status === 'archived'}
|
||||
>
|
||||
删除
|
||||
归档
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
||||
@@ -27,10 +27,10 @@ import {
|
||||
CalendarOutlined,
|
||||
LeftOutlined,
|
||||
RightOutlined,
|
||||
DeleteOutlined,
|
||||
CloudSyncOutlined,
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
StopOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import api from '../../api';
|
||||
@@ -455,26 +455,30 @@ const SchedulesPage: React.FC = () => {
|
||||
void loadClassTeachers(editableSchedule.classId);
|
||||
};
|
||||
|
||||
// ---- Delete schedule ----
|
||||
const removeScheduleFromSelection = (id: number) => {
|
||||
const remaining = selectedSchedules.filter((s) => s.id !== id);
|
||||
setSelectedSchedules(remaining);
|
||||
if (remaining.length === 0) {
|
||||
setModalOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number | null) => {
|
||||
// ---- Disable / delete schedule ----
|
||||
|
||||
const handleDisable = async (id: number | null) => {
|
||||
if (id === null) return;
|
||||
try {
|
||||
await api.delete(`/class-schedules/${id}`);
|
||||
message.success('排课已删除');
|
||||
// Refresh the displayed schedules
|
||||
const remaining = selectedSchedules.filter((s) => s.id !== id);
|
||||
setSelectedSchedules(remaining);
|
||||
if (remaining.length === 0) {
|
||||
setModalOpen(false);
|
||||
}
|
||||
await api.put(`/class-schedules/${id}`, { status: 'inactive' });
|
||||
message.success('排课已停用,历史考勤记录已保留,教室占用已释放');
|
||||
removeScheduleFromSelection(id);
|
||||
fetchData();
|
||||
} catch (e: unknown) {
|
||||
const err = e as { message?: string };
|
||||
message.error(err?.message || '删除失败');
|
||||
message.error(err?.message || '停用失败');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ---- Classroom select options ----
|
||||
|
||||
const classroomOptions = useMemo(
|
||||
@@ -1113,21 +1117,23 @@ const SchedulesPage: React.FC = () => {
|
||||
编辑
|
||||
</PermissionButton>
|
||||
)}
|
||||
<Popconfirm
|
||||
title="确认删除该排课?"
|
||||
onConfirm={() => handleDelete(s.id)}
|
||||
okText="删除"
|
||||
cancelText="取消"
|
||||
>
|
||||
<PermissionButton
|
||||
permission="schedule:delete"
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
{s.scheduleType !== 'RENTAL' && s.status === 'active' && (
|
||||
<Popconfirm
|
||||
title="确认停用该排课?"
|
||||
description="停用后历史考勤记录会保留,但该排课不会再显示或占用教室。"
|
||||
onConfirm={() => handleDisable(s.id)}
|
||||
okText="停用"
|
||||
cancelText="取消"
|
||||
>
|
||||
删除
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
<PermissionButton
|
||||
permission="schedule:edit"
|
||||
size="small"
|
||||
icon={<StopOutlined />}
|
||||
>
|
||||
停用
|
||||
</PermissionButton>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
} from 'antd';
|
||||
import type { UploadProps } from 'antd';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
DownloadOutlined,
|
||||
ExportOutlined,
|
||||
EyeOutlined,
|
||||
@@ -589,7 +588,7 @@ const StudentsPage: React.FC = () => {
|
||||
<PermissionButton
|
||||
permission="student:delete"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
icon={<InboxOutlined />}
|
||||
disabled={selectedRowKeys.length === 0}
|
||||
loading={batchLoading}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user