fix(admin): 编辑消息/切换会话保护、行内编辑撤销与上传进度反馈

- 编辑旧消息会删除其后全部消息时,先弹确认告知影响范围
- 有待发送附件时切换会话,先确认再丢弃(避免静默删除已上传文件)
- EditableCell 保存成功后提供 6 秒内"撤销"入口(把旧值重新保存),
  重新编辑时自动清除
- 导入向导/重新上传显示上传进度条与百分比,不再"假死"
- AI 附件上传透传进度给附件列表
- 租赁合同上传显示按钮 loading 与上传百分比
This commit is contained in:
2026-08-07 17:38:21 +08:00
parent 00e2bc5acf
commit 8dc72d6e1b
9 changed files with 220 additions and 35 deletions

View File

@@ -14,6 +14,7 @@ import {
Descriptions,
Flex,
Modal,
Progress,
Select,
Space,
Spin,
@@ -115,6 +116,7 @@ export const ImportWizardModal: React.FC<ImportWizardModalProps> = ({
const [run, setRun] = useState<ImportRunDetail | null>(null);
const [loadingRun, setLoadingRun] = useState(false);
const [uploading, setUploading] = useState(false);
const [uploadPercent, setUploadPercent] = useState(0);
const [activeStepKey, setActiveStepKey] = useState<ImportStepKey | null>(null);
const [sheetSelection, setSheetSelection] = useState<Record<string, string[]>>({});
const [mappingDraft, setMappingDraft] = useState<Record<string, Record<string, string>>>({});
@@ -188,14 +190,19 @@ export const ImportWizardModal: React.FC<ImportWizardModalProps> = ({
const handleUpload: UploadProps['customRequest'] = async (options) => {
const file = options.file as File;
setUploading(true);
setUploadPercent(0);
try {
const detail = await createImportRun(file, { source: 'manual' });
const detail = await createImportRun(file, {
source: 'manual',
onProgress: (percent) => setUploadPercent(percent),
});
await loadRun(detail.id);
message.success(`已识别 ${detail.sheets.length} 个工作表`);
} catch (error) {
message.error(error instanceof Error ? error.message : '文件上传失败');
} finally {
setUploading(false);
setUploadPercent(0);
}
};
@@ -256,11 +263,13 @@ export const ImportWizardModal: React.FC<ImportWizardModalProps> = ({
const handleReupload = async (file: File) => {
if (!run || !activeStepKey) return;
setUploading(true);
setUploadPercent(0);
try {
const detail = await createImportRun(file, {
source: 'manual',
stages: [{ stepKey: activeStepKey, sheets: sheetSelection[activeStepKey] ?? [] }],
mapping: { [activeStepKey]: mappingDraft[activeStepKey] ?? {} },
onProgress: (percent) => setUploadPercent(percent),
});
await loadRun(detail.id);
message.success('已重新上传,并保留原列映射');
@@ -268,6 +277,7 @@ export const ImportWizardModal: React.FC<ImportWizardModalProps> = ({
message.error(error instanceof Error ? error.message : '重新上传失败');
} finally {
setUploading(false);
setUploadPercent(0);
}
};
@@ -405,6 +415,20 @@ export const ImportWizardModal: React.FC<ImportWizardModalProps> = ({
<p className="ant-upload-text"> .xlsx / .csv </p>
<p className="ant-upload-hint"> 10MB.xls .xlsx</p>
</Upload.Dragger>
{uploading ? (
<Flex vertical gap={4} style={{ marginTop: 8 }}>
<Progress
percent={uploadPercent}
size="small"
status={uploadPercent > 0 && uploadPercent < 100 ? 'active' : 'normal'}
/>
<Typography.Text type="secondary" style={{ fontSize: 12, textAlign: 'center' }}>
{uploadPercent > 0 && uploadPercent < 100
? `正在上传 ${uploadPercent}%...`
: '正在上传并解析文件...'}
</Typography.Text>
</Flex>
) : null}
</Space>
) : (
<Space orientation="vertical" size={16} style={{ width: '100%' }}>