jack 5 days ago
parent
commit
c7122c25ac
3 changed files with 112 additions and 19 deletions
  1. 91 6
      src/hooks/useImport.ts
  2. 1 0
      src/types/slides.ts
  3. 20 13
      src/views/components/element/ShapeElement/index.vue

+ 91 - 6
src/hooks/useImport.ts

@@ -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);

+ 1 - 0
src/types/slides.ts

@@ -311,6 +311,7 @@ export interface ShapeText {
   defaultColor: string
   align: ShapeTextAlign
   type?: TextType
+  style?: string
 }
 
 /**

+ 20 - 13
src/views/components/element/ShapeElement/index.vue

@@ -67,19 +67,21 @@
           </g>
         </svg>
 
-        <div class="shape-text" :class="[text.align, { 'editable': editable || text.content }]">
-          <ProsemirrorEditor
-            ref="prosemirrorEditorRef"
-            v-if="editable || text.content"
-            :elementId="elementInfo.id"
-            :defaultColor="text.defaultColor"
-            :defaultFontName="text.defaultFontName"
-            :editable="!elementInfo.lock"
-            :value="text.content"
-            @update="({ value, ignore }) => updateText(value, ignore)"
-            @blur="checkEmptyText()"
-            @mousedown="$event => handleSelectElement($event, false)"
-          />
+        <div class="shape-text" :style="text.style" :class="[text.align, { 'editable': editable || text.content }]">
+          <div>
+            <ProsemirrorEditor
+              ref="prosemirrorEditorRef"
+              v-if="editable || text.content"
+              :elementId="elementInfo.id"
+              :defaultColor="text.defaultColor"
+              :defaultFontName="text.defaultFontName"
+              :editable="!elementInfo.lock"
+              :value="text.content"
+              @update="({ value, ignore }) => updateText(value, ignore)"
+              @blur="checkEmptyText()"
+              @mousedown="$event => handleSelectElement($event, false)"
+            />
+          </div>
         </div>
       </div>
     </div>
@@ -249,6 +251,11 @@ const startEdit = () => {
   }
   &.middle {
     justify-content: center;
+    left: 50%;
+    top: 50%;
+    -webkit-transform: translate(-50%,-50%);
+    transform: translate(-50%,-50%);
+    padding: 15%
   }
   &.bottom {
     justify-content: flex-end;