|
|
@@ -29,12 +29,27 @@ import type {
|
|
|
|
|
|
const convertFontSizePtToPx = (html: string, ratio: number) => {
|
|
|
//return html;
|
|
|
- return html.replace(/font-size:\s*([\d.]+)pt/g, (match, p1) => {
|
|
|
- return `font-size: ${(parseFloat(p1) * ratio) | 0}px`
|
|
|
+ return html.replace(/\s*([\d.]+)pt/g, (match, p1) => {
|
|
|
+ return `${(parseFloat(p1) * ratio - 1) | 0}px `
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
+const getStyle = (htmlString: string) => {
|
|
|
+ //return html;
|
|
|
+ // 1. 创建 DOMParser 实例
|
|
|
+ const parser = new DOMParser();
|
|
|
+ // 2. 解析 HTML 字符串为文档对象
|
|
|
+ const doc = parser.parseFromString(htmlString, 'text/html');
|
|
|
+ // 3. 获取 p 元素
|
|
|
+ const p = doc.querySelector('p');
|
|
|
+ // 4. 读取 style 属性(内联样式字符串)
|
|
|
+ const styleAttr = p?.getAttribute('allstyle');
|
|
|
+ console.log(styleAttr); // 输出完整的 style 字符串
|
|
|
+ return styleAttr || "";
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
export default () => {
|
|
|
const slidesStore = useSlidesStore()
|
|
|
const { slides, theme, viewportRatio, title, viewportSize } = storeToRefs(useSlidesStore())
|
|
|
@@ -1077,6 +1092,8 @@ export default () => {
|
|
|
// 计算缩放比例
|
|
|
let ratio = 96 / 72; // PPTX 默认 72 DPI,屏幕 96 DPI
|
|
|
const width = json.size.width;
|
|
|
+ const height = json.size.height;
|
|
|
+ const viewportRatio = json.size.viewportRatio || (height && width ? height / width : undefined)
|
|
|
if (fixedViewport) {
|
|
|
ratio = 1000 / width; // 固定视口宽度为 1000px
|
|
|
} else {
|
|
|
@@ -1133,9 +1150,10 @@ export default () => {
|
|
|
};
|
|
|
|
|
|
// ----- 解析元素(递归函数)-----
|
|
|
- const parseElements = async (elements: any[]) => {
|
|
|
+ const parseElements = async (elements: any[], pelements: any = null) => {
|
|
|
// 按绘制顺序排序
|
|
|
const sortedElements = elements.sort((a, b) => a.order - b.order);
|
|
|
+ console.log(sortedElements)
|
|
|
|
|
|
for (const el of sortedElements) {
|
|
|
// 保存原始尺寸用于后续可能的路径计算
|
|
|
@@ -1143,6 +1161,11 @@ export default () => {
|
|
|
const originHeight = el.height || 1;
|
|
|
const originLeft = el.left;
|
|
|
const originTop = el.top;
|
|
|
+ // 保存原始尺寸用于后续可能的路径计算
|
|
|
+ const poriginWidth = pelements?.width;
|
|
|
+ const poriginHeight = pelements?.height;
|
|
|
+ const poriginLeft = pelements?.left;
|
|
|
+ const poriginTop = pelements?.top;
|
|
|
|
|
|
// 应用缩放
|
|
|
el.width = el.width * ratio;
|
|
|
@@ -1339,6 +1362,7 @@ export default () => {
|
|
|
|
|
|
slide.elements.push(element);
|
|
|
}
|
|
|
+
|
|
|
|
|
|
// ---------- 形状 ----------
|
|
|
else if (el.type === 'shape') {
|
|
|
@@ -1390,6 +1414,7 @@ export default () => {
|
|
|
},
|
|
|
text: {
|
|
|
content: convertFontSizePtToPx(el.content, ratio),
|
|
|
+ style: getStyle(el.content),
|
|
|
defaultFontName: theme.value.fontName,
|
|
|
defaultColor: theme.value.fontColor,
|
|
|
align: vAlignMap[el.vAlign] || 'middle',
|
|
|
@@ -1426,7 +1451,9 @@ export default () => {
|
|
|
} else if (el.path && el.path.indexOf('NaN') === -1) {
|
|
|
const { maxX, maxY } = getSvgPathRange(el.path);
|
|
|
element.path = el.path;
|
|
|
- element.viewBox = [maxX || originWidth, maxY || originHeight];
|
|
|
+
|
|
|
+ element.viewBox = [poriginWidth|| originWidth || maxX, poriginHeight || originHeight || maxY];
|
|
|
+ //element.viewBox = [originWidth, originHeight];
|
|
|
}
|
|
|
|
|
|
if (el.shapType === 'custom') {
|
|
|
@@ -1439,7 +1466,9 @@ export default () => {
|
|
|
element.path = el.path!;
|
|
|
}
|
|
|
const { maxX, maxY } = getSvgPathRange(element.path);
|
|
|
- element.viewBox = [maxX || originWidth, maxY || originHeight];
|
|
|
+ element.viewBox = [poriginWidth||maxX || originWidth, poriginHeight||maxY || originHeight];
|
|
|
+ //element.viewBox = [Math.max(maxX, originWidth), Math.max(maxY, originHeight)];
|
|
|
+ //element.viewBox = [originWidth, originHeight];
|
|
|
}
|
|
|
|
|
|
if (element.path) slide.elements.push(element);
|
|
|
@@ -1634,7 +1663,7 @@ export default () => {
|
|
|
if (el.isFlipV) elements = flipGroupElements(elements, 'x');
|
|
|
|
|
|
// 递归解析子元素(注意:子元素的上传任务会加入同一个 uploadTasks 数组)
|
|
|
- await parseElements(elements);
|
|
|
+ await parseElements(elements, pelements || el);
|
|
|
}
|
|
|
|
|
|
// ---------- 图表组合(SmartArt)----------
|
|
|
@@ -1672,6 +1701,62 @@ export default () => {
|
|
|
Promise.all(uploadTasks);
|
|
|
|
|
|
exporting.value = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ // 更新视口尺寸(如果提供了的话)
|
|
|
+ if (width !== undefined && height !== undefined) {
|
|
|
+ console.log('正在触发视口尺寸更新事件:', { width, height, viewportRatio })
|
|
|
+
|
|
|
+ // 同时也要更新slidesStore中的相关数据
|
|
|
+ if (slidesStore.setViewportSize) {
|
|
|
+ console.log('正在更新store中的视口尺寸')
|
|
|
+ slidesStore.setViewportSize(width)
|
|
|
+ if (slidesStore.setViewportRatio && viewportRatio !== undefined) {
|
|
|
+ slidesStore.setViewportRatio(viewportRatio)
|
|
|
+ console.log('视口比例已更新:', viewportRatio)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ window.dispatchEvent(new CustomEvent('viewportSizeUpdated', {
|
|
|
+ detail: { width, height, viewportRatio }
|
|
|
+ }))
|
|
|
+ console.log('视口尺寸更新事件已触发')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 导入成功后,触发画布尺寸更新
|
|
|
+ // 使用 nextTick 确保DOM更新完成后再触发
|
|
|
+ console.log('开始触发画布尺寸更新事件...')
|
|
|
+ nextTick(() => {
|
|
|
+ console.log('DOM更新完成,触发 slidesDataUpdated 事件')
|
|
|
+ // 触发自定义事件,通知需要更新画布尺寸的组件
|
|
|
+ window.dispatchEvent(new CustomEvent('slidesDataUpdated', {
|
|
|
+ detail: {
|
|
|
+ slides,
|
|
|
+ cover,
|
|
|
+ title,
|
|
|
+ theme,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ viewportRatio,
|
|
|
+ timestamp: Date.now()
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ console.log('slidesDataUpdated 事件已触发')
|
|
|
+
|
|
|
+ // 检查并调整幻灯片索引,确保在有效范围内
|
|
|
+ const newSlideCount = slides.length
|
|
|
+ const currentIndex = slidesStore.slideIndex
|
|
|
+ if (currentIndex >= newSlideCount) {
|
|
|
+ console.log('调整幻灯片索引:', currentIndex, '->', Math.max(0, newSlideCount - 1))
|
|
|
+ slidesStore.updateSlideIndex(Math.max(0, newSlideCount - 1))
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('画布尺寸更新事件处理完成')
|
|
|
+
|
|
|
+
|
|
|
+ })
|
|
|
+*/
|
|
|
+
|
|
|
};
|
|
|
|
|
|
reader.readAsArrayBuffer(file);
|