From 0c3ea5f8246b22ad945e4086a9507c30d6245a8b Mon Sep 17 00:00:00 2001 From: xwt <2740516069@qq.com> Date: 星期三, 03 九月 2025 14:57:14 +0800 Subject: [PATCH] 来料检排序,巡检FTP附件 --- pages/QC/XJ/Add.vue | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1,051 insertions(+), 1 deletions(-) diff --git a/pages/QC/XJ/Add.vue b/pages/QC/XJ/Add.vue index 7dbd87b..f8ba422 100644 --- a/pages/QC/XJ/Add.vue +++ b/pages/QC/XJ/Add.vue @@ -119,6 +119,8 @@ <!-- 宸叉湁鍗曟嵁鐨勬搷浣滄寜閽� --> <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="toImage">涓婁紶/鏌ョ湅鍥剧墖</button> + <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="viewAttachmentInfo">鏌ョ湅闄勪欢淇℃伅</button> + <button class="action-btn danger" v-if="!isUpdate && !formData.fcheckResu && !isShowTable && formData.fsubmit !== 1" @click="removeXJ">鍒犻櫎鍗曟嵁</button> <button class="action-btn warning" v-if="!isUpdate && !isShowTable && formData.fsubmit !== 1" @click="saveRemarks">娣诲姞涓嶅悎鏍兼弿杩�</button> @@ -146,6 +148,169 @@ </view> </view> </view> + + <!-- 闄勪欢鍒楄〃寮圭獥 --> + <view v-if="showAttachmentPopup" class="overlay"> + <view class="popup attachment-list-popup"> + <div class="attachment-popup-header"> + <h3 class="attachment-popup-title">闄勪欢鍒楄〃</h3> + <button class="attachment-close-btn" @click="closeAttachmentPopup">鍏抽棴</button> + </div> + + <div class="attachment-popup-content"> + <div v-if="attachmentsLoading" class="attachment-loading"> + <div class="loading-spinner"></div> + <span class="loading-text">姝e湪鍔犺浇闄勪欢...</span> + </div> + + <div v-else-if="attachments.length === 0" class="attachment-empty"> + <div class="empty-icon">馃搧</div> + <div class="empty-text">鏆傛棤闄勪欢</div> + <div class="empty-hint">璇ョ墿鏂欐殏鏈笂浼犱换浣曢檮浠�</div> + </div> + + <div v-else class="attachment-list"> + <div v-for="item in attachments" :key="item.id" class="attachment-item"> + <div class="attachment-info"> + <div class="file-type-badge" :class="getFileTypeClass(item.fattach)"> + {{ getFileTypeIcon(item.fattach) }} + </div> + <div class="attachment-details"> + <div class="attachment-name" @click="showAttachmentDetailDialog(item)"> + {{ item.fattach }} + </div> + <div class="attachment-meta"> + <span class="meta-type">{{ item.ftype || '鏈煡绫诲瀷' }}</span> + <span v-if="item.fversion" class="meta-version">v{{ item.fversion }}</span> + <span v-if="item.fdate" class="meta-date">{{ formatDate(item.fdate) }}</span> + </div> + </div> + </div> + + <div class="attachment-actions"> + <button class="btn-secondary" @click="showAttachmentDetailDialog(item)">璇︽儏</button> + <button v-if="isPreviewable(item.fattach)" + class="btn-primary" + @click="previewFtpFile(item)">棰勮</button> + <button class="btn-success" @click="downloadAttachment(item)">涓嬭浇</button> + </div> + </div> + </div> + </div> + </view> + </view> + + <!-- 闄勪欢璇︽儏寮圭獥 --> + <view v-if="showAttachmentDetail" class="overlay"> + <view class="popup attachment-detail-popup"> + <div class="attachment-popup-header"> + <h3 class="attachment-popup-title">闄勪欢璇︽儏</h3> + <button class="attachment-close-btn" @click="closeAttachmentDetail">杩斿洖</button> + </div> + + <div class="attachment-popup-content"> + <div v-if="selectedAttachment" class="attachment-detail-content"> + <div class="attachment-detail-header"> + <div class="file-type-badge large" :class="getFileTypeClass(selectedAttachment.fattach)"> + {{ getFileTypeIcon(selectedAttachment.fattach) }} + </div> + <div class="attachment-detail-title"> + {{ selectedAttachment.fattach }} + </div> + </div> + + <div class="attachment-detail-info"> + <div class="info-row"> + <div class="info-item"> + <text class="info-label">ID</text> + <text class="info-content">{{ Math.trunc(selectedAttachment.id) }}</text> + </div> + <div class="info-item"> + <text class="info-label">绫诲瀷</text> + <text class="info-content">{{ selectedAttachment.ftype || '鏈煡绫诲瀷' }}</text> + </div> + </div> + + <div class="info-row" v-if="selectedAttachment.fversion"> + <div class="info-item"> + <text class="info-label">鐗堟湰</text> + <text class="info-content">{{ selectedAttachment.fversion }}</text> + </div> + <div class="info-item" v-if="selectedAttachment.fdate"> + <text class="info-label">鍙楁帶鏃ユ湡</text> + <text class="info-content">{{ formatDate(selectedAttachment.fdate) }}</text> + </div> + </div> + + <div class="info-row" v-if="selectedAttachment.createBy"> + <div class="info-item"> + <text class="info-label">涓婁紶浜�</text> + <text class="info-content">{{ selectedAttachment.createBy }}</text> + </div> + <div class="info-item" v-if="selectedAttachment.createDate"> + <text class="info-label">涓婁紶鏃堕棿</text> + <text class="info-content">{{ formatDate(selectedAttachment.createDate) }}</text> + </div> + </div> + </div> + + <div class="attachment-detail-actions"> + <button v-if="isPreviewable(selectedAttachment.fattach)" + class="btn-primary" + @click="previewFtpFile(selectedAttachment)">棰勮</button> + <button class="btn-success" @click="downloadAttachment(selectedAttachment)">涓嬭浇</button> + </div> + </div> + <div v-else class="attachment-detail-empty"> + <div class="empty-icon">鉂�</div> + <div class="empty-text">鏆傛棤闄勪欢淇℃伅</div> + </div> + </div> + </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="aspectFit" + class="preview-image-clickable" + @click="previewImageInPopup" + style="width: 100%; max-height: 400px; cursor: pointer;" + /> + <div class="image-zoom-hint">鐐瑰嚮鍥剧墖鍙斁澶ф煡鐪�</div> + </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> </template> @@ -203,6 +368,19 @@ departmentList: [], selectedDepartment: '', WORKSHOP: '', + + // 闄勪欢鐩稿叧鏁版嵁 + showAttachmentPopup: false, + showAttachmentDetail: false, + showFilePreviewPopup: false, + attachments: [], + attachmentsLoading: false, + selectedAttachment: null, + previewTitle: '', + previewContent: '', + previewType: '', + previewFileUrl: '' + }; }, onLoad(options) { @@ -216,6 +394,13 @@ this.formData.releaseNo = params["releaseNo"]; //getQaItemXj02 this.init(); + + // 濡傛灉鏄粠鍒楄〃椤甸潰鐐瑰嚮鏌ョ湅闄勪欢鎸夐挳璺宠浆杩囨潵鐨勶紝鑷姩鎵撳紑闄勪欢寮圭獥 + if (params["showAttachments"] === "true") { + this.$nextTick(() => { + this.viewAttachmentInfo(); + }); + } } else { //鍒濆鍖栨楠屽崟鍙� this.$post({ @@ -647,7 +832,233 @@ this.$showMessage(res.data.message || "鑾峰彇澶辫触"); } }); - } + }, + + // 闄勪欢鐩稿叧鏂规硶 + viewAttachmentInfo() { + this.showAttachmentPopup = true; + this.attachmentsLoading = true; + this.attachments = []; + this.$post({ + url: "/XJ/getAttachments", + data: { itemNo: this.formData.itemNo } + }).then(res => { + 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 { + uni.showToast({ title: "鑾峰彇闄勪欢澶辫触", icon: "none" }); + } + }); + }, + + closeAttachmentPopup() { + this.showAttachmentPopup = false; + }, + + showAttachmentDetailDialog(item) { + this.selectedAttachment = item; + this.showAttachmentPopup = false; + this.showAttachmentDetail = true; + }, + + closeAttachmentDetail() { + this.showAttachmentDetail = false; + this.selectedAttachment = null; + this.showAttachmentPopup = true; + }, + + isPreviewable(filename) { + if (!filename) return false; + const ext = filename.trim().split('.').pop().toLowerCase(); + return [ + 'pdf', + 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', + 'txt', 'log', 'md', + 'doc', 'docx', + 'xls', 'xlsx', + 'ppt', 'pptx', + 'csv' + ].includes(ext); + }, + + // 鑾峰彇鏂囦欢绫诲瀷鍥炬爣 + getFileTypeIcon(filename) { + if (!filename) return '馃搫'; + const ext = filename.trim().split('.').pop().toLowerCase(); + const iconMap = { + 'pdf': '馃摃', + 'jpg': '馃柤锔�', 'jpeg': '馃柤锔�', 'png': '馃柤锔�', 'gif': '馃柤锔�', 'bmp': '馃柤锔�', 'webp': '馃柤锔�', + 'txt': '馃摑', 'log': '馃摑', 'md': '馃摑', + 'doc': '馃摌', 'docx': '馃摌', + 'xls': '馃搳', 'xlsx': '馃搳', + 'ppt': '馃摍', 'pptx': '馃摍', + 'csv': '馃搳', + 'zip': '馃摝', 'rar': '馃摝', '7z': '馃摝', + 'dwg': '馃彈锔�', 'dxf': '馃彈锔�' + }; + return iconMap[ext] || '馃搫'; + }, + + // 鑾峰彇鏂囦欢绫诲瀷CSS绫� + getFileTypeClass(filename) { + if (!filename) return 'file-unknown'; + const ext = filename.trim().split('.').pop().toLowerCase(); + const classMap = { + 'pdf': 'file-pdf', + 'jpg': 'file-image', 'jpeg': 'file-image', 'png': 'file-image', 'gif': 'file-image', 'bmp': 'file-image', 'webp': 'file-image', + 'txt': 'file-text', 'log': 'file-text', 'md': 'file-text', + 'doc': 'file-word', 'docx': 'file-word', + 'xls': 'file-excel', 'xlsx': 'file-excel', + 'ppt': 'file-powerpoint', 'pptx': 'file-powerpoint', + 'csv': 'file-excel', + 'zip': 'file-archive', 'rar': 'file-archive', '7z': 'file-archive', + 'dwg': 'file-cad', 'dxf': 'file-cad' + }; + return classMap[ext] || 'file-unknown'; + }, + + // 鏍煎紡鍖栨棩鏈� + formatDate(dateString) { + if (!dateString) return ''; + try { + const date = new Date(dateString); + return date.toLocaleDateString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit' + }); + } catch (e) { + return dateString; + } + }, + + downloadAttachment(item) { + const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + const downloadUrl = this.$store.state.serverInfo.serverAPI + "/XJ/DownloadFtpFile?itemNo=" + + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); + + uni.downloadFile({ + url: downloadUrl, + success: (res) => { + if (res.statusCode === 200) { + uni.showToast({ title: '涓嬭浇鎴愬姛', icon: 'success' }); + } else { + uni.showToast({ title: '涓嬭浇澶辫触', icon: 'none' }); + } + }, + fail: (err) => { + console.error('涓嬭浇澶辫触锛�', err); + uni.showToast({ title: '涓嬭浇澶辫触锛岃閲嶈瘯', icon: 'none' }); + } + }); + }, + + previewFtpFile(item) { + const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + const fileExt = fileName.split('.').pop().toLowerCase(); + + if (!this.isPreviewable(fileName)) { + uni.showModal({ + title: '涓嶆敮鎸侀瑙�', + content: '璇ユ枃浠剁被鍨嬩笉鏀寔鍦ㄧ嚎棰勮锛岃涓嬭浇鍚庢煡鐪�', + showCancel: false + }); + return; + } + + const previewUrl = this.$store.state.serverInfo.serverAPI + "/XJ/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 { + this.previewOfficeFile(previewUrl, fileName); + } + }, + + previewPdfFile(url, fileName) { + this.previewTitle = fileName; + this.previewContent = url; + this.previewType = 'pdf'; + this.previewFileUrl = url; + this.showFilePreviewPopup = true; + this.showAttachmentDetail = false; + }, + + previewImageFile(url, fileName) { + this.previewTitle = fileName; + this.previewContent = url; + this.previewType = 'image'; + this.previewFileUrl = url; + this.showFilePreviewPopup = true; + this.showAttachmentDetail = false; + }, + + previewTextFile(url, fileName) { + this.previewTitle = fileName; + this.previewType = 'text'; + this.previewFileUrl = url; + this.showFilePreviewPopup = true; + this.showAttachmentDetail = false; + + uni.request({ + url: url, + method: 'GET', + success: (res) => { + this.previewContent = res.data; + }, + fail: (err) => { + this.previewContent = '棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�'; + } + }); + }, + + previewOfficeFile(url, fileName) { + this.previewTitle = fileName; + this.previewContent = ''; + this.previewType = 'excel'; + this.previewFileUrl = url; + this.showFilePreviewPopup = true; + this.showAttachmentDetail = false; + }, + + closeFilePreview() { + this.showFilePreviewPopup = false; + this.showAttachmentDetail = true; + }, + + downloadPreviewFile() { + if (this.previewFileUrl && this.selectedAttachment) { + this.downloadAttachment(this.selectedAttachment); + } + }, + + previewImageInPopup() { + // 鍦ㄦ柊绐楀彛涓墦寮�鍥剧墖杩涜鏀惧ぇ鏌ョ湅 + if (this.previewContent) { + uni.previewImage({ + urls: [this.previewContent], + current: this.previewContent + }); + } + } + }, onShow() { //姣忔杩涘叆椤甸潰閮戒細鎵ц鐨勬柟娉� @@ -897,6 +1308,16 @@ color: white; } + .action-btn.info { + background-color: #17a2b8; + color: white; + } + + .action-btn.small { + padding: 6px 12px; + font-size: 12px; + } + /* 寮瑰嚭妗嗘牱寮� */ .overlay { position: fixed; @@ -957,6 +1378,56 @@ background-color: white; } + /* 闄勪欢鐩稿叧鏍峰紡 */ + .no-attachments { + text-align: center; + padding: 40px 20px; + color: #7f8c8d; + } + + .attachments-list { + max-height: 400px; + overflow-y: auto; + } + + .attachment-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px; + border: 1px solid #eee; + border-radius: 4px; + margin-bottom: 8px; + background-color: #f8f9fa; + } + + .attachment-info { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + } + + .attachment-name { + font-weight: 500; + color: #2c3e50; + } + + .attachment-type { + font-size: 12px; + color: #7f8c8d; + } + + .attachment-date { + font-size: 12px; + color: #95a5a6; + } + + .attachment-actions { + display: flex; + gap: 8px; + } + .popup-actions { padding: 20px; border-top: 1px solid #eee; @@ -965,6 +1436,504 @@ justify-content: flex-end; } + /* 闄勪欢寮圭獥鏍峰紡 */ + .attachment-list { + padding: 0; + margin: 0; + list-style: none; + max-height: 300px; + overflow-y: auto; + } + + .attachment-list li { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 0; + border-bottom: 1px solid #f0f0f0; + } + + .attachment-info { + flex: 1; + margin-right: 10px; + } + + .attachment-name { + color: #3498db; + cursor: pointer; + font-weight: 500; + transition: color 0.2s; + 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; + font-size: 13px; + border-radius: 3px; + background: #f5f7fa; + color: #333; + border: 1px solid #dbe2ea; + transition: background 0.2s, color 0.2s; + } + + .attachment-list .secondary-btn:hover { + 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-list-popup { + width: 80vw; + max-width: 800px; + max-height: 85vh; + } + + .attachment-detail-popup { + width: 70vw; + max-width: 600px; + } + + .attachment-popup-header { + padding: 16px; + border-bottom: 1px solid #eee; + display: flex; + justify-content: space-between; + align-items: center; + background-color: white; + } + + .attachment-popup-title { + font-size: 16px; + font-weight: 600; + color: #2c3e50; + margin: 0; + } + + .attachment-close-btn { + padding: 8px 16px; + border: 1px solid #ddd; + border-radius: 4px; + background-color: white; + font-size: 14px; + transition: all 0.2s; + color: #2c3e50; + } + + .attachment-close-btn:hover { + background-color: #f8f9fa; + } + + .attachment-popup-content { + padding: 16px; + max-height: 60vh; + overflow-y: auto; + } + + /* 鍔犺浇鐘舵�� */ + .attachment-loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 20px; + gap: 16px; + } + + .loading-spinner { + width: 32px; + height: 32px; + border: 3px solid #f3f3f3; + border-top: 3px solid #3498db; + border-radius: 50%; + animation: spin 1s linear infinite; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + .loading-text { + font-size: 14px; + color: #7f8c8d; + } + + /* 绌虹姸鎬� */ + .attachment-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 20px; + gap: 12px; + text-align: center; + } + + .empty-icon { + font-size: 36px; + opacity: 0.6; + } + + .empty-text { + font-size: 16px; + color: #7f8c8d; + font-weight: 500; + } + + .empty-hint { + font-size: 14px; + color: #95a5a6; + } + + /* 闄勪欢鍒楄〃甯冨眬 - 鎸夌収LLJ鐨勫崱鐗囬鏍� */ + .attachment-list { + display: flex; + flex-direction: column; + gap: 16px; + } + + .attachment-item { + background-color: white; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); + overflow: hidden; + transition: all 0.3s; + border: 1px solid #eee; + } + + .attachment-item:hover { + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); + } + + .attachment-info { + padding: 16px; + border-bottom: 1px solid #eee; + display: flex; + align-items: center; + gap: 16px; + } + + .file-type-badge { + width: 40px; + height: 40px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + background: #f8f9fa; + border: 2px solid #e9ecef; + flex-shrink: 0; + } + + .file-type-badge.large { + width: 56px; + height: 56px; + font-size: 28px; + } + + .file-type-badge.file-pdf { background: #ffe6e6; border-color: #ffcccc; } + .file-type-badge.file-image { background: #e6f3ff; border-color: #cce7ff; } + .file-type-badge.file-text { background: #e6ffe6; border-color: #ccffcc; } + .file-type-badge.file-word { background: #e6f0ff; border-color: #cce0ff; } + .file-type-badge.file-excel { background: #e6ffe6; border-color: #ccffcc; } + .file-type-badge.file-powerpoint { background: #fff0e6; border-color: #ffe0cc; } + .file-type-badge.file-archive { background: #f0e6ff; border-color: #e0ccff; } + .file-type-badge.file-cad { background: #e6fff0; border-color: #ccffe0; } + .file-type-badge.file-unknown { background: #f5f5f5; border-color: #e0e0e0; } + + .attachment-details { + flex: 1; + min-width: 0; + } + + .attachment-name { + font-size: 16px; + font-weight: 600; + color: #2c3e50; + cursor: pointer; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-bottom: 8px; + transition: color 0.2s; + } + + .attachment-name:hover { + color: #3498db; + } + + .attachment-card-body { + padding: 16px 20px 20px; + } + + .attachment-meta { + display: flex; + gap: 16px; + font-size: 12px; + color: #95a5a6; + } + + .meta-type { + background-color: #ecf0f1; + padding: 2px 6px; + border-radius: 10px; + color: #7f8c8d; + } + + .meta-version { + background-color: #e8f5e8; + padding: 2px 6px; + border-radius: 10px; + color: #2e7d32; + } + + .meta-date { + background-color: #fff3e0; + padding: 2px 6px; + border-radius: 10px; + color: #f57c00; + } + + .attachment-actions { + padding: 12px 16px; + border-top: 1px solid #eee; + display: flex; + gap: 8px; + background-color: #f8f9fa; + } + + /* 鎸夐挳鏍峰紡 - 鎸夌収LLJ椋庢牸 */ + .btn-secondary { + padding: 8px 16px; + border: 1px solid #ddd; + border-radius: 4px; + background-color: white; + font-size: 14px; + transition: all 0.2s; + color: #2c3e50; + flex: 1; + } + + .btn-secondary:hover { + background-color: #f8f9fa; + } + + .btn-primary { + padding: 8px 16px; + border: 1px solid #3498db; + border-radius: 4px; + background-color: #3498db; + color: white; + font-size: 14px; + transition: all 0.2s; + flex: 1; + } + + .btn-primary:hover { + background-color: #2980b9; + } + + .btn-success { + padding: 8px 16px; + border: 1px solid #2ecc71; + border-radius: 4px; + background-color: #2ecc71; + color: white; + font-size: 14px; + transition: all 0.2s; + flex: 1; + } + + .btn-success:hover { + background-color: #27ae60; + } + + + + /* 闄勪欢璇︽儏鏍峰紡 */ + .attachment-detail-header { + display: flex; + align-items: center; + gap: 20px; + margin-bottom: 20px; + padding-bottom: 16px; + border-bottom: 1px solid #eee; + } + + .attachment-detail-title { + font-size: 18px; + font-weight: 600; + color: #2c3e50; + flex: 1; + word-break: break-all; + } + + .attachment-detail-info { + margin-bottom: 20px; + } + + .info-row { + display: flex; + margin-bottom: 12px; + gap: 16px; + } + + .info-item { + flex: 1; + } + + .info-label { + display: block; + font-size: 12px; + color: #7f8c8d; + margin-bottom: 4px; + } + + .info-content { + font-size: 14px; + color: #2c3e50; + line-height: 1.5; + } + + .attachment-detail-actions { + padding: 12px 16px; + border-top: 1px solid #eee; + display: flex; + gap: 8px; + background-color: #f8f9fa; + } + + /* 鏂囦欢棰勮寮圭獥鏍峰紡 */ + .file-preview-popup { + width: 80vw; + max-width: 800px; + max-height: 80vh; + } + + .file-preview-title { + padding: 20px; + margin: 0; + font-size: 16px; + font-weight: 600; + color: #2c3e50; + border-bottom: 1px solid #eee; + word-break: break-all; + } + + .file-preview-content { + padding: 20px; + max-height: 60vh; + overflow-y: auto; + } + + .file-preview-content pre { + white-space: pre-wrap; + word-wrap: break-word; + font-family: 'Courier New', monospace; + font-size: 12px; + line-height: 1.4; + background: #f8f9fa; + padding: 15px; + border-radius: 4px; + border: 1px solid #e9ecef; + } + + .image-preview-container { + text-align: center; + } + + .image-zoom-hint { + margin-top: 10px; + font-size: 12px; + color: #7f8c8d; + } + + .unsupported-preview { + text-align: center; + padding: 40px 20px; + } + + .unsupported-icon { + font-size: 48px; + margin-bottom: 16px; + } + + .unsupported-text { + font-size: 16px; + color: #7f8c8d; + margin-bottom: 8px; + } + + .unsupported-hint { + font-size: 14px; + color: #95a5a6; + } + + .file-preview-actions { + padding: 15px 20px; + border-top: 1px solid #eee; + display: flex; + gap: 10px; + justify-content: center; + } + + .file-preview-btn { + padding: 8px 16px; + border-radius: 4px; + border: none; + font-size: 14px; + cursor: pointer; + transition: all 0.2s; + } + + .file-preview-btn.download-btn { + background: #2ecc71; + color: white; + } + + .file-preview-btn.close-btn { + background: #95a5a6; + color: white; + } + + .file-preview-btn:hover { + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + } + /* 鍝嶅簲寮忚璁� */ @media (max-width: 768px) { .info-grid { @@ -974,5 +1943,86 @@ .action-buttons { flex-direction: column; } + + /* 闄勪欢寮圭獥鍝嶅簲寮� */ + .attachment-list-popup { + width: 95vw; + margin: 10px; + } + + .attachment-detail-popup { + width: 95vw; + margin: 10px; + } + + .file-preview-popup { + width: 95vw; + } + + .attachment-grid { + grid-template-columns: 1fr; + gap: 16px; + } + + .attachment-card { + margin: 0; + } + + .attachment-card-actions { + flex-direction: column; + gap: 8px; + } + + .action-btn { + width: 100%; + justify-content: center; + } + + .attachment-detail-actions { + flex-direction: column; + gap: 12px; + } + + .detail-action-btn { + width: 100%; + } + + .attachment-popup-header { + padding: 16px 20px; + } + + .attachment-popup-title { + font-size: 18px; + } + + .attachment-icon { + font-size: 20px; + } + } + + @media (max-width: 480px) { + .attachment-popup-content { + padding: 16px; + } + + .attachment-card-header { + padding: 16px 16px 12px; + } + + .attachment-card-body { + padding: 12px 16px 16px; + } + + .file-type-icon { + width: 40px; + height: 40px; + font-size: 20px; + } + + .file-type-icon.large { + width: 56px; + height: 56px; + font-size: 28px; + } } </style> \ No newline at end of file -- Gitblit v1.9.3