diff --git a/src/configs/keyCode.ts b/src/configs/keyCode.ts index 4f8cd2fa..13ec2d10 100644 --- a/src/configs/keyCode.ts +++ b/src/configs/keyCode.ts @@ -1,5 +1,4 @@ export enum KEYCODE { - S = 83, C = 67, X = 88, Z = 90, diff --git a/src/store/constants.ts b/src/store/constants.ts index c7d9d15c..e654e77b 100644 --- a/src/store/constants.ts +++ b/src/store/constants.ts @@ -9,7 +9,6 @@ export enum MutationTypes { SET_EDITORAREA_FOCUS = 'setEditorAreaFocus', SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState', SET_AVAILABLE_FONTS = 'setAvailableFonts', - SET_SAVE_STATE = 'setSaveState', // slides SET_SLIDES = 'setSlides', diff --git a/src/store/mutations.ts b/src/store/mutations.ts index 2290fe0d..2d385cef 100644 --- a/src/store/mutations.ts +++ b/src/store/mutations.ts @@ -1,5 +1,5 @@ import { MutationTypes } from './constants' -import { State, SaveState } from './state' +import { State } from './state' import { Slide, PPTElement } from '@/types/slides' import { FONT_NAMES } from '@/configs/fontName' import { isSupportFontFamily } from '@/utils/index' @@ -36,7 +36,6 @@ export type Mutations = { [MutationTypes.SET_EDITORAREA_FOCUS](state: State, isFocus: boolean): void; [MutationTypes.SET_DISABLE_HOTKEYS_STATE](state: State, disable: boolean): void; [MutationTypes.SET_AVAILABLE_FONTS](state: State): void; - [MutationTypes.SET_SAVE_STATE](state: State, saveState: SaveState ): void; [MutationTypes.SET_SLIDES](state: State, slides: Slide[]): void; [MutationTypes.ADD_SLIDES](state: State, data: AddSlidesData): void; [MutationTypes.SET_SLIDE](state: State, data: SetSlideData): void; @@ -91,10 +90,6 @@ export const mutations: Mutations = { state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en)) }, - [MutationTypes.SET_SAVE_STATE](state, saveState) { - state.saveState = saveState - }, - // slides [MutationTypes.SET_SLIDES](state, slides) { diff --git a/src/store/state.ts b/src/store/state.ts index 1f7c5b4a..9d500efd 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -2,8 +2,6 @@ import { Slide } from '@/types/slides' import { slides } from '@/mocks/index' import { FontName } from '@/configs/fontName' -export type SaveState = 'complete' | 'pending' - export type State = { activeElementIdList: string[]; handleElementId: string; @@ -13,7 +11,6 @@ export type State = { editorAreaFocus: boolean; disableHotkeys: boolean; availableFonts: FontName[]; - saveState: SaveState; slides: Slide[]; slideIndex: number; cursor: number; @@ -29,7 +26,6 @@ export const state: State = { editorAreaFocus: false, disableHotkeys: false, availableFonts: [], - saveState: 'complete', slides: slides, slideIndex: 0, cursor: -1, diff --git a/src/types/edit.ts b/src/types/edit.ts new file mode 100644 index 00000000..3863e200 --- /dev/null +++ b/src/types/edit.ts @@ -0,0 +1,28 @@ +export type ElementOrderCommand = 'up' | 'down' | 'top' | 'bottom' + +export enum ElementOrderCommands { + UP = 'up', + DOWN = 'down', + TOP = 'top', + BOTTOM = 'bottom', +} + +export type ElementAlignCommand = 'top'| 'bottom' | 'left' | 'right' | 'vertical' | 'horizontal' + +export enum ElementAlignCommands { + TOP = 'top', + BOTTOM = 'bottom', + LEFT = 'left', + RIGHT = 'right', + VERTICAL = 'vertical', + HORIZONTAL = 'horizontal', +} + +export type ElementScaleHandler = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + +export type ElementLockCommand = 'lock' | 'unlock' + +export enum ElementLockCommands { + LOCK = 'lock', + UNLOCK = 'unlock', +} \ No newline at end of file diff --git a/src/types/slides.ts b/src/types/slides.ts index a95f2e7b..1e903ff4 100644 --- a/src/types/slides.ts +++ b/src/types/slides.ts @@ -19,7 +19,6 @@ export interface PPTElementBorderProps { export interface PPTTextElement extends PPTElementBaseProps, PPTElementSizeProps, PPTElementBorderProps { type: 'text'; - textType: string; content: string; rotate?: number; fill?: string; @@ -28,20 +27,18 @@ export interface PPTTextElement extends PPTElementBaseProps, PPTElementSizeProps segmentSpacing?: number; letterSpacing?: number; shadow?: string; - padding?: number; } -interface ImageClip { - range: [[number, number], [number, number]]; - shape: string; -} export interface PPTImageElement extends PPTElementBaseProps, PPTElementSizeProps, PPTElementBorderProps { type: 'image'; lockRatio: boolean; imgUrl: string; rotate?: number; filter?: string; - clip?: ImageClip; + clip?: { + range: [[number, number], [number, number]]; + shape: string; + }; flip?: string; shadow?: string; } @@ -58,15 +55,6 @@ export interface PPTShapeElement extends PPTElementBaseProps, PPTElementSizeProp textAlign?: string; } -export interface PPTIconElement extends PPTElementBaseProps, PPTElementSizeProps { - type: 'icon'; - color: string; - lockRatio: boolean; - svgCode: string; - rotate?: number; - shadow?: string; -} - export interface PPTLineElement extends PPTElementBaseProps { type: 'line'; start: [number, number]; @@ -78,23 +66,11 @@ export interface PPTLineElement extends PPTElementBaseProps { lineType: string; } -export interface BarChartSeries { - name: string; - data: number[]; -} -export interface BarChartData { - axisData: string[]; - series: BarChartSeries[]; -} -export interface PieChartData { - name: string; - value: number -} export interface PPTChartElement extends PPTElementBaseProps, PPTElementSizeProps, PPTElementBorderProps { type: 'chart'; chartType: string; theme: string; - data: PieChartData[] | BarChartData; + data: Object; } export interface TableCell { @@ -111,19 +87,13 @@ export interface PPTTableElement extends PPTElementBaseProps, PPTElementSizeProp colSizes: number[]; data: TableCell[][]; } -export interface PPTIframeElement extends PPTElementBaseProps, PPTElementSizeProps, PPTElementBorderProps { - type: 'iframe'; - src: string; -} export type PPTElement = PPTTextElement | PPTImageElement | PPTShapeElement | - PPTIconElement | PPTLineElement | PPTChartElement | - PPTTableElement | - PPTIframeElement + PPTTableElement export interface PPTAnimation { elId: string; diff --git a/src/utils/index.ts b/src/utils/index.ts index 21a773a0..b8cb8113 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -169,6 +169,17 @@ export const copyText = (text: string) => { }) } +// 读取剪贴板 +export const readClipboard = () => { + if(navigator.clipboard) { + navigator.clipboard.readText().then(text => { + if(!text) return { err: '剪贴板为空或者不包含文本' } + return { text } + }) + } + return { err: '浏览器不支持或禁止访问剪贴板' } +} + // 加密函数 export const encrypt = (msg: string) => { return CryptoJS.AES.encrypt(msg, CRYPTO_KEY).toString() diff --git a/src/views/Editor/Canvas/utils/alignToCanvas.ts b/src/views/Editor/Canvas/utils/alignToCanvas.ts new file mode 100644 index 00000000..4314f9be --- /dev/null +++ b/src/views/Editor/Canvas/utils/alignToCanvas.ts @@ -0,0 +1,44 @@ +import { PPTElement } from '@/types/slides' +import { ElementAlignCommand, ElementAlignCommands } from '@/types/edit' +import { getElementListRange } from './elementRange' +import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' + +// 将元素对齐到屏幕 +export const alignElement = (elementList: PPTElement[], activeElementList: PPTElement[], activeElementIdList: string[], command: ElementAlignCommand) => { + const viewportWidth = VIEWPORT_SIZE + const viewportHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + const { minX, maxX, minY, maxY } = getElementListRange(activeElementList) + + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + for(const element of copyOfElementList) { + if(!activeElementIdList.includes(element.elId)) continue + + if(command === ElementAlignCommands.TOP) { + const offsetY = minY - 0 + element.top = element.top - offsetY + } + else if(command === ElementAlignCommands.VERTICAL) { + const offsetY = minY + (maxY - minY) / 2 - viewportHeight / 2 + element.top = element.top - offsetY + } + else if(command === ElementAlignCommands.BOTTOM) { + const offsetY = maxY - viewportHeight + element.top = element.top - offsetY + } + + else if(command === ElementAlignCommands.LEFT) { + const offsetX = minX - 0 + element.left = element.left - offsetX + } + else if(command === ElementAlignCommands.HORIZONTAL) { + const offsetX = minX + (maxX - minX) / 2 - viewportWidth / 2 + element.left = element.left - offsetX + } + else if(command === ElementAlignCommands.RIGHT) { + const offsetX = maxX - viewportWidth + element.left = element.left - offsetX + } + } + + return copyOfElementList +} \ No newline at end of file diff --git a/src/views/Editor/Canvas/utils/elementCombine.ts b/src/views/Editor/Canvas/utils/elementCombine.ts new file mode 100644 index 00000000..38fbcbc4 --- /dev/null +++ b/src/views/Editor/Canvas/utils/elementCombine.ts @@ -0,0 +1,41 @@ +import { createRandomCode } from '@/utils/index' +import { PPTElement } from '@/types/slides' + +// 组合元素(为当前所有激活元素添加一个相同的groupId) +export const combineElements = (elementList: PPTElement[], activeElementList: PPTElement[], activeElementIdList: string[]) => { + if(!activeElementList.length) return null + + let copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + const groupId = createRandomCode() + + const combineElementList: PPTElement[] = [] + for(const element of copyOfElementList) { + if(activeElementIdList.includes(element.elId)) { + element.groupId = groupId + combineElementList.push(element) + } + } + + // 注意,组合元素的层级应该是连续的,所以需要获取该组元素中最顶层的元素,将组内其他成员从原位置移动到最顶层的元素的下面 + const combineElementMaxIndex = copyOfElementList.findIndex(_element => _element.elId === combineElementList[combineElementList.length - 1].elId) + const combineElementIdList = combineElementList.map(_element => _element.elId) + copyOfElementList = copyOfElementList.filter(_element => !combineElementIdList.includes(_element.elId)) + + const insertIndex = combineElementMaxIndex - combineElementList.length + 1 + copyOfElementList.splice(insertIndex, 0, ...combineElementList) + + return copyOfElementList +} + +// 取消组合元素(移除所有被激活元素的groupId) +export const uncombineElements = (elementList: PPTElement[], activeElementList: PPTElement[], activeElementIdList: string[]) => { + if(!activeElementList.length) return null + const hasElementInGroup = activeElementList.some(item => item.groupId) + if(!hasElementInGroup) return null + + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + for(const element of copyOfElementList) { + if(activeElementIdList.includes(element.elId) && element.groupId) delete element.groupId + } + return copyOfElementList +} \ No newline at end of file diff --git a/src/views/Editor/Canvas/utils/elementLock.ts b/src/views/Editor/Canvas/utils/elementLock.ts new file mode 100644 index 00000000..9cdf12a8 --- /dev/null +++ b/src/views/Editor/Canvas/utils/elementLock.ts @@ -0,0 +1,34 @@ +import { PPTElement } from '@/types/slides' +import { ElementLockCommand, ElementLockCommands } from '@/types/edit' + +const lock = (copyOfElementList: PPTElement[], handleElement: PPTElement, activeElementIdList: string[]) => { + for(const element of copyOfElementList) { + if(activeElementIdList.includes(handleElement.elId)) element.isLock = true + } + return copyOfElementList +} + +const unlock = (copyOfElementList: PPTElement[], handleElement: PPTElement) => { + if(handleElement.groupId) { + for(const element of copyOfElementList) { + if(element.groupId === handleElement.groupId) element.isLock = false + } + return copyOfElementList + } + + for(const element of copyOfElementList) { + if(element.elId === handleElement.elId) { + element.isLock = false + break + } + } + return copyOfElementList +} + +// 锁定&解锁 元素 +export const lockElement = (elementList: PPTElement[], handleElement: PPTElement, activeElementIdList: string[], command: ElementLockCommand) => { + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + + if(command === ElementLockCommands.LOCK) return lock(copyOfElementList, handleElement, activeElementIdList) + return unlock(copyOfElementList, handleElement) +} \ No newline at end of file diff --git a/src/views/Editor/Canvas/utils/elementOrder.ts b/src/views/Editor/Canvas/utils/elementOrder.ts new file mode 100644 index 00000000..0039c804 --- /dev/null +++ b/src/views/Editor/Canvas/utils/elementOrder.ts @@ -0,0 +1,170 @@ +import { PPTElement } from '@/types/slides' +import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit' + +// 获取组合元素层级范围(组合成员中的最大层级和最小层级) +const getCombineElementIndexRange = (elementList: PPTElement[], combineElementList: PPTElement[]) => { + const minIndex = elementList.findIndex(_element => _element.elId === combineElementList[0].elId) + const maxIndex = elementList.findIndex(_element => _element.elId === combineElementList[combineElementList.length - 1].elId) + return { minIndex, maxIndex } +} + +// 上移一层,返回移动后新的元素列表(下移一层逻辑类似) +const moveUpElement = (elementList: PPTElement[], element: PPTElement) => { + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + + // 被操作的元素是组合元素成员 + if(element.groupId) { + + // 获取该组合元素全部成员,以及组合元素层级范围 + const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId) + const { minIndex, maxIndex } = getCombineElementIndexRange(elementList, combineElementList) + + // 无法移动(已经处在顶层) + if(maxIndex === elementList.length - 1) return null + + // 该组合元素上一层的元素,以下简称为【元素next】 + const nextElement = copyOfElementList[maxIndex + 1] + + // 从元素列表中移除该组合元素全部成员 + const movedElementList = copyOfElementList.splice(minIndex, combineElementList.length) + + // 如果【元素next】也是组合元素成员(另一个组合,不是上面被移除的那一组,以下简称为【组合next】) + // 需要获取【组合next】全部成员的长度,将上面移除的组合元素全部成员添加到【组合next】全部成员的上方 + if(nextElement.groupId) { + const nextCombineElementList = copyOfElementList.filter(_element => _element.groupId === nextElement.groupId) + copyOfElementList.splice(minIndex + nextCombineElementList.length, 0, ...movedElementList) + } + + // 如果【元素next】是单独的元素(非组合成员),将上面移除的组合元素全部成员添加到【元素next】上方 + else copyOfElementList.splice(minIndex + 1, 0, ...movedElementList) + } + + // 被操作的元素是单独的元素(非组合成员) + else { + + // 元素在元素列表中的层级 + const elementIndex = elementList.findIndex(item => item.elId === element.elId) + + // 无法移动(已经处在顶层) + if(elementIndex === elementList.length - 1) return null + + // 上一层的元素,以下简称为【元素next】 + const nextElement = copyOfElementList[elementIndex + 1] + + // 从元素列表中移除被操作的元素 + const movedElement = copyOfElementList.splice(elementIndex, 1)[0] + + // 如果【元素next】是组合元素成员 + // 需要获取该组合全部成员的长度,将上面移除的元素添加到该组合全部成员的上方 + if(nextElement.groupId) { + const combineElementList = copyOfElementList.filter(_element => _element.groupId === nextElement.groupId) + copyOfElementList.splice(elementIndex + combineElementList.length, 0, movedElement) + } + + // 如果【元素next】是单独的元素(非组合成员),将上面移除的元素添加到【元素next】上方 + else copyOfElementList.splice(elementIndex + 1, 0, movedElement) + } + + return copyOfElementList +} + +// 下移一层 +const moveDownElement = (elementList: PPTElement[], element: PPTElement) => { + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + + if(element.groupId) { + const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId) + const { minIndex } = getCombineElementIndexRange(elementList, combineElementList) + if(minIndex === 0) return null + const prevElement = copyOfElementList[minIndex - 1] + const movedElementList = copyOfElementList.splice(minIndex, combineElementList.length) + if(prevElement.groupId) { + const prevCombineElementList = copyOfElementList.filter(_element => _element.groupId === prevElement.groupId) + copyOfElementList.splice(minIndex - prevCombineElementList.length, 0, ...movedElementList) + } + else copyOfElementList.splice(minIndex - 1, 0, ...movedElementList) + } + + else { + const elementIndex = elementList.findIndex(item => item.elId === element.elId) + if(elementIndex === 0) return null + const prevElement = copyOfElementList[elementIndex - 1] + const movedElement = copyOfElementList.splice(elementIndex, 1)[0] + if(prevElement.groupId) { + const combineElementList = copyOfElementList.filter(_element => _element.groupId === prevElement.groupId) + copyOfElementList.splice(elementIndex - combineElementList.length, 0, movedElement) + } + else copyOfElementList.splice(elementIndex - 1, 0, movedElement) + } + + return copyOfElementList +} + +// 置顶层,返回移动后新的元素列表(置底层逻辑类似) +const moveTopElement = (elementList: PPTElement[], element: PPTElement) => { + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + + // 被操作的元素是组合元素成员 + if(element.groupId) { + + // 获取该组合元素全部成员,以及组合元素层级范围 + const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId) + const { minIndex, maxIndex } = getCombineElementIndexRange(elementList, combineElementList) + + // 无法移动(已经处在顶层) + if(maxIndex === elementList.length - 1) return null + + // 从元素列表中移除该组合元素全部成员,然后添加到元素列表最上方 + const movedElementList = copyOfElementList.splice(minIndex, combineElementList.length) + copyOfElementList.push(...movedElementList) + } + + // 被操作的元素是单独的元素(非组合成员) + else { + + // 元素在元素列表中的层级 + const elementIndex = elementList.findIndex(item => item.elId === element.elId) + + // 无法移动(已经处在顶层) + if(elementIndex === elementList.length - 1) return null + + // 从元素列表中移除该元素,然后添加到元素列表最上方 + copyOfElementList.splice(elementIndex, 1) + copyOfElementList.push(element) + } + + return copyOfElementList +} + +// 置底层 +const moveBottomElement = (elementList: PPTElement[], element: PPTElement) => { + const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList)) + + if(element.groupId) { + const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId) + const { minIndex } = getCombineElementIndexRange(elementList, combineElementList) + if(minIndex === 0) return null + const movedElementList = copyOfElementList.splice(minIndex, combineElementList.length) + copyOfElementList.unshift(...movedElementList) + } + + else { + const elementIndex = elementList.findIndex(item => item.elId === element.elId) + if(elementIndex === 0) return null + copyOfElementList.splice(elementIndex, 1) + copyOfElementList.unshift(element) + } + + return copyOfElementList +} + +export const setElementOrder = (elementList: PPTElement[], element: PPTElement, command: ElementOrderCommand) => { + let newElementList = null + + if(command === ElementOrderCommands.UP) newElementList = moveUpElement(elementList, element) + else if(command === ElementOrderCommands.DOWN) newElementList = moveDownElement(elementList, element) + else if(command === ElementOrderCommands.TOP) newElementList = moveTopElement(elementList, element) + else if(command === ElementOrderCommands.BOTTOM) newElementList = moveBottomElement(elementList, element) + + return newElementList +} \ No newline at end of file diff --git a/src/views/Editor/Canvas/utils/elementRange.ts b/src/views/Editor/Canvas/utils/elementRange.ts index 80b3a355..af38dde2 100644 --- a/src/views/Editor/Canvas/utils/elementRange.ts +++ b/src/views/Editor/Canvas/utils/elementRange.ts @@ -1,7 +1,7 @@ -import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTIconElement } from '@/types/slides' +import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides' // 获取矩形旋转后在画布中的位置范围 -export const getRectRotatedRange = (element: PPTTextElement | PPTImageElement | PPTShapeElement | PPTIconElement) => { +export const getRectRotatedRange = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => { const { left, top, width, height, rotate = 0 } = element const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2 diff --git a/src/views/Editor/Canvas/utils/elementRotate.ts b/src/views/Editor/Canvas/utils/elementRotate.ts index bd29a9e0..b30c34a0 100644 --- a/src/views/Editor/Canvas/utils/elementRotate.ts +++ b/src/views/Editor/Canvas/utils/elementRotate.ts @@ -1,4 +1,4 @@ -import { PPTTextElement, PPTImageElement, PPTShapeElement, PPTIconElement } from '@/types/slides' +import { PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides' import { OPERATE_KEYS } from '@/configs/element' // 给定一个坐标,计算该坐标到(0, 0)点连线的弧度值 @@ -11,7 +11,7 @@ export const getAngleFromCoordinate = (x: number, y: number) => { } // 计算元素被旋转一定角度后,八个操作点的新坐标 -export const getRotateElementPoints = (element: PPTTextElement | PPTImageElement | PPTShapeElement | PPTIconElement, angle: number) => { +export const getRotateElementPoints = (element: PPTTextElement | PPTImageElement | PPTShapeElement, angle: number) => { const { left, top, width, height } = element const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2 diff --git a/src/views/Editor/index.vue b/src/views/Editor/index.vue index 5887765a..ed0d6bb6 100644 --- a/src/views/Editor/index.vue +++ b/src/views/Editor/index.vue @@ -45,9 +45,6 @@ export default defineComponent({ const thumbnailsFocus = computed(() => store.state.thumbnailsFocus) const disableHotkeys = computed(() => store.state.disableHotkeys) - const save = () => { - message.success('save') - } const copy = () => { message.success('copy') } @@ -89,11 +86,7 @@ export default defineComponent({ if(shiftKey && !shiftKeyDown.value) shiftKeyDown.value = true if(!editorAreaFocus.value && !thumbnailsFocus.value) return - - if(ctrlKey && keyCode === KEYCODE.S) { - e.preventDefault() - save() - } + if(ctrlKey && keyCode === KEYCODE.C) { e.preventDefault() copy() diff --git a/src/views/_common/_element/EditableElement.vue b/src/views/_common/_element/EditableElement.vue index 60c7668c..7cd81c3a 100644 --- a/src/views/_common/_element/EditableElement.vue +++ b/src/views/_common/_element/EditableElement.vue @@ -23,6 +23,16 @@ import { computed, defineComponent, PropType } from 'vue' import { PPTElement } from '@/types/slides' +import { + ElementOrderCommand, + ElementOrderCommands, + ElementAlignCommand, + ElementAlignCommands, + ElementScaleHandler, + ElementLockCommand, + ElementLockCommands, +} from '@/types/edit' + import ImageElement from './ImageElement.index.vue' import TextElement from './TextElement.index.vue' @@ -62,11 +72,11 @@ export default defineComponent({ required: true, }, scaleElement: { - type: Function as PropType<(e: MouseEvent, element: PPTElement, direction: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9) => void>, + type: Function as PropType<(e: MouseEvent, element: PPTElement, command: ElementScaleHandler) => void>, required: true, }, - updateZIndex: { - type: Function as PropType<(element: PPTElement, operation: 'up' | 'down' | 'top' | 'bottom') => void>, + orderElement: { + type: Function as PropType<(element: PPTElement, command: ElementOrderCommand) => void>, required: true, }, combineElements: { @@ -78,7 +88,7 @@ export default defineComponent({ required: true, }, alignElement: { - type: Function as PropType<(direction: 'top' | 'verticalCenter' | 'bottom' | 'left' | 'horizontalCenter' | 'right') => void>, + type: Function as PropType<(command: ElementAlignCommand) => void>, required: true, }, deleteElement: { @@ -86,7 +96,7 @@ export default defineComponent({ required: true, }, lockElement: { - type: Function as PropType<(element: PPTElement, handle: 'lock' | 'unlock') => void>, + type: Function as PropType<(element: PPTElement, command: ElementLockCommand) => void>, required: true, }, copyElement: { @@ -112,7 +122,7 @@ export default defineComponent({ return [{ text: '解锁', icon: 'icon-unlock', - action: () => props.lockElement(props.elementInfo, 'unlock'), + action: () => props.lockElement(props.elementInfo, ElementLockCommands.UNLOCK), }] } @@ -135,29 +145,29 @@ export default defineComponent({ icon: 'icon-top-layer', disable: props.isMultiSelect && !props.elementInfo.groupId, children: [ - { text: '置顶层', action: () => props.updateZIndex(props.elementInfo, 'top') }, - { text: '置底层', action: () => props.updateZIndex(props.elementInfo, 'bottom') }, + { text: '置顶层', action: () => props.orderElement(props.elementInfo, ElementOrderCommands.TOP) }, + { text: '置底层', action: () => props.orderElement(props.elementInfo, ElementOrderCommands.BOTTOM) }, { divider: true }, - { text: '上移一层', action: () => props.updateZIndex(props.elementInfo, 'up') }, - { text: '下移一层', action: () => props.updateZIndex(props.elementInfo, 'down') }, + { text: '上移一层', action: () => props.orderElement(props.elementInfo, ElementOrderCommands.UP) }, + { text: '下移一层', action: () => props.orderElement(props.elementInfo, ElementOrderCommands.DOWN) }, ], }, { text: '水平对齐', icon: 'icon-align-left', children: [ - { text: '水平居中', action: () => props.alignElement('horizontalCenter') }, - { text: '左对齐', action: () => props.alignElement('left') }, - { text: '右对齐', action: () => props.alignElement('right') }, + { text: '水平居中', action: () => props.alignElement(ElementAlignCommands.HORIZONTAL) }, + { text: '左对齐', action: () => props.alignElement(ElementAlignCommands.LEFT) }, + { text: '右对齐', action: () => props.alignElement(ElementAlignCommands.RIGHT) }, ], }, { text: '垂直对齐', icon: 'icon-align-bottom', children: [ - { text: '垂直居中', action: () => props.alignElement('verticalCenter') }, - { text: '上对齐', action: () => props.alignElement('top') }, - { text: '下对齐', action: () => props.alignElement('bottom') }, + { text: '垂直居中', action: () => props.alignElement(ElementAlignCommands.VERTICAL) }, + { text: '上对齐', action: () => props.alignElement(ElementAlignCommands.TOP) }, + { text: '下对齐', action: () => props.alignElement(ElementAlignCommands.BOTTOM) }, ], }, { divider: true }, @@ -172,7 +182,7 @@ export default defineComponent({ text: '锁定', subText: 'Ctrl + L', icon: 'icon-lock', - action: () => props.lockElement(props.elementInfo, 'lock'), + action: () => props.lockElement(props.elementInfo, ElementLockCommands.LOCK), }, { text: '删除',