123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- import { defineStore } from "pinia"
- import tinycolor from "tinycolor2"
- import { omit } from "lodash"
- import type { Slide, SlideTheme, PPTElement, PPTAnimation } from "@/types/slides"
- import { slides } from "@/mocks/slides"
- import { theme } from "@/mocks/theme"
- import { layouts } from "@/mocks/layout"
- interface RemovePropData {
- id: string
- propName: string | string[]
- }
- interface UpdateElementData {
- id: string | string[]
- props: Partial<PPTElement>
- slideId?: string
- }
- interface FormatedAnimation {
- animations: PPTAnimation[]
- autoNext: boolean
- }
- export interface SlidesState {
- title: string
- theme: SlideTheme
- slides: Slide[]
- slideIndex: number
- viewportSize: number
- viewportRatio: number
- }
- export const useSlidesStore = defineStore("slides", {
- state: (): SlidesState => ({
- title: "未命名演示文稿", // 幻灯片标题
- theme: theme, // 主题样式
- slides: slides, // 幻灯片页面数据
- slideIndex: 0, // 当前页面索引
- viewportSize: 1920, // 可视区域宽度基数
- viewportRatio: 0.5625 // 可视区域比例,默认16:9
- }),
- getters: {
- currentSlide(state) {
- return state.slides[state.slideIndex]
- },
- currentSlideAnimations(state) {
- const currentSlide = state.slides[state.slideIndex]
- if (!currentSlide?.animations) return []
- const els = currentSlide.elements
- const elIds = els.map(el => el.id)
- return currentSlide.animations.filter(animation => elIds.includes(animation.elId))
- },
- // 格式化的当前页动画
- // 将触发条件为“与上一动画同时”的项目向上合并到序列中的同一位置
- // 为触发条件为“上一动画之后”项目的上一项添加自动向下执行标记
- formatedAnimations(state) {
- const currentSlide = state.slides[state.slideIndex]
- if (!currentSlide?.animations) return []
- const els = currentSlide.elements
- const elIds = els.map(el => el.id)
- const animations = currentSlide.animations.filter(animation => elIds.includes(animation.elId))
- const formatedAnimations: FormatedAnimation[] = []
- for (const animation of animations) {
- if (animation.trigger === "click" || !formatedAnimations.length) {
- formatedAnimations.push({ animations: [animation], autoNext: false })
- } else if (animation.trigger === "meantime") {
- const last = formatedAnimations[formatedAnimations.length - 1]
- last.animations = last.animations.filter(item => item.elId !== animation.elId)
- last.animations.push(animation)
- formatedAnimations[formatedAnimations.length - 1] = last
- } else if (animation.trigger === "auto") {
- const last = formatedAnimations[formatedAnimations.length - 1]
- last.autoNext = true
- formatedAnimations[formatedAnimations.length - 1] = last
- formatedAnimations.push({ animations: [animation], autoNext: false })
- }
- }
- return formatedAnimations
- },
- layouts(state) {
- const { themeColor, fontColor, fontName, backgroundColor } = state.theme
- const subColor = tinycolor(fontColor).isDark() ? "rgba(230, 230, 230, 0.5)" : "rgba(180, 180, 180, 0.5)"
- const layoutsString = JSON.stringify(layouts)
- .replace(/{{themeColor}}/g, themeColor)
- .replace(/{{fontColor}}/g, fontColor)
- .replace(/{{fontName}}/g, fontName)
- .replace(/{{backgroundColor}}/g, backgroundColor)
- .replace(/{{subColor}}/g, subColor)
- return JSON.parse(layoutsString)
- }
- },
- actions: {
- setTitle(title: string) {
- if (!title) this.title = "未命名演示文稿"
- else this.title = title
- },
- setTheme(themeProps: Partial<SlideTheme>) {
- this.theme = { ...this.theme, ...themeProps }
- },
- setViewportSize(size: number) {
- this.viewportSize = size
- },
- setViewportRatio(viewportRatio: number) {
- this.viewportRatio = viewportRatio
- },
- setSlides(slides: Slide[]) {
- this.slides = slides
- },
- addSlide(slide: Slide | Slide[]) {
- const slides = Array.isArray(slide) ? slide : [slide]
- for (const slide of slides) {
- if (slide.sectionTag) delete slide.sectionTag
- }
- const addIndex = this.slideIndex + 1
- this.slides.splice(addIndex, 0, ...slides)
- this.slideIndex = addIndex
- },
- updateSlide(props: Partial<Slide>, slideId?: string) {
- const slideIndex = slideId ? this.slides.findIndex(item => item.id === slideId) : this.slideIndex
- this.slides[slideIndex] = { ...this.slides[slideIndex], ...props }
- },
- removeSlideProps(data: RemovePropData) {
- const { id, propName } = data
- const slides = this.slides.map(slide => {
- return slide.id === id ? omit(slide, propName) : slide
- }) as Slide[]
- this.slides = slides
- },
- deleteSlide(slideId: string | string[]) {
- const slidesId = Array.isArray(slideId) ? slideId : [slideId]
- const slides: Slide[] = JSON.parse(JSON.stringify(this.slides))
- const deleteSlidesIndex = []
- for (const deletedId of slidesId) {
- const index = slides.findIndex(item => item.id === deletedId)
- deleteSlidesIndex.push(index)
- const deletedSlideSection = slides[index].sectionTag
- if (deletedSlideSection) {
- const handleSlideNext = slides[index + 1]
- if (handleSlideNext && !handleSlideNext.sectionTag) {
- delete slides[index].sectionTag
- slides[index + 1].sectionTag = deletedSlideSection
- }
- }
- slides.splice(index, 1)
- }
- let newIndex = Math.min(...deleteSlidesIndex)
- const maxIndex = slides.length - 1
- if (newIndex > maxIndex) newIndex = maxIndex
- this.slideIndex = newIndex
- this.slides = slides
- },
- updateSlideIndex(index: number) {
- this.slideIndex = index
- },
- addElement(element: PPTElement | PPTElement[]) {
- const elements = Array.isArray(element) ? element : [element]
- const currentSlideEls = this.slides[this.slideIndex].elements
- const newEls = [...currentSlideEls, ...elements]
- this.slides[this.slideIndex].elements = newEls
- },
- deleteElement(elementId: string | string[]) {
- const elementIdList = Array.isArray(elementId) ? elementId : [elementId]
- const currentSlideEls = this.slides[this.slideIndex].elements
- const newEls = currentSlideEls.filter(item => !elementIdList.includes(item.id))
- this.slides[this.slideIndex].elements = newEls
- },
- updateElement(data: UpdateElementData) {
- const { id, props, slideId } = data
- const elIdList = typeof id === "string" ? [id] : id
- const slideIndex = slideId ? this.slides.findIndex(item => item.id === slideId) : this.slideIndex
- const slide = this.slides[slideIndex]
- const elements = slide.elements.map(el => {
- return elIdList.includes(el.id) ? { ...el, ...props } : el
- })
- this.slides[slideIndex].elements = elements as PPTElement[]
- },
- removeElementProps(data: RemovePropData) {
- const { id, propName } = data
- const propsNames = typeof propName === "string" ? [propName] : propName
- const slideIndex = this.slideIndex
- const slide = this.slides[slideIndex]
- const elements = slide.elements.map(el => {
- return el.id === id ? omit(el, propsNames) : el
- })
- this.slides[slideIndex].elements = elements as PPTElement[]
- }
- }
- })
|