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() {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
@mixin flex-grid-layout-children($col, $colWidth) {
|
||||
|
@ -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 元素列表数据
|
||||
|
@ -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,
|
||||
|
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 { 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, // 预置版式
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
|
||||
interface RotatedElementData {
|
||||
left: number;
|
||||
@ -149,3 +150,26 @@ 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,
|
||||
}
|
||||
}
|
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-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
|
||||
class="thumbnail-list"
|
||||
:modelValue="slides"
|
||||
@ -34,7 +43,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { fillDigit } from '@/utils/common'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
@ -43,12 +52,14 @@ import useScreening from '@/hooks/useScreening'
|
||||
|
||||
import Draggable from 'vuedraggable'
|
||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||
import LayoutPool from './LayoutPool.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'thumbnails',
|
||||
components: {
|
||||
Draggable,
|
||||
ThumbnailSlide,
|
||||
LayoutPool,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
@ -58,10 +69,13 @@ export default defineComponent({
|
||||
const shiftKeyState = computed(() => store.state.shiftKeyState)
|
||||
const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value])
|
||||
|
||||
const presetLayoutPopoverVisible = ref(false)
|
||||
|
||||
const {
|
||||
copySlide,
|
||||
pasteSlide,
|
||||
createSlide,
|
||||
createSlideByTemplate,
|
||||
copyAndPasteSlide,
|
||||
deleteSlide,
|
||||
cutSlide,
|
||||
@ -225,11 +239,13 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
setThumbnailsFocus,
|
||||
slides,
|
||||
slideIndex,
|
||||
selectedSlidesIndex,
|
||||
presetLayoutPopoverVisible,
|
||||
createSlide,
|
||||
createSlideByTemplate,
|
||||
setThumbnailsFocus,
|
||||
handleClickSlideThumbnail,
|
||||
contextmenusThumbnails,
|
||||
contextmenusThumbnailItem,
|
||||
@ -252,12 +268,32 @@ export default defineComponent({
|
||||
height: 40px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid $borderColor;
|
||||
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 {
|
||||
margin-right: 3px;
|
||||
font-size: 14px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user