浏览代码

更新全局SCSS变量以与Tailwind CSS保持一致,调整首页布局以包含导航和背景组件,删除不再使用的Canvas OCR、OCR测试、电子签名测试、腾讯文档爬虫及相关功能测试页面,优化代码结构和可读性。

xbx 1 周之前
父节点
当前提交
d84b3cffe4

二进制
src/assets/imgs/home/bg1.png


+ 2 - 0
src/styles/variables.css

@@ -0,0 +1,2 @@
+@charset "UTF-8";
+/* 全局 SCSS 变量 */

+ 7 - 7
src/styles/variables.scss

@@ -1,12 +1,12 @@
 /* 全局 SCSS 变量 */
 
-// 屏幕尺寸断点
-$screen-xs: 480px;  // Extra small screen / phone
-$screen-sm: 576px;  // Small screen / tablet
-$screen-md: 768px;  // Medium screen / desktop
-$screen-lg: 992px;  // Large screen / wide desktop
-$screen-xl: 1200px; // Extra large screen / full hd
-$screen-xxl: 1600px; // Extra extra large screen / large desktop
+// 屏幕尺寸断点 (与Tailwind CSS保持一致)
+$screen-xs: 480px;  // 自定义断点 (Tailwind无此断点)
+$screen-sm: 640px;  // Tailwind sm: 640px
+$screen-md: 768px;  // Tailwind md: 768px
+$screen-lg: 1024px; // Tailwind lg: 1024px
+$screen-xl: 1280px; // Tailwind xl: 1280px
+$screen-xxl: 1536px; // Tailwind 2xl: 1536px
 
 // 媒体查询混合宏
 @mixin xs {

+ 19 - 0
src/types/images.d.ts

@@ -0,0 +1,19 @@
+declare module '*.png' {
+  const value: string;
+  export default value;
+}
+
+declare module '*.jpg' {
+  const value: string;
+  export default value;
+}
+
+declare module '*.jpeg' {
+  const value: string;
+  export default value;
+}
+
+declare module '*.svg' {
+  const value: string;
+  export default value;
+} 

+ 21 - 0
src/views/home/components/ParallaxBackground.vue

@@ -0,0 +1,21 @@
+<template>
+    <div ref="containerRef" class="absolute inset-0 overflow-hidden">
+        <div v-for="(image, index) in images" :key="index" class="absolute inset-0 bg-cover bg-center bg-no-repeat" :style="{ backgroundImage: `url(${image})` }"></div>
+    </div>
+</template>
+<script setup lang="ts">
+import { useScroll, useTransform, motion } from 'motion-v';
+import {ref} from 'vue';    
+import bg1 from '@/assets/imgs/home/bg1.png';
+
+interface ParallaxBackgroundProps {
+    images: string[]
+}
+//内容容器
+const containerRef = ref<HTMLElement | null>(null);
+
+const images = ref<string[]>([bg1]);   
+
+
+
+</script>

+ 35 - 0
src/views/home/components/nav.vue

@@ -0,0 +1,35 @@
+<template>
+  <nav
+    class="home-nav fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md shadow-sm"
+  >
+    <div class="container mx-auto px-6 py-4 flex justify-between items-center">
+      <div class="text-xl font-bold text-blue-600">ZW多人语音合成</div>
+
+      <ul class="flex items-center space-x-6">
+        <li class="text-gray-600 hover:text-blue-500 transition cursor-pointer">
+          产品列表
+        </li>
+
+        <li class="text-gray-600 hover:text-blue-500 transition cursor-pointer">
+          关于我们
+        </li>
+
+        <Button type="primary">登录</Button>
+      </ul>
+    </div>
+  </nav>
+
+  <div>  我是导航栏</div>
+</template>
+<script lang="ts" setup>
+import { Button } from 'ant-design-vue';
+
+defineOptions({
+  name: 'HomeNav',
+});
+</script>
+<style lang="sass" scoped>
+.home-nav{
+
+}
+</style>

+ 6 - 2
src/views/home/index.vue

@@ -1,6 +1,10 @@
 <template>
-    <div class="w-full h-full">我是首页</div>
+    <div class="min-h-screen flex flex-col  relative w-full">
+        <HomeNav />
+        <ParallaxBackground />
+    </div>
 </template>
 <script setup lang="ts">
-
+import HomeNav from './components/nav.vue';
+import ParallaxBackground from './components/parallaxBackground.vue';
 </script>

+ 0 - 350
src/views/test/canvasOcr.vue

@@ -1,350 +0,0 @@
-<template>
-  <div class="canvas-ocr-container">
-    <h3>Canvas内容识别</h3>
-
-    <div class="form-section">
-      <div class="form-group">
-        <label for="targetUrl">目标网页URL:</label>
-        <input 
-          id="targetUrl"
-          v-model="targetUrl" 
-          type="text" 
-          placeholder="https://docs.qq.com/sheet/DQVZpaFVqdnJFU3hn"
-        />
-        <button 
-          class="btn primary-btn"
-          @click="openUrlInNewTab"
-          :disabled="!isValidUrl"
-        >
-          在新标签页中打开
-        </button>
-      </div>
-
-      <div class="instruction-section">
-        <h4>识别步骤:</h4>
-        <ol>
-          <li>输入目标网页URL并点击"在新标签页中打开"</li>
-          <li>在打开的页面中定位到需要识别的Canvas区域</li>
-          <li>点击下方"开始截图"按钮</li>
-          <li>在弹出的共享屏幕对话框中,选择对应的浏览器标签页</li>
-          <li>选择区域后,系统将自动进行OCR识别</li>
-        </ol>
-      </div>
-
-      <div class="actions">
-        <button 
-          class="btn capture-btn" 
-          @click="startScreenCapture"
-          :disabled="isCapturing"
-        >
-          {{ isCapturing ? '截图中...' : '开始截图' }}
-        </button>
-      </div>
-    </div>
-
-    <!-- 截图预览 -->
-    <div v-if="capturedImage" class="preview-section">
-      <h4>截图预览:</h4>
-      <div class="image-container">
-        <img :src="capturedImage" alt="截图预览" />
-      </div>
-      <div class="image-actions">
-        <button class="btn secondary-btn" @click="processImage">增强图像</button>
-        <button class="btn primary-btn" @click="performOcr" :disabled="isOcrProcessing">
-          {{ isOcrProcessing ? 'OCR识别中...' : '开始OCR识别' }}
-        </button>
-      </div>
-    </div>
-
-    <!-- OCR结果 -->
-    <div v-if="ocrResult" class="result-section">
-      <h4>OCR识别结果:</h4>
-      <div class="result-container">
-        <textarea 
-          v-model="ocrResult" 
-          rows="10"
-          readonly
-        />
-      </div>
-      <div class="result-actions">
-        <button class="btn secondary-btn" @click="copyToClipboard">复制到剪贴板</button>
-        <button class="btn secondary-btn" @click="downloadAsText">下载为文本文件</button>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, computed } from 'vue';
-import { captureScreen, preprocessImageForOCR, dataURLtoBlob } from '@/utils/screenshot';
-import { createWorker } from 'tesseract.js';
-
-defineOptions({
-  name: 'CanvasOcr',
-});
-
-// 状态变量
-const targetUrl = ref<string>('');
-const capturedImage = ref<string>('');
-const processedImage = ref<string>('');
-const ocrResult = ref<string>('');
-const isCapturing = ref<boolean>(false);
-const isOcrProcessing = ref<boolean>(false);
-
-// 计算属性
-const isValidUrl = computed(() => {
-  if (!targetUrl.value) return false;
-  try {
-    new URL(targetUrl.value);
-    return true;
-  } catch (e) {
-    return false;
-  }
-});
-
-// 在新标签页中打开URL
-const openUrlInNewTab = () => {
-  if (!isValidUrl.value) return;
-  window.open(targetUrl.value, '_blank');
-};
-
-// 开始屏幕截图
-const startScreenCapture = async () => {
-  try {
-    isCapturing.value = true;
-    capturedImage.value = '';
-    processedImage.value = '';
-    ocrResult.value = '';
-    
-    // 调用截图功能
-    const screenshotDataUrl = await captureScreen();
-    capturedImage.value = screenshotDataUrl;
-  } catch (error) {
-    console.error('截图失败:', error);
-    alert('截图失败: ' + (error instanceof Error ? error.message : '未知错误'));
-  } finally {
-    isCapturing.value = false;
-  }
-};
-
-// 图像预处理
-const processImage = async () => {
-  if (!capturedImage.value) return;
-  
-  try {
-    // 对图像进行预处理以提高OCR识别率
-    processedImage.value = await preprocessImageForOCR(capturedImage.value);
-    // 更新预览图像
-    capturedImage.value = processedImage.value;
-  } catch (error) {
-    console.error('图像处理失败:', error);
-    alert('图像处理失败: ' + (error instanceof Error ? error.message : '未知错误'));
-  }
-};
-
-// 执行OCR识别
-const performOcr = async () => {
-  const imageToProcess = processedImage.value || capturedImage.value;
-  if (!imageToProcess) return;
-  
-  try {
-    isOcrProcessing.value = true;
-    ocrResult.value = '';
-    
-    // 创建Tesseract Worker
-    const worker = await createWorker(['chi_sim', 'eng'], 1, {
-      logger: m => console.log(m),
-      langPath: 'https://tessdata.projectnaptha.com/4.0.0'
-    });
-    
-    // 执行OCR识别
-    const { data: { text } } = await worker.recognize(imageToProcess);
-    ocrResult.value = text;
-    
-    // 终止Worker
-    await worker.terminate();
-  } catch (error) {
-    console.error('OCR识别失败:', error);
-    alert('OCR识别失败: ' + (error instanceof Error ? error.message : '未知错误'));
-  } finally {
-    isOcrProcessing.value = false;
-  }
-};
-
-// 复制到剪贴板
-const copyToClipboard = () => {
-  if (!ocrResult.value) return;
-  
-  navigator.clipboard.writeText(ocrResult.value)
-    .then(() => {
-      alert('已复制到剪贴板');
-    })
-    .catch(err => {
-      console.error('复制失败:', err);
-      alert('复制失败: ' + err);
-    });
-};
-
-// 下载为文本文件
-const downloadAsText = () => {
-  if (!ocrResult.value) return;
-  
-  const blob = new Blob([ocrResult.value], { type: 'text/plain' });
-  const url = URL.createObjectURL(blob);
-  const a = document.createElement('a');
-  a.href = url;
-  a.download = `ocr_result_${new Date().toISOString().replace(/[:.]/g, '-')}.txt`;
-  document.body.appendChild(a);
-  a.click();
-  document.body.removeChild(a);
-  URL.revokeObjectURL(url);
-};
-</script>
-
-<style scoped>
-.canvas-ocr-container {
-  max-width: 800px;
-  margin: 0 auto;
-  padding: 20px;
-}
-
-.form-section {
-  background-color: #f9f9f9;
-  border-radius: 8px;
-  padding: 20px;
-  margin-bottom: 20px;
-}
-
-.form-group {
-  margin-bottom: 15px;
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.form-group label {
-  display: block;
-  margin-bottom: 5px;
-  font-weight: bold;
-  flex: 0 0 100px;
-}
-
-.form-group input {
-  flex: 1;
-  padding: 8px;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  font-size: 14px;
-}
-
-.instruction-section {
-  background-color: #f0f8ff;
-  padding: 15px;
-  border-radius: 4px;
-  margin: 15px 0;
-}
-
-.instruction-section h4 {
-  margin-top: 0;
-  margin-bottom: 10px;
-}
-
-.instruction-section ol {
-  margin: 0;
-  padding-left: 20px;
-}
-
-.instruction-section li {
-  margin-bottom: 5px;
-}
-
-.actions {
-  margin-top: 20px;
-  display: flex;
-  justify-content: center;
-}
-
-.btn {
-  padding: 10px 16px;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  font-size: 14px;
-  transition: background-color 0.3s;
-}
-
-.btn:disabled {
-  background-color: #cccccc;
-  cursor: not-allowed;
-}
-
-.primary-btn {
-  background-color: #4CAF50;
-  color: white;
-}
-
-.primary-btn:hover:not(:disabled) {
-  background-color: #45a049;
-}
-
-.secondary-btn {
-  background-color: #2196F3;
-  color: white;
-  margin-right: 10px;
-}
-
-.secondary-btn:hover:not(:disabled) {
-  background-color: #0b7dda;
-}
-
-.capture-btn {
-  background-color: #ff9800;
-  color: white;
-  font-size: 16px;
-  padding: 12px 24px;
-}
-
-.capture-btn:hover:not(:disabled) {
-  background-color: #e68a00;
-}
-
-.preview-section, .result-section {
-  margin-top: 30px;
-  border-top: 1px solid #eee;
-  padding-top: 20px;
-}
-
-.image-container {
-  max-width: 100%;
-  overflow: hidden;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  margin: 10px 0;
-}
-
-.image-container img {
-  max-width: 100%;
-  height: auto;
-  display: block;
-}
-
-.image-actions, .result-actions {
-  margin-top: 15px;
-  display: flex;
-  gap: 10px;
-}
-
-.result-container {
-  margin: 10px 0;
-}
-
-.result-container textarea {
-  width: 100%;
-  padding: 10px;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  font-family: monospace;
-  font-size: 14px;
-  resize: vertical;
-}
-</style> 

+ 0 - 170
src/views/test/ocrTest.vue

@@ -1,170 +0,0 @@
-<template>
-  <div class="ocr-container">
-    <h3>文件上传测试</h3>
-    
-    <div class="upload-section">
-      <input 
-        type="file" 
-        ref="fileInput" 
-        accept="image/*" 
-        style="display: none" 
-        @change="handleFileChange" 
-      />
-      <button class="upload-btn" @click="triggerFileInput">选择图片文件</button>
-      <span v-if="fileName" class="file-name">已选择: {{ fileName }}</span>
-    </div>
-    
-    <button 
-      class="convert-btn" 
-      @click="convertToBase64" 
-      :disabled="!selectedFile"
-    >
-      转换为Base64
-    </button>
-    
-    <div v-if="base64Result" class="result-section">
-      <p>转换成功!Base64字符串已保存,长度为: {{ base64Result.length }}</p>
-      <div class="preview">
-        <img :src="base64Result" alt="预览" />
-      </div>
-    </div>
-
-    <button 
-      class="convert-btn" 
-      @click="beginOcr" 
-      
-    >
-      开始orc 识别
-    </button>
-  </div>
-</template>
-<script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import { fileToBase64 } from '@/utils/image';
-import { createWorker } from 'tesseract.js';
-
-defineOptions({
-  name: 'OcrTest',
-});
-
-
-const fileInput = ref<HTMLInputElement | null>(null);
-const selectedFile = ref<File | null>(null);
-const fileName = ref<string>('');
-const base64Result = ref<string>('');
-
-// 触发文件选择
-const triggerFileInput = () => {
-  fileInput.value?.click();
-};
-
-// 处理文件选择
-const handleFileChange = (event: Event) => {
-  const input = event.target as HTMLInputElement;
-  if (input.files && input.files.length > 0) {
-    selectedFile.value = input.files[0];
-    fileName.value = selectedFile.value.name;
-    // 自动重置input以便于再次选择相同文件
-    input.value = '';
-  }
-};
-
-
-//开始ocr
-const beginOcr = async () => {
-  console.log('我开始识别~~~~~')
-  const worker = await createWorker(['chi_sim'],1,{
-    logger: (m) => console.log(m),
-    langPath: 'https://tessdata.projectnaptha.com/4.0.0'
-  });
-     
-        const res = await worker.recognize(base64Result.value);
-				console.log('识别结果:', res); //text是最后识别到的内容
-        await worker.terminate(); //终止worker线程,节省内存资源
-
-};
-
-// 转换文件为base64
-const convertToBase64 = async () => {
-  if (!selectedFile.value) return;
-  
-  try {
-    base64Result.value = await fileToBase64(selectedFile.value);
-    console.log('文件已转换为base64格式');
-  } catch (error) {
-    console.error('转换失败:', error);
-    alert('转换失败: ' + (error instanceof Error ? error.message : '未知错误'));
-  }
-};
-
-onMounted(() => {
-  console.log('OcrTest mounted');
-});
-</script>
-
-<style scoped>
-.ocr-container {
-  max-width: 800px;
-  margin: 0 auto;
-  padding: 20px;
-}
-
-.upload-section {
-  margin-bottom: 20px;
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.upload-btn, .convert-btn {
-  padding: 8px 16px;
-  background-color: #4CAF50;
-  color: white;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  font-size: 14px;
-}
-
-.upload-btn:hover, .convert-btn:hover {
-  background-color: #45a049;
-}
-
-.convert-btn {
-  background-color: #2196F3;
-}
-
-.convert-btn:hover {
-  background-color: #0b7dda;
-}
-
-.convert-btn:disabled {
-  background-color: #cccccc;
-  cursor: not-allowed;
-}
-
-.file-name {
-  margin-left: 10px;
-  font-size: 14px;
-}
-
-.result-section {
-  margin-top: 20px;
-  border-top: 1px solid #eee;
-  padding-top: 20px;
-}
-
-.preview {
-  margin-top: 10px;
-  max-width: 300px;
-  max-height: 300px;
-  overflow: hidden;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-}
-
-.preview img {
-  width: 100%;
-  height: auto;
-}
-</style>

+ 0 - 159
src/views/test/signatureTest.vue

@@ -1,159 +0,0 @@
-<template>
-  <div class="signature-container">
-    <h3>电子签名测试</h3>
-    
-    <div class="demo-section">
-      <h4>基础用法</h4>
-      <SignaturePad
-        v-model:value="signatureImage"
-        height="250px"
-        @save="handleSave"
-        @clear="handleClear"
-      />
-    </div>
-    
-    <div class="demo-section">
-      <h4>自定义样式</h4>
-      <SignaturePad
-        v-model:value="customSignature"
-        height="200px"
-        :line-width="3"
-        line-color="#2196F3"
-        background-color="#f5f5f5"
-        clear-btn-text="重置"
-        save-btn-text="确认"
-      />
-    </div>
-    
-    <div class="demo-section">
-      <h4>无控制按钮</h4>
-      <SignaturePad
-        ref="noControlsPad"
-        v-model:value="noControlsSignature"
-        height="150px"
-        :show-controls="false"
-      />
-      <div class="custom-controls">
-        <button class="action-btn clear-btn" @click="clearNoControls">清除</button>
-        <button class="action-btn save-btn" @click="saveNoControls">保存</button>
-      </div>
-    </div>
-    
-    <div v-if="signatureImage" class="result-section">
-      <h4>签名结果</h4>
-      <p>签名已保存为Base64格式,长度为: {{ signatureImage.length }}</p>
-      <div class="preview">
-        <img :src="signatureImage" alt="签名预览" />
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import SignaturePad from '@/components/SignaturePad.vue';
-
-defineOptions({
-  name: 'SignatureTest',
-});
-
-// 签名数据
-const signatureImage = ref<string>('');
-const customSignature = ref<string>('');
-const noControlsSignature = ref<string>('');
-
-// 无控制按钮的签名板引用
-const noControlsPad = ref<InstanceType<typeof SignaturePad> | null>(null);
-
-// 处理保存事件
-const handleSave = (dataUrl: string) => {
-  console.log('签名已保存,长度为:', dataUrl.length);
-};
-
-// 处理清除事件
-const handleClear = () => {
-  console.log('签名已清除');
-};
-
-// 清除无控制按钮的签名
-const clearNoControls = () => {
-  noControlsPad.value?.clear();
-};
-
-// 保存无控制按钮的签名
-const saveNoControls = () => {
-  noControlsPad.value?.save();
-};
-
-onMounted(() => {
-  console.log('SignatureTest mounted');
-});
-</script>
-
-<style scoped>
-.signature-container {
-  max-width: 800px;
-  margin: 0 auto;
-  padding: 20px;
-}
-
-.demo-section {
-  margin-bottom: 30px;
-}
-
-h4 {
-  margin-bottom: 10px;
-  color: #333;
-}
-
-.custom-controls {
-  display: flex;
-  gap: 10px;
-  margin-top: 10px;
-}
-
-.action-btn {
-  padding: 8px 16px;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  font-size: 14px;
-  color: white;
-}
-
-.clear-btn {
-  background-color: #f44336;
-}
-
-.clear-btn:hover {
-  background-color: #d32f2f;
-}
-
-.save-btn {
-  background-color: #4CAF50;
-}
-
-.save-btn:hover {
-  background-color: #45a049;
-}
-
-.result-section {
-  margin-top: 30px;
-  border-top: 1px solid #eee;
-  padding-top: 20px;
-}
-
-.preview {
-  margin-top: 10px;
-  max-width: 300px;
-  max-height: 300px;
-  overflow: hidden;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-}
-
-.preview img {
-  width: 100%;
-  height: auto;
-}
-</style> 

+ 0 - 299
src/views/test/tencentDocCrawler.vue

@@ -1,299 +0,0 @@
-<template>
-  <div class="tencent-doc-crawler">
-    <h3>腾讯文档内容获取</h3>
-
-    <div class="form-section">
-      <div class="form-group">
-        <label for="documentUrl">文档URL:</label>
-        <input 
-          id="documentUrl"
-          v-model="documentUrl" 
-          type="text" 
-          placeholder="https://docs.qq.com/sheet/DQVZpaFVqdnJFU3hn"
-        />
-      </div>
-
-      <div class="form-group">
-        <label for="cookie">Cookie:</label>
-        <textarea 
-          id="cookie"
-          v-model="cookie" 
-          placeholder="从浏览器复制Cookie,确保已登录腾讯文档"
-          rows="3"
-        />
-        <div class="help-text">
-          <p>提示: 获取Cookie方法</p>
-          <ol>
-            <li>登录腾讯文档</li>
-            <li>按F12打开开发者工具</li>
-            <li>选择Network(网络)选项卡</li>
-            <li>刷新页面</li>
-            <li>选择任意请求,在Headers中找到Cookie</li>
-          </ol>
-        </div>
-      </div>
-
-      <div class="actions">
-        <button 
-          class="primary-btn" 
-          @click="startExport" 
-          :disabled="isLoading || !isFormValid"
-        >
-          {{ isLoading ? '处理中...' : '获取文档内容' }}
-        </button>
-      </div>
-    </div>
-
-    <!-- 进度显示 -->
-    <div v-if="isLoading" class="progress-section">
-      <div class="progress-bar">
-        <div class="progress-fill" :style="{ width: `${progress}%` }"/>
-      </div>
-      <p>{{ progressText }}</p>
-    </div>
-
-    <!-- 错误信息 -->
-    <div v-if="errorMessage" class="error-message">
-      <p>{{ errorMessage }}</p>
-    </div>
-
-    <!-- 结果显示 -->
-    <div v-if="exportedData" class="result-section">
-      <h4>导出成功</h4>
-      <div class="action-buttons">
-        <button class="secondary-btn" @click="downloadExcel">
-          下载Excel文件
-        </button>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, computed } from 'vue';
-import { TencentDocClient } from '@/utils/tencentDocApi';
-
-defineOptions({
-  name: 'TencentDocCrawler',
-});
-
-// 表单数据
-const documentUrl = ref<string>('');
-const cookie = ref<string>('');
-const isLoading = ref<boolean>(false);
-const progress = ref<number>(0);
-const progressText = ref<string>('');
-const errorMessage = ref<string>('');
-const exportedData = ref<ArrayBuffer | null>(null);
-
-// 表单验证
-const isFormValid = computed(() => {
-  return documentUrl.value.trim() !== '' && 
-         cookie.value.trim() !== '' && 
-         documentUrl.value.includes('docs.qq.com');
-});
-
-// 开始导出
-const startExport = async () => {
-  if (!isFormValid.value) return;
-  
-  try {
-    isLoading.value = true;
-    errorMessage.value = '';
-    exportedData.value = null;
-    progress.value = 0;
-    progressText.value = '创建导出任务...';
-
-    // 创建API客户端
-    const client = new TencentDocClient({
-      cookie: cookie.value,
-      documentUrl: documentUrl.value
-    });
-
-    // 创建导出任务
-    const operationResult = await client.createExportTask();
-    console.log(operationResult,'22222')
-
-    if (!operationResult.status) {
-      throw new Error(`创建导出任务失败: ${operationResult.message}`);
-    }
-
-    const operationId = operationResult.operationId;
-    let retries = 0;
-    const maxRetries = 20;
-    let fileUrl = '';
-
-    progressText.value = '等待导出处理...';
-
-    // 轮询查询进度
-    while (retries < maxRetries) {
-      const progressResult = await client.queryExportProgress(operationId);
-      progress.value = progressResult.progress || 0;
-      progressText.value = `导出进度: ${progress.value}%`;
-      
-      if (progressResult.progress === 100 && progressResult.file_url) {
-        fileUrl = progressResult.file_url;
-        break;
-      }
-      
-      retries++;
-      await new Promise(resolve => setTimeout(resolve, 1000));
-    }
-
-    if (!fileUrl) {
-      throw new Error('导出超时或未获取到文件下载地址');
-    }
-
-    progressText.value = '下载文件中...';
-    // 下载文件
-    exportedData.value = await client.downloadExportedFile(fileUrl);
-    progressText.value = '导出成功!';
-
-  } catch (error) {
-    console.error('导出失败:', error);
-    errorMessage.value = error instanceof Error ? error.message : '未知错误';
-  } finally {
-    isLoading.value = false;
-  }
-};
-
-// 下载Excel文件
-const downloadExcel = () => {
-  if (!exportedData.value) return;
-
-  const blob = new Blob([exportedData.value], { 
-    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
-  });
-  
-  const url = window.URL.createObjectURL(blob);
-  const link = document.createElement('a');
-  
-  // 从文档URL中提取文件名
-  const urlParts = documentUrl.value.split('/');
-  const docId = urlParts[urlParts.length - 1].split('?')[0];
-  const fileName = `tencent_doc_${docId}.xlsx`;
-  
-  link.href = url;
-  link.setAttribute('download', fileName);
-  document.body.appendChild(link);
-  link.click();
-  document.body.removeChild(link);
-  window.URL.revokeObjectURL(url);
-};
-</script>
-
-<style scoped>
-.tencent-doc-crawler {
-  max-width: 800px;
-  margin: 0 auto;
-  padding: 20px;
-}
-
-.form-section {
-  background-color: #f9f9f9;
-  border-radius: 8px;
-  padding: 20px;
-  margin-bottom: 20px;
-}
-
-.form-group {
-  margin-bottom: 15px;
-}
-
-.form-group label {
-  display: block;
-  margin-bottom: 5px;
-  font-weight: bold;
-}
-
-input, textarea {
-  width: 100%;
-  padding: 8px;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  font-size: 14px;
-}
-
-.help-text {
-  margin-top: 5px;
-  font-size: 12px;
-  color: #666;
-}
-
-.help-text ol {
-  padding-left: 20px;
-  margin-top: 5px;
-}
-
-.actions {
-  margin-top: 20px;
-}
-
-.primary-btn, .secondary-btn {
-  padding: 10px 16px;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  font-size: 14px;
-  transition: background-color 0.3s;
-}
-
-.primary-btn {
-  background-color: #4CAF50;
-  color: white;
-}
-
-.primary-btn:hover {
-  background-color: #45a049;
-}
-
-.primary-btn:disabled {
-  background-color: #cccccc;
-  cursor: not-allowed;
-}
-
-.secondary-btn {
-  background-color: #2196F3;
-  color: white;
-  margin-right: 10px;
-}
-
-.secondary-btn:hover {
-  background-color: #0b7dda;
-}
-
-.progress-section {
-  margin: 20px 0;
-}
-
-.progress-bar {
-  height: 20px;
-  background-color: #f1f1f1;
-  border-radius: 4px;
-  overflow: hidden;
-}
-
-.progress-fill {
-  height: 100%;
-  background-color: #4CAF50;
-  transition: width 0.3s;
-}
-
-.error-message {
-  background-color: #ffebee;
-  color: #c62828;
-  padding: 10px;
-  border-radius: 4px;
-  margin: 20px 0;
-}
-
-.result-section {
-  margin-top: 20px;
-  border-top: 1px solid #eee;
-  padding-top: 20px;
-}
-
-.action-buttons {
-  margin-top: 15px;
-}
-</style> 

+ 0 - 226
src/views/test/test3.vue

@@ -1,226 +0,0 @@
-<template>
-  <div class="test3-container">
-    <h3>功能测试页面</h3>
-    <input type="file" @change="handleFileChange" accept=".docx,.doc" />
-
-    <div v-if="convertedHtml" class="result-section">
-      <h4>转换结果:</h4>
-      <div v-html="convertedHtml" class="html-result" style="width: 100%" />
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import mammoth from 'mammoth';
-
-defineOptions({
-  name: 'Test3Page',
-});
-
-const convertedHtml = ref<string>('');
-const loading = ref<boolean>(false);
-
-const handleFileChange = (e: Event) => {
-  const file = (e.target as HTMLInputElement).files?.[0];
-  if (!file) return;
-
-  loading.value = true;
-  convertedHtml.value = '';
-
-  // 读取文件为ArrayBuffer
-  const reader = new FileReader();
-  reader.onload = async (event) => {
-    try {
-      const arrayBuffer = reader.result as ArrayBuffer;
-
-      // 定义转换选项
-      const options = {
-        styleMap: [
-          "p[style-name='Section Title'] => h1:fresh",
-          "p[style-name='Subsection Title'] => h2:fresh",
-          "p[style-name='Normal'] => p:fresh",
-          // 添加标题映射
-          "p[style-name='Title'] => h1.document-title:fresh",
-          "p[style-name='Heading 1'] => h1.heading1:fresh",
-          "p[style-name='Heading 2'] => h2.heading2:fresh",
-          "p[style-name='Heading 3'] => h3.heading3:fresh",
-          // 添加对齐方式映射
-          "p[align='center'] => p.center:fresh",
-          "p[align='right'] => p.right:fresh",
-          "p[align='justify'] => p.justify:fresh",
-          // 添加列表段落样式
-          "p[style-name='List Paragraph'] => p.list-paragraph:fresh",
-          // 添加下划线样式映射
-          'u => span.underline:fresh',
-        ],
-        includeDefaultStyleMap: true,
-        ignoreEmptyParagraphs: false,
-        preserveStyles: true,
-        transformDocument: transformElement,
-      };
-
-      // 自定义转换函数,处理特殊字符和下划线
-      function transformElement(element: any): any {
-        // 处理特殊元素
-        if (element.type === 'element' && element.tag && 
-            (element.tag.includes('line') || element.tag.includes('shape'))) {
-          return {
-            type: 'element',
-            tag: 'span',
-            children: [],
-            attributes: {
-              'class': 'form-field-line'
-            }
-          };
-        }
-        
-        // 处理文本内容中的下划线
-        if (element.type === 'text' && element.value) {
-          const text = element.value;
-          
-          // 检测连续的下划线、横线或特殊字符
-          if (text.match(/_{3,}|—{2,}|={2,}|-{3,}/)) {
-            const newText = text.replace(/_{3,}|—{2,}|={2,}|-{3,}/g, match => {
-              const width = match.length * 8;
-              return `<span class="form-field" style="display:inline-block;border-bottom:1px solid #000;width:${width}px;"></span>`;
-            });
-            
-            if (newText !== text) {
-              return {
-                ...element,
-                value: newText
-              };
-            }
-          }
-        }
-        
-        if (element.children) {
-          const children = element.children.map((child: any) => transformElement(child));
-          return {
-            ...element,
-            children
-          };
-        }
-        
-        return element;
-      }
-
-      // 添加后处理函数来处理HTML结果
-      const postProcessHtml = (html: string): string => {
-        let processedHtml = html;
-        
-        // 1. 处理连续的下划线和横线
-        processedHtml = processedHtml.replace(/_{3,}|—{2,}|={2,}|-{3,}/g, 
-          match => `<span class="form-field-underline" style="display:inline-block;border-bottom:1px solid #000;width:${match.length * 8}px;"></span>`
-        );
-        
-        // 2. 处理Word中的表单域占位符(通常是空白区域)
-        processedHtml = processedHtml.replace(
-          /<v:line[^>]*>|<v:shape[^>]*>|<w:drawing[^>]*>/g,
-          '<span class="form-field-underline" style="display:inline-block;border-bottom:1px solid #000;width:120px;"></span>'
-        );
-        
-        return processedHtml;
-      };
-
-      // 使用arrayBuffer而不是path
-      const result = await mammoth.convertToHtml(
-        { arrayBuffer: arrayBuffer },
-        options,
-      );
-
-      // 在转换结果后添加样式和后处理
-      convertedHtml.value = postProcessHtml(result.value);
-
-      // 添加必要的CSS样式到结果中
-      convertedHtml.value = `
-<style>
-  /* 保留文档格式 */
-  .document-title { 
-    text-align: center;
-    font-size: 1.5em;
-    font-weight: bold;
-    margin: 20px 0;
-  }
-  .center { text-align: center; }
-  .right { text-align: right; }
-  .justify { text-align: justify; }
-  .underline { text-decoration: underline; }
-  .list-paragraph { margin-left: 20px; }
-  
-  /* 表单域样式 */
-  .form-field, .form-field-underline, .form-field-line { 
-    display: inline-block;
-    border-bottom: 1px solid #000;
-    min-width: 80px;
-    margin: 0 4px;
-  }
-</style>
-${convertedHtml.value}`;
-
-      // 如果有任何警告或错误,打印到控制台
-      if (result.messages.length > 0) {
-        console.log('转换消息:', result.messages);
-      }
-    } catch (error) {
-      console.error('转换文档时出错:', error);
-      alert(
-        '转换文档时出错: ' +
-          (error instanceof Error ? error.message : '未知错误'),
-      );
-    } finally {
-      loading.value = false;
-    }
-  };
-
-  reader.onerror = () => {
-    loading.value = false;
-    console.error('读取文件时出错');
-    alert('读取文件时出错');
-  };
-
-  reader.readAsArrayBuffer(file);
-};
-
-onMounted(() => {
-  console.log('Test3Page mounted');
-});
-</script>
-
-<style scoped lang="scss">
-.test3-container {
-  max-width: 800px;
-  margin: 0 auto;
-  padding: 20px;
-}
-
-input[type='file'] {
-  margin: 20px 0;
-  padding: 10px;
-  border: 1px dashed #ccc;
-  border-radius: 4px;
-  width: 100%;
-}
-
-.result-section {
-  margin-top: 30px;
-  border-top: 1px solid #eee;
-  padding-top: 20px;
-}
-
-h4 {
-  margin-bottom: 15px;
-  color: #333;
-}
-
-.html-result {
-  padding: 15px;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  background-color: #f9f9f9;
-  min-height: 200px;
-  max-height: 600px;
-  overflow: auto;
-}
-</style>

+ 0 - 740
src/views/test/test4.vue

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