diff --git a/packages/client/package.json b/packages/client/package.json index f4383f43..6035a2ad 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -63,6 +63,7 @@ "dompurify": "^2.3.5", "downloadjs": "^1.4.7", "html-to-docx": "^1.4.0", + "htmldiff-js": "^1.0.5", "interactjs": "^1.10.11", "katex": "^0.15.2", "kity": "^2.0.4", diff --git a/packages/client/src/components/document/version/index.module.scss b/packages/client/src/components/document/version/index.module.scss index 5182225b..4cb062cc 100644 --- a/packages/client/src/components/document/version/index.module.scss +++ b/packages/client/src/components/document/version/index.module.scss @@ -39,6 +39,44 @@ overflow: auto; } } + + :global { + #diff-visual { + del { + color: #cb4000; + text-decoration: none; + list-style: none; + background-color: #ffeaea; + } + + del::before { + position: relative; + top: -2px; + padding: 0 4px; + font-weight: 400; + color: #8a8f8d; + text-decoration: none; + content: '-'; + } + + ins { + color: green; + text-decoration: none; + list-style: none; + background-color: #e9ffe9; + } + + ins::before { + position: relative; + top: -2px; + padding: 0 4px; + font-weight: 400; + color: #8a8f8d; + text-decoration: none; + content: '+'; + } + } + } } aside { diff --git a/packages/client/src/components/document/version/index.tsx b/packages/client/src/components/document/version/index.tsx index 43d9ae01..8ea79304 100644 --- a/packages/client/src/components/document/version/index.tsx +++ b/packages/client/src/components/document/version/index.tsx @@ -1,10 +1,11 @@ import { IconChevronLeft } from '@douyinfe/semi-icons'; -import { Button, Modal, Typography } from '@douyinfe/semi-ui'; +import { Button, Modal, Select, Space, Tag, Typography } from '@douyinfe/semi-ui'; import { EditorContent, useEditor } from '@tiptap/react'; import cls from 'classnames'; import { DataRender } from 'components/data-render'; import { LocaleTime } from 'components/locale-time'; import { useDocumentVersion } from 'data/document'; +import { generateDiffHtml } from 'helpers/generate-html'; import { safeJSONParse } from 'helpers/json'; import { DocumentVersionControl } from 'hooks/use-document-version'; import { IsOnMobile } from 'hooks/use-on-mobile'; @@ -28,6 +29,7 @@ export const DocumentVersion: React.FC> = ({ documentId, onSelec const { visible, toggleVisible } = DocumentVersionControl.useHook(); const { data, loading, error, refresh } = useDocumentVersion(documentId, { enabled: visible }); const [selectedVersion, setSelectedVersion] = useState(null); + const [diffVersion, setDiffVersion] = useState(null); const editor = useEditor({ editable: false, @@ -42,10 +44,18 @@ export const DocumentVersion: React.FC> = ({ documentId, onSelec const select = useCallback( (version) => { + setDiffVersion(null); setSelectedVersion(version); editor.commands.setContent(safeJSONParse(version.data, { default: {} }).default); }, - [editor] + [editor, setDiffVersion] + ); + + const changeDiffVision = useCallback( + (version) => { + setDiffVersion(version); + }, + [setDiffVersion] ); const restore = useCallback(() => { @@ -54,6 +64,20 @@ export const DocumentVersion: React.FC> = ({ documentId, onSelec close(); }, [selectedVersion, close, onSelect]); + useEffect(() => { + if (diffVersion && selectedVersion) { + const historyVersion = data.find((item) => item.version === diffVersion); + + const diffHtml = generateDiffHtml( + safeJSONParse(selectedVersion.data, { default: {} }).default, + safeJSONParse(historyVersion.data, { default: {} }).default + ); + + const element = document.getElementById('diff-visual'); + element.innerHTML = diffHtml; + } + }, [diffVersion, data, selectedVersion]); + useEffect(() => { if (!editor) return; if (!data.length) return; @@ -77,11 +101,28 @@ export const DocumentVersion: React.FC> = ({ documentId, onSelec 版本记录 -
- -
+ {selectedVersion && !isMobile && ( +
+ + {new Date(+selectedVersion.version).toLocaleString()} + +
+ +
对比
+ + 增加的内容 + 删除的内容 + +
+ )}
+
} @@ -106,7 +150,11 @@ export const DocumentVersion: React.FC> = ({ documentId, onSelec
- + {diffVersion ? ( +
+ ) : ( + + )}