mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 添加预设版式
This commit is contained in:
parent
3e78005567
commit
ef0c0db036
@ -16,6 +16,7 @@
|
|||||||
@mixin flex-grid-layout() {
|
@mixin flex-grid-layout() {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin flex-grid-layout-children($col, $colWidth) {
|
@mixin flex-grid-layout-children($col, $colWidth) {
|
||||||
|
@ -3,6 +3,7 @@ import { MutationTypes, useStore } from '@/store'
|
|||||||
import { decrypt } from '@/utils/crypto'
|
import { decrypt } from '@/utils/crypto'
|
||||||
import { PPTElement, Slide } from '@/types/slides'
|
import { PPTElement, Slide } from '@/types/slides'
|
||||||
import { createRandomCode } from '@/utils/common'
|
import { createRandomCode } from '@/utils/common'
|
||||||
|
import { createElementIdMap } from '@/utils/element'
|
||||||
import { parseText2Paragraphs } from '@/utils/textParser'
|
import { parseText2Paragraphs } from '@/utils/textParser'
|
||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||||
import useCreateElement from '@/hooks/useCreateElement'
|
import useCreateElement from '@/hooks/useCreateElement'
|
||||||
@ -19,29 +20,6 @@ export default () => {
|
|||||||
const { addHistorySnapshot } = useHistorySnapshot()
|
const { addHistorySnapshot } = useHistorySnapshot()
|
||||||
const { createTextElement } = useCreateElement()
|
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 元素列表数据
|
* @param elements 元素列表数据
|
||||||
|
@ -4,6 +4,7 @@ import { Slide } from '@/types/slides'
|
|||||||
import { createRandomCode } from '@/utils/common'
|
import { createRandomCode } from '@/utils/common'
|
||||||
import { copyText, readClipboard } from '@/utils/clipboard'
|
import { copyText, readClipboard } from '@/utils/clipboard'
|
||||||
import { encrypt } from '@/utils/crypto'
|
import { encrypt } from '@/utils/crypto'
|
||||||
|
import { createElementIdMap } from '@/utils/element'
|
||||||
import { KEYS } from '@/configs/hotkey'
|
import { KEYS } from '@/configs/hotkey'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
|
import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
|
||||||
@ -85,6 +86,23 @@ export default () => {
|
|||||||
addHistorySnapshot()
|
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 copyAndPasteSlide = () => {
|
||||||
const slide = JSON.parse(JSON.stringify(currentSlide.value))
|
const slide = JSON.parse(JSON.stringify(currentSlide.value))
|
||||||
@ -122,6 +140,7 @@ export default () => {
|
|||||||
copySlide,
|
copySlide,
|
||||||
pasteSlide,
|
pasteSlide,
|
||||||
createSlide,
|
createSlide,
|
||||||
|
createSlideByTemplate,
|
||||||
copyAndPasteSlide,
|
copyAndPasteSlide,
|
||||||
deleteSlide,
|
deleteSlide,
|
||||||
cutSlide,
|
cutSlide,
|
||||||
|
464
src/mocks/layout.ts
Normal file
464
src/mocks/layout.ts
Normal file
@ -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: '<p style=\'text-align: center;\'><strong><span style=\'font-size: 80px\'>在此处添加标题</span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'font-size: 48px\'>在此处添加标题</span></strong></p>',
|
||||||
|
rotate: 0,
|
||||||
|
defaultFontName: 'Microsoft Yahei',
|
||||||
|
defaultColor: '#333',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
id: '7stmVP',
|
||||||
|
left: 207.50000000000003,
|
||||||
|
top: 249.84259259259264,
|
||||||
|
width: 585,
|
||||||
|
height: 56,
|
||||||
|
content: '<p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处添加副标题</span></p>',
|
||||||
|
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: '<p style=\'\'><strong><span style=\'font-size: 48px\'>在此处添加标题</span></strong></p>',
|
||||||
|
rotate: 0,
|
||||||
|
defaultFontName: 'Microsoft Yahei',
|
||||||
|
defaultColor: '#333',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
id: '57jpaB',
|
||||||
|
left: 45,
|
||||||
|
top: 150,
|
||||||
|
width: 585,
|
||||||
|
height: 56,
|
||||||
|
content: '<p style=\'\'><span style=\'font-size: 24px\'>在此处添加副标题</span></p>',
|
||||||
|
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: '<p><strong><span style=\'font-size: 48px\'>在此处添加标题</span></strong></p>',
|
||||||
|
rotate: 0,
|
||||||
|
defaultFontName: 'Microsoft Yahei',
|
||||||
|
defaultColor: '#333',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
id: '4lvQ5n',
|
||||||
|
left: 45,
|
||||||
|
top: 460,
|
||||||
|
width: 585,
|
||||||
|
height: 56,
|
||||||
|
content: '<p><span style=\'font-size: 24px\'>在此处添加副标题</span></p>',
|
||||||
|
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: '<p style=\'\'><strong><span style=\'font-size: 80px\'>输入标题</span></strong></p>',
|
||||||
|
rotate: 0,
|
||||||
|
defaultFontName: 'Microsoft Yahei',
|
||||||
|
defaultColor: '#333',
|
||||||
|
wordSpace: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
id: '7stmVP',
|
||||||
|
left: 355,
|
||||||
|
top: 253.25,
|
||||||
|
width: 585,
|
||||||
|
height: 56,
|
||||||
|
content: '<p><span style=\'font-size: 24px\'>请在此处输入副标题</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 36px\'>1.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 36px\'>2.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 24px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 32px\'>1.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 32px\'>2.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 32px\'>3.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 32px\'>4.请输入标题</span></span></strong></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p><p style=\'text-align: center;\'><span style=\'font-size: 22px\'>在此处输入内容</span></p>',
|
||||||
|
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: '<p style=\'text-align: center;\'><strong><span style=\'color: #ffffff;\'><span style=\'font-size: 40px\'>请在此处输入标题</span></span></strong></p>',
|
||||||
|
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: '<blockquote><p style=\'\'>请在此处输入内容1</p></blockquote>',
|
||||||
|
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: '<blockquote><p style=\'\'>请在此处输入内容2</p></blockquote>',
|
||||||
|
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: '<blockquote><p style=\'\'>请在此处输入内容3</p></blockquote>',
|
||||||
|
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: '<blockquote><p style=\'\'>请在此处输入内容4</p></blockquote>',
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
@ -3,6 +3,7 @@ import { CreatingElement } from '@/types/edit'
|
|||||||
import { ToolbarState } from '@/types/toolbar'
|
import { ToolbarState } from '@/types/toolbar'
|
||||||
import { slides } from '@/mocks/slides'
|
import { slides } from '@/mocks/slides'
|
||||||
import { theme } from '@/mocks/theme'
|
import { theme } from '@/mocks/theme'
|
||||||
|
import { layouts } from '@/mocks/layout'
|
||||||
import { SYS_FONTS } from '@/configs/font'
|
import { SYS_FONTS } from '@/configs/font'
|
||||||
import { TextAttrs, defaultRichTextAttrs } from '@/utils/prosemirror/utils'
|
import { TextAttrs, defaultRichTextAttrs } from '@/utils/prosemirror/utils'
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ export interface State {
|
|||||||
richTextAttrs: TextAttrs;
|
richTextAttrs: TextAttrs;
|
||||||
selectedTableCells: string[];
|
selectedTableCells: string[];
|
||||||
isScaling: boolean;
|
isScaling: boolean;
|
||||||
|
layouts: Slide[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const state: State = {
|
export const state: State = {
|
||||||
@ -62,4 +64,5 @@ export const state: State = {
|
|||||||
richTextAttrs: defaultRichTextAttrs, // 富文本状态
|
richTextAttrs: defaultRichTextAttrs, // 富文本状态
|
||||||
selectedTableCells: [], // 选中的表格单元格
|
selectedTableCells: [], // 选中的表格单元格
|
||||||
isScaling: false, // 正在进行元素缩放
|
isScaling: false, // 正在进行元素缩放
|
||||||
|
layouts: layouts, // 预置版式
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { PPTElement } from '@/types/slides'
|
import { PPTElement } from '@/types/slides'
|
||||||
|
import { createRandomCode } from '@/utils/common'
|
||||||
|
|
||||||
interface RotatedElementData {
|
interface RotatedElementData {
|
||||||
left: number;
|
left: number;
|
||||||
@ -148,4 +149,27 @@ export const uniqAlignLines = (lines: AlignLine[]) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return uniqLines
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
63
src/views/Editor/Thumbnails/LayoutPool.vue
Normal file
63
src/views/Editor/Thumbnails/LayoutPool.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-pool">
|
||||||
|
<div
|
||||||
|
class="layout-item"
|
||||||
|
v-for="slide in layouts"
|
||||||
|
:key="slide.id"
|
||||||
|
@click="selectSlideTemplate(slide)"
|
||||||
|
>
|
||||||
|
<ThumbnailSlide class="thumbnail" :slide="slide" :size="180" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent } from 'vue'
|
||||||
|
import { useStore } from '@/store'
|
||||||
|
import { Slide } from '@/types/slides'
|
||||||
|
|
||||||
|
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'layout-pool',
|
||||||
|
components: {
|
||||||
|
ThumbnailSlide,
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const store = useStore()
|
||||||
|
const layouts = computed(() => store.state.layouts)
|
||||||
|
|
||||||
|
const selectSlideTemplate = (slide: Slide) => {
|
||||||
|
emit('select', slide)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
layouts,
|
||||||
|
selectSlideTemplate,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.layout-pool {
|
||||||
|
width: 400px;
|
||||||
|
height: 500px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
@include flex-grid-layout();
|
||||||
|
}
|
||||||
|
.layout-item {
|
||||||
|
@include flex-grid-layout-children(2, 48%);
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
outline: 1px solid $borderColor;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
outline-color: $themeColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -5,7 +5,16 @@
|
|||||||
v-click-outside="() => setThumbnailsFocus(false)"
|
v-click-outside="() => setThumbnailsFocus(false)"
|
||||||
v-contextmenu="contextmenusThumbnails"
|
v-contextmenu="contextmenusThumbnails"
|
||||||
>
|
>
|
||||||
<div class="add-slide" @click="createSlide()"><IconPlus class="icon" />添加幻灯片</div>
|
<div class="add-slide">
|
||||||
|
<div class="btn" @click="createSlide()"><IconPlus class="icon" />添加幻灯片</div>
|
||||||
|
<Popover trigger="click" placement="bottomLeft" v-model:visible="presetLayoutPopoverVisible">
|
||||||
|
<template #content>
|
||||||
|
<LayoutPool @select="slide => { createSlideByTemplate(slide); presetLayoutPopoverVisible = false }" />
|
||||||
|
</template>
|
||||||
|
<div class="select-btn"><IconDown /></div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Draggable
|
<Draggable
|
||||||
class="thumbnail-list"
|
class="thumbnail-list"
|
||||||
:modelValue="slides"
|
:modelValue="slides"
|
||||||
@ -34,7 +43,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed, defineComponent, ref } from 'vue'
|
||||||
import { MutationTypes, useStore } from '@/store'
|
import { MutationTypes, useStore } from '@/store'
|
||||||
import { fillDigit } from '@/utils/common'
|
import { fillDigit } from '@/utils/common'
|
||||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||||
@ -43,12 +52,14 @@ import useScreening from '@/hooks/useScreening'
|
|||||||
|
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||||
|
import LayoutPool from './LayoutPool.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'thumbnails',
|
name: 'thumbnails',
|
||||||
components: {
|
components: {
|
||||||
Draggable,
|
Draggable,
|
||||||
ThumbnailSlide,
|
ThumbnailSlide,
|
||||||
|
LayoutPool,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@ -58,10 +69,13 @@ export default defineComponent({
|
|||||||
const shiftKeyState = computed(() => store.state.shiftKeyState)
|
const shiftKeyState = computed(() => store.state.shiftKeyState)
|
||||||
const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value])
|
const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value])
|
||||||
|
|
||||||
|
const presetLayoutPopoverVisible = ref(false)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
copySlide,
|
copySlide,
|
||||||
pasteSlide,
|
pasteSlide,
|
||||||
createSlide,
|
createSlide,
|
||||||
|
createSlideByTemplate,
|
||||||
copyAndPasteSlide,
|
copyAndPasteSlide,
|
||||||
deleteSlide,
|
deleteSlide,
|
||||||
cutSlide,
|
cutSlide,
|
||||||
@ -225,11 +239,13 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setThumbnailsFocus,
|
|
||||||
slides,
|
slides,
|
||||||
slideIndex,
|
slideIndex,
|
||||||
selectedSlidesIndex,
|
selectedSlidesIndex,
|
||||||
|
presetLayoutPopoverVisible,
|
||||||
createSlide,
|
createSlide,
|
||||||
|
createSlideByTemplate,
|
||||||
|
setThumbnailsFocus,
|
||||||
handleClickSlideThumbnail,
|
handleClickSlideThumbnail,
|
||||||
contextmenusThumbnails,
|
contextmenusThumbnails,
|
||||||
contextmenusThumbnailItem,
|
contextmenusThumbnailItem,
|
||||||
@ -252,12 +268,32 @@ export default defineComponent({
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-bottom: 1px solid $borderColor;
|
border-bottom: 1px solid $borderColor;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $lightGray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.select-btn {
|
||||||
|
width: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-left: 1px solid $borderColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $lightGray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user