106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { Modal, List, Button, Toast, Typography, Spin, Popconfirm } from '@douyinfe/semi-ui';
|
|
import { IconHistory, IconRotate } from '@douyinfe/semi-icons';
|
|
import { useNoteStore } from '../../stores/useNoteStore';
|
|
import noteService from '../../services/note.service';
|
|
import type { IHistory } from '../../types';
|
|
|
|
const { Text } = Typography;
|
|
|
|
interface Props {
|
|
visible: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function NoteHistoryModal({ visible, onClose }: Props) {
|
|
const { currentNoteId, setCurrentNote } = useNoteStore();
|
|
const [list, setList] = useState<IHistory[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!visible || !currentNoteId) return;
|
|
setLoading(true);
|
|
noteService
|
|
.getHistory(currentNoteId)
|
|
.then((res) => setList(res.data ?? []))
|
|
.catch(() => Toast.error('加载历史版本失败'))
|
|
.finally(() => setLoading(false));
|
|
}, [visible, currentNoteId]);
|
|
|
|
const handleRestore = useCallback(
|
|
async (item: IHistory) => {
|
|
try {
|
|
const res = await noteService.getHistoryContent(item.id);
|
|
const h = res.data;
|
|
// Restore: update note with history content
|
|
await noteService.update(h.nid, h.title, h.context);
|
|
// Reload the current note into the editor
|
|
const noteRes = await noteService.get(h.nid);
|
|
const note = noteRes.data;
|
|
setCurrentNote(note.id, note.title, note.context);
|
|
Toast.success(`已恢复到 ${h.createtime} 的版本`);
|
|
onClose();
|
|
} catch {
|
|
Toast.error('恢复失败');
|
|
}
|
|
},
|
|
[setCurrentNote, onClose],
|
|
);
|
|
|
|
return (
|
|
<Modal
|
|
title={
|
|
<span>
|
|
<IconHistory style={{ marginRight: 8 }} />
|
|
历史版本
|
|
</span>
|
|
}
|
|
visible={visible}
|
|
onCancel={onClose}
|
|
footer={null}
|
|
width={520}
|
|
>
|
|
{loading ? (
|
|
<div style={{ textAlign: 'center', padding: 32 }}>
|
|
<Spin size="large" />
|
|
</div>
|
|
) : list.length === 0 ? (
|
|
<div style={{ textAlign: 'center', padding: 32, color: 'var(--semi-color-text-2)' }}>
|
|
暂无历史版本
|
|
</div>
|
|
) : (
|
|
<List
|
|
dataSource={list}
|
|
renderItem={(item: IHistory) => (
|
|
<List.Item
|
|
main={
|
|
<div>
|
|
<Text strong style={{ display: 'block' }}>{item.title}</Text>
|
|
<Text type="tertiary" size="small">{item.createtime}</Text>
|
|
</div>
|
|
}
|
|
extra={
|
|
<Popconfirm
|
|
title="确认恢复"
|
|
content="恢复后当前内容将被该版本覆盖,确定吗?"
|
|
onConfirm={() => void handleRestore(item)}
|
|
okText="确定"
|
|
cancelText="取消"
|
|
>
|
|
<Button
|
|
size="small"
|
|
type="secondary"
|
|
icon={<IconRotate />}
|
|
>
|
|
恢复
|
|
</Button>
|
|
</Popconfirm>
|
|
}
|
|
/>
|
|
)}
|
|
/>
|
|
)}
|
|
</Modal>
|
|
);
|
|
}
|