|
|
@@ -11,8 +11,8 @@ import useSlideHandler from '@/hooks/useSlideHandler'
|
|
|
import useHistorySnapshot from './useHistorySnapshot'
|
|
|
import message from '@/utils/message'
|
|
|
import { getSvgPathRange } from '@/utils/svgPathParser'
|
|
|
-import { EMFJS, WMFJS } from 'rtf.js';
|
|
|
-import * as UTIF from 'utif2';
|
|
|
+import { EMFJS, WMFJS } from 'rtf.js'
|
|
|
+import * as UTIF from 'utif2'
|
|
|
|
|
|
import type {
|
|
|
Slide,
|
|
|
@@ -32,7 +32,9 @@ import type {
|
|
|
} from '@/types/slides'
|
|
|
|
|
|
const convertFontSizePtToPx = (html: string, ratio: number, autoFit: any) => {
|
|
|
- if (autoFit?.fontScale && autoFit?.type == "text") { ratio = ratio * autoFit.fontScale / 100; }
|
|
|
+ if (autoFit?.fontScale && autoFit?.type == 'text') {
|
|
|
+ ratio = ratio * autoFit.fontScale / 100
|
|
|
+ }
|
|
|
// return html;
|
|
|
return html.replace(/\s*([\d.]+)pt/g, (match, p1) => {
|
|
|
return `${Math.round(parseFloat(p1) * ratio)}px `
|
|
|
@@ -64,6 +66,7 @@ export default () => {
|
|
|
const { isEmptySlide } = useSlideHandler()
|
|
|
|
|
|
const exporting = ref(false)
|
|
|
+ const imgExporting = ref(false)
|
|
|
|
|
|
// 导入JSON文件
|
|
|
const importJSON = (files: FileList, cover = false) => {
|
|
|
@@ -224,6 +227,7 @@ export default () => {
|
|
|
const win = window as any
|
|
|
if (!win.exportJSON) win.exportJSON = exportJSON2
|
|
|
if (!win.readJSON) win.readJSON = readJSON
|
|
|
+ if (!win.imgExporting) win.imgExporting = () => imgExporting.value
|
|
|
}
|
|
|
|
|
|
// 导入pptist文件
|
|
|
@@ -737,108 +741,113 @@ export default () => {
|
|
|
filename: string,
|
|
|
options?: { tolerance?: number }
|
|
|
): Promise<File> => {
|
|
|
- const tolerance = options?.tolerance ?? 15;
|
|
|
+ const tolerance = options?.tolerance ?? 15
|
|
|
|
|
|
// 1. 统一输入为 Blob 和 MIME
|
|
|
- const { blob, mime } = await getBlobAndMime(data);
|
|
|
- const format = getFormat(mime, filename);
|
|
|
+ const { blob, mime } = await getBlobAndMime(data)
|
|
|
+ const format = getFormat(mime, filename)
|
|
|
|
|
|
// 2. 浏览器原生支持的格式直接返回
|
|
|
if (format === 'browser') {
|
|
|
- return new File([blob], filename, { type: mime });
|
|
|
+ return new File([blob], filename, { type: mime })
|
|
|
}
|
|
|
|
|
|
// 3. 需要转换成 PNG 的格式
|
|
|
- let pngBlob: Blob;
|
|
|
+ let pngBlob: Blob
|
|
|
if (format === 'tiff') {
|
|
|
- pngBlob = await convertTiffToPng(blob);
|
|
|
- } else if (format === 'emf') {
|
|
|
- pngBlob = await convertEmfToPng(blob);
|
|
|
- } else if (format === 'wmf') {
|
|
|
- pngBlob = await convertWmfToPng(blob);
|
|
|
- } else {
|
|
|
+ pngBlob = await convertTiffToPng(blob)
|
|
|
+ }
|
|
|
+ else if (format === 'emf') {
|
|
|
+ pngBlob = await convertEmfToPng(blob)
|
|
|
+ }
|
|
|
+ else if (format === 'wmf') {
|
|
|
+ pngBlob = await convertWmfToPng(blob)
|
|
|
+ }
|
|
|
+ else {
|
|
|
// format === 'png' 的情况
|
|
|
- pngBlob = blob;
|
|
|
+ pngBlob = blob
|
|
|
}
|
|
|
|
|
|
// --- 新增:检测 PNG 是否已经包含透明背景 ---
|
|
|
- let alreadyTransparent = false;
|
|
|
+ let alreadyTransparent = false
|
|
|
// 无论原始格式是 PNG 还是转换后得到的 PNG,都进行检测
|
|
|
- const checkUrl = URL.createObjectURL(pngBlob);
|
|
|
+ const checkUrl = URL.createObjectURL(pngBlob)
|
|
|
try {
|
|
|
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
|
- const image = new Image();
|
|
|
- image.onload = () => resolve(image);
|
|
|
- image.onerror = reject;
|
|
|
- image.src = checkUrl;
|
|
|
- });
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
- canvas.width = img.width;
|
|
|
- canvas.height = img.height;
|
|
|
- const ctx = canvas.getContext('2d')!;
|
|
|
- ctx.drawImage(img, 0, 0);
|
|
|
- alreadyTransparent = hasTransparency(img, ctx);
|
|
|
- } finally {
|
|
|
- URL.revokeObjectURL(checkUrl);
|
|
|
+ const image = new Image()
|
|
|
+ image.onload = () => resolve(image)
|
|
|
+ image.onerror = reject
|
|
|
+ image.src = checkUrl
|
|
|
+ })
|
|
|
+ const canvas = document.createElement('canvas')
|
|
|
+ canvas.width = img.width
|
|
|
+ canvas.height = img.height
|
|
|
+ const ctx = canvas.getContext('2d')!
|
|
|
+ ctx.drawImage(img, 0, 0)
|
|
|
+ alreadyTransparent = hasTransparency(img, ctx)
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ URL.revokeObjectURL(checkUrl)
|
|
|
}
|
|
|
|
|
|
- let transparentPngBlob: Blob;
|
|
|
- transparentPngBlob = pngBlob;
|
|
|
+ let transparentPngBlob: Blob
|
|
|
+ transparentPngBlob = pngBlob
|
|
|
/*
|
|
|
if (alreadyTransparent) {
|
|
|
// 图片已有透明背景,直接使用原 PNG Blob
|
|
|
- console.log('检测到透明背景,跳过白色变透明处理');
|
|
|
- transparentPngBlob = pngBlob;
|
|
|
- } else {
|
|
|
+ console.log('检测到透明背景,跳过白色变透明处理')
|
|
|
+ transparentPngBlob = pngBlob
|
|
|
+ }
|
|
|
+ else {
|
|
|
// 否则执行白色变透明处理
|
|
|
- transparentPngBlob = await makeWhiteTransparentFromPng(pngBlob, tolerance);
|
|
|
+ transparentPngBlob = await makeWhiteTransparentFromPng(pngBlob, tolerance)
|
|
|
}
|
|
|
*/
|
|
|
- const finalFilename = format === 'png' ? filename : filename.replace(/\.[^.]*$/, '') + '.png';
|
|
|
- return new File([transparentPngBlob], finalFilename, { type: 'image/png' });
|
|
|
- };
|
|
|
+ const finalFilename = format === 'png' ? filename : filename.replace(/\.[^.]*$/, '') + '.png'
|
|
|
+ return new File([transparentPngBlob], finalFilename, { type: 'image/png' })
|
|
|
+ }
|
|
|
|
|
|
|
|
|
// ================== 辅助函数 ==================
|
|
|
|
|
|
async function getBlobAndMime(input: string | Blob): Promise<{ blob: Blob; mime: string }> {
|
|
|
- if (input instanceof Blob) return { blob: input, mime: input.type };
|
|
|
+ if (input instanceof Blob) return { blob: input, mime: input.type }
|
|
|
if (input.startsWith('data:') || input.startsWith('blob:')) {
|
|
|
- const res = await fetch(input);
|
|
|
- const blob = await res.blob();
|
|
|
- return { blob, mime: blob.type };
|
|
|
+ const res = await fetch(input)
|
|
|
+ const blob = await res.blob()
|
|
|
+ return { blob, mime: blob.type }
|
|
|
}
|
|
|
- const binary = atob(input);
|
|
|
- const bytes = new Uint8Array(binary.length);
|
|
|
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
|
- const blob = new Blob([bytes], { type: 'image/png' });
|
|
|
- return { blob, mime: 'image/png' };
|
|
|
+ const binary = atob(input)
|
|
|
+ const bytes = new Uint8Array(binary.length)
|
|
|
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
|
|
|
+ const blob = new Blob([bytes], { type: 'image/png' })
|
|
|
+ return { blob, mime: 'image/png' }
|
|
|
}
|
|
|
|
|
|
function getFormat(mime: string, filename: string): string {
|
|
|
- const ext = filename.split('.').pop()?.toLowerCase();
|
|
|
- if (mime === 'image/png') return 'png';
|
|
|
- if (mime === 'image/tiff' || mime === 'image/x-tiff' || ext === 'tiff' || ext === 'tif') return 'tiff';
|
|
|
- if (mime === 'image/x-emf' || mime === 'application/x-emf' || ext === 'emf') return 'emf';
|
|
|
- if (mime === 'image/x-wmf' || mime === 'application/x-wmf' || ext === 'wmf') return 'wmf';
|
|
|
- return 'browser';
|
|
|
+ const ext = filename.split('.').pop()?.toLowerCase()
|
|
|
+ if (mime === 'image/png') return 'png'
|
|
|
+ if (mime === 'image/tiff' || mime === 'image/x-tiff' || ext === 'tiff' || ext === 'tif') return 'tiff'
|
|
|
+ if (mime === 'image/x-emf' || mime === 'application/x-emf' || ext === 'emf') return 'emf'
|
|
|
+ if (mime === 'image/x-wmf' || mime === 'application/x-wmf' || ext === 'wmf') return 'wmf'
|
|
|
+ return 'browser'
|
|
|
}
|
|
|
|
|
|
// TIFF 转 PNG(使用 UTIF.js)
|
|
|
async function convertTiffToPng(blob: Blob): Promise<Blob> {
|
|
|
- const arrayBuffer = await blob.arrayBuffer();
|
|
|
- const ifds = UTIF.decode(arrayBuffer);
|
|
|
- if (!ifds || ifds.length === 0) throw new Error('No TIFF image found');
|
|
|
- UTIF.decodeImage(arrayBuffer, ifds[0]);
|
|
|
- const rgba = UTIF.toRGBA8(ifds[0]);
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
- canvas.width = ifds[0].width;
|
|
|
- canvas.height = ifds[0].height;
|
|
|
- const ctx = canvas.getContext('2d')!;
|
|
|
- ctx.putImageData(new ImageData(rgba, ifds[0].width, ifds[0].height), 0, 0);
|
|
|
+ const arrayBuffer = await blob.arrayBuffer()
|
|
|
+ const ifds = UTIF.decode(arrayBuffer)
|
|
|
+ if (!ifds || ifds.length === 0) throw new Error('No TIFF image found')
|
|
|
+ UTIF.decodeImage(arrayBuffer, ifds[0])
|
|
|
+ const rgba = UTIF.toRGBA8(ifds[0])
|
|
|
+ const canvas = document.createElement('canvas')
|
|
|
+ canvas.width = ifds[0].width
|
|
|
+ canvas.height = ifds[0].height
|
|
|
+ const ctx = canvas.getContext('2d')!
|
|
|
+ ctx.putImageData(new ImageData(rgba, ifds[0].width, ifds[0].height), 0, 0)
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('TIFF to PNG failed'))), 'image/png');
|
|
|
- });
|
|
|
+ canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('TIFF to PNG failed'))), 'image/png')
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
// 通用函数:将 EMF/WMF 通过 Renderer 转换为 PNG
|
|
|
@@ -848,10 +857,10 @@ export default () => {
|
|
|
RendererClass: any // new (data: ArrayBuffer) => { render(settings: any): SVGElement }
|
|
|
): Promise<Blob> {
|
|
|
// 1. 创建 Renderer 实例
|
|
|
- const renderer = new RendererClass(arrayBuffer);
|
|
|
+ const renderer = new RendererClass(arrayBuffer)
|
|
|
|
|
|
// 2. 先尝试获取图片的真实尺寸(通过临时渲染并解析 SVG 的 viewBox)
|
|
|
- let width = 800, height = 600; // 默认值
|
|
|
+ let width = 800, height = 600 // 默认值
|
|
|
try {
|
|
|
// 使用一个较大的临时尺寸进行第一次渲染,以获取 SVG 的 viewBox
|
|
|
const tempSettings = {
|
|
|
@@ -860,26 +869,28 @@ export default () => {
|
|
|
xExt: 1000,
|
|
|
yExt: 1000,
|
|
|
mapMode: 8, // 保持宽高比
|
|
|
- };
|
|
|
- const tempSvg = renderer.render(tempSettings);
|
|
|
- const viewBox = tempSvg.getAttribute('viewBox');
|
|
|
+ }
|
|
|
+ const tempSvg = renderer.render(tempSettings)
|
|
|
+ const viewBox = tempSvg.getAttribute('viewBox')
|
|
|
if (viewBox) {
|
|
|
- const parts = viewBox.split(/[\s,]+/);
|
|
|
+ const parts = viewBox.split(/[\s,]+/)
|
|
|
if (parts.length >= 4) {
|
|
|
- width = parseFloat(parts[2]);
|
|
|
- height = parseFloat(parts[3]);
|
|
|
+ width = parseFloat(parts[2])
|
|
|
+ height = parseFloat(parts[3])
|
|
|
}
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ else {
|
|
|
// 尝试从 width/height 属性获取
|
|
|
- const svgWidth = tempSvg.getAttribute('width');
|
|
|
- const svgHeight = tempSvg.getAttribute('height');
|
|
|
+ const svgWidth = tempSvg.getAttribute('width')
|
|
|
+ const svgHeight = tempSvg.getAttribute('height')
|
|
|
if (svgWidth && svgHeight) {
|
|
|
- width = parseFloat(svgWidth);
|
|
|
- height = parseFloat(svgHeight);
|
|
|
+ width = parseFloat(svgWidth)
|
|
|
+ height = parseFloat(svgHeight)
|
|
|
}
|
|
|
}
|
|
|
- } catch (e) {
|
|
|
- console.warn('Failed to get dimensions from SVG, using default', e);
|
|
|
+ }
|
|
|
+ catch (e) {
|
|
|
+ console.warn('Failed to get dimensions from SVG, using default', e)
|
|
|
}
|
|
|
|
|
|
// 3. 使用实际尺寸重新渲染
|
|
|
@@ -889,97 +900,99 @@ export default () => {
|
|
|
xExt: width,
|
|
|
yExt: height,
|
|
|
mapMode: 8, // 保持宽高比
|
|
|
- };
|
|
|
- const svg = renderer.render(settings);
|
|
|
+ }
|
|
|
+ const svg = renderer.render(settings)
|
|
|
|
|
|
// 4. 将 SVG 转为 data URL 并用 Image 加载
|
|
|
- const serializer = new XMLSerializer();
|
|
|
- let svgString = serializer.serializeToString(svg);
|
|
|
+ const serializer = new XMLSerializer()
|
|
|
+ let svgString = serializer.serializeToString(svg)
|
|
|
// 确保有命名空间
|
|
|
if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {
|
|
|
- svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');
|
|
|
+ svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"')
|
|
|
}
|
|
|
- const blob = new Blob([svgString], { type: 'image/svg+xml' });
|
|
|
- const url = URL.createObjectURL(blob);
|
|
|
+ const blob = new Blob([svgString], { type: 'image/svg+xml' })
|
|
|
+ const url = URL.createObjectURL(blob)
|
|
|
try {
|
|
|
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
|
- const image = new Image();
|
|
|
- image.onload = () => resolve(image);
|
|
|
- image.onerror = reject;
|
|
|
- image.src = url;
|
|
|
- });
|
|
|
+ const image = new Image()
|
|
|
+ image.onload = () => resolve(image)
|
|
|
+ image.onerror = reject
|
|
|
+ image.src = url
|
|
|
+ })
|
|
|
// 5. 绘制到 canvas
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
- canvas.width = img.width;
|
|
|
- canvas.height = img.height;
|
|
|
- const ctx = canvas.getContext('2d')!;
|
|
|
- ctx.drawImage(img, 0, 0);
|
|
|
+ const canvas = document.createElement('canvas')
|
|
|
+ canvas.width = img.width
|
|
|
+ canvas.height = img.height
|
|
|
+ const ctx = canvas.getContext('2d')!
|
|
|
+ ctx.drawImage(img, 0, 0)
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('Metafile to PNG failed'))), 'image/png');
|
|
|
- });
|
|
|
- } finally {
|
|
|
- URL.revokeObjectURL(url);
|
|
|
+ canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('Metafile to PNG failed'))), 'image/png')
|
|
|
+ })
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ URL.revokeObjectURL(url)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// EMF 转 PNG(使用 EMFJS.Renderer)
|
|
|
async function convertEmfToPng(blob: Blob): Promise<Blob> {
|
|
|
- const arrayBuffer = await blob.arrayBuffer();
|
|
|
- return convertMetafileToPng(arrayBuffer, EMFJS.Renderer);
|
|
|
+ const arrayBuffer = await blob.arrayBuffer()
|
|
|
+ return convertMetafileToPng(arrayBuffer, EMFJS.Renderer)
|
|
|
}
|
|
|
|
|
|
// WMF 转 PNG(使用 WMFJS.Renderer)
|
|
|
async function convertWmfToPng(blob: Blob): Promise<Blob> {
|
|
|
- const arrayBuffer = await blob.arrayBuffer();
|
|
|
- return convertMetafileToPng(arrayBuffer, WMFJS.Renderer);
|
|
|
+ const arrayBuffer = await blob.arrayBuffer()
|
|
|
+ return convertMetafileToPng(arrayBuffer, WMFJS.Renderer)
|
|
|
}
|
|
|
|
|
|
function hasTransparency(img: HTMLImageElement, ctx: CanvasRenderingContext2D): boolean {
|
|
|
- const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
|
|
- const data = imageData.data;
|
|
|
+ const imageData = ctx.getImageData(0, 0, img.width, img.height)
|
|
|
+ const data = imageData.data
|
|
|
// 遍历 Alpha 通道(索引 3)
|
|
|
for (let i = 3; i < data.length; i += 4) {
|
|
|
if (data[i] < 255) {
|
|
|
- return true; // 发现任意一个像素不是完全不透明
|
|
|
+ return true // 发现任意一个像素不是完全不透明
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
+ return false
|
|
|
}
|
|
|
|
|
|
// 对 PNG 执行白色变透明
|
|
|
async function makeWhiteTransparentFromPng(pngBlob: Blob, tolerance: number): Promise<Blob> {
|
|
|
- const url = URL.createObjectURL(pngBlob);
|
|
|
+ const url = URL.createObjectURL(pngBlob)
|
|
|
try {
|
|
|
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
|
- const image = new Image();
|
|
|
- image.onload = () => resolve(image);
|
|
|
- image.onerror = reject;
|
|
|
- image.src = url;
|
|
|
- });
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
- canvas.width = img.width;
|
|
|
- canvas.height = img.height;
|
|
|
- const ctx = canvas.getContext('2d')!;
|
|
|
- ctx.drawImage(img, 0, 0);
|
|
|
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
|
- const data = imageData.data;
|
|
|
+ const image = new Image()
|
|
|
+ image.onload = () => resolve(image)
|
|
|
+ image.onerror = reject
|
|
|
+ image.src = url
|
|
|
+ })
|
|
|
+ const canvas = document.createElement('canvas')
|
|
|
+ canvas.width = img.width
|
|
|
+ canvas.height = img.height
|
|
|
+ const ctx = canvas.getContext('2d')!
|
|
|
+ ctx.drawImage(img, 0, 0)
|
|
|
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
|
+ const data = imageData.data
|
|
|
for (let i = 0; i < data.length; i += 4) {
|
|
|
- const r = data[i];
|
|
|
- const g = data[i + 1];
|
|
|
- const b = data[i + 2];
|
|
|
- const dr = r - 255;
|
|
|
- const dg = g - 255;
|
|
|
- const db = b - 255;
|
|
|
+ const r = data[i]
|
|
|
+ const g = data[i + 1]
|
|
|
+ const b = data[i + 2]
|
|
|
+ const dr = r - 255
|
|
|
+ const dg = g - 255
|
|
|
+ const db = b - 255
|
|
|
if (Math.sqrt(dr * dr + dg * dg + db * db) <= tolerance) {
|
|
|
- data[i + 3] = 0;
|
|
|
+ data[i + 3] = 0
|
|
|
}
|
|
|
}
|
|
|
- ctx.putImageData(imageData, 0, 0);
|
|
|
+ ctx.putImageData(imageData, 0, 0)
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('Canvas toBlob failed'))), 'image/png');
|
|
|
- });
|
|
|
- } finally {
|
|
|
- URL.revokeObjectURL(url);
|
|
|
+ canvas.toBlob(blob => (blob ? resolve(blob) : reject(new Error('Canvas toBlob failed'))), 'image/png')
|
|
|
+ })
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ URL.revokeObjectURL(url)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1585,6 +1598,7 @@ export default () => {
|
|
|
if (!file) return
|
|
|
|
|
|
exporting.value = true // 假设 exporting 是一个全局 ref
|
|
|
+ imgExporting.value = true // 假设 imgExporting 是一个全局 ref
|
|
|
|
|
|
// 预加载形状库(用于后续形状匹配)
|
|
|
const shapeList: ShapePoolItem[] = []
|
|
|
@@ -1597,6 +1611,7 @@ export default () => {
|
|
|
// 检查是否已取消
|
|
|
if (signal?.aborted) {
|
|
|
exporting.value = false
|
|
|
+ imgExporting.value = false
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -1606,6 +1621,7 @@ export default () => {
|
|
|
}
|
|
|
catch (error) {
|
|
|
exporting.value = false
|
|
|
+ imgExporting.value = false
|
|
|
console.log('导入PPTX文件失败:', error)
|
|
|
message.error(lang.ssFileReadFail)
|
|
|
return
|
|
|
@@ -1613,6 +1629,7 @@ export default () => {
|
|
|
|
|
|
if (signal?.aborted) {
|
|
|
exporting.value = false
|
|
|
+ imgExporting.value = false
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -2265,7 +2282,11 @@ export default () => {
|
|
|
|
|
|
// 等待当前幻灯片内所有上传任务完成
|
|
|
// await Promise.all(uploadTasks)
|
|
|
- Promise.all(uploadTasks)
|
|
|
+ Promise.all(uploadTasks).then(() => {
|
|
|
+ imgExporting.value = false
|
|
|
+ }).catch(() => {
|
|
|
+ imgExporting.value = false
|
|
|
+ })
|
|
|
|
|
|
exporting.value = false
|
|
|
onclose?.()
|
|
|
@@ -2414,6 +2435,7 @@ export default () => {
|
|
|
readJSON,
|
|
|
exportJSON2,
|
|
|
exporting,
|
|
|
+ imgExporting,
|
|
|
getFile,
|
|
|
getFile2,
|
|
|
dataToFile,
|