CatPtain commited on
Commit
f184abd
·
verified ·
1 Parent(s): 773dbcc

Upload useExport.ts

Browse files
Files changed (1) hide show
  1. frontend/src/hooks/useExport.ts +105 -3
frontend/src/hooks/useExport.ts CHANGED
@@ -818,9 +818,32 @@ export default () => {
818
  return isSVGBase64 || isSVGUrl
819
  }
820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  // 导出PPTX文件
822
- const exportPPTX = (_slides: Slide[], masterOverwrite: boolean, ignoreMedia: boolean) => {
823
  exporting.value = true
 
 
 
 
 
 
 
 
824
  const pptx = new pptxgen()
825
 
826
  if (viewportRatio.value === 0.625) pptx.layout = 'LAYOUT_16x10'
@@ -974,8 +997,87 @@ export default () => {
974
  else if (el.type === 'shape') {
975
  if (el.special) {
976
  const svgRef = document.querySelector(`.thumbnail-list .base-element-${el.id} svg`) as HTMLElement
977
- if (svgRef.clientWidth < 1 || svgRef.clientHeight < 1) continue // 临时处理(导入PPTX文件带来的异常数据)
978
- const base64SVG = svg2Base64(svgRef)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
979
 
980
  const options: pptxgen.ImageProps = {
981
  data: base64SVG,
 
818
  return isSVGBase64 || isSVGUrl
819
  }
820
 
821
+ // 确保元素已渲染的辅助函数
822
+ const ensureElementsRendered = async () => {
823
+ return new Promise<void>((resolve) => {
824
+ // 强制重绘
825
+ document.body.offsetHeight;
826
+
827
+ // 等待下一个动画帧
828
+ requestAnimationFrame(() => {
829
+ requestAnimationFrame(() => {
830
+ resolve();
831
+ });
832
+ });
833
+ });
834
+ };
835
+
836
  // 导出PPTX文件
837
+ const exportPPTX = async (_slides: Slide[], masterOverwrite: boolean, ignoreMedia: boolean) => {
838
  exporting.value = true
839
+
840
+ try {
841
+ // 确保所有元素已渲染
842
+ await ensureElementsRendered();
843
+ } catch (error) {
844
+ console.warn('Failed to ensure elements rendered:', error);
845
+ }
846
+
847
  const pptx = new pptxgen()
848
 
849
  if (viewportRatio.value === 0.625) pptx.layout = 'LAYOUT_16x10'
 
997
  else if (el.type === 'shape') {
998
  if (el.special) {
999
  const svgRef = document.querySelector(`.thumbnail-list .base-element-${el.id} svg`) as HTMLElement
1000
+
1001
+ // 改进的尺寸检查逻辑
1002
+ if (!svgRef) {
1003
+ console.warn(`SVG element not found for shape ${el.id}`);
1004
+ continue;
1005
+ }
1006
+
1007
+ // 获取多种尺寸信息进行判断
1008
+ const clientWidth = svgRef.clientWidth;
1009
+ const clientHeight = svgRef.clientHeight;
1010
+ const boundingRect = svgRef.getBoundingClientRect();
1011
+ const computedStyle = window.getComputedStyle(svgRef);
1012
+
1013
+ // 更智能的尺寸判断
1014
+ const hasValidSize = (
1015
+ (clientWidth > 0 && clientHeight > 0) ||
1016
+ (boundingRect.width > 0 && boundingRect.height > 0) ||
1017
+ (parseFloat(computedStyle.width) > 0 && parseFloat(computedStyle.height) > 0)
1018
+ );
1019
+
1020
+ if (!hasValidSize) {
1021
+ console.warn(`Invalid SVG dimensions for shape ${el.id}:`, {
1022
+ clientWidth,
1023
+ clientHeight,
1024
+ boundingRect: { width: boundingRect.width, height: boundingRect.height },
1025
+ computedStyle: { width: computedStyle.width, height: computedStyle.height }
1026
+ });
1027
+
1028
+ // 降级到普通形状处理
1029
+ console.info(`Falling back to path-based export for shape ${el.id}`);
1030
+ const scale = {
1031
+ x: el.width / el.viewBox[0],
1032
+ y: el.height / el.viewBox[1],
1033
+ };
1034
+ const points = formatPoints(toPoints(el.path), scale);
1035
+
1036
+ let fillColor = formatColor(el.fill);
1037
+ if (el.gradient) {
1038
+ const colors = el.gradient.colors;
1039
+ const color1 = colors[0].color;
1040
+ const color2 = colors[colors.length - 1].color;
1041
+ const color = tinycolor.mix(color1, color2).toHexString();
1042
+ fillColor = formatColor(color);
1043
+ }
1044
+ if (el.pattern) fillColor = formatColor('#00000000');
1045
+ const opacity = el.opacity === undefined ? 1 : el.opacity;
1046
+
1047
+ const fallbackOptions: pptxgen.ShapeProps = {
1048
+ x: el.left / ratioPx2Inch.value,
1049
+ y: el.top / ratioPx2Inch.value,
1050
+ w: el.width / ratioPx2Inch.value,
1051
+ h: el.height / ratioPx2Inch.value,
1052
+ fill: { color: fillColor.color, transparency: (1 - fillColor.alpha * opacity) * 100 },
1053
+ points,
1054
+ };
1055
+
1056
+ if (el.flipH) fallbackOptions.flipH = el.flipH;
1057
+ if (el.flipV) fallbackOptions.flipV = el.flipV;
1058
+ if (el.shadow) fallbackOptions.shadow = getShadowOption(el.shadow);
1059
+ if (el.outline?.width) fallbackOptions.line = getOutlineOption(el.outline);
1060
+ if (el.rotate) fallbackOptions.rotate = el.rotate;
1061
+ if (el.link) {
1062
+ const linkOption = getLinkOption(el.link);
1063
+ if (linkOption) fallbackOptions.hyperlink = linkOption;
1064
+ }
1065
+
1066
+ pptxSlide.addShape('custGeom' as pptxgen.ShapeType, fallbackOptions);
1067
+ continue;
1068
+ }
1069
+
1070
+ // SVG序列化with错误处理
1071
+ let base64SVG;
1072
+ try {
1073
+ base64SVG = svg2Base64(svgRef);
1074
+ if (!base64SVG || base64SVG === 'data:image/svg+xml;base64,') {
1075
+ throw new Error('SVG serialization returned empty result');
1076
+ }
1077
+ } catch (error) {
1078
+ console.error(`SVG serialization failed for shape ${el.id}:`, error);
1079
+ continue;
1080
+ }
1081
 
1082
  const options: pptxgen.ImageProps = {
1083
  data: base64SVG,