jvs-ppt-ui 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/jvs-ppt-ui.es.js +72 -65
- package/dist/lib/jvs-ppt-ui.umd.js +8 -8
- package/dist/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/App.vue +36 -14
- package/src/components/CanvasArea.vue +0 -2
- package/src/components/Header.vue +7 -1
- package/src/components/PresentationGroupChild.vue +1 -1
- package/src/components/PresentationMode.vue +1 -1
- package/src/components/SidebarLeft.vue +1 -1
- package/src/components/Toolbar.vue +6 -4
- package/src/composables/useSlides.ts +8 -4
- package/src/utils/canvas/elementStyles.ts +1 -1
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import PptEditor from './components/PptEditor.vue'
|
|
4
|
-
import type { DeckData, PptEditorApi } from './types'
|
|
4
|
+
import type { DeckData, PptEditorApi, UploadResourceContext } from './types'
|
|
5
5
|
|
|
6
6
|
const editorRef = ref<PptEditorApi | null>(null)
|
|
7
7
|
|
|
@@ -12,20 +12,42 @@ function handleSave(deck: DeckData) {
|
|
|
12
12
|
function handleReady(api: PptEditorApi) {
|
|
13
13
|
console.log('[JVS-PPT 独立运行模式] 编辑器初始化完成:', api)
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 模拟资源上传函数
|
|
18
|
+
* 覆盖场景:导入 PPTX/JSON、上传图片、视频、音频、剪贴板粘贴、占位符上传、背景上传等
|
|
19
|
+
*/
|
|
20
|
+
async function handleCustomUpload(fileOrBlob: File | Blob, context: UploadResourceContext): Promise<string> {
|
|
21
|
+
console.log('[模拟自定义上传函数触发] 接收到待上传资源:', {
|
|
22
|
+
type: context.type, // 资源类型: 'image' | 'video' | 'audio'
|
|
23
|
+
source: context.source, // 触发来源: 'file-upload' | 'pptx-import' | 'json-import' | 'paste' | 'placeholder' | 'background'
|
|
24
|
+
filename: context.filename,
|
|
25
|
+
size: `${(fileOrBlob.size / 1024).toFixed(2)} KB`,
|
|
26
|
+
fileOrBlob
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// 1. 模拟网络上传请求耗时
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 300))
|
|
31
|
+
|
|
32
|
+
// 2. 实际业务生产代码范例:
|
|
33
|
+
// const formData = new FormData()
|
|
34
|
+
// formData.append('file', fileOrBlob, context.filename || `upload_${Date.now()}`)
|
|
35
|
+
// formData.append('type', context.type)
|
|
36
|
+
// const res = await fetch('/api/oss/upload', { method: 'POST', body: formData }).then(r => r.json())
|
|
37
|
+
// return res.data.url
|
|
38
|
+
|
|
39
|
+
// 3. 模拟环境:生成可正常渲染的地址作为模拟的服务器返回 URL
|
|
40
|
+
const mockServerUrl = URL.createObjectURL(fileOrBlob)
|
|
41
|
+
console.log(`[模拟上传成功] 已返回服务器文件地址:`, mockServerUrl)
|
|
42
|
+
return mockServerUrl
|
|
43
|
+
}
|
|
15
44
|
</script>
|
|
16
45
|
|
|
17
46
|
<template>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:enable-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
material-tree-api-url="/jvs-dam/api/dam/material/tree"
|
|
25
|
-
material-page-api-url="/jvs-dam/api/dam/material/page"
|
|
26
|
-
material-api-url="/jvs-dam/api/dam/material/tree"
|
|
27
|
-
material-save-api-url="/jvs-dam/api/dam/material/save"
|
|
28
|
-
@save="handleSave"
|
|
29
|
-
@ready="handleReady"
|
|
30
|
-
/>
|
|
47
|
+
<!-- :custom-upload="handleCustomUpload" -->
|
|
48
|
+
<PptEditor ref="editorRef" :custom-upload="handleCustomUpload" :enable-mcp="true" :enable-ai="true"
|
|
49
|
+
ai-api-url="/jvs-dam/api/ppt/ai-replace" :enable-material="true"
|
|
50
|
+
material-tree-api-url="/jvs-dam/api/dam/material/tree" material-page-api-url="/jvs-dam/api/dam/material/page"
|
|
51
|
+
material-api-url="/jvs-dam/api/dam/material/tree" material-save-api-url="/jvs-dam/api/dam/material/save"
|
|
52
|
+
@save="handleSave" @ready="handleReady" />
|
|
31
53
|
</template>
|
|
@@ -3604,8 +3604,6 @@ function handleBorderMouseDown(e: MouseEvent, el: any) {
|
|
|
3604
3604
|
}
|
|
3605
3605
|
|
|
3606
3606
|
function handleElementDblClick(e: MouseEvent, el: any) {
|
|
3607
|
-
// TODO(debug): 定位“双击元素却新建了文本框”的拦截层,问题定位后移除
|
|
3608
|
-
console.info('[元素dblclick调试]', el?.id, el?.type)
|
|
3609
3607
|
let target = el
|
|
3610
3608
|
if (selectedElementIds.value.length > 0 && !selectedElementIds.value.includes(el.id)) {
|
|
3611
3609
|
const activeSelectedEl = findSelectedElementUnderPoint(e.clientX, e.clientY)
|
|
@@ -4188,7 +4188,10 @@ const parsePPTXJSONData = (json: any, zipMeta?: any) => {
|
|
|
4188
4188
|
const borderGrad = el.border?.gradient || el.outline?.gradient
|
|
4189
4189
|
const outlineGrad = borderGrad ? normalizeGradientConfig(borderGrad) : undefined
|
|
4190
4190
|
|
|
4191
|
-
const
|
|
4191
|
+
const fillVal = el.fill?.type === 'image' ? el.fill.value : null
|
|
4192
|
+
const pattern: string | undefined = fillVal
|
|
4193
|
+
? (fillVal.blob || fillVal.base64 || fillVal.src || fillVal.url || (typeof fillVal === 'string' ? fillVal : undefined))
|
|
4194
|
+
: undefined
|
|
4192
4195
|
|
|
4193
4196
|
const fill = typeof el.fill === 'string'
|
|
4194
4197
|
? (el.fill.trim() === '' ? 'none' : el.fill)
|
|
@@ -4254,6 +4257,9 @@ const parsePPTXJSONData = (json: any, zipMeta?: any) => {
|
|
|
4254
4257
|
element.style.flipH = flipH
|
|
4255
4258
|
element.style.flipV = flipV
|
|
4256
4259
|
element.style.fill = fill
|
|
4260
|
+
if (pattern) {
|
|
4261
|
+
element.style.pattern = pattern
|
|
4262
|
+
}
|
|
4257
4263
|
element.style.borderColor = el.borderColor || (el.outline?.color || 'transparent')
|
|
4258
4264
|
element.style.borderWidth = el.borderWidth !== undefined ? `${+(el.borderWidth * ratio).toFixed(2)}px` : (el.outline?.width !== undefined ? `${el.outline.width}px` : '0px')
|
|
4259
4265
|
element.style.borderStyle = el.borderType || (el.outline?.style || 'solid')
|
|
@@ -165,7 +165,7 @@ function getElementPattern(el: any): string | undefined {
|
|
|
165
165
|
if (typeof val === 'string') {
|
|
166
166
|
pattern = val
|
|
167
167
|
} else if (val && typeof val === 'object') {
|
|
168
|
-
pattern = val.
|
|
168
|
+
pattern = val.blob || val.base64 || val.src || val.url || ''
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
}
|
|
@@ -553,7 +553,7 @@ function getElementPattern(el: any): string | undefined {
|
|
|
553
553
|
if (typeof val === 'string') {
|
|
554
554
|
pattern = val
|
|
555
555
|
} else if (val && typeof val === 'object') {
|
|
556
|
-
pattern = val.
|
|
556
|
+
pattern = val.blob || val.base64 || val.src || val.url || ''
|
|
557
557
|
}
|
|
558
558
|
}
|
|
559
559
|
}
|
|
@@ -1499,7 +1499,7 @@ function getElementPattern(el: any): string | undefined {
|
|
|
1499
1499
|
if (el.pattern || el.style?.pattern) return el.pattern || el.style?.pattern
|
|
1500
1500
|
const rawFill = (el.style && el.style.fill !== undefined) ? el.style.fill : el.fill
|
|
1501
1501
|
if (rawFill && typeof rawFill === 'object' && (rawFill.type === 'image' || rawFill.type === 'pattern')) {
|
|
1502
|
-
return rawFill.value?.src || rawFill.value?.url || rawFill.value
|
|
1502
|
+
return rawFill.value?.blob || rawFill.value?.src || rawFill.value?.base64 || rawFill.value?.url || (typeof rawFill.value === 'string' ? rawFill.value : undefined)
|
|
1503
1503
|
}
|
|
1504
1504
|
return undefined
|
|
1505
1505
|
}
|
|
@@ -346,8 +346,9 @@ async function handleVideoFileChange(e: Event) {
|
|
|
346
346
|
})
|
|
347
347
|
})
|
|
348
348
|
if (url) {
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
addElement('video', url)
|
|
350
|
+
mediaPopoverVisible.value = false
|
|
351
|
+
notify('已成功添加视频')
|
|
351
352
|
}
|
|
352
353
|
} catch (err: any) {
|
|
353
354
|
console.error(err)
|
|
@@ -370,8 +371,9 @@ async function handleAudioFileChange(e: Event) {
|
|
|
370
371
|
})
|
|
371
372
|
})
|
|
372
373
|
if (url) {
|
|
373
|
-
|
|
374
|
-
|
|
374
|
+
addElement('audio', url)
|
|
375
|
+
mediaPopoverVisible.value = false
|
|
376
|
+
notify('已成功添加音频')
|
|
375
377
|
}
|
|
376
378
|
} catch (err: any) {
|
|
377
379
|
console.error(err)
|
|
@@ -5269,7 +5269,7 @@ function extractPatternFromFill(el: any): string | undefined {
|
|
|
5269
5269
|
if (typeof val === 'string') {
|
|
5270
5270
|
pattern = val
|
|
5271
5271
|
} else if (val && typeof val === 'object') {
|
|
5272
|
-
pattern = val.
|
|
5272
|
+
pattern = val.blob || val.base64 || val.src || val.url || ''
|
|
5273
5273
|
}
|
|
5274
5274
|
}
|
|
5275
5275
|
}
|
|
@@ -8058,9 +8058,13 @@ async function uploadMediaResourcesInSlides(deckOrSlides: any): Promise<void> {
|
|
|
8058
8058
|
const remote = await uploadMediaUrl(targetSrc, 'image', 'svg')
|
|
8059
8059
|
el.src = remote
|
|
8060
8060
|
}
|
|
8061
|
-
} else if (el.type === 'shape'
|
|
8062
|
-
const
|
|
8063
|
-
|
|
8061
|
+
} else if (el.type === 'shape') {
|
|
8062
|
+
const targetPattern = el.pattern || el.style?.pattern || (el.fill?.type === 'image' ? (el.fill.value?.blob || el.fill.value?.base64 || el.fill.value?.src) : undefined)
|
|
8063
|
+
if (targetPattern && shouldUpload(targetPattern)) {
|
|
8064
|
+
const remote = await uploadMediaUrl(targetPattern, 'image', 'png')
|
|
8065
|
+
el.pattern = remote
|
|
8066
|
+
if (el.style) el.style.pattern = remote
|
|
8067
|
+
}
|
|
8064
8068
|
}
|
|
8065
8069
|
}
|
|
8066
8070
|
|
|
@@ -186,7 +186,7 @@ export function getElementPattern(el: any): string | undefined {
|
|
|
186
186
|
if (typeof val === 'string') {
|
|
187
187
|
pattern = val
|
|
188
188
|
} else if (val && typeof val === 'object') {
|
|
189
|
-
pattern = val.
|
|
189
|
+
pattern = val.blob || val.base64 || val.src || val.url || ''
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
}
|