From ef0c0db036264b6510add7544f1594dac29589d4 Mon Sep 17 00:00:00 2001 From: pipipi-pikachu Date: Sun, 4 Jul 2021 16:01:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=A2=84=E8=AE=BE?= =?UTF-8?q?=E7=89=88=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/styles/mixin.scss | 1 + src/hooks/usePasteTextClipboardData.ts | 24 +- src/hooks/useSlideHandler.ts | 19 + src/mocks/layout.ts | 464 +++++++++++++++++++++ src/store/state.ts | 3 + src/utils/element.ts | 24 ++ src/views/Editor/Thumbnails/LayoutPool.vue | 63 +++ src/views/Editor/Thumbnails/index.vue | 46 +- 8 files changed, 616 insertions(+), 28 deletions(-) create mode 100644 src/mocks/layout.ts create mode 100644 src/views/Editor/Thumbnails/LayoutPool.vue diff --git a/src/assets/styles/mixin.scss b/src/assets/styles/mixin.scss index a90e2dfd..555fdc64 100644 --- a/src/assets/styles/mixin.scss +++ b/src/assets/styles/mixin.scss @@ -16,6 +16,7 @@ @mixin flex-grid-layout() { display: flex; flex-wrap: wrap; + align-content: flex-start; } @mixin flex-grid-layout-children($col, $colWidth) { diff --git a/src/hooks/usePasteTextClipboardData.ts b/src/hooks/usePasteTextClipboardData.ts index e9521347..626a0b97 100644 --- a/src/hooks/usePasteTextClipboardData.ts +++ b/src/hooks/usePasteTextClipboardData.ts @@ -3,6 +3,7 @@ import { MutationTypes, useStore } from '@/store' import { decrypt } from '@/utils/crypto' import { PPTElement, Slide } from '@/types/slides' import { createRandomCode } from '@/utils/common' +import { createElementIdMap } from '@/utils/element' import { parseText2Paragraphs } from '@/utils/textParser' import useHistorySnapshot from '@/hooks/useHistorySnapshot' import useCreateElement from '@/hooks/useCreateElement' @@ -19,29 +20,6 @@ export default () => { const { addHistorySnapshot } = useHistorySnapshot() const { createTextElement } = useCreateElement() - /** - * 以元素列表为基础,为每一个元素生成新的ID,并关联到旧ID形成一个字典 - * 主要用于复制元素时,维持数据中各处元素ID原有的关系 - * 例如:原本两个组合的元素拥有相同的groupId,复制后依然会拥有另一个相同的groupId - * @param elements 元素列表数据 - * @returns - */ - const createElementIdMap = (elements: PPTElement[]) => { - const groupIdMap = {} - const elIdMap = {} - for (const element of elements) { - const groupId = element.groupId - if (groupId && !groupIdMap[groupId]) { - groupIdMap[groupId] = createRandomCode() - } - elIdMap[element.id] = createRandomCode() - } - return { - groupIdMap, - elIdMap, - } - } - /** * 粘贴元素(一组) * @param elements 元素列表数据 diff --git a/src/hooks/useSlideHandler.ts b/src/hooks/useSlideHandler.ts index cc8794e2..ff66a18c 100644 --- a/src/hooks/useSlideHandler.ts +++ b/src/hooks/useSlideHandler.ts @@ -4,6 +4,7 @@ import { Slide } from '@/types/slides' import { createRandomCode } from '@/utils/common' import { copyText, readClipboard } from '@/utils/clipboard' import { encrypt } from '@/utils/crypto' +import { createElementIdMap } from '@/utils/element' import { KEYS } from '@/configs/hotkey' import { message } from 'ant-design-vue' import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData' @@ -85,6 +86,23 @@ export default () => { addHistorySnapshot() } + // 根据模板创建新页面 + const createSlideByTemplate = (slide: 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] + } + const newSlide = { + ...slide, + id: createRandomCode(8), + } + store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, []) + store.commit(MutationTypes.ADD_SLIDE, newSlide) + addHistorySnapshot() + } + // 将当前页复制一份到下一页 const copyAndPasteSlide = () => { const slide = JSON.parse(JSON.stringify(currentSlide.value)) @@ -122,6 +140,7 @@ export default () => { copySlide, pasteSlide, createSlide, + createSlideByTemplate, copyAndPasteSlide, deleteSlide, cutSlide, diff --git a/src/mocks/layout.ts b/src/mocks/layout.ts new file mode 100644 index 00000000..ed97f930 --- /dev/null +++ b/src/mocks/layout.ts @@ -0,0 +1,464 @@ +import { Slide } from '@/types/slides' + +export const layouts: Slide[] = [ + { + id: 'template', + elements: [ + { + type: 'text', + id: 'dTwwDl', + left: 104.12962962962959, + top: 213.75000000000003, + width: 791.7407407407408, + height: 116, + lineHeight: 1.2, + content: '

在此处添加标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + wordSpace: 6, + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'idn7Mx', + left: 145, + top: 148, + width: 711, + height: 77, + lineHeight: 1.2, + content: '

在此处添加标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + { + type: 'text', + id: '7stmVP', + left: 207.50000000000003, + top: 249.84259259259264, + width: 585, + height: 56, + content: '

在此处添加副标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'Ri5fok', + left: 45, + top: 40, + width: 711, + height: 77, + lineHeight: 1.2, + content: '

在此处添加标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + { + type: 'text', + id: '57jpaB', + left: 45, + top: 150, + width: 585, + height: 56, + content: '

在此处添加副标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'xEykLD', + left: 45, + top: 355, + width: 711, + height: 77, + lineHeight: 1.2, + content: '

在此处添加标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + { + type: 'text', + id: '4lvQ5n', + left: 45, + top: 460, + width: 585, + height: 56, + content: '

在此处添加副标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'shape', + id: '4cbRxp', + left: 0, + top: 200, + width: 546, + height: 362.5, + viewBox: 200, + path: 'M 0 0 L 0 200 L 200 200 Z', + fill: '#5b9bd5', + fixedRatio: false, + opacity: 0.7, + rotate: 0 + }, + { + type: 'shape', + id: 'ookHrf', + left: 0, + top: 0, + width: 300, + height: 320, + viewBox: 200, + path: 'M 0 0 L 0 200 L 200 200 Z', + fill: '#5b9bd5', + fixedRatio: false, + flipH: true, + rotate: 0 + }, + { + type: 'text', + id: 'AkIh3E', + left: 355, + top: 95.11111111111111, + width: 585, + height: 116, + lineHeight: 1.2, + content: '

输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + wordSpace: 6 + }, + { + type: 'text', + id: '7stmVP', + left: 355, + top: 253.25, + width: 585, + height: 56, + content: '

请在此处输入副标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333' + }, + { + type: 'line', + id: 'FnpZs4', + left: 361, + top: 238, + start: [0, 0], + end: [549, 0], + points: ['', ''], + color: '#5b9bd5', + style: 'solid', + width: 2, + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'Hj7ttp', + left: 69.35185185185185, + top: 49.21759259259262, + width: 420, + height: 63, + lineHeight: 1.2, + content: '

1.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'FmKMNB', + left: 69.35185185185185, + top: 129.28240740740745, + width: 420, + height: 384, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'rI7ZeO', + left: 510.64814814814815, + top: 49.21759259259262, + width: 420, + height: 63, + lineHeight: 1.2, + content: '

2.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'KspwGc', + left: 510.64814814814815, + top: 129.28240740740745, + width: 420, + height: 384, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'Rx63Jo', + left: 69.35185185185179, + top: 51.71759259259262, + width: 420, + height: 58, + lineHeight: 1.2, + content: '

1.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'ulyuzE', + left: 69.35185185185179, + top: 131.78240740740745, + width: 420, + height: 129, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'kr35Ca', + left: 510.6481481481481, + top: 51.71759259259262, + width: 420, + height: 58, + lineHeight: 1.2, + content: '

2.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'BNQSpC', + left: 510.6481481481481, + top: 131.78240740740745, + width: 420, + height: 129, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'Vr38Nu', + left: 69.35185185185185, + top: 301.71759259259255, + width: 420, + height: 58, + lineHeight: 1.2, + content: '

3.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'IwKRSu', + left: 69.35185185185185, + top: 381.7824074074074, + width: 420, + height: 129, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: '0Opr1v', + left: 510.64814814814815, + top: 301.71759259259255, + width: 420, + height: 58, + lineHeight: 1.2, + content: '

4.请输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: '4L9Uzz', + left: 510.64814814814815, + top: 381.7824074074074, + width: 420, + height: 129, + content: '

在此处输入内容

在此处输入内容

在此处输入内容

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + ], + }, + { + id: 'template', + elements: [ + { + type: 'text', + id: 'GdEGxg', + left: 134.53703703703704, + top: 127.25, + width: 152.77777777777777, + height: 308, + lineHeight: 1.8, + content: '

请在此处输入标题

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + wordSpace: 8, + fill: 'rgba(91,155,213,1)', + }, + { + type: 'text', + id: 'y5sAfw', + left: 332.8703703703704, + top: 127.25, + width: 532.5925925925926, + height: 50, + content: '

请在此处输入内容1

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'VeuocM', + left: 332.8703703703704, + top: 212.0648148148148, + width: 532.5925925925926, + height: 50, + content: '

请在此处输入内容2

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'RyFWQe', + left: 332.8703703703704, + top: 296.8796296296296, + width: 532.5925925925926, + height: 50, + content: '

请在此处输入内容3

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + { + type: 'text', + id: 'Q56viI', + left: 332.8703703703704, + top: 381.69444444444446, + width: 532.5925925925926, + height: 50, + content: '

请在此处输入内容4

', + rotate: 0, + defaultFontName: 'Microsoft Yahei', + defaultColor: '#333', + fill: 'rgb(242, 242, 242)', + }, + ], + background: { + type: 'solid', + color: '#ffffff', + }, + }, + { + id: 'template', + elements: [], + background: { + type: 'solid', + color: '#ffffff', + }, + }, +] \ No newline at end of file diff --git a/src/store/state.ts b/src/store/state.ts index bbd0d5c2..dbc9d632 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -3,6 +3,7 @@ import { CreatingElement } from '@/types/edit' import { ToolbarState } from '@/types/toolbar' import { slides } from '@/mocks/slides' import { theme } from '@/mocks/theme' +import { layouts } from '@/mocks/layout' import { SYS_FONTS } from '@/configs/font' import { TextAttrs, defaultRichTextAttrs } from '@/utils/prosemirror/utils' @@ -33,6 +34,7 @@ export interface State { richTextAttrs: TextAttrs; selectedTableCells: string[]; isScaling: boolean; + layouts: Slide[]; } export const state: State = { @@ -62,4 +64,5 @@ export const state: State = { richTextAttrs: defaultRichTextAttrs, // 富文本状态 selectedTableCells: [], // 选中的表格单元格 isScaling: false, // 正在进行元素缩放 + layouts: layouts, // 预置版式 } \ No newline at end of file diff --git a/src/utils/element.ts b/src/utils/element.ts index 1b058635..95418482 100644 --- a/src/utils/element.ts +++ b/src/utils/element.ts @@ -1,4 +1,5 @@ import { PPTElement } from '@/types/slides' +import { createRandomCode } from '@/utils/common' interface RotatedElementData { left: number; @@ -148,4 +149,27 @@ export const uniqAlignLines = (lines: AlignLine[]) => { } }) return uniqLines +} + +/** + * 以元素列表为基础,为每一个元素生成新的ID,并关联到旧ID形成一个字典 + * 主要用于复制元素时,维持数据中各处元素ID原有的关系 + * 例如:原本两个组合的元素拥有相同的groupId,复制后依然会拥有另一个相同的groupId + * @param elements 元素列表数据 + * @returns + */ +export const createElementIdMap = (elements: PPTElement[]) => { + const groupIdMap = {} + const elIdMap = {} + for (const element of elements) { + const groupId = element.groupId + if (groupId && !groupIdMap[groupId]) { + groupIdMap[groupId] = createRandomCode() + } + elIdMap[element.id] = createRandomCode() + } + return { + groupIdMap, + elIdMap, + } } \ No newline at end of file diff --git a/src/views/Editor/Thumbnails/LayoutPool.vue b/src/views/Editor/Thumbnails/LayoutPool.vue new file mode 100644 index 00000000..44ac5a74 --- /dev/null +++ b/src/views/Editor/Thumbnails/LayoutPool.vue @@ -0,0 +1,63 @@ + + + + + \ No newline at end of file diff --git a/src/views/Editor/Thumbnails/index.vue b/src/views/Editor/Thumbnails/index.vue index 22335a1e..eeacaa7d 100644 --- a/src/views/Editor/Thumbnails/index.vue +++ b/src/views/Editor/Thumbnails/index.vue @@ -5,7 +5,16 @@ v-click-outside="() => setThumbnailsFocus(false)" v-contextmenu="contextmenusThumbnails" > -
添加幻灯片
+
+
添加幻灯片
+ + +
+
+
+