Commit f8159880 authored by 罗超's avatar 罗超

Merge branch 'master' of http://gitlab.oytour.com/viitto/pptist

# Conflicts:
#	src/App.vue
parents 9bde0bff 1a7dd09f
<template> <template>
<div v-if="isFinish" style="height: 100%;">
<Screen v-if="screening" /> <Screen v-if="screening" />
<Market v-else-if="Market"></Market> <Market v-else-if="market"></Market>
<!-- <NewFile v-else-if="market"></NewFile> -->
<Editor v-else-if="_isPC" /> <Editor v-else-if="_isPC" />
<Mobile v-else /> <Mobile v-else />
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted,ref } from 'vue' import { onMounted,ref,provide } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useScreenStore, useMainStore, useSnapshotStore } from '@/store' import { useScreenStore, useMainStore, useSnapshotStore } from '@/store'
import { LOCALSTORAGE_KEY_DISCARDED_DB } from '@/configs/storage' import { LOCALSTORAGE_KEY_DISCARDED_DB } from '@/configs/storage'
import { deleteDiscardedDB } from '@/utils/database' import { deleteDiscardedDB } from '@/utils/database'
import { isPC, query } from './utils/common' import { isPC, query } from './utils/common'
import { userStore } from './store/user' import { userStore } from './store/user'
import { injectKeyTemplate } from '@/types/injectKey'
import Editor from './views/Editor/index.vue' import Editor from './views/Editor/index.vue'
import Screen from './views/Screen/index.vue' import Screen from './views/Screen/index.vue'
import Mobile from './views/Mobile/index.vue' import Mobile from './views/Mobile/index.vue'
import Market from './views/Market/Index.vue' import Market from './views/Market/Index.vue'
import NewFile from './views/Market/newFile.vue'
const searchData = ref({} as any)
provide(injectKeyTemplate,searchData)
const isFinish = ref(false) const isFinish = ref(false)
const _isPC = isPC()
const mainStore = useMainStore()
const snapshotStore = useSnapshotStore()
const modelStore = useScreenStore()
const ConfigIdStore = useScreenStore()
const { databaseId } = storeToRefs(mainStore)
const { screening, market, model, ConfigId } = storeToRefs(useScreenStore())
if (process.env.NODE_ENV === 'production') {
window.onbeforeunload = () => false
}
const userLoginHandler = async ()=>{ const userLoginHandler = async ()=>{
let param = query() let param = query()
let userId = 1 let userId = 1
let ConfigId = 0
let model = 1
if(param.uid) userId=parseInt(param.uid) if(param.uid) userId=parseInt(param.uid)
if(ConfigId) ConfigIdStore.setConfigId(ConfigId)
if(model) modelStore.setModel(model)
try { try {
await userStore().setUserLoginAsync(userId) await userStore().setUserLoginAsync(userId)
} catch (error) { } catch (error) {
...@@ -37,17 +59,6 @@ const userLoginHandler = async ()=>{ ...@@ -37,17 +59,6 @@ const userLoginHandler = async ()=>{
} }
userLoginHandler() userLoginHandler()
const _isPC = isPC()
const mainStore = useMainStore()
const snapshotStore = useSnapshotStore()
const { databaseId } = storeToRefs(mainStore)
const { screening, market } = storeToRefs(useScreenStore())
if (process.env.NODE_ENV === 'production') {
window.onbeforeunload = () => false
}
onMounted(async () => { onMounted(async () => {
await deleteDiscardedDB() await deleteDiscardedDB()
snapshotStore.initSnapshotDatabase() snapshotStore.initSnapshotDatabase()
......
...@@ -263,6 +263,9 @@ page { ...@@ -263,6 +263,9 @@ page {
.q-pt-md{ .q-pt-md{
padding-top: 12px; padding-top: 12px;
} }
.q-pb-md{
padding-bottom: 10px;
}
.q-ma-lg{ .q-ma-lg{
margin:20px margin:20px
} }
...@@ -278,6 +281,9 @@ page { ...@@ -278,6 +281,9 @@ page {
.q-mt-lg{ .q-mt-lg{
margin-top:20px margin-top:20px
} }
.q-mb-md{
margin-bottom:10px
}
.q-mb-lg{ .q-mb-lg{
margin-bottom:20px margin-bottom:20px
} }
...@@ -309,3 +315,6 @@ page { ...@@ -309,3 +315,6 @@ page {
.text-light{ .text-light{
font-weight: 300; font-weight: 300;
} }
.text-nowrap{
white-space: nowrap;
}
\ No newline at end of file
...@@ -65,7 +65,7 @@ const getErrorCode2text = (response: AxiosResponse): string => { ...@@ -65,7 +65,7 @@ const getErrorCode2text = (response: AxiosResponse): string => {
* service.get<{data: string; code: number}>('/test').then(({data}) => { console.log(data.code) }) * service.get<{data: string; code: number}>('/test').then(({data}) => { console.log(data.code) })
*/ */
const service = Axios.create({ const service = Axios.create({
baseURL: 'http://192.168.10.160/api/common/post', baseURL: 'http://192.168.10.214/api/common/post',
timeout: 20000, timeout: 20000,
headers: { headers: {
'User-Type': 'bus', 'User-Type': 'bus',
......
...@@ -5,7 +5,7 @@ import { saveAs } from 'file-saver' ...@@ -5,7 +5,7 @@ import { saveAs } from 'file-saver'
import pptxgen from 'pptxgenjs' import pptxgen from 'pptxgenjs'
import tinycolor from 'tinycolor2' import tinycolor from 'tinycolor2'
import { toPng, toJpeg } from 'html-to-image' import { toPng, toJpeg } from 'html-to-image'
import { useSlidesStore } from '@/store' import { useSlidesStore, useScreenStore } from '@/store'
import type { PPTElementOutline, PPTElementShadow, PPTElementLink, Slide } from '@/types/slides' import type { PPTElementOutline, PPTElementShadow, PPTElementLink, Slide } from '@/types/slides'
import { getElementRange, getLineElementPath, getTableSubThemeColor } from '@/utils/element' import { getElementRange, getLineElementPath, getTableSubThemeColor } from '@/utils/element'
import { type AST, toAST } from '@/utils/htmlParser' import { type AST, toAST } from '@/utils/htmlParser'
...@@ -25,18 +25,18 @@ interface ExportImageConfig { ...@@ -25,18 +25,18 @@ interface ExportImageConfig {
export default () => { export default () => {
const slidesStore = useSlidesStore() const slidesStore = useSlidesStore()
const coverImgStore = useScreenStore()
const isCoverImgStore = useScreenStore()
const { slides, theme, viewportRatio, title } = storeToRefs(slidesStore) const { slides, theme, viewportRatio, title } = storeToRefs(slidesStore)
const { isCoverImg } = storeToRefs(useScreenStore())
const exporting = ref(false) const exporting = ref(false)
// 导出图片 // 导出图片
const exportImage = (domRef: HTMLElement, format: string, quality: number, ignoreWebfont = true) => { const exportImage = (domRef: HTMLElement, format: string, quality: number, ignoreWebfont = true) => {
exporting.value = true exporting.value = true
const toImage = format === 'png' ? toPng : toJpeg const toImage = format === 'png' ? toPng : toJpeg
const foreignObjectSpans = domRef.querySelectorAll('foreignObject [xmlns]') const foreignObjectSpans = domRef.querySelectorAll('foreignObject [xmlns]')
foreignObjectSpans.forEach(spanRef => spanRef.removeAttribute('xmlns')) foreignObjectSpans.forEach(spanRef => spanRef.removeAttribute('xmlns'))
setTimeout(() => { setTimeout(() => {
const config: ExportImageConfig = { const config: ExportImageConfig = {
quality, quality,
...@@ -47,7 +47,12 @@ export default () => { ...@@ -47,7 +47,12 @@ export default () => {
toImage(domRef, config).then(dataUrl => { toImage(domRef, config).then(dataUrl => {
exporting.value = false exporting.value = false
if (isCoverImg.value) {
coverImgStore.setCoverImg(dataUrl)
isCoverImgStore.setIsCoverImg(false)
} else {
saveAs(dataUrl, `${title.value}.${format}`) saveAs(dataUrl, `${title.value}.${format}`)
}
}).catch(() => { }).catch(() => {
exporting.value = false exporting.value = false
message.error('导出图片失败') message.error('导出图片失败')
......
...@@ -120,6 +120,7 @@ export default () => { ...@@ -120,6 +120,7 @@ export default () => {
id: nanoid(10), id: nanoid(10),
elements: [], elements: [],
background, background,
pageType: 1
} }
const parseElements = (elements: Element[]) => { const parseElements = (elements: Element[]) => {
......
...@@ -35,6 +35,7 @@ export default () => { ...@@ -35,6 +35,7 @@ export default () => {
type: 'solid', type: 'solid',
color: theme.value.backgroundColor, color: theme.value.backgroundColor,
}, },
pageType: 1
} }
slidesStore.updateSlideIndex(0) slidesStore.updateSlideIndex(0)
mainStore.setActiveElementIdList([]) mainStore.setActiveElementIdList([])
...@@ -84,6 +85,7 @@ export default () => { ...@@ -84,6 +85,7 @@ export default () => {
type: 'solid', type: 'solid',
color: theme.value.backgroundColor, color: theme.value.backgroundColor,
}, },
pageType: 1,
} }
mainStore.setActiveElementIdList([]) mainStore.setActiveElementIdList([])
slidesStore.addSlide(emptySlide) slidesStore.addSlide(emptySlide)
......
...@@ -3,6 +3,9 @@ import { createPinia } from 'pinia' ...@@ -3,6 +3,9 @@ import { createPinia } from 'pinia'
import App from './App.vue' import App from './App.vue'
import './registerServiceWorker' import './registerServiceWorker'
import { ElMessage, ElMessageBox } from 'element-plus'
import 'element-plus/dist/index.css'
import '@icon-park/vue-next/styles/index.css' import '@icon-park/vue-next/styles/index.css'
import 'prosemirror-view/style/prosemirror.css' import 'prosemirror-view/style/prosemirror.css'
import 'animate.css' import 'animate.css'
......
...@@ -5,6 +5,7 @@ import type { Slide } from '@/types/slides' ...@@ -5,6 +5,7 @@ import type { Slide } from '@/types/slides'
export const layouts: Slide[] = [ export const layouts: Slide[] = [
{ {
id: 'template', id: 'template',
pageType: 1,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -80,6 +81,7 @@ export const layouts: Slide[] = [ ...@@ -80,6 +81,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 2,
elements: [ elements: [
{ {
type: 'text', type: 'text',
...@@ -139,6 +141,7 @@ export const layouts: Slide[] = [ ...@@ -139,6 +141,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 3,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -188,6 +191,7 @@ export const layouts: Slide[] = [ ...@@ -188,6 +191,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'MZVO1kkj', id: 'MZVO1kkj',
pageType: 4,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -273,6 +277,7 @@ export const layouts: Slide[] = [ ...@@ -273,6 +277,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 4,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -457,6 +462,7 @@ export const layouts: Slide[] = [ ...@@ -457,6 +462,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 4,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -510,6 +516,7 @@ export const layouts: Slide[] = [ ...@@ -510,6 +516,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 1,
elements: [ elements: [
{ {
type: 'text', type: 'text',
...@@ -573,6 +580,7 @@ export const layouts: Slide[] = [ ...@@ -573,6 +580,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 1,
elements: [ elements: [
{ {
type: 'text', type: 'text',
...@@ -690,6 +698,7 @@ export const layouts: Slide[] = [ ...@@ -690,6 +698,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 1,
elements: [ elements: [
{ {
type: 'text', type: 'text',
...@@ -766,6 +775,7 @@ export const layouts: Slide[] = [ ...@@ -766,6 +775,7 @@ export const layouts: Slide[] = [
}, },
{ {
id: 'template', id: 'template',
pageType: 1,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
......
import type { Slide } from '@/types/slides' import type { Slide } from '@/types/slides'
// pageType 1基础 2酒店 3景 4餐
export const slides: Slide[] = [ export const slides: Slide[] = [
{ {
id: 'test-slide-1', id: 'test-slide-1',
pageType: 1,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
...@@ -77,6 +79,7 @@ export const slides: Slide[] = [ ...@@ -77,6 +79,7 @@ export const slides: Slide[] = [
}, },
{ {
id: 'test-slide-2', id: 'test-slide-2',
pageType: 2,
elements: [ elements: [
{ {
type: 'text', type: 'text',
...@@ -136,6 +139,7 @@ export const slides: Slide[] = [ ...@@ -136,6 +139,7 @@ export const slides: Slide[] = [
}, },
{ {
id: 'test-slide-3', id: 'test-slide-3',
pageType: 3,
elements: [ elements: [
{ {
type: 'shape', type: 'shape',
......
...@@ -96,7 +96,9 @@ import { ...@@ -96,7 +96,9 @@ import {
ListView, ListView,
Magic, Magic,
HighLight, HighLight,
Upload,
Download, Download,
Check,
IndentLeft, IndentLeft,
IndentRight, IndentRight,
VerticalSpacingBetweenItems, VerticalSpacingBetweenItems,
...@@ -221,7 +223,9 @@ export const icons: Icons = { ...@@ -221,7 +223,9 @@ export const icons: Icons = {
IconListView: ListView, IconListView: ListView,
IconMagic: Magic, IconMagic: Magic,
IconHighLight: HighLight, IconHighLight: HighLight,
IconUpload: Upload,
IconDownload: Download, IconDownload: Download,
IconCheck: Check,
IconIndentLeft: IndentLeft, IconIndentLeft: IndentLeft,
IconIndentRight: IndentRight, IconIndentRight: IndentRight,
IconVerticalSpacingBetweenItems: VerticalSpacingBetweenItems, IconVerticalSpacingBetweenItems: VerticalSpacingBetweenItems,
......
import Api,{ HttpResponse, Result } from './../utils/request';
/**
* 配置相关方法
*/
class ConfigService{
/**
* 根据ConfigId获取行程配置相关数据
*/
static async triptemplateGetTripFiledData(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTripFiledData",params)
}
/**
* 根据团期配置编号获取行程详情
*/
static async triptemplateGetTripConfig(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTripConfig",params)
}
/**
* 新增修改模版数据
*/
static async SetSetTripConfig(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_SetTripConfig",params)
}
/**
* 新增修改模版
*/
static async SetTripTemplateSlide(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_SetTripTemplate",params)
}
/**
* 根据TempId获取模版数据
*/
static async GetTripTemplateSlide(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTripTemplate",params)
}
/**
* 获取绑定数据源列表
*/
static async TemplateGetTripFiled(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTripFiled",params)
}
/**
*
* @returns 获取模板查询条件
*/
static async GetTemplateQueryAsync():Promise<HttpResponse>{
return Api.Post("triptemplate_GetTemplateConfigData",{})
}
/**
* 获取模板市场分页列表
*/
static async GetTemplagePageAsync(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTripTemplatePage",params)
}
}
export default ConfigService;
\ No newline at end of file
...@@ -2,7 +2,17 @@ import Api,{ HttpResponse, Result } from './../utils/request'; ...@@ -2,7 +2,17 @@ import Api,{ HttpResponse, Result } from './../utils/request';
class LineService{ class LineService{
// 获取配置项数据(颜色、国家、季节)
static async GetTemplateConfigData(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_GetTemplateConfigData",params)
}
// 系列
static async GetSeriesListAsync(params : any):Promise<HttpResponse>{
return Api.Post("team_post_GetList",params)
}
// 线路
static async GetLineListAsync():Promise<HttpResponse>{ static async GetLineListAsync():Promise<HttpResponse>{
return Api.Post("line_post_GetAllList",{}) return Api.Post("line_post_GetAllList",{})
} }
......
...@@ -59,7 +59,7 @@ export const useMainStore = defineStore('main', { ...@@ -59,7 +59,7 @@ export const useMainStore = defineStore('main', {
creatingElement: null, // 正在插入的元素信息,需要通过绘制插入的元素(文字、形状、线条) creatingElement: null, // 正在插入的元素信息,需要通过绘制插入的元素(文字、形状、线条)
creatingCustomShape: false, // 正在绘制任意多边形 creatingCustomShape: false, // 正在绘制任意多边形
availableFonts: SYS_FONTS, // 当前环境可用字体 availableFonts: SYS_FONTS, // 当前环境可用字体
toolbarState: ToolbarStates.SLIDE_DESIGN, // 右侧工具栏状态 toolbarState: ToolbarStates.SLIDE_DESIGN, // 右侧工具栏状态 设计 模版数据EL_TEMPLATEDATA
clipingImageElementId: '', // 当前正在裁剪的图片ID clipingImageElementId: '', // 当前正在裁剪的图片ID
richTextAttrs: defaultRichTextAttrs, // 富文本状态 richTextAttrs: defaultRichTextAttrs, // 富文本状态
selectedTableCells: [], // 选中的表格单元格 selectedTableCells: [], // 选中的表格单元格
......
import { fa } from 'element-plus/es/locale'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export interface ScreenState { export interface ScreenState {
screening: boolean, screening: boolean,
market:boolean market:boolean,
model:number,
isModel: boolean,
ConfigId:number,
TemplateType: [],
TemplateDataSource: [],
CoverImg: any,
isCoverImg: boolean,
dataLoading: boolean,
} }
export const useScreenStore = defineStore('screen', { export const useScreenStore = defineStore('screen', {
state: (): ScreenState => ({ state: (): ScreenState => ({
screening: false, // 是否进入放映状态 screening: false, // 是否进入放映状态
market: true market: true,
model: 0, // 是否有新增修改模版权限
isModel: false, // 该团是否存在模版
ConfigId: 0,
TemplateType: [], // 数据源分类
TemplateDataSource: [], // 所有数据源
CoverImg: null, // 封面图
isCoverImg: false, // 封面
dataLoading: false, // 记录保存是否成功
}), }),
actions: { actions: {
...@@ -18,8 +35,32 @@ export const useScreenStore = defineStore('screen', { ...@@ -18,8 +35,32 @@ export const useScreenStore = defineStore('screen', {
this.market = false this.market = false
} }
}, },
setMarket(market: boolean){ setMarket(market: boolean) {
this.market = market this.market = market
},
setModel(model: number) {
this.model = model
},
setIsModel(isModel: boolean) {
this.isModel = isModel
},
setConfigId(ConfigId: number) {
this.ConfigId = ConfigId
},
setTemplateType(TemplateType: []) {
this.TemplateType = TemplateType
},
setCoverImg(CoverImg: any) {
this.CoverImg = CoverImg
},
setIsCoverImg(isCoverImg: boolean) {
this.isCoverImg = isCoverImg
},
setTemplateDataSource(TemplateDataSource: []) {
this.TemplateDataSource = TemplateDataSource
},
setDataLoading(dataLoading: boolean) {
this.dataLoading = dataLoading
} }
}, },
}) })
\ No newline at end of file
...@@ -28,6 +28,7 @@ export interface SlidesState { ...@@ -28,6 +28,7 @@ export interface SlidesState {
slides: Slide[] slides: Slide[]
slideIndex: number slideIndex: number
viewportRatio: number viewportRatio: number
layoutSlides: Slide[]
} }
export const useSlidesStore = defineStore('slides', { export const useSlidesStore = defineStore('slides', {
...@@ -36,7 +37,8 @@ export const useSlidesStore = defineStore('slides', { ...@@ -36,7 +37,8 @@ export const useSlidesStore = defineStore('slides', {
theme: theme, // 主题样式 theme: theme, // 主题样式
slides: slides, // 幻灯片页面数据 slides: slides, // 幻灯片页面数据
slideIndex: 0, // 当前页面索引 slideIndex: 0, // 当前页面索引
viewportRatio: 0.5625, // 可视区域比例,默认16:9 viewportRatio: 0.75, // 可视区域比例,默认16:9 0.5625
layoutSlides: slides, // 所有模版数据
}), }),
getters: { getters: {
...@@ -92,10 +94,9 @@ export const useSlidesStore = defineStore('slides', { ...@@ -92,10 +94,9 @@ export const useSlidesStore = defineStore('slides', {
fontName, fontName,
backgroundColor, backgroundColor,
} = state.theme } = state.theme
const subColor = tinycolor(fontColor).isDark() ? 'rgba(230, 230, 230, 0.5)' : 'rgba(180, 180, 180, 0.5)' const subColor = tinycolor(fontColor).isDark() ? 'rgba(230, 230, 230, 0.5)' : 'rgba(180, 180, 180, 0.5)'
console.log('layouts,--------')
const layoutsString = JSON.stringify(layouts) const layoutsString = JSON.stringify(state.layoutSlides)
.replaceAll('{{themeColor}}', themeColor) .replaceAll('{{themeColor}}', themeColor)
.replaceAll('{{fontColor}}', fontColor) .replaceAll('{{fontColor}}', fontColor)
.replaceAll('{{fontName}}', fontName) .replaceAll('{{fontName}}', fontName)
...@@ -124,6 +125,10 @@ export const useSlidesStore = defineStore('slides', { ...@@ -124,6 +125,10 @@ export const useSlidesStore = defineStore('slides', {
this.slides = slides this.slides = slides
}, },
setLayouts(layoutSlides: Slide[]) {
this.layoutSlides = layoutSlides
},
addSlide(slide: Slide | Slide[]) { addSlide(slide: Slide | Slide[]) {
const slides = Array.isArray(slide) ? slide : [slide] const slides = Array.isArray(slide) ? slide : [slide]
const addIndex = this.slideIndex + 1 const addIndex = this.slideIndex + 1
......
...@@ -6,7 +6,9 @@ export type RadioGroupValue = { ...@@ -6,7 +6,9 @@ export type RadioGroupValue = {
value: Ref<string> value: Ref<string>
updateValue: (value: string) => void updateValue: (value: string) => void
} }
export type SlideDataSource = Ref<object>
export const injectKeySlideScale: InjectionKey<SlideScale> = Symbol() export const injectKeySlideScale: InjectionKey<SlideScale> = Symbol()
export const injectKeySlideId: InjectionKey<SlideId> = Symbol() export const injectKeySlideId: InjectionKey<SlideId> = Symbol()
export const injectKeyRadioGroupValue: InjectionKey<RadioGroupValue> = Symbol() export const injectKeyRadioGroupValue: InjectionKey<RadioGroupValue> = Symbol()
export const injectKeyDataSource: InjectionKey<SlideDataSource> = Symbol()
export const injectKeyTemplate: InjectionKey<SlideDataSource> = Symbol()
\ No newline at end of file
...@@ -676,6 +676,7 @@ export interface Slide { ...@@ -676,6 +676,7 @@ export interface Slide {
background?: SlideBackground background?: SlideBackground
animations?: PPTAnimation[] animations?: PPTAnimation[]
turningMode?: TurningMode turningMode?: TurningMode
pageType: number
} }
/** /**
......
export const enum ToolbarStates { export const enum ToolbarStates {
SYMBOL = 'symbol', SYMBOL = 'symbol',
EL_ANIMATION = 'elAnimation', EL_ANIMATION = 'elAnimation',
EL_TEMPLATEDATA = 'elTemplateData',
EL_STYLE = 'elStyle', EL_STYLE = 'elStyle',
EL_POSITION = 'elPosition', EL_POSITION = 'elPosition',
SLIDE_DESIGN = 'slideDesign', SLIDE_DESIGN = 'slideDesign',
......
...@@ -27,3 +27,16 @@ export const query = (url?:string)=>{ ...@@ -27,3 +27,16 @@ export const query = (url?:string)=>{
} }
return json return json
} }
/**
* 提取字符串中的文字
*/
export const getHtmlPlainText = (html_str:string) => {
let re = new RegExp('<[^<>]+>', 'g')
if (html_str) {
let text = html_str.replace(re, '')
return text
} else {
return ''
}
}
\ No newline at end of file
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
width: viewportStyles.width * canvasScale + 'px', width: viewportStyles.width * canvasScale + 'px',
height: viewportStyles.height * canvasScale + 'px', height: viewportStyles.height * canvasScale + 'px',
left: viewportStyles.left + 'px', left: viewportStyles.left + 'px',
top: viewportStyles.top + 'px', top: viewportStyles.top-20 + 'px',
}" }"
> >
<div class="operates"> <div class="operates">
...@@ -168,7 +168,7 @@ watch(handleElementId, () => { ...@@ -168,7 +168,7 @@ watch(handleElementId, () => {
const elementList = ref<PPTElement[]>([]) const elementList = ref<PPTElement[]>([])
const setLocalElementList = () => { const setLocalElementList = () => {
elementList.value = currentSlide.value ? JSON.parse(JSON.stringify(currentSlide.value.elements)) : [] elementList.value = currentSlide.value&&currentSlide.value.elements ? JSON.parse(JSON.stringify(currentSlide.value.elements)) : []
} }
watchEffect(setLocalElementList) watchEffect(setLocalElementList)
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
<IconInsertTable class="handler-item" v-tooltip="'插入表格'" /> <IconInsertTable class="handler-item" v-tooltip="'插入表格'" />
</Popover> </Popover>
<IconFormula class="handler-item" v-tooltip="'插入公式'" @click="latexEditorVisible = true" /> <IconFormula class="handler-item" v-tooltip="'插入公式'" @click="latexEditorVisible = true" />
<Popover trigger="click" v-model:value="mediaInputVisible"> <!-- <Popover trigger="click" v-model:value="mediaInputVisible">
<template #content> <template #content>
<MediaInput <MediaInput
@close="mediaInputVisible = false" @close="mediaInputVisible = false"
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
/> />
</template> </template>
<IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" /> <IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" />
</Popover> </Popover> -->
</div> </div>
<div class="right-handler"> <div class="right-handler">
......
<template>
<div v-if="datas.DataSource.DataSourceOverlay">
<div class="DataaSourceOverlay" @click="OffDataSource"></div>
<div class="DataaSource">
<div class="DataaSourceList">
<el-table
:data="datas.DataSource.DataSourceList"
style="width: 100%"
border
>
<el-table-column
prop=""
label="基础数据">
<template #default="scope">
<div class="DataaSourceL">
<div v-if="scope.row.type=='text'">
{{scope.row.FiledTypeStr}}
</div>
<div v-if="scope.row.type=='image'">
<img style="width: 20px; height: 20px"
:src="scope.row.FiledTypeStr" />
</div>
</div>
</template>
</el-table-column>
<el-table-column
prop=""
label="绑定数据源"
width="170">
<template #default="scope">
<div class="DataaSourceR" v-if="scope.row.TemplateList">
<el-select v-model="scope.row.TemplateDataSource.Id" class="m-2"
placeholder="请绑定数据源"
@change="setTemplateDataSource(scope.row.TemplateDataSource.Id,scope.$index)">
<!-- :disabled="scope.row.type=='image'&&item.Name.indexOf('图')==-1" -->
<el-option
v-for="item in setType(scope.row)"
:key="item.Id"
:label="item.Name"
:value="item.Id"/>
</el-select>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, nextTick, ref, watch, reactive, inject } from 'vue'
import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store'
import { injectKeyDataSource } from '@/types/injectKey'
import { getHtmlPlainText } from '@/utils/common'
const datas = reactive({
DataSource:{},
})
datas.DataSource = inject(injectKeyDataSource)
const slidesStore = useSlidesStore()
const { slides, slideIndex } = storeToRefs(slidesStore)
const setType = (x) =>{
if(x.type=="image"){
return x.TemplateList.filter(item=>{ return item.Name.indexOf('图')!=-1})
}if(x.type=="text"){
return x.TemplateList.filter(item=>{ return item.Name.indexOf('图')==-1})
}
}
const setNewDatas = () => {
const slidesData = slides.value
// 更新Slides数据
const savelides = []
const newSlides = []
let obj = slidesData.find((x,index)=>{
return slideIndex.value == index
})
if(obj){
obj.elements.forEach(x=>{
let dataObj = datas.DataSource.DataSourceList.find(y=>{
return y.id == x.id
})
if(dataObj){
x = dataObj
}
savelides.push(x)
})
obj.elements = JSON.parse(JSON.stringify(savelides))
slidesData.forEach((x,index)=>{
if(slideIndex.value == index){
x.pgaeType = datas.DataSource.pgaeType
x.elements = obj.elements
}
newSlides.push(x)
})
slidesStore.setSlides(JSON.parse(JSON.stringify(newSlides)))
}
}
// 数据源关键数据赋值
const setTemplateDataSource = (Id,index) => {
datas.DataSource.DataSourceList.forEach((x,indexs)=>{
if(index==indexs){
let obj = x.TemplateList.find(y=>{
return y.Id==x.TemplateDataSource.Id
})
x.TemplateDataSource.Content = obj.Content
x.TemplateDataSource.Name = obj.Name
if(x.type=="text"){
x.FiledTypeStr = obj.Name
x.content = x.content.replace(getHtmlPlainText(x.content),obj.Name)
}
}
})
setNewDatas()
}
const OffDataSource = () =>{
datas.DataSource.DataSourceOverlay = !datas.DataSource.DataSourceOverlay
}
</script>
<style lang="scss" scoped>
.DataaSourceOverlay{
position: fixed;
left: 160px;
top: 80px;
right: 260px;
bottom: 0;
z-index: 1;
background: rgba(23,23,23,0.5);
cursor: pointer;
}
.DataaSource{
position: fixed;
left: 200px;
top: 120px;
right: 300px;
bottom: 30px;
z-index: 2;
padding: 40px;
border-radius: 10px;
background: #fff;
}
.DataaSourceList{
height: 100%;
border: 1px solid #ebeef5;
padding: 20px;
border-radius: 5px;
overflow: auto;
}
.DataaSourceL{
font-weight: bold;
color: black;
font-size: 14px;
}
</style>
\ No newline at end of file
<template> <template>
<div class="editor-header"> <div class="editor-header">
<div class="left"> <div class="left">
<div class="menu-item" v-tooltip="'去首页'" @click="goBack()">首页</div>
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible"> <Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
<template #content> <template #content>
<FileInput accept=".pptist" @change="files => { <FileInput accept=".pptist" @change="files => {
...@@ -28,21 +29,21 @@ ...@@ -28,21 +29,21 @@
<Input <Input
class="title-input" class="title-input"
ref="titleInputRef" ref="titleInputRef"
v-model:value="titleValue" v-model:value="queryObj.Title"
@blur="handleUpdateTitle()" @blur="handleUpdateTitle()"
v-if="editingTitle" v-if="editingTitle"
></Input> ></Input>
<div <div
class="title-text" class="title-text"
@click="startEditTitle()" @click="startEditTitle()"
:title="title" :title="queryObj.Title"
v-else v-else
>{{ title }}</div> >{{ queryObj.Title }}</div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="group-menu-item"> <!-- <div class="group-menu-item">
<div class="menu-item" v-tooltip="'幻灯片放映'" @click="enterScreening()"> <div class="menu-item" v-tooltip="'幻灯片放映'" @click="enterScreening()">
<IconPpt class="icon" /> <IconPpt class="icon" />
</div> </div>
...@@ -53,13 +54,21 @@ ...@@ -53,13 +54,21 @@
</template> </template>
<div class="arrow-btn"><IconDown class="arrow" /></div> <div class="arrow-btn"><IconDown class="arrow" /></div>
</Popover> </Popover>
</div> -->
<div class="group-menu-item" v-if="userInfo.IsEditTripTemplate==1&&model">
<div class="menu-item" v-tooltip="'导入PSD'" @click="UploadPsd()">
<IconUpload class="icon" />
</div>
</div> </div>
<div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')"> <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
<IconDownload class="icon" /> <IconDownload class="icon" />
</div> </div>
<a class="github-link" href="https://github.com/pipipi-pikachu/PPTist" target="_blank"> <el-button v-tooltip="'保存'" type="danger"
size="small" icon="Check" circle :loading="datas.loading"
@click="setTemplate()" style="color: #ffff;"></el-button>
<!-- <a class="github-link" href="https://github.com/pipipi-pikachu/PPTist" target="_blank">
<div class="menu-item"><IconGithub class="icon" /></div> <div class="menu-item"><IconGithub class="icon" /></div>
</a> </a> -->
</div> </div>
<Drawer <Drawer
...@@ -75,13 +84,18 @@ ...@@ -75,13 +84,18 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, ref } from 'vue' import { nextTick, ref, reactive, inject } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store' import { useMainStore, useSlidesStore } from '@/store'
import useScreening from '@/hooks/useScreening' import useScreening from '@/hooks/useScreening'
import useImport from '@/hooks/useImport' import useImport from '@/hooks/useImport'
import useSlideHandler from '@/hooks/useSlideHandler' import useSlideHandler from '@/hooks/useSlideHandler'
import type { DialogForExportTypes } from '@/types/export' import type { DialogForExportTypes } from '@/types/export'
import { userStore } from "@/store/user";
import { useScreenStore } from "@/store/screen";
import ConfigService from '@/services/ConfigService'
import { injectKeyDataSource, injectKeyTemplate } from '@/types/injectKey'
import { svg2Base64 } from '@/utils/svg2Base64'
import HotkeyDoc from './HotkeyDoc.vue' import HotkeyDoc from './HotkeyDoc.vue'
import FileInput from '@/components/FileInput.vue' import FileInput from '@/components/FileInput.vue'
...@@ -93,7 +107,8 @@ import PopoverMenuItem from '@/components/PopoverMenuItem.vue' ...@@ -93,7 +107,8 @@ import PopoverMenuItem from '@/components/PopoverMenuItem.vue'
const mainStore = useMainStore() const mainStore = useMainStore()
const slidesStore = useSlidesStore() const slidesStore = useSlidesStore()
const { title } = storeToRefs(slidesStore) const layoutsStore = useSlidesStore()
const { title, slides } = storeToRefs(slidesStore)
const { enterScreening, enterScreeningFromStart } = useScreening() const { enterScreening, enterScreeningFromStart } = useScreening()
const { importSpecificFile, importPPTXFile, exporting } = useImport() const { importSpecificFile, importPPTXFile, exporting } = useImport()
const { resetSlides } = useSlideHandler() const { resetSlides } = useSlideHandler()
...@@ -104,6 +119,165 @@ const editingTitle = ref(false) ...@@ -104,6 +119,165 @@ const editingTitle = ref(false)
const titleInputRef = ref<InstanceType<typeof Input>>() const titleInputRef = ref<InstanceType<typeof Input>>()
const titleValue = ref('') const titleValue = ref('')
const { userInfo } = storeToRefs(userStore())
const datas = reactive({
DataSource:{},
loading: false
})
const queryObj = ref({} as any)
const searchData = ref({} as any)
datas.DataSource = inject(injectKeyDataSource)
queryObj.value = inject(injectKeyDataSource).queryObj
searchData.value = inject(injectKeyTemplate)
const marketStore = useScreenStore()
const CoverImgStore = useScreenStore()
const dataLoadingStore = useScreenStore()
const { market, model, ConfigId, CoverImg, dataLoading } = storeToRefs(useScreenStore())
// 返回到首页
const goBack = () =>{
let list = [
{
id: 'test-slide-1',
pageType: 1,
elements: [],
background: {
type: 'solid',
color: '#ffffff',
},
}
]
if(model.value) {
searchData.value.TempId = 0
marketStore.setMarket(true)
slidesStore.setSlides(list)
layoutsStore.setLayouts([])
CoverImgStore.setCoverImg(null)
return
}
ElMessageBox.confirm(
'退出此页面将清空当前数据,请谨慎操作?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
searchData.value.TempId = 0
marketStore.setMarket(true)
slidesStore.setSlides(list)
layoutsStore.setLayouts([])
CoverImgStore.setCoverImg(null)
})
.catch(() => {
})
}
// 导入PSD
const UploadPsd = () => {
}
// 新增修改模版
const SetTripTemplateSlide = async () => {
// console.log(JSON.parse(queryObj.value.TempData),'--------')
try {
console.log(queryObj.value,'新增修改模版---')
let TemplateRes = await ConfigService.SetTripTemplateSlide(queryObj.value);
if (TemplateRes.data.resultCode == 1) {
}
dataLoadingStore.setDataLoading(true)
datas.loading = false
} catch (error) {
datas.loading = false
console.log("TemplateGetTripFiled", error);
}
}
// 用户新增修改数据
const SetTripTemplateConfig = async () => {
try {
let queryMsg = {
ConfigId: ConfigId.value,
TempId: queryObj.value.TempId,
TempData: queryObj.value.TempData
}
console.log(queryMsg,'新增修改团数据---')
let TemplateRes = await ConfigService.SetSetTripConfig(queryMsg);
if (TemplateRes.data.resultCode == 1) {
}
dataLoadingStore.setDataLoading(true)
datas.loading = false
} catch (error) {
datas.loading = false
console.log("TemplateGetTripFiled", error);
}
}
// 保存
const setTemplate = async () =>{
if(dataLoading.value){
dataLoadingStore.setDataLoading(false)
}
// console.log(JSON.stringify(slides.value),'----保存接口',queryObj.value)
if(model.value&&userInfo.value.IsEditTripTemplate==1){
if(CoverImg&&CoverImg.value) queryObj.value.CoverImg = CoverImg.value
else return ElMessage({
showClose: true,
message: '请生成封面图',
type: 'warning',
})
if(queryObj.value.Title==''||!queryObj.value.LineId||!queryObj.value.LtId
||queryObj.value.CoverImg==''
||queryObj.value.CountryName==''||queryObj.value.SeasonName==''
||queryObj.value.ColorName==''||queryObj.value.ColorStr==''||queryObj.value.LineName==''){
return ElMessage({
showClose: true,
message: '请完善右侧模版数据',
type: 'warning',
})
}
}
for(let i=0;i<slides.value.length;i++){
if(slides.value[i].elements.length==0) {
return ElMessage({
showClose: true,
message: `请设计 第 ${i+1} 页 的数据`,
type: 'warning',
})
}
// for(let j=0;j<slides.value[i].elements.length;j++){
// if(model.value&&userInfo.value.IsEditTripTemplate==1){
// if(slides.value[i].elements[j].type=="text"||slides.value[i].elements[j].type=="image"){
// if(!slides.value[i].elements[j].TemplateDataSource
// ||!slides.value[i].elements[j].TemplateDataSource.Id) {
// return ElMessage({
// showClose: true,
// message: `请完善 第 ${i+1} 页 需要绑定的数据源`,
// type: 'warning',
// })
// }
// }
// }
// }
}
queryObj.value.TempData = JSON.stringify(slides.value)
datas.loading = true
if(model.value&&userInfo.value.IsEditTripTemplate==1){
await SetTripTemplateSlide()
}else if(ConfigId.value){
await SetTripTemplateConfig()
}
}
const startEditTitle = () => { const startEditTitle = () => {
titleValue.value = title.value titleValue.value = title.value
editingTitle.value = true editingTitle.value = true
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
</div> </div>
<div class="configs"> <div class="configs">
<div class="row"> <div class="row">
<div class="title">导出格式:</div> <div class="title">{{isCoverImg?'生成格式:':'导出格式:'}}</div>
<RadioGroup <RadioGroup
class="config-item" class="config-item"
v-model:value="format" v-model:value="format"
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</RadioGroup> </RadioGroup>
</div> </div>
<div class="row"> <div class="row">
<div class="title">导出范围:</div> <div class="title">{{isCoverImg?'生成范围:':'导出范围:'}}</div>
<RadioGroup <RadioGroup
class="config-item" class="config-item"
v-model:value="rangeType" v-model:value="rangeType"
...@@ -65,18 +65,19 @@ ...@@ -65,18 +65,19 @@
</div> </div>
<div class="btns"> <div class="btns">
<Button class="btn export" type="primary" @click="expImage()">导出图片</Button> <Button class="btn export" type="primary" @click="expImage()">
{{isCoverImg?'生成封面':'导出图片'}}</Button>
<Button class="btn close" @click="emit('close')">关闭</Button> <Button class="btn close" @click="emit('close')">关闭</Button>
</div> </div>
<FullscreenSpin :loading="exporting" tip="正在导出..." /> <FullscreenSpin :loading="exporting" :tip="isCoverImg?'正在生成...':'正在导出...'" />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store' import { useSlidesStore, useScreenStore } from '@/store'
import useExport from '@/hooks/useExport' import useExport from '@/hooks/useExport'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue' import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
...@@ -92,13 +93,15 @@ const emit = defineEmits<{ ...@@ -92,13 +93,15 @@ const emit = defineEmits<{
}>() }>()
const { slides, currentSlide } = storeToRefs(useSlidesStore()) const { slides, currentSlide } = storeToRefs(useSlidesStore())
const { isCoverImg } = storeToRefs(useScreenStore())
const imageThumbnailsRef = ref<HTMLElement>() const imageThumbnailsRef = ref<HTMLElement>()
const rangeType = ref<'all' | 'current' | 'custom'>('all') const rangeType = ref<'all' | 'current' | 'custom'>('current')
const range = ref<[number, number]>([1, slides.value.length]) const range = ref<[number, number]>([1, slides.value.length])
const format = ref<'jpeg' | 'png'>('jpeg') const format = ref<'jpeg' | 'png'>('jpeg')
const quality = ref(1) const quality = ref(1)
const ignoreWebfont = ref(true) const ignoreWebfont = ref(false) //开启在线字体
const renderSlides = computed(() => { const renderSlides = computed(() => {
if (rangeType.value === 'all') return slides.value if (rangeType.value === 'all') return slides.value
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
@update:value="key => setDialogForExport(key as DialogForExportTypes)" @update:value="key => setDialogForExport(key as DialogForExportTypes)"
/> />
<div class="content"> <div class="content">
<component :is="currentDialogComponent" @close="setDialogForExport('')"></component> <component :is="currentDialogComponent" @close="setDialogForExport(''),setDialogIsCoverImg()"></component>
</div> </div>
</div> </div>
</template> </template>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store' import { useMainStore, useScreenStore } from '@/store'
import type { DialogForExportTypes } from '@/types/export' import type { DialogForExportTypes } from '@/types/export'
import ExportImage from './ExportImage.vue' import ExportImage from './ExportImage.vue'
...@@ -30,11 +30,17 @@ interface TabItem { ...@@ -30,11 +30,17 @@ interface TabItem {
label: string label: string
} }
const isCoverImgStore = useScreenStore()
const mainStore = useMainStore() const mainStore = useMainStore()
const { dialogForExport } = storeToRefs(mainStore) const { dialogForExport } = storeToRefs(mainStore)
const { isCoverImg } = storeToRefs(isCoverImgStore)
const setDialogForExport = mainStore.setDialogForExport const setDialogForExport = mainStore.setDialogForExport
const setDialogIsCoverImg = () => {
isCoverImgStore.setIsCoverImg(false)
}
const tabs: TabItem[] = [ const tabs: TabItem[] = [
{ key: 'pptist', label: '导出 pptist 文件' }, { key: 'pptist', label: '导出 pptist 文件' },
{ key: 'pptx', label: '导出 PPTX' }, { key: 'pptx', label: '导出 PPTX' },
...@@ -51,8 +57,8 @@ const currentDialogComponent = computed<unknown>(() => { ...@@ -51,8 +57,8 @@ const currentDialogComponent = computed<unknown>(() => {
'pptx': ExportPPTX, 'pptx': ExportPPTX,
'pptist': ExportSpecificFile, 'pptist': ExportSpecificFile,
} }
if (dialogForExport.value) return dialogMap[dialogForExport.value] || null if (dialogForExport.value) return dialogMap[dialogForExport.value] || isCoverImgStore.setIsCoverImg(false)
return null return isCoverImgStore.setIsCoverImg(false)
}) })
</script> </script>
......
...@@ -23,7 +23,6 @@ const emit = defineEmits<{ ...@@ -23,7 +23,6 @@ const emit = defineEmits<{
}>() }>()
const { layouts } = storeToRefs(useSlidesStore()) const { layouts } = storeToRefs(useSlidesStore())
const selectSlideTemplate = (slide: Slide) => { const selectSlideTemplate = (slide: Slide) => {
emit('select', slide) emit('select', slide)
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<template #content> <template #content>
<LayoutPool @select="slide => { createSlideByTemplate(slide); presetLayoutPopoverVisible = false }" /> <LayoutPool @select="slide => { createSlideByTemplate(slide); presetLayoutPopoverVisible = false }" />
</template> </template>
<div class="select-btn"><IconDown /></div> <div class="select-btn" v-if="layoutSlides.length>0"><IconDown /></div>
</Popover> </Popover>
</div> </div>
...@@ -47,30 +47,36 @@ ...@@ -47,30 +47,36 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, nextTick, ref, watch } from 'vue' import { computed, nextTick, ref, reactive, watch, inject } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store' import { useMainStore, useSlidesStore, useKeyboardStore, useScreenStore } from '@/store'
import { fillDigit } from '@/utils/common' import { fillDigit } from '@/utils/common'
import { isElementInViewport } from '@/utils/element' import { isElementInViewport } from '@/utils/element'
import type { ContextmenuItem } from '@/components/Contextmenu/types' import type { ContextmenuItem } from '@/components/Contextmenu/types'
import useSlideHandler from '@/hooks/useSlideHandler' import useSlideHandler from '@/hooks/useSlideHandler'
import useScreening from '@/hooks/useScreening' import useScreening from '@/hooks/useScreening'
import useLoadSlides from '@/hooks/useLoadSlides' import useLoadSlides from '@/hooks/useLoadSlides'
import { injectKeyDataSource, injectKeyTemplate } from '@/types/injectKey'
import ConfigService from '@/services/ConfigService'
import { getHtmlPlainText } from '@/utils/common'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue' import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
import LayoutPool from './LayoutPool.vue' import LayoutPool from './LayoutPool.vue'
import Popover from '@/components/Popover.vue' import Popover from '@/components/Popover.vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
const mainStore = useMainStore() const mainStore = useMainStore()
const slidesStore = useSlidesStore() const slidesStore = useSlidesStore()
const layoutsStore = useSlidesStore()
const keyboardStore = useKeyboardStore() const keyboardStore = useKeyboardStore()
const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore) const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore)
const { slides, slideIndex } = storeToRefs(slidesStore) const { slides, slideIndex, layoutSlides } = storeToRefs(slidesStore)
const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore) const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore)
const { slidesLoadLimit } = useLoadSlides() const { slidesLoadLimit } = useLoadSlides()
const TemplateTypeStore = useScreenStore()
const CoverImgStore = useScreenStore()
const dataLoadingStore = useScreenStore()
const { ConfigId, TemplateDataSource, TemplateType, dataLoading } = storeToRefs(TemplateTypeStore)
const selectedSlidesIndex = computed(() => [..._selectedSlidesIndex.value, slideIndex.value]) const selectedSlidesIndex = computed(() => [..._selectedSlidesIndex.value, slideIndex.value])
const presetLayoutPopoverVisible = ref(false) const presetLayoutPopoverVisible = ref(false)
...@@ -87,10 +93,15 @@ const { ...@@ -87,10 +93,15 @@ const {
sortSlides, sortSlides,
} = useSlideHandler() } = useSlideHandler()
// 页面被切换时 const datas = reactive({
const thumbnailsRef = ref<InstanceType<typeof Draggable>>() DataSource:{}
watch(() => slideIndex.value, () => { })
const queryObj = ref({} as any)
const searchData = ref({} as any)
datas.DataSource = inject(injectKeyDataSource)
searchData.value = inject(injectKeyTemplate)
watch(() => slideIndex.value, () => {
// 清除多选状态的幻灯片 // 清除多选状态的幻灯片
if (selectedSlidesIndex.value.length) { if (selectedSlidesIndex.value.length) {
mainStore.updateSelectedSlidesIndex([]) mainStore.updateSelectedSlidesIndex([])
...@@ -107,10 +118,169 @@ watch(() => slideIndex.value, () => { ...@@ -107,10 +118,169 @@ watch(() => slideIndex.value, () => {
}) })
}) })
// 监听请求保存成功 重新请求数据
watch(() => dataLoading.value, (n,o) =>{
if(n!=o&&n){
GetTripTemplate()
}
})
queryObj.value = inject(injectKeyDataSource).queryObj
// 获取行程团数据
const GetTripFiledData = async (status) =>{
if(queryObj.value.TempId&&!status) return
const slidesData = slides.value
try {
let queryMsg = {
ConfigId: ConfigId.value
}
let dataRes = await ConfigService.triptemplateGetTripFiledData(queryMsg);
if (dataRes.data.resultCode == 1) {
if(!dataRes.data.data) return
const travel = dataRes.data.data
const cursors = [] as Array<any>
slidesData.forEach((x,index)=>{
x.elements.forEach(y=>{
if(y.TemplateDataSource && y.TemplateDataSource.Content){
let dataPath = y.TemplateDataSource.Content.split('.')
let value=JSON.parse(JSON.stringify(travel));
dataPath.forEach((oo,i)=>{
if(value && value[oo]){
if(i==0 && Array.isArray(value[oo])){
let temp = cursors.find(item=>item.key==oo)
if(temp){
temp.index++
}else{
temp={key:oo,index:0}
cursors.push(temp)
}
if(value[oo].length>temp.index) value=value[oo][temp.index]
else value=value[oo]
}else{
value=value[oo]
}
}else{
value = null
}
})
if(value && typeof(value) == 'string'){
//替换
y.content= y.content.replace(getHtmlPlainText(y.content),value)
}else if(value && Array.isArray(value)){
//替换
y.content=value[0]
}
}
})
})
slidesStore.setSlides(slidesData)
}
} catch (error) {
console.log("triptemplateGetTripFiledData", error);
}
}
// 获取行程模版数据
const GetTripTemplate = async () =>{
if(!queryObj.value.TempId) {
let list = [
{
id: 'test-slide-1',
pageType: 1,
elements: [],
background: {
type: 'solid',
color: '#ffffff',
},
}
]
return slidesStore.setSlides(list)
}
try {
let queryMsg = {
TempId:queryObj.value.TempId
}
let dataRes = await ConfigService.GetTripTemplateSlide(queryMsg);
if (dataRes.data.resultCode == 1) {
let viewportRatio = 1.414
if(dataRes.data.data.TempType==1) viewportRatio = 0.75
slidesStore.setViewportRatio(viewportRatio)
let SlidesData = JSON.parse(dataRes.data.data.TempData)
let newSlides = []
if(typeof SlidesData=='object'&&!SlidesData.length){
let obj = {
pageType: 1,
...SlidesData
}
newSlides.push(obj)
}else if(SlidesData.length>0){
newSlides = SlidesData
}
slidesStore.setSlides(newSlides)
layoutsStore.setLayouts(JSON.parse(JSON.stringify(newSlides)))
CoverImgStore.setCoverImg(dataRes.data.data.CoverImg)
queryObj.value.TempId = dataRes.data.data.TempId
queryObj.value.LineId = dataRes.data.data.LineId
queryObj.value.LineName = dataRes.data.data.LineName
queryObj.value.LtId = dataRes.data.data.LtId
queryObj.value.Title = dataRes.data.data.Title
queryObj.value.TempData = dataRes.data.data.TempData
queryObj.value.CoverImg = dataRes.data.data.CoverImg
queryObj.value.CountryName = dataRes.data.data.CountryName
queryObj.value.SeasonName = dataRes.data.data.SeasonName
queryObj.value.ColorName = dataRes.data.data.ColorName
queryObj.value.ColorStr = dataRes.data.data.ColorStr
queryObj.value.TempType = dataRes.data.data.TempType
if(ConfigId.value==0) return
await GetTripFiledData(1)
}
} catch (error) {
console.log("GetTripTemplateSlide", error);
}
}
// 页面被切换时
const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
// 切换页面 // 切换页面
const changeSlideIndex = (index: number) => { const changeSlideIndex = (index: number) => {
mainStore.setActiveElementIdList([]) mainStore.setActiveElementIdList([])
// 绑定数据源
const newElements = slides.value.find((slide,indexs) => {
return index==indexs
})
datas.DataSource.pageType = newElements.pageType
let TemplateList = TemplateDataSource.value.filter(x=>{
return x.FiledType==newElements.pageType
})
datas.DataSource.DataSourceList = []
newElements&&newElements.elements&&newElements.elements.forEach(slide=>{
if(slide.type=="text"||slide.type=="image") {
let FiledTypeStr
if(slide.type=="text") FiledTypeStr = getHtmlPlainText(slide.content)
if(slide.type=="image") FiledTypeStr = slide.src
let Obj = {}
Obj = {
...slide,
FiledTypeStr: FiledTypeStr,
TemplateList: TemplateList,
TemplateDataSource: {
Content: slide.TemplateDataSource&&slide.TemplateDataSource.Content?slide.TemplateDataSource.Content:'',
Name: slide.TemplateDataSource&&slide.TemplateDataSource.Name?slide.TemplateDataSource.Name:'',
Id: slide.TemplateDataSource&&slide.TemplateDataSource.Id?slide.TemplateDataSource.Id:null as Number
}
}
if(Obj){
datas.DataSource.DataSourceList.push(Obj)
}
}
})
if (slideIndex.value === index) return if (slideIndex.value === index) return
slidesStore.updateSlideIndex(index) slidesStore.updateSlideIndex(index)
} }
...@@ -125,6 +295,7 @@ const handleClickSlideThumbnail = (e: MouseEvent, index: number) => { ...@@ -125,6 +295,7 @@ const handleClickSlideThumbnail = (e: MouseEvent, index: number) => {
// 如果被取消选中的页面刚好是当前激活页面,则需要从其他被选中的页面中选择第一个作为当前激活页面 // 如果被取消选中的页面刚好是当前激活页面,则需要从其他被选中的页面中选择第一个作为当前激活页面
if (ctrlKeyState.value) { if (ctrlKeyState.value) {
if (slideIndex.value === index) { if (slideIndex.value === index) {
if (!isMultiSelected) return if (!isMultiSelected) return
const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index) const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index)
...@@ -253,6 +424,8 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => { ...@@ -253,6 +424,8 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
}, },
] ]
} }
GetTripTemplate()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
This diff is collapsed.
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
<div class="row"> <div class="row">
<div style="width: 40%;">画布尺寸:</div> <div style="width: 40%;">画布尺寸:</div>
<Select <!-- <Select
style="width: 60%;" style="width: 60%;"
:value="viewportRatio" :value="viewportRatio"
@update:value="value => updateViewportRatio(value as number)" @update:value="value => updateViewportRatio(value as number)"
...@@ -114,6 +114,15 @@ ...@@ -114,6 +114,15 @@
{ label: '标准 4 : 3', value: 0.75 }, { label: '标准 4 : 3', value: 0.75 },
{ label: '纸张 A3 / A4', value: 0.70710678 }, { label: '纸张 A3 / A4', value: 0.70710678 },
]" ]"
/> -->
<Select
style="width: 60%;"
:value="viewportRatio"
@update:value="value => updateViewportRatio(value as number)"
:options="[
{ label: '横屏', value: 0.75 },
{ label: '竖屏', value: 1.414 },
]"
/> />
</div> </div>
...@@ -290,7 +299,7 @@ ...@@ -290,7 +299,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue' import { computed, ref, reactive,inject } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store' import { useMainStore, useSlidesStore } from '@/store'
import type { SlideBackground, SlideTheme } from '@/types/slides' import type { SlideBackground, SlideTheme } from '@/types/slides'
...@@ -299,6 +308,7 @@ import { WEB_FONTS } from '@/configs/font' ...@@ -299,6 +308,7 @@ import { WEB_FONTS } from '@/configs/font'
import useHistorySnapshot from '@/hooks/useHistorySnapshot' import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useSlideTheme from '@/hooks/useSlideTheme' import useSlideTheme from '@/hooks/useSlideTheme'
import { getImageDataURL } from '@/utils/image' import { getImageDataURL } from '@/utils/image'
import { injectKeyDataSource } from '@/types/injectKey'
import ColorButton from './common/ColorButton.vue' import ColorButton from './common/ColorButton.vue'
import FileInput from '@/components/FileInput.vue' import FileInput from '@/components/FileInput.vue'
...@@ -310,9 +320,17 @@ import Select from '@/components/Select.vue' ...@@ -310,9 +320,17 @@ import Select from '@/components/Select.vue'
import Popover from '@/components/Popover.vue' import Popover from '@/components/Popover.vue'
import NumberInput from '@/components/NumberInput.vue' import NumberInput from '@/components/NumberInput.vue'
const datas = reactive({
DataSource:{
DataSourceOverlay: false
}
})
const queryObj = ref({} as any)
datas.DataSource = inject(injectKeyDataSource)
queryObj.value = inject(injectKeyDataSource).queryObj
const slidesStore = useSlidesStore() const slidesStore = useSlidesStore()
const { availableFonts } = storeToRefs(useMainStore()) const { availableFonts } = storeToRefs(useMainStore())
const { slides, currentSlide, viewportRatio, theme } = storeToRefs(slidesStore) const { slides, currentSlide, viewportRatio, theme, slideIndex } = storeToRefs(slidesStore)
const moreThemeConfigsVisible = ref(false) const moreThemeConfigsVisible = ref(false)
...@@ -390,6 +408,7 @@ const applyBackgroundAllSlide = () => { ...@@ -390,6 +408,7 @@ const applyBackgroundAllSlide = () => {
addHistorySnapshot() addHistorySnapshot()
} }
// 设置主题 // 设置主题
const updateTheme = (themeProps: Partial<SlideTheme>) => { const updateTheme = (themeProps: Partial<SlideTheme>) => {
slidesStore.setTheme(themeProps) slidesStore.setTheme(themeProps)
...@@ -397,6 +416,11 @@ const updateTheme = (themeProps: Partial<SlideTheme>) => { ...@@ -397,6 +416,11 @@ const updateTheme = (themeProps: Partial<SlideTheme>) => {
// 设置画布尺寸(宽高比例) // 设置画布尺寸(宽高比例)
const updateViewportRatio = (value: number) => { const updateViewportRatio = (value: number) => {
if(value==0.75){
queryObj.value.TempType = 1
}else{
queryObj.value.TempType = 2
}
slidesStore.setViewportRatio(value) slidesStore.setViewportRatio(value)
} }
</script> </script>
......
...@@ -13,14 +13,16 @@ ...@@ -13,14 +13,16 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store' import { useMainStore } from '@/store'
import { useScreenStore } from '@/store'
import { ToolbarStates } from '@/types/toolbar' import { ToolbarStates } from '@/types/toolbar'
import ElementStylePanel from './ElementStylePanel/index.vue' import ElementStylePanel from './ElementStylePanel/index.vue'
import ElementPositionPanel from './ElementPositionPanel.vue' import ElementPositionPanel from './ElementPositionPanel.vue'
import ElementAnimationPanel from './ElementAnimationPanel.vue' import ElementAnimationPanel from './ElementAnimationPanel.vue'
import ElementTemplateData from './ElementTemplateData.vue'
import SlideDesignPanel from './SlideDesignPanel.vue' import SlideDesignPanel from './SlideDesignPanel.vue'
import SlideAnimationPanel from './SlideAnimationPanel.vue' import SlideAnimationPanel from './SlideAnimationPanel.vue'
import MultiPositionPanel from './MultiPositionPanel.vue' import MultiPositionPanel from './MultiPositionPanel.vue'
...@@ -34,6 +36,7 @@ interface ElementTabs { ...@@ -34,6 +36,7 @@ interface ElementTabs {
const mainStore = useMainStore() const mainStore = useMainStore()
const { activeElementIdList, handleElement, toolbarState } = storeToRefs(mainStore) const { activeElementIdList, handleElement, toolbarState } = storeToRefs(mainStore)
const { model } = storeToRefs(useScreenStore())
const elementTabs = computed<ElementTabs[]>(() => { const elementTabs = computed<ElementTabs[]>(() => {
if (handleElement.value?.type === 'text') { if (handleElement.value?.type === 'text') {
...@@ -50,11 +53,22 @@ const elementTabs = computed<ElementTabs[]>(() => { ...@@ -50,11 +53,22 @@ const elementTabs = computed<ElementTabs[]>(() => {
{ label: '动画', key: ToolbarStates.EL_ANIMATION }, { label: '动画', key: ToolbarStates.EL_ANIMATION },
] ]
}) })
const slideTabs = [ const slideTabs = ref([] as any)
if(model.value){
slideTabs.value = [
{ label: '设计', key: ToolbarStates.SLIDE_DESIGN }, { label: '设计', key: ToolbarStates.SLIDE_DESIGN },
{ label: '切换', key: ToolbarStates.SLIDE_ANIMATION }, { label: '切换', key: ToolbarStates.SLIDE_ANIMATION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION }, { label: '动画', key: ToolbarStates.EL_ANIMATION },
] { label: '模版数据', key: ToolbarStates.EL_TEMPLATEDATA },
]
}else {
slideTabs.value = [
{ label: '设计', key: ToolbarStates.SLIDE_DESIGN },
{ label: '切换', key: ToolbarStates.SLIDE_ANIMATION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION },
]
}
const multiSelectTabs = [ const multiSelectTabs = [
{ label: '样式', key: ToolbarStates.EL_STYLE }, { label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '位置', key: ToolbarStates.MULTI_POSITION }, { label: '位置', key: ToolbarStates.MULTI_POSITION },
...@@ -65,7 +79,7 @@ const setToolbarState = (value: ToolbarStates) => { ...@@ -65,7 +79,7 @@ const setToolbarState = (value: ToolbarStates) => {
} }
const currentTabs = computed(() => { const currentTabs = computed(() => {
if (!activeElementIdList.value.length) return slideTabs if (!activeElementIdList.value.length) return slideTabs.value
else if (activeElementIdList.value.length > 1) return multiSelectTabs else if (activeElementIdList.value.length > 1) return multiSelectTabs
return elementTabs.value return elementTabs.value
}) })
...@@ -82,6 +96,7 @@ const currentPanelComponent = computed(() => { ...@@ -82,6 +96,7 @@ const currentPanelComponent = computed(() => {
[ToolbarStates.EL_STYLE]: ElementStylePanel, [ToolbarStates.EL_STYLE]: ElementStylePanel,
[ToolbarStates.EL_POSITION]: ElementPositionPanel, [ToolbarStates.EL_POSITION]: ElementPositionPanel,
[ToolbarStates.EL_ANIMATION]: ElementAnimationPanel, [ToolbarStates.EL_ANIMATION]: ElementAnimationPanel,
[ToolbarStates.EL_TEMPLATEDATA]: ElementTemplateData,
[ToolbarStates.SLIDE_DESIGN]: SlideDesignPanel, [ToolbarStates.SLIDE_DESIGN]: SlideDesignPanel,
[ToolbarStates.SLIDE_ANIMATION]: SlideAnimationPanel, [ToolbarStates.SLIDE_ANIMATION]: SlideAnimationPanel,
[ToolbarStates.MULTI_POSITION]: MultiPositionPanel, [ToolbarStates.MULTI_POSITION]: MultiPositionPanel,
......
...@@ -5,12 +5,14 @@ ...@@ -5,12 +5,14 @@
<Thumbnails class="layout-content-left" /> <Thumbnails class="layout-content-left" />
<div class="layout-content-center"> <div class="layout-content-center">
<CanvasTool class="center-top" /> <CanvasTool class="center-top" />
<Canvas class="center-body" :style="{ height: `calc(100% - ${remarkHeight + 40}px)` }" /> <!-- :style="{ height: `calc(100% - ${remarkHeight + 40}px)` }" -->
<Remark <Canvas class="center-body" :style="{ height: `100%`}" />
<!-- <Remark
class="center-bottom" class="center-bottom"
v-model:height="remarkHeight" v-model:height="remarkHeight"
:style="{ height: `${remarkHeight}px` }" :style="{ height: `${remarkHeight}px` }"
/> /> -->
<DataaSource/>
</div> </div>
<Toolbar class="layout-content-right" /> <Toolbar class="layout-content-right" />
</div> </div>
...@@ -29,11 +31,12 @@ ...@@ -29,11 +31,12 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue' import { ref, reactive, provide, watch, inject } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store' import { useMainStore, useSlidesStore, useScreenStore } from '@/store'
import useGlobalHotkey from '@/hooks/useGlobalHotkey' import useGlobalHotkey from '@/hooks/useGlobalHotkey'
import usePasteEvent from '@/hooks/usePasteEvent' import usePasteEvent from '@/hooks/usePasteEvent'
import { injectKeyDataSource, injectKeyTemplate } from '@/types/injectKey'
import EditorHeader from './EditorHeader/index.vue' import EditorHeader from './EditorHeader/index.vue'
import Canvas from './Canvas/index.vue' import Canvas from './Canvas/index.vue'
...@@ -45,6 +48,69 @@ import ExportDialog from './ExportDialog/index.vue' ...@@ -45,6 +48,69 @@ import ExportDialog from './ExportDialog/index.vue'
import SelectPanel from './SelectPanel.vue' import SelectPanel from './SelectPanel.vue'
import SearchPanel from './SearchPanel.vue' import SearchPanel from './SearchPanel.vue'
import Modal from '@/components/Modal.vue' import Modal from '@/components/Modal.vue'
import DataaSource from './DataaSource/index.vue'
import ConfigService from '@/services/ConfigService'
const datas = reactive({
DataSource:{
ConfigId: inject(injectKeyTemplate).ConfigId?inject(injectKeyTemplate).ConfigId:0,
pageType: 1,//1基础 2酒店 3景 4餐
DataSourceOverlay: false,
DataSourceList:[],
queryObj:{
TempId: inject(injectKeyTemplate).TempId?inject(injectKeyTemplate).TempId:0,//编号(新增传0) 是 [int]
LineId: null,//线路Id 是 [int]
LineName: '',//线路名称 是 [string]
LtId: null,//系列Id 是 [int]
Title: '',//名称 是 [string]
TempData: null,//模板数据 是 [json]
CoverImg: '',//封面图 是 [string]
CountryName: null,//国家 是 [string]
SeasonName: '',//季节 是 [string]
ColorName: '',//颜色名称 是 [string]
ColorStr: null,//颜色值 是 [string]
TempType: 1,// 版面类型(1-横版,2-竖版)
}
},
})
const slidesStore = useSlidesStore()
const TemplateTypeStore = useScreenStore()
const TempDataSourceStore = useScreenStore()
const { slides, slideIndex } = storeToRefs(slidesStore)
const { TemplateType } = storeToRefs(TemplateTypeStore)
const pageTypesList = ref([] as any)
watch(() => datas.DataSource, () => {
provide(injectKeyDataSource,datas.DataSource)
})
// 数据源
const GetTripFiled = async () =>{
try {
let TemplateRes = await ConfigService.TemplateGetTripFiled();
if (TemplateRes.data.resultCode == 1) {
TemplateRes.data.data.forEach(x=>{
let obj = pageTypesList.value.findIndex(z=>{
return z.FiledType==x.FiledType
})
if(obj==-1){
let object = {
FiledType: x.FiledType,
Name: x.FiledTypeStr
}
pageTypesList.value.push(object)
}
})
TemplateTypeStore.setTemplateType(pageTypesList.value)
TempDataSourceStore.setTemplateDataSource(TemplateRes.data.data)
}
} catch (error) {
console.log("TemplateGetTripFiled", error);
}
}
GetTripFiled()
const mainStore = useMainStore() const mainStore = useMainStore()
const { dialogForExport, showSelectPanel, showSearchPanel } = storeToRefs(mainStore) const { dialogForExport, showSelectPanel, showSearchPanel } = storeToRefs(mainStore)
...@@ -52,8 +118,12 @@ const closeExportDialog = () => mainStore.setDialogForExport('') ...@@ -52,8 +118,12 @@ const closeExportDialog = () => mainStore.setDialogForExport('')
const remarkHeight = ref(40) const remarkHeight = ref(40)
useGlobalHotkey() useGlobalHotkey()
usePasteEvent() usePasteEvent()
provide(injectKeyDataSource,datas.DataSource)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
This diff is collapsed.
...@@ -29,7 +29,7 @@ import BaseVideoElement from '@/views/components/element/VideoElement/BaseVideoE ...@@ -29,7 +29,7 @@ import BaseVideoElement from '@/views/components/element/VideoElement/BaseVideoE
import BaseAudioElement from '@/views/components/element/AudioElement/BaseAudioElement.vue' import BaseAudioElement from '@/views/components/element/AudioElement/BaseAudioElement.vue'
const props = defineProps<{ const props = defineProps<{
elementInfo: PPTElement elementInfo: PPTElement,
elementIndex: number elementIndex: number
}>() }>()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment