Procházet zdrojové kódy

fix: 修复事件监听器重复绑定与PDF导出尺寸问题

yusheng před 2 měsíci
rodič
revize
5d9fb6a2c4

+ 110 - 24
src/components/addDoc/seal.vue

@@ -109,7 +109,14 @@
         privateImages: [],
         droppedImages: [],
         selectedImage: null,
-        baseCanvasData: null // 缓存基础内容的 Canvas 数据
+        baseCanvasData: null, // 缓存基础内容的 Canvas 数据
+        _isMoving: false, // 是否正在移动图片
+        _currentMoveImageId: null, // 当前正在移动的图片ID
+        _moveHandler: null, // 移动事件处理函数引用
+        _mouseUpHandler: null, // 鼠标释放事件处理函数引用
+        _dragOverHandler: null, // dragover事件处理函数引用
+        _dropHandler: null, // drop事件处理函数引用
+        _contextMenuHandler: null // contextmenu事件处理函数引用
       };
     },
     created() {
@@ -139,7 +146,7 @@
     mounted() {
       // 组件挂载后自动渲染一次
       this.$nextTick(() => {
-        // this.renderToCanvas();
+        this.renderToCanvas();
       });
 
       // 保存组件实例引用,用于事件处理器
@@ -163,6 +170,21 @@
       };
     },
     beforeDestroy() {
+      // 清理移动事件监听器
+      this._cancelMove();
+      // 清理 Canvas 事件监听器
+      const canvas = document.getElementById('outputCanvas');
+      if (canvas) {
+        if (this._dragOverHandler) {
+          canvas.removeEventListener('dragover', this._dragOverHandler);
+        }
+        if (this._dropHandler) {
+          canvas.removeEventListener('drop', this._dropHandler);
+        }
+        if (this._contextMenuHandler) {
+          canvas.removeEventListener('contextmenu', this._contextMenuHandler);
+        }
+      }
       // 清理引用
       if (window._aaComponentInstance === this) {
         window._aaComponentInstance = null;
@@ -237,12 +259,24 @@
         );
         console.log('Canvas 位置:', canvas.getBoundingClientRect());
 
-        canvas.addEventListener('dragover', (e) => {
+        // 先移除旧的事件监听器,防止重复绑定
+        if (this._dragOverHandler) {
+          canvas.removeEventListener('dragover', this._dragOverHandler);
+        }
+        if (this._dropHandler) {
+          canvas.removeEventListener('drop', this._dropHandler);
+        }
+        if (this._contextMenuHandler) {
+          canvas.removeEventListener('contextmenu', this._contextMenuHandler);
+        }
+
+        // 创建事件处理函数并保存引用
+        this._dragOverHandler = (e) => {
           e.preventDefault();
           e.dataTransfer.dropEffect = 'copy';
-        });
+        };
 
-        canvas.addEventListener('drop', (e) => {
+        this._dropHandler = (e) => {
           e.preventDefault();
           console.log('触发 drop 事件');
           const imageData = e.dataTransfer.getData('imageData');
@@ -252,13 +286,17 @@
             console.log('解析后的数据:', data);
             this.addImageToCanvas(data, e.offsetX, e.offsetY);
           }
-        });
+        };
 
-        // 添加右键点击事件监听
-        canvas.addEventListener('contextmenu', (e) => {
+        this._contextMenuHandler = (e) => {
           e.preventDefault();
           this.handleCanvasRightClick(e);
-        });
+        };
+
+        // 添加新的事件监听器
+        canvas.addEventListener('dragover', this._dragOverHandler);
+        canvas.addEventListener('drop', this._dropHandler);
+        canvas.addEventListener('contextmenu', this._contextMenuHandler);
       },
 
       // 处理拖拽开始
@@ -603,6 +641,15 @@
         const image = this.droppedImages[imageIndex];
         console.log('找到图片:', image);
 
+        // 如果已经在移动中,先移除旧的事件监听器
+        if (this._isMoving) {
+          this._cancelMove();
+        }
+
+        // 设置移动状态标志
+        this._isMoving = true;
+        this._currentMoveImageId = imageId;
+
         // 创建一个临时指示器
         const indicator = document.createElement('div');
         indicator.id = `move_indicator_${imageId}`;
@@ -625,9 +672,9 @@
           message: '📍 移动鼠标调整位置,释放鼠标完成移动',
           type: 'info'
         });
-        // this.showMessage('📍 移动鼠标调整位置,释放鼠标完成移动', 'info');
 
-        const moveHandler = (e) => {
+        // 保存事件处理函数引用,用于后续移除
+        this._moveHandler = (e) => {
           console.log('moveHandler 被调用,鼠标位置:', e.clientX, e.clientY);
           const rect = canvas.getBoundingClientRect();
           const scaleX = canvas.width / rect.width;
@@ -652,7 +699,7 @@
           }
         };
 
-        const mouseUpHandler = (e) => {
+        this._mouseUpHandler = (e) => {
           console.log(
             'mouseUpHandler 被调用,位置:',
             e.clientX,
@@ -667,9 +714,14 @@
           // 确保只处理一次
           if (indicator.parentNode) {
             console.log('指示器仍在DOM中,移除事件监听器');
-            document.removeEventListener('mousemove', moveHandler);
-            document.removeEventListener('mouseup', mouseUpHandler);
+            document.removeEventListener('mousemove', this._moveHandler);
+            document.removeEventListener('mouseup', this._mouseUpHandler);
             indicator.remove();
+            // 重置移动状态
+            this._isMoving = false;
+            this._currentMoveImageId = null;
+            this._moveHandler = null;
+            this._mouseUpHandler = null;
             // 使用组件实例引用
             const component = window._aaComponentInstance || this;
             if (component) {
@@ -678,7 +730,6 @@
                 message: '图片已移动',
                 type: 'success'
               });
-              // component.showMessage('✅ 图片已移动', 'success');
             }
           } else {
             console.log('指示器已不在DOM中');
@@ -687,10 +738,10 @@
 
         // 确保事件只绑定一次
         console.log('绑定事件监听器');
-        document.removeEventListener('mousemove', moveHandler);
-        document.removeEventListener('mouseup', mouseUpHandler);
-        document.addEventListener('mousemove', moveHandler);
-        document.addEventListener('mouseup', mouseUpHandler);
+        document.removeEventListener('mousemove', this._moveHandler);
+        document.removeEventListener('mouseup', this._mouseUpHandler);
+        document.addEventListener('mousemove', this._moveHandler);
+        document.addEventListener('mouseup', this._mouseUpHandler);
       },
 
       // 删除图片
@@ -705,6 +756,11 @@
         // 删除控制菜单
         this.safeRemoveElement(`menu_${imageId}`);
 
+        // 如果正在移动这张图片,取消移动状态
+        if (this._currentMoveImageId === imageId) {
+          this._cancelMove();
+        }
+
         this.redrawCanvas();
         this.$message({
           showClose: true,
@@ -713,6 +769,28 @@
         });
       },
 
+      // 取消移动操作
+      _cancelMove() {
+        if (this._moveHandler) {
+          document.removeEventListener('mousemove', this._moveHandler);
+        }
+        if (this._mouseUpHandler) {
+          document.removeEventListener('mouseup', this._mouseUpHandler);
+        }
+        // 移除指示器
+        if (this._currentMoveImageId) {
+          const indicator = document.getElementById(`move_indicator_${this._currentMoveImageId}`);
+          if (indicator && indicator.parentNode) {
+            indicator.remove();
+          }
+        }
+        // 重置状态
+        this._isMoving = false;
+        this._currentMoveImageId = null;
+        this._moveHandler = null;
+        this._mouseUpHandler = null;
+      },
+
       // 渲染Canvas核心函数
       async renderToCanvas() {
         const targetElement = document.getElementById('captureTarget');
@@ -802,15 +880,23 @@
 
         try {
           const imgData = outputCanvas.toDataURL('image/png');
-          const canvasWidth = outputCanvas.width;
-          const canvasHeight = outputCanvas.height;
+          // 使用 Canvas 的 CSS 尺寸(显示尺寸),而不是内部像素尺寸
+          const canvasWidth = parseFloat(outputCanvas.style.width) || outputCanvas.width;
+          const canvasHeight = parseFloat(outputCanvas.style.height) || outputCanvas.height;
 
           // 创建 PDF 实例,横向或纵向根据 Canvas 尺寸决定
           const orientation = canvasWidth > canvasHeight ? 'l' : 'p';
-          const pdf = new jsPDF(orientation, 'px', [canvasWidth, canvasHeight]);
+          // 使用 'mm' 单位,并根据 96 DPI 转换为毫米
+          // 96 DPI 下:1px = 25.4 / 96 mm ≈ 0.2646 mm
+          const DPI = 96;
+          const pxToMm = 25.4 / DPI;
+          const pdfWidth = canvasWidth * pxToMm;
+          const pdfHeight = canvasHeight * pxToMm;
+
+          const pdf = new jsPDF(orientation, 'mm', [pdfWidth, pdfHeight]);
 
           // 将 Canvas 图片添加到 PDF
-          pdf.addImage(imgData, 'PNG', 0, 0, canvasWidth, canvasHeight);
+          pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
 
           // 获取 PDF 文件流并触发事件
           const pdfBlob = pdf.output('blob');
@@ -824,7 +910,7 @@
             droppedImages: this.droppedImages
           });
 
-          // // 保存 PDF
+          // 保存 PDF
           // const timestamp = new Date()
           //   .toISOString()
           //   .slice(0, 19)

+ 1 - 0
src/components/addDoc/sealManagement.vue

@@ -5,6 +5,7 @@
     custom-class="ele-dialog-form"
     append-to-body
     :fullscreen="true"
+    v-if="showEditFlag"
   >
     <iframe
       :src="fileUrl"