|
@@ -1,740 +0,0 @@
|
|
-<template>
|
|
|
|
- <div class="test-container">
|
|
|
|
- <div class="test-header">
|
|
|
|
- <h3>Word文档转换测试</h3>
|
|
|
|
- <div class="upload-section">
|
|
|
|
- <input type="file" @change="handleFileUpload" accept=".docx,.doc" />
|
|
|
|
- <div class="quick-actions" v-if="htmlContent">
|
|
|
|
- <button @click="directToPdf" class="action-btn">直接转为PDF并下载</button>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <div class="convert-type">
|
|
|
|
- <label>
|
|
|
|
- <input type="radio" v-model="convertType" value="html" /> HTML
|
|
|
|
- </label>
|
|
|
|
- <label>
|
|
|
|
- <input type="radio" v-model="convertType" value="image" /> Image
|
|
|
|
- </label>
|
|
|
|
- <label>
|
|
|
|
- <input type="radio" v-model="convertType" value="pdf" /> PDF
|
|
|
|
- </label>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div v-if="loading" class="loading">
|
|
|
|
- <div class="spinner" />
|
|
|
|
- <div v-if="pdfProgress > 0" class="progress">
|
|
|
|
- 转换进度: {{ pdfProgress }}%
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="result-container">
|
|
|
|
- <!-- HTML显示 -->
|
|
|
|
- <div v-if="convertType === 'html'" class="result-section">
|
|
|
|
- <div id="html-container" class="html-result" v-html="htmlContent" />
|
|
|
|
- <div class="actions">
|
|
|
|
- <button @click="copyToClipboard">复制HTML</button>
|
|
|
|
- <button @click="convertHtmlToImage">转为图片</button>
|
|
|
|
- <button @click="convertHtmlToPdf">转为PDF</button>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 图片显示 -->
|
|
|
|
- <div v-if="convertType === 'image'" class="result-section">
|
|
|
|
- <div v-if="imageUrl" class="image-result">
|
|
|
|
- <img :src="imageUrl" alt="转换后的图片" />
|
|
|
|
- </div>
|
|
|
|
- <div v-else class="no-result">请先转换为图片</div>
|
|
|
|
- <div class="actions" v-if="imageUrl">
|
|
|
|
- <button @click="downloadImage">下载图片</button>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- PDF显示 -->
|
|
|
|
- <div v-if="convertType === 'pdf'" class="result-section">
|
|
|
|
- <div v-if="pdfUrl" class="pdf-result">
|
|
|
|
- <iframe :src="pdfUrl" frameborder="0" />
|
|
|
|
- </div>
|
|
|
|
- <div v-else class="no-result">请先转换为PDF</div>
|
|
|
|
- <div class="actions" v-if="pdfUrl">
|
|
|
|
- <button @click="downloadPdf">下载PDF</button>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-</template>
|
|
|
|
-
|
|
|
|
-<script setup lang="ts">
|
|
|
|
-import { ref, onMounted, watch, onUnmounted } from 'vue';
|
|
|
|
-import mammoth from 'mammoth';
|
|
|
|
-import html2canvas from 'html2canvas';
|
|
|
|
-import jsPDF from 'jspdf';
|
|
|
|
-import 'jspdf-autotable';
|
|
|
|
-
|
|
|
|
-defineOptions({
|
|
|
|
- name: 'Test4Page',
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
-const loading = ref<boolean>(false);
|
|
|
|
-const convertType = ref<'html' | 'image' | 'pdf'>('html');
|
|
|
|
-const imageUrl = ref<string>('');
|
|
|
|
-const pdfUrl = ref<string>('');
|
|
|
|
-const pdfBytes = ref<Uint8Array | null>(null);
|
|
|
|
-const pdfDocument = ref<jsPDF | null>(null);
|
|
|
|
-const pdfProgress = ref<number>(0);
|
|
|
|
-const htmlContent = ref<string>('');
|
|
|
|
-const fileData = ref<ArrayBuffer | null>(null);
|
|
|
|
-const fileName = ref<string>('');
|
|
|
|
-
|
|
|
|
-// 监听转换类型变化
|
|
|
|
-watch(convertType, async (newType) => {
|
|
|
|
- if (newType === 'image' && htmlContent.value && !imageUrl.value) {
|
|
|
|
- // 如果切换到图片模式且已有HTML但没有图片,则生成图片
|
|
|
|
- await convertHtmlToImage();
|
|
|
|
- } else if (newType === 'pdf' && htmlContent.value && !pdfUrl.value) {
|
|
|
|
- // 如果切换到PDF模式且已有HTML但没有PDF,则生成PDF
|
|
|
|
- await convertHtmlToPdf();
|
|
|
|
- }
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
-const handleFileUpload = async (event: Event) => {
|
|
|
|
- const input = event.target as HTMLInputElement;
|
|
|
|
- const file = input.files?.[0];
|
|
|
|
-
|
|
|
|
- if (!file) {
|
|
|
|
- alert('请选择文件');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fileName.value = file.name;
|
|
|
|
- pdfUrl.value = '';
|
|
|
|
- pdfBytes.value = null;
|
|
|
|
- htmlContent.value = '';
|
|
|
|
- fileData.value = null;
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- // 读取Word文件
|
|
|
|
- const arrayBuffer = await file.arrayBuffer();
|
|
|
|
- fileData.value = arrayBuffer;
|
|
|
|
-
|
|
|
|
- // 根据当前选择的转换类型进行处理
|
|
|
|
- if (convertType.value === 'html') {
|
|
|
|
- await convertWordToHtml(arrayBuffer);
|
|
|
|
- } else if (convertType.value === 'image') {
|
|
|
|
- alert('请先选择HTML模式进行转换');
|
|
|
|
- convertType.value = 'html';
|
|
|
|
- await convertWordToHtml(arrayBuffer);
|
|
|
|
- } else if (convertType.value === 'pdf') {
|
|
|
|
- // 先转为HTML,再转为PDF
|
|
|
|
- await convertWordToHtml(arrayBuffer);
|
|
|
|
- // 等待DOM更新
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
- await convertHtmlToPdf();
|
|
|
|
- }
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('文件处理失败:', error);
|
|
|
|
- alert('文件处理失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- loading.value = false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// Word转HTML方法
|
|
|
|
-const convertWordToHtml = async (arrayBuffer: ArrayBuffer): Promise<void> => {
|
|
|
|
- try {
|
|
|
|
- loading.value = true;
|
|
|
|
- console.log('开始转换Word到HTML');
|
|
|
|
-
|
|
|
|
- // 使用mammoth转换为HTML
|
|
|
|
- const result = await mammoth.convertToHtml({ arrayBuffer });
|
|
|
|
- htmlContent.value = result.value;
|
|
|
|
-
|
|
|
|
- // 确保转换类型是html
|
|
|
|
- convertType.value = 'html';
|
|
|
|
-
|
|
|
|
- console.log('HTML转换完成');
|
|
|
|
- loading.value = false;
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('HTML转换失败:', error);
|
|
|
|
- alert('HTML转换失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- loading.value = false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// HTML转图片方法
|
|
|
|
-const convertHtmlToImage = async (): Promise<boolean> => {
|
|
|
|
- try {
|
|
|
|
- loading.value = true;
|
|
|
|
-
|
|
|
|
- // 确保HTML已经渲染
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
-
|
|
|
|
- // 必须确保HTML容器是可见的
|
|
|
|
- if (convertType.value !== 'html') {
|
|
|
|
- convertType.value = 'html';
|
|
|
|
- // 再次等待DOM更新
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const container = document.getElementById('html-container') as HTMLElement;
|
|
|
|
- if (!container) {
|
|
|
|
- console.error('找不到HTML容器');
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log('开始转换HTML到图片');
|
|
|
|
-
|
|
|
|
- // 获取原始容器高度和样式
|
|
|
|
- const originalHeight = container.offsetHeight;
|
|
|
|
- const originalScrollHeight = container.scrollHeight;
|
|
|
|
-
|
|
|
|
- console.log(`容器实际高度: ${originalHeight}px, 滚动高度: ${originalScrollHeight}px`);
|
|
|
|
-
|
|
|
|
- // 设置样式(临时)
|
|
|
|
- const originalStyles = {
|
|
|
|
- border: container.style.border,
|
|
|
|
- boxShadow: container.style.boxShadow,
|
|
|
|
- borderRadius: container.style.borderRadius,
|
|
|
|
- margin: container.style.margin,
|
|
|
|
- padding: container.style.padding,
|
|
|
|
- height: container.style.height,
|
|
|
|
- maxHeight: container.style.maxHeight,
|
|
|
|
- overflow: container.style.overflow
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // 修改容器使其显示全部内容,不产生滚动条
|
|
|
|
- container.style.border = 'none';
|
|
|
|
- container.style.boxShadow = 'none';
|
|
|
|
- container.style.borderRadius = '0';
|
|
|
|
- container.style.margin = '0';
|
|
|
|
- container.style.padding = '0';
|
|
|
|
- container.style.height = `${originalScrollHeight}px`; // 关键修改:设置为滚动高度
|
|
|
|
- container.style.maxHeight = 'none'; // 移除最大高度限制
|
|
|
|
- container.style.overflow = 'visible'; // 确保内容不被裁剪
|
|
|
|
-
|
|
|
|
- // 让DOM更新样式
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
-
|
|
|
|
- console.log('修改后容器高度:', container.offsetHeight);
|
|
|
|
-
|
|
|
|
- // 使用html2canvas转换,关键修改:禁用滚动处理
|
|
|
|
- const canvas = await html2canvas(container, {
|
|
|
|
- scale: 2, // 提高清晰度
|
|
|
|
- useCORS: true,
|
|
|
|
- allowTaint: true,
|
|
|
|
- backgroundColor: '#ffffff',
|
|
|
|
- windowHeight: container.scrollHeight, // 使用滚动高度
|
|
|
|
- height: container.scrollHeight, // 设置捕获高度为滚动高度
|
|
|
|
- width: container.offsetWidth,
|
|
|
|
- scrollY: 0, // 禁用滚动捕获
|
|
|
|
- scrollX: 0, // 禁用滚动捕获
|
|
|
|
- logging: true, // 开启日志便于调试
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 恢复容器原始样式
|
|
|
|
- container.style.border = originalStyles.border;
|
|
|
|
- container.style.boxShadow = originalStyles.boxShadow;
|
|
|
|
- container.style.borderRadius = originalStyles.borderRadius;
|
|
|
|
- container.style.margin = originalStyles.margin;
|
|
|
|
- container.style.padding = originalStyles.padding;
|
|
|
|
- container.style.height = originalStyles.height;
|
|
|
|
- container.style.maxHeight = originalStyles.maxHeight;
|
|
|
|
- container.style.overflow = originalStyles.overflow;
|
|
|
|
-
|
|
|
|
- console.log(`Canvas尺寸: ${canvas.width}x${canvas.height}`);
|
|
|
|
-
|
|
|
|
- // 转为图片URL
|
|
|
|
- imageUrl.value = canvas.toDataURL('image/png');
|
|
|
|
-
|
|
|
|
- // 切换到图片模式
|
|
|
|
- convertType.value = 'image';
|
|
|
|
-
|
|
|
|
- console.log('图片转换完成');
|
|
|
|
- loading.value = false;
|
|
|
|
- return true;
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('图片转换失败:', error);
|
|
|
|
- alert('图片转换失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- loading.value = false;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// HTML转PDF方法 - 简化版,不使用分页处理
|
|
|
|
-const convertHtmlToPdf = async (): Promise<boolean> => {
|
|
|
|
- try {
|
|
|
|
- // 重置进度
|
|
|
|
- pdfProgress.value = 0;
|
|
|
|
- loading.value = true;
|
|
|
|
-
|
|
|
|
- // 确保HTML已经渲染
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
-
|
|
|
|
- // 必须确保HTML容器是可见的
|
|
|
|
- if (convertType.value !== 'html') {
|
|
|
|
- convertType.value = 'html';
|
|
|
|
- // 再次等待DOM更新
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const container = document.getElementById('html-container') as HTMLElement;
|
|
|
|
- if (!container) {
|
|
|
|
- console.error('找不到HTML容器');
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log('开始转换HTML到PDF (简化方法)');
|
|
|
|
- pdfProgress.value = 10;
|
|
|
|
-
|
|
|
|
- // 获取原始容器高度和样式
|
|
|
|
- const originalHeight = container.offsetHeight;
|
|
|
|
- const originalScrollHeight = container.scrollHeight;
|
|
|
|
- const originalWidth = container.offsetWidth;
|
|
|
|
-
|
|
|
|
- console.log(`容器实际高度: ${originalHeight}px, 滚动高度: ${originalScrollHeight}px, 宽度: ${originalWidth}px`);
|
|
|
|
-
|
|
|
|
- // 获取样式(临时)
|
|
|
|
- const originalStyles = {
|
|
|
|
- border: container.style.border,
|
|
|
|
- boxShadow: container.style.boxShadow,
|
|
|
|
- borderRadius: container.style.borderRadius,
|
|
|
|
- margin: container.style.margin,
|
|
|
|
- padding: container.style.padding,
|
|
|
|
- height: container.style.height,
|
|
|
|
- maxHeight: container.style.maxHeight,
|
|
|
|
- overflow: container.style.overflow
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // 修改容器使其显示全部内容,不产生滚动条
|
|
|
|
- container.style.border = 'none';
|
|
|
|
- container.style.boxShadow = 'none';
|
|
|
|
- container.style.borderRadius = '0';
|
|
|
|
- container.style.margin = '0';
|
|
|
|
- container.style.padding = '0';
|
|
|
|
- container.style.height = `${originalScrollHeight}px`; // 关键修改:设置为滚动高度
|
|
|
|
- container.style.maxHeight = 'none'; // 移除最大高度限制
|
|
|
|
- container.style.overflow = 'visible'; // 确保内容不被裁剪
|
|
|
|
-
|
|
|
|
- // 让DOM更新样式
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
-
|
|
|
|
- console.log('修改后容器高度:', container.offsetHeight);
|
|
|
|
- pdfProgress.value = 30;
|
|
|
|
-
|
|
|
|
- // 使用html2canvas捕获整个内容为一个大canvas
|
|
|
|
- const canvas = await html2canvas(container, {
|
|
|
|
- scale: 2, // 提高清晰度
|
|
|
|
- useCORS: true,
|
|
|
|
- allowTaint: true,
|
|
|
|
- backgroundColor: '#ffffff',
|
|
|
|
- windowHeight: container.scrollHeight, // 使用滚动高度
|
|
|
|
- height: container.scrollHeight, // 设置捕获高度为滚动高度
|
|
|
|
- width: container.offsetWidth,
|
|
|
|
- scrollY: 0, // 禁用滚动捕获
|
|
|
|
- scrollX: 0, // 禁用滚动捕获
|
|
|
|
- logging: true, // 开启日志便于调试
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- console.log(`Canvas尺寸: ${canvas.width}x${canvas.height}`);
|
|
|
|
- pdfProgress.value = 70;
|
|
|
|
-
|
|
|
|
- // 恢复容器原始样式
|
|
|
|
- container.style.border = originalStyles.border;
|
|
|
|
- container.style.boxShadow = originalStyles.boxShadow;
|
|
|
|
- container.style.borderRadius = originalStyles.borderRadius;
|
|
|
|
- container.style.margin = originalStyles.margin;
|
|
|
|
- container.style.padding = originalStyles.padding;
|
|
|
|
- container.style.height = originalStyles.height;
|
|
|
|
- container.style.maxHeight = originalStyles.maxHeight;
|
|
|
|
- container.style.overflow = originalStyles.overflow;
|
|
|
|
-
|
|
|
|
- // 创建PDF实例 - 使用自定义大小以适应内容
|
|
|
|
- const imgWidth = 550; // A4宽度左右,减去边距
|
|
|
|
- const imgHeight = canvas.height * imgWidth / canvas.width;
|
|
|
|
-
|
|
|
|
- // 创建合适尺寸的PDF
|
|
|
|
- const pdf = new jsPDF({
|
|
|
|
- orientation: imgHeight > imgWidth ? 'portrait' : 'landscape',
|
|
|
|
- unit: 'pt',
|
|
|
|
- format: [imgWidth + 40, imgHeight + 40] // 添加边距
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 存储PDF引用
|
|
|
|
- pdfDocument.value = pdf;
|
|
|
|
-
|
|
|
|
- // 将canvas添加到PDF
|
|
|
|
- pdf.addImage(
|
|
|
|
- canvas.toDataURL('image/jpeg', 0.95),
|
|
|
|
- 'JPEG',
|
|
|
|
- 20, // 左边距
|
|
|
|
- 20, // 上边距
|
|
|
|
- imgWidth,
|
|
|
|
- imgHeight
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- pdfProgress.value = 90;
|
|
|
|
- console.log('PDF页面生成完成');
|
|
|
|
-
|
|
|
|
- // 保存PDF (两种方式)
|
|
|
|
- try {
|
|
|
|
- // 方式1: 使用Blob URL (用于预览)
|
|
|
|
- const pdfOutput = pdf.output('blob');
|
|
|
|
- pdfUrl.value = URL.createObjectURL(pdfOutput);
|
|
|
|
- console.log('PDF Blob URL创建成功:', pdfUrl.value);
|
|
|
|
-
|
|
|
|
- // 方式2: 保存PDF字节 (用于直接下载)
|
|
|
|
- const pdfData = pdf.output('arraybuffer');
|
|
|
|
- pdfBytes.value = new Uint8Array(pdfData);
|
|
|
|
- console.log('PDF字节数据创建成功, 大小:', pdfBytes.value.length);
|
|
|
|
-
|
|
|
|
- // 转换为PDF模式
|
|
|
|
- convertType.value = 'pdf';
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('创建PDF URL失败:', error);
|
|
|
|
- alert('创建PDF URL失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log('PDF生成完成');
|
|
|
|
- pdfProgress.value = 100;
|
|
|
|
-
|
|
|
|
- loading.value = false;
|
|
|
|
- pdfProgress.value = 0; // 清除进度
|
|
|
|
- return true;
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('PDF转换失败:', error);
|
|
|
|
- alert('PDF转换失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- loading.value = false;
|
|
|
|
- pdfProgress.value = 0; // 清除进度
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// 下载PDF
|
|
|
|
-const downloadPdf = () => {
|
|
|
|
- console.log('开始下载PDF...');
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- // 方法1: 使用存储的PDF文档直接保存 (优先)
|
|
|
|
- if (pdfDocument.value) {
|
|
|
|
- const outputFilename = (fileName.value ? fileName.value.replace(/\.[^/.]+$/, '') : 'document') + '.pdf';
|
|
|
|
- console.log('使用jsPDF直接保存文件:', outputFilename);
|
|
|
|
- pdfDocument.value.save(outputFilename);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 方法2: 使用Blob URL (如果pdfDocument不可用)
|
|
|
|
- if (pdfUrl.value) {
|
|
|
|
- console.log('使用Blob URL下载PDF:', pdfUrl.value);
|
|
|
|
- const link = document.createElement('a');
|
|
|
|
- link.href = pdfUrl.value;
|
|
|
|
- link.download = (fileName.value ? fileName.value.replace(/\.[^/.]+$/, '') : 'document') + '.pdf';
|
|
|
|
- document.body.appendChild(link);
|
|
|
|
- link.click();
|
|
|
|
- document.body.removeChild(link);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 没有可用的PDF数据
|
|
|
|
- console.error('没有PDF可下载');
|
|
|
|
- alert('没有PDF可下载');
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('PDF下载失败:', error);
|
|
|
|
- alert('PDF下载失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// 下载图片
|
|
|
|
-const downloadImage = () => {
|
|
|
|
- if (!imageUrl.value) {
|
|
|
|
- alert('没有图片可下载');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const link = document.createElement('a');
|
|
|
|
- link.href = imageUrl.value;
|
|
|
|
- link.download = (fileName.value ? fileName.value.replace(/\.[^/.]+$/, '') : 'document') + '.png';
|
|
|
|
- document.body.appendChild(link);
|
|
|
|
- link.click();
|
|
|
|
- document.body.removeChild(link);
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// 一键转为PDF
|
|
|
|
-const directToPdf = async () => {
|
|
|
|
- try {
|
|
|
|
- loading.value = true;
|
|
|
|
- console.log('一键转换文档为PDF');
|
|
|
|
-
|
|
|
|
- // 如果当前已经是HTML模式并且有HTML内容,直接转PDF
|
|
|
|
- if (convertType.value === 'html' && htmlContent.value) {
|
|
|
|
- console.log('直接从HTML转为PDF');
|
|
|
|
- const success = await convertHtmlToPdf();
|
|
|
|
-
|
|
|
|
- if (success) {
|
|
|
|
- // 等待PDF生成完成后下载
|
|
|
|
- console.log('HTML转PDF成功,准备下载');
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
- downloadPdf();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- loading.value = false;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 否则,先转为HTML,再转为PDF
|
|
|
|
- if (fileData.value) {
|
|
|
|
- console.log('从Word文档转为HTML,再转为PDF');
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- // 转换为HTML
|
|
|
|
- const result = await mammoth.convertToHtml({ arrayBuffer: fileData.value });
|
|
|
|
- htmlContent.value = result.value;
|
|
|
|
- convertType.value = 'html';
|
|
|
|
-
|
|
|
|
- // 等待DOM更新
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
-
|
|
|
|
- // 然后转为PDF
|
|
|
|
- const success = await convertHtmlToPdf();
|
|
|
|
-
|
|
|
|
- if (success) {
|
|
|
|
- // 等待PDF生成完成后下载
|
|
|
|
- console.log('HTML转PDF成功,准备下载');
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
- downloadPdf();
|
|
|
|
- }
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('文档转换过程中出错:', error);
|
|
|
|
- alert('文档转换失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- alert('请先上传Word文档');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- loading.value = false;
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('一键转PDF失败:', error);
|
|
|
|
- alert('一键转PDF失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
|
|
|
- loading.value = false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// HTML相关方法
|
|
|
|
-const copyToClipboard = async () => {
|
|
|
|
- if (!htmlContent.value) {
|
|
|
|
- alert('没有HTML内容可复制');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- await navigator.clipboard.writeText(htmlContent.value);
|
|
|
|
- alert('已复制到剪贴板');
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('复制失败:', error);
|
|
|
|
- alert('复制失败');
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-onMounted(() => {
|
|
|
|
- console.log('Test4Page mounted');
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
-// 在组件销毁时清理资源
|
|
|
|
-onUnmounted(() => {
|
|
|
|
- console.log('Test4Page unmounted, 清理资源');
|
|
|
|
-
|
|
|
|
- // 清理Blob URL
|
|
|
|
- if (pdfUrl.value) {
|
|
|
|
- try {
|
|
|
|
- URL.revokeObjectURL(pdfUrl.value);
|
|
|
|
- console.log('已清理PDF Blob URL');
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('清理PDF Blob URL失败:', error);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (imageUrl.value) {
|
|
|
|
- try {
|
|
|
|
- URL.revokeObjectURL(imageUrl.value);
|
|
|
|
- console.log('已清理图片Blob URL');
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('清理图片Blob URL失败:', error);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 清理其他引用
|
|
|
|
- pdfDocument.value = null;
|
|
|
|
- pdfBytes.value = null;
|
|
|
|
- htmlContent.value = '';
|
|
|
|
- fileData.value = null;
|
|
|
|
-});
|
|
|
|
-</script>
|
|
|
|
-
|
|
|
|
-<style scoped lang="scss">
|
|
|
|
-.test-container {
|
|
|
|
- max-width: 800px;
|
|
|
|
- margin: 0 auto;
|
|
|
|
- padding: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.test-header {
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.upload-section {
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.convert-type {
|
|
|
|
- margin-top: 10px;
|
|
|
|
- display: flex;
|
|
|
|
- gap: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.loading {
|
|
|
|
- margin-top: 10px;
|
|
|
|
- color: #666;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.result-container {
|
|
|
|
- margin-top: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.result-section {
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
- border-top: 1px solid #eee;
|
|
|
|
- padding-top: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-h4 {
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
- color: #333;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.html-result {
|
|
|
|
- padding: 15px;
|
|
|
|
- border: 1px solid #eee;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- background-color: #fff;
|
|
|
|
- min-height: 200px;
|
|
|
|
- overflow: visible;
|
|
|
|
- width: 100%;
|
|
|
|
- box-sizing: border-box;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.image-container, .pdf-container {
|
|
|
|
- border: 1px solid #ddd;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- background-color: #f9f9f9;
|
|
|
|
- min-height: 200px;
|
|
|
|
- overflow: hidden;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.actions {
|
|
|
|
- margin-top: 15px;
|
|
|
|
- text-align: right;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.download-btn {
|
|
|
|
- padding: 8px 16px;
|
|
|
|
- background-color: #4CAF50;
|
|
|
|
- color: white;
|
|
|
|
- border: none;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- cursor: pointer;
|
|
|
|
- font-size: 14px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.download-btn:hover {
|
|
|
|
- background-color: #45a049;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.action-buttons {
|
|
|
|
- margin-top: 20px;
|
|
|
|
- text-align: right;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.convert-btn {
|
|
|
|
- padding: 8px 16px;
|
|
|
|
- background-color: #4CAF50;
|
|
|
|
- color: white;
|
|
|
|
- border: none;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- cursor: pointer;
|
|
|
|
- font-size: 14px;
|
|
|
|
- margin-left: 10px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.convert-btn:hover {
|
|
|
|
- background-color: #45a049;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.quick-actions {
|
|
|
|
- margin-top: 10px;
|
|
|
|
- text-align: right;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.action-btn {
|
|
|
|
- padding: 8px 16px;
|
|
|
|
- background-color: #4CAF50;
|
|
|
|
- color: white;
|
|
|
|
- border: none;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- cursor: pointer;
|
|
|
|
- font-size: 14px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.action-btn:hover {
|
|
|
|
- background-color: #45a049;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.image-result {
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
- width: 100%;
|
|
|
|
- overflow: auto;
|
|
|
|
-
|
|
|
|
- img {
|
|
|
|
- max-width: 100%;
|
|
|
|
- display: block;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.no-result {
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
- color: #666;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.pdf-result {
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
- width: 100%;
|
|
|
|
- height: 600px;
|
|
|
|
-
|
|
|
|
- iframe {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
- border: 1px solid #eee;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.spinner {
|
|
|
|
- border: 4px solid rgba(0, 0, 0, 0.1);
|
|
|
|
- border-left-color: #4CAF50;
|
|
|
|
- border-radius: 50%;
|
|
|
|
- width: 30px;
|
|
|
|
- height: 30px;
|
|
|
|
- animation: spin 1s linear infinite;
|
|
|
|
- margin: 0 auto;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-@keyframes spin {
|
|
|
|
- 0% {
|
|
|
|
- transform: rotate(0deg);
|
|
|
|
- }
|
|
|
|
- 100% {
|
|
|
|
- transform: rotate(360deg);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.progress {
|
|
|
|
- margin-top: 10px;
|
|
|
|
- color: #666;
|
|
|
|
-}
|
|
|
|
-</style>
|
|
|