From fca192d3c38c5dcfbb6ace8bc71d6078f6a079b2 Mon Sep 17 00:00:00 2001 From: 啊鑫 <t2856754968@163.com> Date: 星期日, 20 七月 2025 18:09:06 +0800 Subject: [PATCH] LLJ附件系统全面优化:多格式文件预览与APK兼容性 --- pages/QC/LLJ/Add.vue | 852 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 794 insertions(+), 58 deletions(-) diff --git a/pages/QC/LLJ/Add.vue b/pages/QC/LLJ/Add.vue index 04f0623..52ddd2a 100644 --- a/pages/QC/LLJ/Add.vue +++ b/pages/QC/LLJ/Add.vue @@ -103,12 +103,6 @@ - <!-- 鎿嶄綔鎸夐挳鍖� --> - <view class="action-buttons" v-if="this.current"> - <button class="secondary-btn" @click="handleEmergencyRelease">绱ф�ユ斁琛�</button> - <button class="secondary-btn" @click="handleWithdraw">鎾ゅ洖</button> - <button class="secondary-btn" @click="getInspectionItems">鑾峰彇妫�楠岄」鐩�</button> - </view> @@ -147,14 +141,22 @@ </table> </view> - <!-- 鎿嶄綔鎸夐挳鍖� --> - <view class="action-buttons"> - <button class="secondary-btn" @click="addDestruction" v-if="this.current">鐮村潖瀹為獙</button> - <button class="secondary-btn" @click="uploadImages">涓婁紶/鏌ョ湅鍥剧墖</button> - <button class="secondary-btn" @click="fetchDrawingNumber">璋冨彇PLM鍥剧焊</button> - <button class="secondary-btn" @click="viewAttachmentInfo">鏌ョ湅闄勪欢淇℃伅</button> - <button class="secondary-btn" @click="addDefectDescription" v-if="this.current">娣诲姞涓嶈壇鎻忚堪</button> - <button class="primary-btn" @click="submitInspection" v-if="this.current">妫�楠屾彁浜�</button> + <!-- 椤甸潰鍐呭鍖哄煙 --> + <view class="content-wrapper"> + <!-- 涓哄簳閮ㄦ寜閽暀鍑虹┖闂� --> + </view> + + <!-- 鍥哄畾鍦ㄥ簳閮ㄧ殑鎿嶄綔鎸夐挳鍖� --> + <view class="fixed-action-buttons"> + <button class="action-btn" @click="handleEmergencyRelease" v-if="this.current">绱ф�ユ斁琛�</button> + <button class="action-btn" @click="handleWithdraw" v-if="this.current">鎾ゅ洖</button> + <button class="action-btn" @click="getInspectionItems" v-if="this.current">鑾峰彇妫�楠岄」鐩�</button> + <button class="action-btn" @click="addDestruction" v-if="this.current">鐮村潖瀹為獙</button> + <button class="action-btn" @click="uploadImages">涓婁紶/鏌ョ湅鍥剧墖</button> + <button class="action-btn" @click="fetchDrawingNumber">璋冨彇PLM鍥剧焊</button> + <button class="action-btn" @click="viewAttachmentInfo">鏌ョ湅闄勪欢淇℃伅</button> + <button class="action-btn" @click="addDefectDescription" v-if="this.current">娣诲姞涓嶈壇鎻忚堪</button> + <button class="action-btn primary" @click="submitInspection" v-if="this.current">妫�楠屾彁浜�</button> </view> <view v-if="remarksPopup" class="overlay"> <view class="popup"> @@ -189,8 +191,8 @@ <view class="barcode"> <u-modal :show="drawingShow" title="鍥剧焊鏄庣粏" @confirm="drawingConfirm" @cancel="drawingCancel" - showCancelButton> - <uni-table border stripe emptyText="鏆傛棤鏇村鏁版嵁" style="margin-left: 5px;margin-right: 5px;height: 500px;"> + showCancelButton :z-index="1000"> + <uni-table border stripe emptyText="鏆傛棤鏇村鏁版嵁" style="margin-left: 5px;margin-right: 5px;height: 400px;max-height: 60vh;overflow-y: auto;"> <uni-tr> <uni-th align="center">鐩稿叧鏂囨。</uni-th> <uni-th align="center" width="90">鏈夋棤鍏宠仈PDF鏂囦欢</uni-th> @@ -227,19 +229,16 @@ <div class="attachment-detail-row"><span class="attachment-label">鍙楁帶鏃ユ湡锛�</span><span>{{ selectedAttachment.fdate }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">涓婁紶浜猴細</span><span>{{ selectedAttachment.createBy }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">涓婁紶鏃堕棿锛�</span><span>{{ selectedAttachment.createDate }}</span></div> - <div v-if="isPreviewable(selectedAttachment.fattach)" class="attachment-preview-area"> - <div v-if="['pdf','jpg','jpeg','png','gif'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="getAttachmentUrl(selectedAttachment)" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - <div v-else-if="['txt'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="getAttachmentUrl(selectedAttachment)" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - <div v-else-if="['doc','docx','xls','xlsx'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="'https://view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(getAttachmentUrl(selectedAttachment))" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - </div> - <div v-else class="attachment-download-area"> - <button class="attachment-download-link" @click="downloadAttachment(selectedAttachment)">涓嬭浇闄勪欢</button> + <div class="attachment-actions-detail"> + <button class="attachment-action-btn preview-btn" + @click="previewFtpFile(selectedAttachment)" + v-if="isPreviewable(selectedAttachment.fattach)"> + 馃攳 鍦ㄧ嚎棰勮 + </button> + <button class="attachment-action-btn download-btn" + @click="downloadAttachment(selectedAttachment)"> + 馃摜 涓嬭浇鏂囦欢 + </button> </div> </div> <div v-else class="attachment-detail-empty">鏆傛棤闄勪欢淇℃伅</div> @@ -254,16 +253,58 @@ <div v-else-if="attachments.length === 0">鏆傛棤闄勪欢</div> <ul class="attachment-list" v-else> <li v-for="item in attachments" :key="item.id"> - <span class="attachment-name" @click="showAttachmentDetailDialog(item)"> - {{ item.fattach }} - </span> + <div class="attachment-info"> + <span class="attachment-name" @click="showAttachmentDetailDialog(item)"> + {{ item.fattach }} + </span> + <div class="attachment-meta"> + <span class="attachment-type">{{ item.ftype || '鏈煡绫诲瀷' }}</span> + </div> + </div> <div class="attachment-actions"> <button class="secondary-btn" @click="showAttachmentDetailDialog(item)">璇︽儏</button> + <button class="secondary-btn preview-btn" @click="previewFtpFile(item)" + v-if="isPreviewable(item.fattach)">棰勮</button> <button class="secondary-btn" @click="downloadAttachment(item)">涓嬭浇</button> </div> </li> </ul> <button class="attachment-popup-close" @click="closeAttachmentPopup">鍏抽棴</button> + </view> + </view> + + <!-- 鏂囦欢棰勮寮圭獥 --> + <view v-if="showFilePreviewPopup" class="overlay"> + <view class="popup file-preview-popup"> + <h3 class="file-preview-title">{{ previewTitle }}</h3> + <div class="file-preview-divider"></div> + <div class="file-preview-content"> + <!-- 鏂囨湰鍐呭棰勮 --> + <pre v-if="previewType === 'text'">{{ previewContent }}</pre> + + <!-- 鍥剧墖鍐呭棰勮 --> + <view v-else-if="previewType === 'image'" class="image-preview-container"> + <image :src="previewContent" mode="widthFix" style="width: 100%; max-height: 400px;"></image> + </view> + + <!-- Excel 绛� Office 鏂囦欢鎻愮ず --> + <view v-else-if="previewType === 'excel'" class="unsupported-preview"> + <view class="unsupported-icon">馃搳</view> + <view class="unsupported-text">Excel 鏂囦欢鏆備笉鏀寔鍦ㄧ嚎棰勮</view> + <view class="unsupported-hint">璇风偣鍑讳笅杞芥寜閽幏鍙栧畬鏁存枃浠�</view> + </view> + + <!-- 涓嶆敮鎸佺殑鏂囦欢绫诲瀷 --> + <view v-else class="unsupported-preview"> + <view class="unsupported-icon">馃搫</view> + <view class="unsupported-text">姝ゆ枃浠舵牸寮忔殏涓嶆敮鎸侀瑙�</view> + <view class="unsupported-hint">璇风偣鍑讳笅杞芥寜閽幏鍙栧畬鏁存枃浠�</view> + </view> + </div> + <div class="file-preview-actions"> + <button v-if="previewType !== 'text'" class="file-preview-btn download-btn" @click="downloadPreviewFile">馃摜 涓嬭浇鏂囦欢</button> + <button class="file-preview-btn close-btn" @click="closeFilePreview">鍏抽棴</button> + </div> </view> </view> </view> @@ -325,6 +366,11 @@ attachmentsLoading: false, selectedAttachment: null, showAttachmentDetail: false, + showFilePreviewPopup: false, + previewContent: '', + previewTitle: '', + previewItemNo: '', + previewType: '', // 'text', 'image', 'excel', 'unsupported' } }, @@ -1286,6 +1332,11 @@ this.attachmentsLoading = false; if (res.status === 0) { this.attachments = res.data.tbBillList; + // 涓烘瘡涓檮浠惰缃粯璁ゅ彲鐢ㄧ姸鎬� + this.attachments.forEach((item, index) => { + this.$set(item, 'ftpAvailable', true); // 榛樿璁や负鏂囦欢鍙敤 + this.$set(item, 'checking', false); + }); } else if (res.status === 1 && res.message === "璇ユ楠屽崟鏈笂浼犻檮浠朵俊鎭紒") { uni.showToast({ title: res.message, icon: "none" }); } else { @@ -1297,10 +1348,10 @@ this.showAttachmentPopup = false; }, getAttachmentUrl(item) { - const baseUrl = "http://192.168.1.22:10054"; // 鍘婚櫎鎵�鏈夌┖鐧藉瓧绗︼紙鍖呮嫭涓嫳鏂囩┖鏍笺�佸埗琛ㄧ绛夛級 - let fileName = item.fattach.replace(/[\s\u3000]+/g, '').trim(); - return baseUrl + "/api/LLJ/DownloadAttachment?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName); + let fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + // 缁熶竴浣跨敤FTP涓嬭浇鎺ュ彛锛屽寘鍚獸TP鏈嶅姟鍣ㄥ湴鍧� + return this.$store.state.serverInfo.serverAPI + "/LLJ/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); }, showAttachmentDetailDialog(item) { console.log('鏌ョ湅璇︽儏', item); @@ -1319,7 +1370,13 @@ const ext = filename.trim().split('.').pop().toLowerCase(); // 鏀寔鍦ㄧ嚎棰勮鐨勬枃浠剁被鍨� return [ - 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'txt', 'doc', 'docx', 'xls', 'xlsx' + 'pdf', // PDF鏂囦欢 + 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', // 鍥剧墖鏂囦欢 + 'txt', 'log', 'md', // 鏂囨湰鏂囦欢 + 'doc', 'docx', // Word鏂囨。 + 'xls', 'xlsx', // Excel琛ㄦ牸 + 'ppt', 'pptx', // PowerPoint婕旂ず鏂囩 + 'csv' // CSV鏂囦欢 ].includes(ext); }, // 澶勭悊闄勪欢涓嬭浇閿欒 @@ -1330,32 +1387,474 @@ showCancel: false }); }, - downloadAttachment(item) { - const baseUrl = "http://192.168.1.22:10054"; - // 鍘婚櫎鎵�鏈夌┖鏍笺�佸叏瑙掔┖鏍笺�佸洖杞︺�佹崲琛� + // 棰勮FTP鏂囦欢 + previewFtpFile(item) { const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); - const url = baseUrl + "/api/Llj/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName); - uni.downloadFile({ + const fileExt = fileName.split('.').pop().toLowerCase(); + + // 妫�鏌ユ枃浠剁被鍨嬫槸鍚︽敮鎸侀瑙� + if (!this.isPreviewable(fileName)) { + uni.showModal({ + title: '涓嶆敮鎸侀瑙�', + content: '璇ユ枃浠剁被鍨嬩笉鏀寔鍦ㄧ嚎棰勮锛岃涓嬭浇鍚庢煡鐪�', + showCancel: false + }); + return; + } + + const previewUrl = this.$store.state.serverInfo.serverAPI + "/LLJ/PreviewFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); + + // 鏍规嵁鏂囦欢绫诲瀷杩涜涓嶅悓鐨勯瑙堝鐞� + if (['pdf'].includes(fileExt)) { + this.previewPdfFile(previewUrl, fileName); + } else if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(fileExt)) { + this.previewImageFile(previewUrl, fileName); + } else if (['txt'].includes(fileExt)) { + this.previewTextFile(previewUrl, fileName); + } else if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(fileExt)) { + this.previewOfficeFile(previewUrl, fileName); + } else { + // 灏濊瘯閫氱敤棰勮 + this.previewGenericFile(previewUrl, fileName); + } + }, + + // 棰勮PDF鏂囦欢 + previewPdfFile(url, fileName) { + // 鍏堜笅杞絇DF鏂囦欢锛岃浆涓篵ase64鍚庨瑙� + uni.request({ url: url, + method: 'GET', + responseType: 'arraybuffer', success: (res) => { if (res.statusCode === 200) { - if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.openFile) { - plus.runtime.openFile({ path: res.tempFilePath }, () => { - uni.showToast({ title: '鎵撳紑鎴愬姛', icon: 'success' }); - }, (e) => { - uni.showModal({ title: '鎻愮ず', content: '鏂囦欢涓嬭浇鎴愬姛锛屼絾鏃犳硶鑷姩鎵撳紑銆傝鍦ㄦ枃浠剁鐞嗕腑鎵嬪姩鏌ユ壘骞舵墦寮�銆�', showCancel: false }); - }); - } else { - uni.showModal({ title: '鎻愮ず', content: '鏂囦欢涓嬭浇鎴愬姛锛屼絾褰撳墠鐜鏃犳硶鑷姩鎵撳紑銆傝鍦ㄦ枃浠剁鐞嗕腑鎵嬪姩鏌ユ壘骞舵墦寮�銆�', showCancel: false }); - } + const base64Data = uni.arrayBufferToBase64(res.data); + // 瀛樺偍鍒板叏灞�鍙橀噺 + getApp().globalData.tempPDF = base64Data; + uni.navigateTo({ + url: `/pages/fileView/pdfView` + }); } else { - uni.showModal({ title: '涓嬭浇澶辫触', content: `涓嬭浇澶辫触锛岀姸鎬佺爜锛�${res.statusCode}`, showCancel: false }); + this.handlePreviewError(res.statusCode, fileName); } }, fail: (error) => { - uni.showModal({ title: '涓嬭浇澶辫触', content: `涓嬭浇澶辫触锛岃妫�鏌ョ綉缁滆繛鎺ャ��${error.errMsg}`, showCancel: false }); + this.handlePreviewError(0, fileName, error.errMsg); } }); + }, + + // 棰勮鍥剧墖鏂囦欢 + previewImageFile(url, fileName) { + // #ifdef APP-PLUS + // APP鐜锛氬厛涓嬭浇鍒版湰鍦板啀棰勮锛岄伩鍏嶇綉缁滃浘鐗囧姞杞介棶棰� + uni.showLoading({ title: '鍔犺浇鍥剧墖...' }); + uni.downloadFile({ + url: url, + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + // 浣跨敤鏈湴涓存椂璺緞 + uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(res.tempFilePath)}` + }); + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + uni.hideLoading(); + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + // #endif + + // #ifdef H5 || MP + // H5鍜屽皬绋嬪簭锛氱洿鎺ヤ娇鐢ㄧ綉缁淯RL + uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(url)}` + }); + // #endif + }, + + // 棰勮鏂囨湰鏂囦欢 + previewTextFile(url, fileName) { + // 鏂囨湰鏂囦欢鐩存帴鏄剧ず鍦ㄥ脊绐椾腑 + uni.showLoading({ title: '鍔犺浇鏂囦欢鍐呭...' }); + uni.request({ + url: url, + method: 'GET', + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + const fileType = this.getFileType(fileName); + + if (fileType === 'text') { + // 鏂囨湰鏂囦欢锛氭樉绀哄唴瀹� + this.showFilePreview(res.data, fileName); + } else if (fileType === 'image') { + // 鍥剧墖鏂囦欢锛氭樉绀哄浘鐗嘦RL + this.showFilePreview(url, fileName); + } else { + // 鍏朵粬鏂囦欢绫诲瀷锛氭樉绀烘彁绀轰俊鎭� + this.showFilePreview('', fileName); + } + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + uni.hideLoading(); + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + }, + + // 妫�娴嬫枃浠剁被鍨� + getFileType(fileName) { + const fileExt = fileName.split('.').pop().toLowerCase(); + + if (['txt', 'log', 'md', 'csv', 'json', 'xml'].includes(fileExt)) { + return 'text'; + } else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExt)) { + return 'image'; + } else if (['xls', 'xlsx', 'doc', 'docx', 'ppt', 'pptx'].includes(fileExt)) { + return 'excel'; + } else { + return 'unsupported'; + } + }, + + // 鏄剧ず鏂囦欢棰勮寮圭獥 + showFilePreview(content, fileName) { + this.previewContent = content; + this.previewTitle = fileName; + this.previewItemNo = this.selectedAttachment?.itemNo || ''; + this.previewType = this.getFileType(fileName); + this.showFilePreviewPopup = true; + }, + + // 鍏抽棴鏂囦欢棰勮寮圭獥 + closeFilePreview() { + this.showFilePreviewPopup = false; + this.previewContent = ''; + this.previewTitle = ''; + this.previewItemNo = ''; + this.previewType = ''; + }, + + // 涓嬭浇棰勮鏂囦欢 + downloadPreviewFile() { + const item = { fattach: this.previewTitle, itemNo: this.previewItemNo }; + this.downloadAttachment(item); + this.closeFilePreview(); + }, + + // 棰勮Office鏂囦欢 + previewOfficeFile(url, fileName) { + // 鍏堟鏌xcel鏂囦欢锛屼娇鐢ㄤ笓闂ㄧ殑Excel棰勮椤甸潰 + const fileExt = fileName.split('.').pop().toLowerCase(); + if (['xls', 'xlsx'].includes(fileExt)) { + // Excel鏂囦欢棰勮 + uni.request({ + url: url, + method: 'GET', + responseType: 'arraybuffer', + success: (res) => { + if (res.statusCode === 200) { + const base64Data = uni.arrayBufferToBase64(res.data); + // 瀛樺偍 Base64 鏁版嵁鍒版湰鍦板瓨鍌� + uni.setStorageSync('excelBase64Data', base64Data); + uni.navigateTo({ + url: `/pages/fileView/excelView` + }); + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + } else if (['doc', 'docx'].includes(fileExt)) { + // Word鏂囦欢锛屽皾璇曚娇鐢╓ord棰勮椤甸潰鎴栬�呭井杞湪绾块瑙� + try { + const officePreviewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`; + // 濡傛灉鏈墂ebView椤甸潰锛屼娇鐢╳ebView棰勮 + this.previewGenericFile(officePreviewUrl, fileName); + } catch (error) { + this.handlePreviewError(0, fileName, '涓嶆敮鎸佹Office鏂囦欢绫诲瀷鐨勯瑙�'); + } + } else { + // 鍏朵粬Office鏂囦欢锛屼娇鐢ㄥ井杞湪绾块瑙堟湇鍔� + const officePreviewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`; + this.previewGenericFile(officePreviewUrl, fileName); + } + }, + + // 閫氱敤鏂囦欢棰勮 + previewGenericFile(url, fileName) { + // 鐢变簬娌℃湁閫氱敤鐨剋ebView椤甸潰锛屾樉绀烘彁绀哄苟鎻愪緵涓嬭浇 + uni.showModal({ + title: '鏂囦欢棰勮', + content: `鏂囦欢 "${fileName}" 闇�瑕佷笅杞藉悗鏌ョ湅锛屾槸鍚︾珛鍗充笅杞斤紵`, + showCancel: true, + confirmText: '涓嬭浇', + cancelText: '鍙栨秷', + success: (res) => { + if (res.confirm) { + const item = { fattach: fileName, itemNo: this.selectedAttachment.itemNo }; + this.downloadAttachment(item); + } + } + }); + }, + + // 澶勭悊棰勮閿欒 + handlePreviewError(statusCode, fileName, errorMsg = '') { + let message = ''; + if (statusCode === 404) { + message = `鏂囦欢 ${fileName} 鍦‵TP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜; + } else if (statusCode === 0) { + message = `棰勮澶辫触锛�${errorMsg}`; + } else { + message = `棰勮澶辫触锛岀姸鎬佺爜锛�${statusCode}`; + } + + uni.showModal({ + title: '棰勮澶辫触', + content: message, + showCancel: true, + confirmText: '涓嬭浇', + cancelText: '鍙栨秷', + success: (res) => { + if (res.confirm) { + // 鐢ㄦ埛閫夋嫨涓嬭浇鏂囦欢 + const item = { fattach: fileName, itemNo: this.selectedAttachment.itemNo }; + this.downloadAttachment(item); + } + } + }); + }, + + downloadAttachment(item) { + // 鍘婚櫎鎵�鏈夌┖鏍笺�佸叏瑙掔┖鏍笺�佸洖杞︺�佹崲琛� + const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + // 浣跨敤閰嶇疆鐨勬湇鍔″櫒鍦板潃鍜孎TP鏈嶅姟鍣ㄥ湴鍧� + const url = this.$store.state.serverInfo.serverAPI + "/LLJ/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); + + // 妫�鏌ヨ繍琛岀幆澧� + // #ifdef H5 + // H5鐜锛氫娇鐢ㄦ祻瑙堝櫒涓嬭浇 + this.downloadFileInBrowser(url, fileName); + // #endif + + // #ifdef APP-PLUS + // APP鐜锛氫娇鐢╱ni.downloadFile + this.downloadFileInApp(url, fileName); + // #endif + + // #ifdef MP + // 灏忕▼搴忕幆澧冿細浣跨敤uni.downloadFile + this.downloadFileInApp(url, fileName); + // #endif + }, + + // 鍦ㄦ祻瑙堝櫒涓笅杞芥枃浠� + downloadFileInBrowser(url, fileName) { + uni.showLoading({ title: '姝e湪鍑嗗涓嬭浇...' }); + + // 鏂规硶1锛氬垱寤洪殣钘忕殑a鏍囩涓嬭浇 + try { + const link = document.createElement('a'); + link.href = url; + link.download = fileName; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇宸插紑濮�', + icon: 'success', + duration: 2000 + }); + } catch (error) { + console.log('a鏍囩涓嬭浇澶辫触锛屽皾璇晈indow.open鏂瑰紡:', error); + // 鏂规硶2锛氫娇鐢╳indow.open + try { + window.open(url, '_blank'); + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇宸插紑濮�', + icon: 'success', + duration: 2000 + }); + } catch (error2) { + console.log('window.open涓嬭浇澶辫触锛屽皾璇昮etch鏂瑰紡:', error2); + // 鏂规硶3锛氫娇鐢╢etch涓嬭浇 + this.downloadFileWithFetch(url, fileName); + } + } + }, + + // 浣跨敤fetch涓嬭浇鏂囦欢 + downloadFileWithFetch(url, fileName) { + fetch(url) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.blob(); + }) + .then(blob => { + // 鍒涘缓blob URL + const blobUrl = window.URL.createObjectURL(blob); + + // 鍒涘缓涓嬭浇閾炬帴 + const link = document.createElement('a'); + link.href = blobUrl; + link.download = fileName; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + // 閲婃斁blob URL + window.URL.revokeObjectURL(blobUrl); + + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇鎴愬姛', + icon: 'success', + duration: 2000 + }); + }) + .catch(error => { + console.error('Fetch涓嬭浇澶辫触:', error); + uni.hideLoading(); + if (error.message.includes('404')) { + uni.showModal({ + title: '鏂囦欢涓嶅瓨鍦�', + content: `璇ラ檮浠跺湪FTP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜, + showCancel: false + }); + } else { + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `涓嬭浇澶辫触: ${error.message}`, + showCancel: false + }); + } + }); + }, + + // 鍦ˋPP涓笅杞芥枃浠� + downloadFileInApp(url, fileName) { + // #ifdef APP-PLUS + uni.showLoading({ title: '浠嶧TP鏈嶅姟鍣ㄤ笅杞戒腑...' }); + + // Android 鑾峰彇瀛樺偍璺緞 + const saveDir = plus.os.name === 'Android' ? plus.io.convertLocalFileSystemURL('_downloads/') : plus.io.convertLocalFileSystemURL('_documents/'); + const filePath = `${saveDir}${fileName}`; + + const downloadTask = uni.downloadFile({ + url: url, + filePath: filePath, // 鎸囧畾淇濆瓨璺緞 + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + const fileInfo = { + name: fileName, + path: res.filePath || filePath, + tempPath: res.tempFilePath + }; + + uni.showModal({ + title: '涓嬭浇鎴愬姛', + content: `鏂囦欢宸蹭繚瀛樺埌锛�${fileInfo.path}`, + showCancel: true, + confirmText: '鎵撳紑鏂囦欢', + cancelText: '纭畾', + success: (modalRes) => { + if (modalRes.confirm) { + // 鐢ㄦ埛閫夋嫨鎵撳紑鏂囦欢 + this.openFileInApp(fileInfo); + } + } + }); + } else if (res.statusCode === 404) { + uni.showModal({ + title: '鏂囦欢涓嶅瓨鍦�', + content: `璇ラ檮浠跺湪FTP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜, + showCancel: false + }); + } else { + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `鐘舵�佺爜锛�${res.statusCode}`, + showCancel: false + }); + } + }, + fail: (error) => { + uni.hideLoading(); + console.error('涓嬭浇澶辫触:', error); + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `缃戠粶閿欒锛�${error.errMsg}`, + showCancel: false + }); + } + }); + + // 鐩戝惉涓嬭浇杩涘害 + downloadTask.onProgressUpdate((res) => { + const progress = Math.round(res.progress); + uni.showLoading({ + title: `涓嬭浇涓� ${progress}%`, + mask: true + }); + }); + // #endif + + // #ifdef MP + // 灏忕▼搴忕幆澧冪殑绠�鍖栧疄鐜� + uni.showLoading({ title: '涓嬭浇涓�...' }); + uni.downloadFile({ + url: url, + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + uni.showToast({ title: '涓嬭浇瀹屾垚', icon: 'success' }); + } + }, + fail: (error) => { + uni.hideLoading(); + uni.showModal({ title: '涓嬭浇澶辫触', content: error.errMsg, showCancel: false }); + } + }); + // #endif + }, + + // APP涓墦寮�鏂囦欢 + openFileInApp(fileInfo) { + // #ifdef APP-PLUS + if (typeof plus !== 'undefined') { + const filePath = fileInfo.path || fileInfo.tempPath; + + // 灏濊瘯鎵撳紑鏂囦欢 + plus.runtime.openFile(filePath, {}, (error) => { + console.error('鎵撳紑鏂囦欢澶辫触:', error); + uni.showModal({ + title: '鏃犳硶鎵撳紑', + content: '绯荤粺涓病鏈夋壘鍒拌兘鎵撳紑姝ゆ枃浠剁殑搴旂敤绋嬪簭', + showCancel: false + }); + }); + } + // #endif }, } @@ -1368,9 +1867,11 @@ font-family: 'Microsoft YaHei', 'Segoe UI', sans-serif; max-width: 1000px; margin: 0 auto; - padding: 20px; + padding: 20px 20px 160px 20px; /* 搴曢儴澧炲姞padding涓哄浐瀹氭寜閽暀绌洪棿 */ background-color: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + min-height: 100vh; + position: relative; } /* 澶撮儴鏍峰紡 */ @@ -1491,7 +1992,60 @@ background-color: #f1f5f9; } - /* 鎸夐挳鏍峰紡 */ + /* 鍥哄畾搴曢儴鎸夐挳鏍峰紡 */ + .fixed-action-buttons { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background-color: #fff; + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); + padding: 10px 15px 20px 15px; + z-index: 100; + display: flex; + flex-direction: column; + gap: 8px; + max-height: 150px; + overflow-y: auto; + } + + .action-btn { + background-color: #ecf0f1; + color: #34495e; + padding: 12px 15px; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + transition: all 0.3s ease; + text-align: center; + min-height: 44px; + display: flex; + align-items: center; + justify-content: center; + } + + .action-btn:hover { + background-color: #d5dbdb; + transform: translateY(-1px); + } + + .action-btn.primary { + background-color: #3498db; + color: #fff; + } + + .action-btn.primary:hover { + background-color: #2980b9; + } + + /* 鍐呭鍖呰鍣紝涓哄簳閮ㄦ寜閽暀鍑虹┖闂� */ + .content-wrapper { + height: 20px; /* 棰濆鐨勭┖鐧藉尯鍩� */ + } + + /* 鍘熸湁鎸夐挳鏍峰紡淇濇寔鍏煎 */ .action-buttons { display: flex; gap: 10px; @@ -1600,7 +2154,7 @@ display: flex; justify-content: center; align-items: center; - z-index: 10; + z-index: 1000; /* 鎻愰珮灞傜骇锛岀‘淇濆湪鍥哄畾鎸夐挳涓婃柟 */ } /* 寮圭獥鏁翠綋缇庡寲 */ @@ -1612,6 +2166,9 @@ border: none; position: relative; min-width: 260px; + z-index: 1001; /* 纭繚寮圭獥鍐呭鍦ㄦ渶涓婂眰 */ + max-height: 80vh; /* 闄愬埗鏈�澶ч珮搴︼紝閬垮厤琚簳閮ㄦ寜閽伄鎸� */ + overflow-y: auto; /* 鍐呭杩囧鏃跺彲婊氬姩 */ } .attachment-popup-title { font-size: 22px; @@ -1690,6 +2247,164 @@ background: linear-gradient(90deg,#bdbdbd 0%,#e0e0e0 100%); color: #1976d2; } + + /* 闄勪欢璇︽儏椤甸潰鐨勬搷浣滄寜閽� */ + .attachment-actions-detail { + margin: 20px 0; + display: flex; + gap: 12px; + justify-content: center; + flex-wrap: wrap; + } + .attachment-action-btn { + padding: 10px 20px; + border: none; + border-radius: 8px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + min-width: 120px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + .attachment-action-btn.preview-btn { + background: linear-gradient(135deg, #4CAF50, #45a049); + color: white; + } + .attachment-action-btn.preview-btn:hover { + background: linear-gradient(135deg, #45a049, #3d8b40); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); + } + .attachment-action-btn.download-btn { + background: linear-gradient(135deg, #2196F3, #1976D2); + color: white; + } + .attachment-action-btn.download-btn:hover { + background: linear-gradient(135deg, #1976D2, #1565C0); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); + } + + /* 鏂囦欢棰勮寮圭獥鏍峰紡 */ + .file-preview-popup { + width: 80vw; + max-width: 600px; + max-height: 70vh; + display: flex; + flex-direction: column; + } + + /* APP鐜閫傞厤 */ + /* #ifdef APP-PLUS */ + .file-preview-popup { + width: 85vw; + max-height: 75vh; + } + .file-preview-content { + max-height: 350px; + } + /* #endif */ + .file-preview-title { + font-size: 18px; + font-weight: 700; + color: #222; + margin-bottom: 8px; + text-align: center; + word-break: break-all; + } + .file-preview-divider { + height: 1px; + background: linear-gradient(90deg,#e0e7ef 0%,#f5f7fa 100%); + margin-bottom: 16px; + } + .file-preview-content { + flex: 1; + max-height: 400px; + overflow-y: auto; + background: #f8fafc; + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; + border: 1px solid #e2e8f0; + } + .file-preview-content pre { + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 12px; + line-height: 1.5; + color: #2d3748; + white-space: pre-wrap; + word-wrap: break-word; + margin: 0; + } + + /* 鍥剧墖棰勮鏍峰紡 */ + .image-preview-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 200px; + } + + /* 涓嶆敮鎸佹枃浠剁被鍨嬬殑鎻愮ず鏍峰紡 */ + .unsupported-preview { + text-align: center; + padding: 40px 20px; + color: #666; + } + .unsupported-icon { + font-size: 48px; + margin-bottom: 16px; + } + .unsupported-text { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 8px; + } + .unsupported-hint { + font-size: 14px; + color: #999; + line-height: 1.4; + } + + .file-preview-actions { + display: flex; + gap: 12px; + justify-content: center; + } + .file-preview-btn { + padding: 8px 20px; + border: none; + border-radius: 6px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + min-width: 120px; + } + .file-preview-btn.download-btn { + background: linear-gradient(135deg, #2196F3, #1976D2); + color: white; + } + .file-preview-btn.download-btn:hover { + background: linear-gradient(135deg, #1976D2, #1565C0); + transform: translateY(-1px); + } + .file-preview-btn.close-btn { + background: linear-gradient(135deg, #e0e0e0, #bdbdbd); + color: #444; + } + .file-preview-btn.close-btn:hover { + background: linear-gradient(135deg, #bdbdbd, #9e9e9e); + transform: translateY(-1px); + } /* 鍒楄〃寮圭獥缇庡寲锛堜繚鐣欏師鏈夛級 */ .attachment-list { padding: 0; @@ -1702,24 +2417,36 @@ display: flex; align-items: center; justify-content: space-between; - padding: 8px 0; + padding: 12px 0; border-bottom: 1px solid #f0f0f0; } - .attachment-name { + .attachment-info { flex: 1; + margin-right: 10px; + } + .attachment-name { color: #3498db; cursor: pointer; font-weight: 500; transition: color 0.2s; - margin-right: 10px; + display: block; + margin-bottom: 4px; } .attachment-name:hover { color: #217dbb; text-decoration: underline; } + .attachment-meta { + font-size: 12px; + } + .attachment-type { + color: #7f8c8d; + font-style: italic; + } .attachment-actions { display: flex; gap: 8px; + flex-shrink: 0; } .attachment-list .secondary-btn { padding: 4px 10px; @@ -1734,6 +2461,15 @@ background: #e6f0fa; color: #1976d2; } + .preview-btn { + background: #e8f5e8 !important; + color: #2e7d2e !important; + border-color: #a5d6a5 !important; + } + .preview-btn:hover { + background: #d4eecc !important; + color: #1e5f1e !important; + } .attachment-popup-close { margin-top: 18px; width: 100%; -- Gitblit v1.9.3