From afc86d0adfc53c43508505ec6b7f8a574b4c57b6 Mon Sep 17 00:00:00 2001 From: pipipi-pikachu Date: Sun, 29 May 2022 10:53:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=AF=BC=E5=85=A5/?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=89=B9=E6=9C=89=E6=96=87=E4=BB=B6=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useAddSlidesOrElements.ts | 72 +++++++++ src/hooks/useExport.ts | 29 ++++ src/hooks/usePasteTextClipboardData.ts | 71 +-------- src/hooks/useSlideHandler.ts | 6 +- src/types/export.ts | 2 +- src/views/Editor/EditorHeader/index.vue | 6 + src/views/Editor/ExportDialog/ExportPPTX.vue | 6 - .../ExportDialog/ExportSpecificFile.vue | 137 ++++++++++++++++++ src/views/Editor/ExportDialog/index.vue | 3 + 9 files changed, 256 insertions(+), 76 deletions(-) create mode 100644 src/hooks/useAddSlidesOrElements.ts create mode 100644 src/views/Editor/ExportDialog/ExportSpecificFile.vue diff --git a/src/hooks/useAddSlidesOrElements.ts b/src/hooks/useAddSlidesOrElements.ts new file mode 100644 index 00000000..2ff2505e --- /dev/null +++ b/src/hooks/useAddSlidesOrElements.ts @@ -0,0 +1,72 @@ +import { storeToRefs } from 'pinia' +import { nanoid } from 'nanoid' +import { useSlidesStore, useMainStore } from '@/store' +import { PPTElement, Slide } from '@/types/slides' +import { createElementIdMap } from '@/utils/element' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' + +export default () => { + const mainStore = useMainStore() + const slidesStore = useSlidesStore() + const { currentSlide } = storeToRefs(slidesStore) + + const { addHistorySnapshot } = useHistorySnapshot() + + /** + * 添加指定的元素数据(一组) + * @param elements 元素列表数据 + */ + const addElementsFromData = (elements: PPTElement[]) => { + const { groupIdMap, elIdMap } = createElementIdMap(elements) + const currentSlideElementIdList = currentSlide.value.elements.map(el => el.id) + + for (const element of elements) { + const inCurrentSlide = currentSlideElementIdList.includes(element.id) + + element.id = elIdMap[element.id] + + if (inCurrentSlide) { + element.left = element.left + 10 + element.top = element.top + 10 + } + + if (element.groupId) element.groupId = groupIdMap[element.groupId] + } + slidesStore.addElement(elements) + mainStore.setActiveElementIdList(Object.values(elIdMap)) + addHistorySnapshot() + } + + /** + * 添加指定的页面数据 + * @param slide 页面数据 + */ + const addSlidesFromData = (slides: Slide[]) => { + const newSlides = slides.map(slide => { + const { groupIdMap, elIdMap } = createElementIdMap(slide.elements) + + for (const element of slide.elements) { + element.id = elIdMap[element.id] + if (element.groupId) element.groupId = groupIdMap[element.groupId] + } + // 动画id替换 + if (slide.animations) { + for (const animation of slide.animations) { + animation.id = nanoid(10) + animation.elId = elIdMap[animation.elId] + } + } + return { + ...slide, + id: nanoid(10), + } + }) + slidesStore.addSlide(newSlides) + addHistorySnapshot() + } + + return { + addElementsFromData, + addSlidesFromData, + } +} \ No newline at end of file diff --git a/src/hooks/useExport.ts b/src/hooks/useExport.ts index a4e5a048..bb89f642 100644 --- a/src/hooks/useExport.ts +++ b/src/hooks/useExport.ts @@ -10,8 +10,10 @@ import { PPTElementOutline, PPTElementShadow, PPTElementLink, Slide } from '@/ty import { getElementRange, getLineElementPath, getTableSubThemeColor } from '@/utils/element' import { AST, toAST } from '@/utils/htmlParser' import { SvgPoints, toPoints } from '@/utils/svgPathParser' +import { decrypt, encrypt } from '@/utils/crypto' import { svg2Base64 } from '@/utils/svg2Base64' import { message } from 'ant-design-vue' +import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements' interface ExportImageConfig { quality: number; @@ -22,6 +24,8 @@ interface ExportImageConfig { export default () => { const { slides, theme, viewportRatio } = storeToRefs(useSlidesStore()) + const { addSlidesFromData } = useAddSlidesOrElements() + const exporting = ref(false) // 导出图片 @@ -50,6 +54,29 @@ export default () => { }, 200) } + // 导出pptist文件(特有 .pptist 后缀文件) + const exportSpecificFile = (_slides: Slide[]) => { + const blob = new Blob([encrypt(JSON.stringify(_slides))], { type: '' }) + saveAs(blob, 'pptist_slides.pptist') + } + + // 导入pptist文件 + const importSpecificFile = (files: File[]) => { + const file = files[0] + + const reader = new FileReader() + reader.addEventListener('load', () => { + try { + const slides = JSON.parse(decrypt(reader.result as string)) + addSlidesFromData(slides) + } + catch { + message.error('无法正确读取 / 解析该文件') + } + }) + reader.readAsText(file) + } + // 导出JSON文件 const exportJSON = () => { const blob = new Blob([JSON.stringify(slides.value)], { type: '' }) @@ -738,6 +765,8 @@ export default () => { exporting, exportImage, exportJSON, + importSpecificFile, + exportSpecificFile, exportPPTX, } } \ No newline at end of file diff --git a/src/hooks/usePasteTextClipboardData.ts b/src/hooks/usePasteTextClipboardData.ts index 4da73394..a1606d24 100644 --- a/src/hooks/usePasteTextClipboardData.ts +++ b/src/hooks/usePasteTextClipboardData.ts @@ -1,12 +1,7 @@ -import { storeToRefs } from 'pinia' -import { nanoid } from 'nanoid' -import { useSlidesStore, useMainStore } from '@/store' import { pasteCustomClipboardString } from '@/utils/clipboard' -import { PPTElement, Slide } from '@/types/slides' -import { createElementIdMap } from '@/utils/element' import { parseText2Paragraphs } from '@/utils/textParser' -import useHistorySnapshot from '@/hooks/useHistorySnapshot' import useCreateElement from '@/hooks/useCreateElement' +import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements' interface PasteTextClipboardDataOptions { onlySlide?: boolean; @@ -14,65 +9,8 @@ interface PasteTextClipboardDataOptions { } export default () => { - const mainStore = useMainStore() - const slidesStore = useSlidesStore() - const { currentSlide } = storeToRefs(slidesStore) - - const { addHistorySnapshot } = useHistorySnapshot() const { createTextElement } = useCreateElement() - - /** - * 粘贴元素(一组) - * @param elements 元素列表数据 - */ - const addElementsFromClipboard = (elements: PPTElement[]) => { - const { groupIdMap, elIdMap } = createElementIdMap(elements) - const currentSlideElementIdList = currentSlide.value.elements.map(el => el.id) - - for (const element of elements) { - const inCurrentSlide = currentSlideElementIdList.includes(element.id) - - element.id = elIdMap[element.id] - - if (inCurrentSlide) { - element.left = element.left + 10 - element.top = element.top + 10 - } - - if (element.groupId) element.groupId = groupIdMap[element.groupId] - } - slidesStore.addElement(elements) - mainStore.setActiveElementIdList(Object.values(elIdMap)) - addHistorySnapshot() - } - - /** - * 粘贴页面 - * @param slide 页面数据 - */ - const addSlidesFromClipboard = (slides: Slide[]) => { - const newSlides = slides.map(slide => { - const { groupIdMap, elIdMap } = createElementIdMap(slide.elements) - - for (const element of slide.elements) { - element.id = elIdMap[element.id] - if (element.groupId) element.groupId = groupIdMap[element.groupId] - } - // 动画id替换 - if (slide.animations) { - for (const animation of slide.animations) { - animation.id = nanoid(10) - animation.elId = elIdMap[animation.elId] - } - } - return { - ...slide, - id: nanoid(10), - } - }) - slidesStore.addSlide(newSlides) - addHistorySnapshot() - } + const { addElementsFromData, addSlidesFromData } = useAddSlidesOrElements() /** * 粘贴普通文本:创建为新的文本元素 @@ -102,8 +40,8 @@ export default () => { if (typeof clipboardData === 'object') { const { type, data } = clipboardData - if (type === 'elements' && !onlySlide) addElementsFromClipboard(data) - else if (type === 'slides' && !onlyElements) addSlidesFromClipboard(data) + if (type === 'elements' && !onlySlide) addElementsFromData(data) + else if (type === 'slides' && !onlyElements) addSlidesFromData(data) } // 普通文本 @@ -114,7 +52,6 @@ export default () => { } return { - addSlidesFromClipboard, pasteTextClipboardData, } } \ No newline at end of file diff --git a/src/hooks/useSlideHandler.ts b/src/hooks/useSlideHandler.ts index 257bfb2b..eb2c3f2b 100644 --- a/src/hooks/useSlideHandler.ts +++ b/src/hooks/useSlideHandler.ts @@ -10,6 +10,7 @@ import { KEYS } from '@/configs/hotkey' import { message } from 'ant-design-vue' import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData' import useHistorySnapshot from '@/hooks/useHistorySnapshot' +import useAddSlidesOrElements from '@/hooks//useAddSlidesOrElements' export default () => { const mainStore = useMainStore() @@ -21,7 +22,8 @@ export default () => { const selectedSlides = computed(() => slides.value.filter((item, index) => selectedSlidesIndex.value.includes(index))) const selectedSlidesId = computed(() => selectedSlides.value.map(item => item.id)) - const { pasteTextClipboardData, addSlidesFromClipboard } = usePasteTextClipboardData() + const { pasteTextClipboardData } = usePasteTextClipboardData() + const { addSlidesFromData } = useAddSlidesOrElements() const { addHistorySnapshot } = useHistorySnapshot() // 重置幻灯片 @@ -108,7 +110,7 @@ export default () => { // 将当前页复制一份到下一页 const copyAndPasteSlide = () => { const slide = JSON.parse(JSON.stringify(currentSlide.value)) - addSlidesFromClipboard([slide]) + addSlidesFromData([slide]) } // 删除当前页,若将删除全部页面,则执行重置幻灯片操作 diff --git a/src/types/export.ts b/src/types/export.ts index 54ecdb78..896f7e39 100644 --- a/src/types/export.ts +++ b/src/types/export.ts @@ -1 +1 @@ -export type DialogForExportTypes = 'image' | 'pdf' | 'json' | 'pptx' | '' \ No newline at end of file +export type DialogForExportTypes = 'image' | 'pdf' | 'json' | 'pptx' | 'pptist' | '' \ No newline at end of file diff --git a/src/views/Editor/EditorHeader/index.vue b/src/views/Editor/EditorHeader/index.vue index ff337105..d376c0ec 100644 --- a/src/views/Editor/EditorHeader/index.vue +++ b/src/views/Editor/EditorHeader/index.vue @@ -5,6 +5,9 @@