From 8e11385a7f9c3b10754eed3d446b4dcc83de0d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A6=85=E9=A5=BC?= <2815246336@qq.com> Date: Thu, 4 Sep 2025 20:26:46 +0800 Subject: [PATCH] 2 --- pages/work/inspection/scanSign/index.vue | 323 ++++++++++++++++++++++- 1 file changed, 309 insertions(+), 14 deletions(-) diff --git a/pages/work/inspection/scanSign/index.vue b/pages/work/inspection/scanSign/index.vue index a012896..9659913 100644 --- a/pages/work/inspection/scanSign/index.vue +++ b/pages/work/inspection/scanSign/index.vue @@ -10,9 +10,25 @@ - + + + + + + + × + + + + + + + 添加图片 + + + + 最多选择3张图片,支持自动压缩 + + @@ -59,7 +75,6 @@ remark: "" }, img: [], - sourceType: ['camera'], imgFiles: "", msgType: '', messageText: '', @@ -90,20 +105,132 @@ }); }, - deleteImg(e) { - const index = this.img.findIndex(f => f.path === e.tempFile.path); - if (index !== -1) { + // 自定义图片选择方法 + chooseImage() { + if (this.isUploading) { + this.showMessage('warning', '图片正在上传中,请稍等'); + return; + } + + uni.chooseImage({ + count: 3 - this.img.length, // 最多选择剩余可选数量 + sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 + sourceType: ['camera', 'album'], // 可以指定来源是相册还是相机,默认二者都有 + success: (res) => { + // 处理选择的图片 + res.tempFilePaths.forEach((filePath, index) => { + this.handleCustomImageUpload(filePath, res.tempFiles[index]); + }); + }, + fail: (err) => { + console.error('选择图片失败:', err); + this.showMessage('error', '选择图片失败'); + } + }); + }, + + // 删除自定义图片 + deleteCustomImg(index) { + if (index >= 0 && index < this.img.length) { + // 释放URL对象 + if (this.img[index].url && this.img[index].url.startsWith('blob:')) { + URL.revokeObjectURL(this.img[index].url); + } + this.form.ImgUrl.splice(index, 1); this.img.splice(index, 1); } }, + // 兼容旧的删除方法 + deleteImg(e) { + const index = this.img.findIndex(f => f.path === e.tempFile.path); + if (index !== -1) { + this.deleteCustomImg(index); + } + }, + + // 兼容旧的上传方法 upload(e) { if (e.tempFiles && e.tempFiles.length > 0) { this.handleImageUpload(e.tempFiles[0]); } }, + // 处理自定义图片上传 + async handleCustomImageUpload(filePath, fileInfo) { + this.isUploading = true; + + try { + // 将uni.chooseImage返回的文件转换为File对象 + const file = await this.convertToFile(filePath, fileInfo); + + // 生成水印文字 + const watermarkText = `${this.form.inspectionPoint || '未命名地点'} \n${this.getCurrentDate()}`; + + // 添加水印 + let processedFile = await addWatermarkToImage(file, watermarkText); + + // 自动压缩图片(所有图片都进行压缩优化) + processedFile = await this.compressImage(processedFile); + + // 上传处理后的文件 + const fileUrl = await this.uploadFile(processedFile); + + // 更新UI显示 + this.img.push({ + raw: processedFile, + name: processedFile.name, + url: fileUrl, + path: filePath + }); + + } catch (error) { + console.error("图片处理失败:", error); + this.showMessage('error', `图片处理失败: ${error.message}`); + } finally { + this.isUploading = false; + } + }, + + // 将uni.chooseImage的结果转换为File对象 + async convertToFile(filePath, fileInfo) { + return new Promise((resolve, reject) => { + // 在uni-app中,可以直接使用filePath创建File对象 + // 对于H5平台,需要特殊处理 + // #ifdef H5 + const xhr = new XMLHttpRequest(); + xhr.open('GET', filePath, true); + xhr.responseType = 'blob'; + xhr.onload = function() { + if (xhr.status === 200) { + const blob = xhr.response; + const file = new File([blob], fileInfo.name || 'image.jpg', { + type: fileInfo.type || 'image/jpeg' + }); + resolve(file); + } else { + reject(new Error('文件读取失败')); + } + }; + xhr.onerror = () => reject(new Error('文件读取失败')); + xhr.send(); + // #endif + + // #ifndef H5 + // 对于非H5平台,创建一个模拟的File对象 + const file = { + name: fileInfo.name || 'image.jpg', + type: fileInfo.type || 'image/jpeg', + size: fileInfo.size || 0, + path: filePath, + lastModified: Date.now() + }; + resolve(file); + // #endif + }); + }, + cancel() { uni.reLaunch({ url: '/pages/work/index' @@ -114,6 +241,7 @@ return this.form.ImgUrl.join(','); }, + // 处理原有的图片上传(兼容uni-file-picker) async handleImageUpload(file) { this.isUploading = true; @@ -128,12 +256,8 @@ // 添加水印 let processedFile = await addWatermarkToImage(file.file, watermarkText); - // 如果是移动浏览器且文件大于300KB,则进行压缩 - if (this.isMobileBrowser && processedFile.size > 300 * 1024) { - console.log('原始文件大小:', (processedFile.size / 1024).toFixed(2), 'KB'); - processedFile = await this.compressImageForMobile(processedFile); - console.log('压缩后文件大小:', (processedFile.size / 1024).toFixed(2), 'KB'); - } + // 使用新的压缩方法 + processedFile = await this.compressImage(processedFile); // 上传处理后的文件 const fileUrl = await this.uploadFile(processedFile); @@ -153,7 +277,92 @@ } }, - // 专门为移动浏览器优化的压缩方法 + // 通用图片压缩方法 + compressImage(file, quality = 0.7, maxWidth = 1200, maxHeight = 1200) { + return new Promise((resolve, reject) => { + // 如果文件小于200KB,直接返回 + if (file.size < 200 * 1024) { + console.log('文件较小,无需压缩'); + resolve(file); + return; + } + + console.log('原始文件大小:', (file.size / 1024).toFixed(2), 'KB'); + + const img = new Image(); + const reader = new FileReader(); + + reader.onload = (event) => { + img.onload = () => { + // 计算压缩比例 + let width = img.width; + let height = img.height; + + // 限制最大尺寸 + if (width > maxWidth || height > maxHeight) { + const ratio = Math.min(maxWidth / width, maxHeight / height); + width = Math.floor(width * ratio); + height = Math.floor(height * ratio); + } + + // 创建canvas + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext('2d'); + + // 设置更高的压缩质量 + ctx.imageSmoothingQuality = 'high'; + ctx.drawImage(img, 0, 0, width, height); + + // 使用toBlob进行压缩 + if (canvas.toBlob) { + canvas.toBlob( + (blob) => { + if (!blob) { + console.warn('压缩失败,返回原始文件'); + resolve(file); + return; + } + + // 创建压缩后的文件对象 + const compressedFile = new File([blob], file.name, { + type: 'image/jpeg', + lastModified: Date.now() + }); + + console.log('压缩后文件大小:', (compressedFile.size / 1024).toFixed(2), 'KB'); + resolve(compressedFile); + }, + 'image/jpeg', + quality + ); + } else { + // 不支持toBlob的浏览器直接返回原文件 + console.warn('浏览器不支持toBlob方法,无法压缩'); + resolve(file); + } + }; + + img.onerror = () => { + console.warn('图片加载失败,返回原始文件'); + resolve(file); + }; + + img.src = event.target.result; + }; + + reader.onerror = () => { + console.warn('文件读取失败,返回原始文件'); + resolve(file); + }; + + reader.readAsDataURL(file); + }); + }, + + // 专门为移动浏览器优化的压缩方法(保留兼容性) compressImageForMobile(file, quality = 0.6, maxWidth = 1200, maxHeight = 1200) { return new Promise((resolve, reject) => { const img = new Image(); @@ -339,4 +548,90 @@ /* 使按钮平分可用空间 */ /* 可能还需要设置一些其他的样式来确保按钮看起来正确,比如 text-align, padding 等 */ } + + /* 自定义图片选择器样式 */ + .custom-image-picker { + width: 100%; + } + + .image-preview-container { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 10px; + } + + .image-preview-item { + position: relative; + width: 80px; + height: 80px; + border-radius: 8px; + overflow: hidden; + border: 1px solid #e0e0e0; + } + + .preview-image { + width: 100%; + height: 100%; + object-fit: cover; + } + + .delete-btn { + position: absolute; + top: -5px; + right: -5px; + width: 20px; + height: 20px; + background-color: #ff4757; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + } + + .delete-icon { + color: white; + font-size: 14px; + font-weight: bold; + line-height: 1; + } + + .add-image-btn { + width: 80px; + height: 80px; + border: 2px dashed #c0c0c0; + border-radius: 8px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + background-color: #fafafa; + transition: all 0.3s ease; + } + + .add-image-btn:hover { + border-color: #007aff; + background-color: #f0f8ff; + } + + .add-icon { + font-size: 24px; + color: #c0c0c0; + margin-bottom: 4px; + } + + .add-text { + font-size: 12px; + color: #999; + } + + .image-tip { + font-size: 12px; + color: #666; + text-align: center; + margin-top: 5px; + } \ No newline at end of file