| manifest.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/BasePages/main.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/BasePages/user.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/LLJ/Add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/LLJ/detail.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/RKJ/Add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/RKJ/List.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/SJ/Add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/SJ/List.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/XJ/Add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/QC/XJ/List.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| store/index.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
manifest.json
@@ -2,7 +2,7 @@ "name" : "GS-MES-AP", "appid" : "__UNI__F08FAE3", "description" : "", "versionName" : "1.1.4.1", "versionName" : "1.1.4.2", "versionCode" : 1, "transformPx" : false, /* 5+App特有相关 */ pages/BasePages/main.vue
@@ -1,7 +1,7 @@ <template> <uni-base-page :footer="false"> <view slot="page"> <view v-if="loginInfo.hasLogin"> <view v-if="loginInfo.hasLogin" class="main-container"> <!-- 教学视频、公司内部宣传图片等 --> <!-- <swiper indicator-dots="true" :autoplay="true" :interval="3000">--> <!-- <swiper-item v-for="(img,key) in imgUrls" :key="key">--> @@ -10,6 +10,51 @@ <!-- </swiper>--> <!-- 通报批评、消息预警、公告、报告 --> <uni-notice-bar :show-icon="true" :scrollable="true" :speed="30" :single="true" :text="msg" /> <!-- 筛选按钮 --> <view class="filter-btn" @click="toggleFilter"> <uni-icons type="funnel-fill" size="20" color="#fff"></uni-icons> <text class="filter-btn-text">筛选</text> <view v-if="selectedDepartmentId || selectedLineId" class="filter-badge"></view> </view> <!-- 筛选弹出层 --> <view v-if="showFilter" class="filter-overlay" @click="closeFilter"> <view class="filter-panel" @click.stop> <view class="filter-header"> <text class="filter-title">筛选条件</text> <view class="close-icon" @click="closeFilter"> <uni-icons type="close" size="20" color="#666"></uni-icons> </view> </view> <view class="filter-content"> <view class="filter-row"> <text class="filter-label">车间</text> <picker @change="onDepartmentChange" :value="departmentIndex" :range="departments" range-key="departmentname" class="filter-picker"> <view class="picker-text"> {{departmentIndex >= 0 ? departments[departmentIndex].departmentname : '请选择车间'}} </view> </picker> </view> <view class="filter-row"> <text class="filter-label">线体</text> <picker @change="onLineChange" :value="lineIndex" :range="lines" range-key="lineName" :disabled="!selectedDepartmentId" class="filter-picker"> <view class="picker-text" :class="{'disabled': !selectedDepartmentId}"> {{lineIndex >= 0 ? lines[lineIndex].lineName : selectedDepartmentId ? '请选择线体' : '请先选择车间'}} </view> </picker> </view> </view> <view class="filter-footer"> <button class="reset-btn" @click="clearFilters">清空</button> <button class="confirm-btn" @click="closeFilter">确定</button> </view> </view> </view> <!-- 用户系统菜单模块 --> <view class="example-body"> <uni-grid :column="col" :showBorder="false"> @@ -54,11 +99,153 @@ ], col: 4, //菜单列数 msg: "宁波广深科技有限公司", updateChecked: false updateChecked: false, // 车间和线体筛选相关数据 departments: [], departmentIndex: -1, selectedDepartmentId: '', lines: [], lineIndex: -1, selectedLineId: '', showFilter: false // 控制筛选面板显示 }; }, methods: { // 切换筛选面板显示 toggleFilter() { this.showFilter = !this.showFilter; }, // 关闭筛选面板 closeFilter() { this.showFilter = false; }, // 获取车间列表 getDepartments() { this.$post({ url: "/Base/GetQCDepartments", data: {} }).then(res => { this.departments = res.data || []; // 从缓存中恢复选择 const cachedDeptId = uni.getStorageSync('qc_filter_departmentId'); if (cachedDeptId && this.departments.length > 0) { const index = this.departments.findIndex(d => d.departmentid == cachedDeptId); if (index >= 0) { this.departmentIndex = index; this.selectedDepartmentId = cachedDeptId; this.getLines(); } } }).catch(err => { console.error('获取车间列表失败:', err); }); }, // 获取线体列表(根据车间过滤) getLines() { if (!this.selectedDepartmentId) { this.lines = []; return; } this.$post({ url: "/Base/GetQCLines", data: { departmentId: this.selectedDepartmentId } }).then(res => { this.lines = res.data || []; // 从缓存中恢复选择 const cachedLineId = uni.getStorageSync('qc_filter_lineId'); if (cachedLineId && this.lines.length > 0) { const index = this.lines.findIndex(l => l.lineNo == cachedLineId); if (index >= 0) { this.lineIndex = index; this.selectedLineId = cachedLineId; } else { // 如果缓存的线体不在当前车间下,清除线体选择 this.lineIndex = -1; this.selectedLineId = ''; uni.removeStorageSync('qc_filter_lineId'); uni.removeStorageSync('qc_filter_lineName'); } } }).catch(err => { console.error('获取线体列表失败:', err); }); }, // 车间选择改变 onDepartmentChange(e) { const index = parseInt(e.detail.value); this.departmentIndex = index; if (index >= 0 && this.departments[index]) { this.selectedDepartmentId = this.departments[index].departmentid; const departmentName = this.departments[index].departmentname; // 保存到缓存 uni.setStorageSync('qc_filter_departmentId', this.selectedDepartmentId); uni.setStorageSync('qc_filter_departmentName', departmentName); // 清除线体选择 this.lineIndex = -1; this.selectedLineId = ''; uni.removeStorageSync('qc_filter_lineId'); uni.removeStorageSync('qc_filter_lineName'); // 加载该车间下的线体 this.getLines(); uni.showToast({ title: `已选择车间:${departmentName}`, icon: 'none' }); } }, // 线体选择改变 onLineChange(e) { const index = parseInt(e.detail.value); this.lineIndex = index; if (index >= 0 && this.lines[index]) { this.selectedLineId = this.lines[index].lineNo; const lineName = this.lines[index].lineName; // 保存到缓存 uni.setStorageSync('qc_filter_lineId', this.selectedLineId); uni.setStorageSync('qc_filter_lineName', lineName); uni.showToast({ title: `已选择线体:${lineName}`, icon: 'none' }); } }, // 清空筛选条件 clearFilters() { this.departmentIndex = -1; this.selectedDepartmentId = ''; this.lineIndex = -1; this.selectedLineId = ''; this.lines = []; // 清除缓存 uni.removeStorageSync('qc_filter_departmentId'); uni.removeStorageSync('qc_filter_departmentName'); uni.removeStorageSync('qc_filter_lineId'); uni.removeStorageSync('qc_filter_lineName'); uni.showToast({ title: '已清空筛选条件', icon: 'success' }); }, getMenu(isShowMask) { if (isShowMask) uni.showLoading({ mask: true, @@ -199,12 +386,26 @@ this.getMenu(true); this.checkForUpdate(); this.getDepartments(); // 加载车间列表 } }, onShow() { // this.getIsMsg(); // 每次显示页面时恢复筛选条件显示 if (this.loginInfo.hasLogin && this.departments.length === 0) { this.getDepartments(); } // 检查缓存的筛选条件,如果不存在则重置UI状态 const cachedDeptId = uni.getStorageSync('qc_filter_departmentId'); if (!cachedDeptId) { this.departmentIndex = -1; this.selectedDepartmentId = ''; this.lineIndex = -1; this.selectedLineId = ''; this.lines = []; } }, onPullDownRefresh() { if (this.loginInfo.hasLogin) @@ -268,4 +469,160 @@ flex-direction: row; justify-content: flex-start; } .main-container { position: relative; } /* 筛选按钮样式 */ .filter-btn { position: fixed; top: 20rpx; right: 20rpx; z-index: 1000; display: flex; align-items: center; gap: 8rpx; padding: 12rpx 24rpx; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 50rpx; box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4); } .filter-btn-text { font-size: 24rpx; color: #fff; font-weight: 600; } .filter-badge { position: absolute; top: 4rpx; right: 4rpx; width: 16rpx; height: 16rpx; background-color: #ff4757; border-radius: 50%; border: 2rpx solid #fff; } /* 筛选弹出层 */ .filter-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); z-index: 999; display: flex; align-items: flex-start; justify-content: flex-end; padding: 80rpx 20rpx 20rpx 20rpx; } .filter-panel { width: 500rpx; max-width: 90%; background-color: #fff; border-radius: 16rpx; box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2); animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } .filter-header { display: flex; align-items: center; justify-content: space-between; padding: 24rpx 28rpx; border-bottom: 1rpx solid #f0f0f0; } .filter-title { font-size: 32rpx; font-weight: 700; color: #333; } .close-icon { padding: 8rpx; } .filter-content { padding: 32rpx 28rpx; } .filter-row { margin-bottom: 32rpx; } .filter-row:last-child { margin-bottom: 0; } .filter-label { display: block; font-size: 28rpx; color: #666; margin-bottom: 16rpx; font-weight: 600; } .filter-picker { width: 100%; } .picker-text { padding: 20rpx 24rpx; background-color: #f8f9ff; border-radius: 12rpx; border: 2rpx solid #e0e5ff; font-size: 28rpx; color: #333; text-align: left; } .picker-text.disabled { background-color: #f5f5f5; color: #999; border-color: #e5e5e5; } .filter-footer { display: flex; gap: 16rpx; padding: 24rpx 28rpx; border-top: 1rpx solid #f0f0f0; } .reset-btn, .confirm-btn { flex: 1; padding: 20rpx; border-radius: 12rpx; font-size: 28rpx; font-weight: 600; border: none; } .reset-btn { background-color: #f5f5f5; color: #666; } .confirm-btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; } </style> pages/BasePages/user.vue
@@ -46,6 +46,13 @@ } }); // 清除QC筛选条件 uni.removeStorageSync('qc_filter_departmentId'); uni.removeStorageSync('qc_filter_departmentName'); uni.removeStorageSync('qc_filter_lineId'); uni.removeStorageSync('qc_filter_lineName'); /** * 如果需要强制登录跳转回登录页面 */ pages/QC/LLJ/Add.vue
@@ -373,57 +373,119 @@ <!-- 附件详情弹窗 --> <view v-if="showAttachmentDetail" class="overlay"> <view class="popup attachment-detail-popup"> <h3 class="attachment-popup-title">附件详情</h3> <div class="attachment-popup-divider"></div> <div v-if="selectedAttachment" class="attachment-detail-content"> <div class="attachment-detail-row"><span class="attachment-label">ID:</span><span>{{ Math.trunc(selectedAttachment.id) }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">附件名:</span><span>{{ selectedAttachment.fattach }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">类型:</span><span>{{ selectedAttachment.ftype }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">版本:</span><span>{{ selectedAttachment.fversion }}</span></div> <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 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 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> <div v-else class="attachment-detail-empty">暂无附件信息</div> <button class="attachment-popup-close" @click="closeAttachmentDetail">返回附件列表</button> </view> </view> <!-- 附件列表弹窗 --> <view v-if="showAttachmentPopup" class="overlay"> <view class="popup" style="width: 60vw; max-width: 500px;"> <h3>附件列表</h3> <div v-if="attachmentsLoading">加载中...</div> <div v-else-if="attachments.length === 0">暂无附件</div> <ul class="attachment-list" v-else> <li v-for="item in attachments" :key="item.id"> <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> <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">正在加载附件...</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 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> </div> </div> </view> </view> @@ -516,7 +578,7 @@ WORKSHOP: '', REMARK: '', // picker 选项和索引 badreasonOptions: ['', '外观不良', '尺寸不良', '包装不良', '性能不良', '装配不良', '安规不良'], badreasonOptions: ['', '外观不良', '尺寸不良', '包装不良', '性能不良', '装配不良', '安规不良','图纸不良'], badreasonIndex: 0, workshopOptions: ['', '生产一部', '生产二部', '注塑车间', '其他'], workshopIndex: 0, @@ -771,7 +833,11 @@ // 统一推送给HMCS,不管哪个账号 this.QcIssueResultDetailes = { fbatchQty: this.formData.fcovertQty, itemName: this.formData.itemName, itemName: (() => { const combined = `${this.formData.itemName || ''} ${this.formData.itemModel || ''}`.trim(); // 截断处理:超过1000字符保留前1000位 return combined.length > 1000 ? combined.substring(0, 1000) : combined; })(), itemNo: this.formData.itemNo, suppName: this.formData.suppName, appicationReason: this.formData.fngDesc, @@ -2198,6 +2264,59 @@ 'csv' // 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; } }, // 处理附件下载错误 handleAttachmentError(item) { uni.showModal({ @@ -3240,7 +3359,7 @@ } /* 弹窗整体美化 */ .popup, .attachment-detail-popup { .popup { background: #fff; border-radius: 16px; box-shadow: 0 8px 32px rgba(60,60,60,0.18); @@ -3252,123 +3371,9 @@ max-height: 80vh; /* 限制最大高度,避免被底部按钮遮挡 */ overflow-y: auto; /* 内容过多时可滚动 */ } .attachment-popup-title { font-size: 22px; font-weight: 700; color: #222; margin-bottom: 8px; letter-spacing: 1px; text-align: center; } .attachment-popup-divider { height: 1px; background: linear-gradient(90deg,#e0e7ef 0%,#f5f7fa 100%); margin-bottom: 18px; } .attachment-detail-content { margin-bottom: 18px; } .attachment-detail-row { display: flex; align-items: center; margin-bottom: 8px; font-size: 15px; } .attachment-label { min-width: 80px; color: #1976d2; font-weight: 500; margin-right: 8px; } .attachment-preview-area { margin: 18px 0 8px 0; border-radius: 10px; background: #f8fafc; padding: 10px; box-shadow: 0 2px 8px rgba(60,60,60,0.06); } .attachment-download-area { margin: 18px 0 8px 0; text-align: center; } .attachment-download-link { display: inline-block; padding: 7px 18px; background: linear-gradient(90deg,#4f8cff 0%,#1976d2 100%); color: #fff; border-radius: 6px; font-weight: 500; text-decoration: none; transition: background 0.2s; box-shadow: 0 2px 8px rgba(60,60,60,0.08); } .attachment-download-link:hover { background: linear-gradient(90deg,#1976d2 0%,#4f8cff 100%); } .attachment-detail-empty { color: #888; text-align: center; margin: 30px 0; font-size: 16px; } .attachment-popup-close { margin-top: 18px; width: 100%; background: linear-gradient(90deg,#e0e0e0 0%,#f5f7fa 100%); color: #444; border-radius: 8px; font-size: 16px; padding: 10px 0; border: none; font-weight: 600; letter-spacing: 1px; transition: background 0.2s, color 0.2s; box-shadow: 0 2px 8px rgba(60,60,60,0.06); } .attachment-popup-close:hover { 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); } /* 文件预览弹窗样式 */ @@ -3487,84 +3492,321 @@ background: linear-gradient(135deg, #bdbdbd, #9e9e9e); transform: translateY(-1px); } /* 列表弹窗美化(保留原有) */ .attachment-list { padding: 0; /* 附件相关样式 */ .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; list-style: none; max-height: 300px; } .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-list li { /* 加载状态 */ .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; } /* 附件列表布局 */ .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; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #f0f0f0; gap: 16px; } .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 { .file-type-badge { width: 40px; height: 40px; border-radius: 8px; display: flex; gap: 8px; align-items: center; justify-content: center; font-size: 20px; background: #f8f9fa; border: 2px solid #e9ecef; 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; .file-type-badge.large { width: 56px; height: 56px; font-size: 28px; } .attachment-list .secondary-btn:hover { background: #e6f0fa; color: #1976d2; .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; } .preview-btn { background: #e8f5e8 !important; color: #2e7d2e !important; border-color: #a5d6a5 !important; .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; } .preview-btn:hover { background: #d4eecc !important; color: #1e5f1e !important; .attachment-name:hover { color: #3498db; } .attachment-popup-close { margin-top: 18px; width: 100%; background: #e0e0e0; color: #444; .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; } /* 按钮样式 */ .btn-secondary { padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; font-size: 15px; padding: 8px 0; border: none; transition: background 0.2s; background-color: white; font-size: 14px; transition: all 0.2s; color: #2c3e50; flex: 1; } .attachment-popup-close:hover { background: #bdbdbd; .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; } /* 响应式设计 */ pages/QC/LLJ/detail.vue
@@ -75,11 +75,19 @@ <text class="spec-text">{{ formData.fspecRequ }}</text> </view> </view> <!-- 规格要求 --> <!-- 检验描述 --> <view class="section"> <view class="section-header">检验描述</view> <view class="section-body"> <text class="spec-text">{{ formData.fcheckItemDesc }}</text> <!-- 查看附件信息按钮 --> <view class="attachment-btn-container"> <button class="btn attachment-btn" @tap="viewAttachmentInfo"> <uni-icons type="folder" size="16" color="#fff"></uni-icons> 查看附件信息 </button> </view> </view> </view> <!-- 检验结果 --> @@ -139,6 +147,7 @@ <uni-icons type="upload" size="16" color="#fff"></uni-icons> 上传/查看图片 </button> <button v-if="this.current" class="btn upload-btn" @tap="upRemarks"> <uni-icons type="compose" size="16" color="#fff"></uni-icons> 不良描述 @@ -184,6 +193,7 @@ <uni-icons type="upload" size="16" color="#fff"></uni-icons> 上传/查看图片 </button> <button v-if="this.current" class="btn upload-btn" @tap="upRemarks"> <uni-icons type="compose" size="16" color="#fff"></uni-icons> 不良描述 @@ -322,7 +332,169 @@ </form> </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">正在加载附件...</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> </view> </template> @@ -357,6 +529,17 @@ showMeom:false, meom: '', isFocus: false, // 新增,控制输入框聚焦 // ===== 附件相关数据 ===== showAttachmentPopup: false, showAttachmentDetail: false, showFilePreviewPopup: false, attachments: [], attachmentsLoading: false, selectedAttachment: null, previewTitle: '', previewContent: '', previewType: '', previewFileUrl: '' } }, computed: { @@ -664,6 +847,280 @@ url: 'ImageItem?id=' + this.formData.id }); }, // ===== 附件相关方法 ===== viewAttachmentInfo() { this.showAttachmentPopup = true; this.attachmentsLoading = true; this.attachments = []; // fversion 的值是当前检验项目名称 // 使用当前激活标签的 fcheckItem:tabs[currentTab].fcheckItem const currentTabData = this.tabs[this.currentTab]; const fversion = currentTabData && currentTabData.fcheckItem ? currentTabData.fcheckItem : ''; console.log("========================================"); console.log("调用附件接口:"); console.log("检验单号 releaseNo:", this.releaseNo); console.log("当前标签索引 currentTab:", this.currentTab); console.log("当前标签数据:", currentTabData); console.log("检验项目名称 fcheckItem:", currentTabData ? currentTabData.fcheckItem : ''); console.log("版本号 fversion (检验项目名称):", fversion); console.log("========================================"); // 先通过 releaseNo 获取物料编码 this.$post({ url: "/LLJ/getPage", data: { PageIndex: 1, Limit: 1, selectedIndex: 5, // 5表示按检验单号搜索 SearchValue: this.releaseNo, createUser: this.$loginInfo.account, UserIndex: this.$loginInfo.userIndex || "0" } }).then(res => { let tbBillListElement = res.data.tbBillList[0]; if (tbBillListElement && tbBillListElement.itemNo) { const itemNo = tbBillListElement.itemNo; console.log("获取到的物料编码:", itemNo); console.log("最终调用 getAttachments 参数:", { itemNo, fversion, fromPage: 'Detail' }); // 调用附件接口 return this.$post({ url: "/LLJ/getAttachments", data: { itemNo: itemNo, fversion: fversion, // 使用检验项目ID作为版本号 fromPage: 'Detail' } }); } else { throw new Error("未找到物料编码信息"); } }).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" }); } }).catch(err => { this.attachmentsLoading = false; console.error("获取附件失败:", err); 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 + "/LLJ/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer) + "&fversion=" + encodeURIComponent(item.fversion || ''); 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 + "/LLJ/PreviewFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer) + "&fversion=" + encodeURIComponent(item.fversion || ''); 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 }); } }, upRemarks() { this.remarksPopup = true; }, @@ -1311,4 +1768,434 @@ font-weight: bold; font-size: 12px; } /* 附件按钮样式 */ .attachment-btn-container { margin-top: 16px; display: flex; justify-content: flex-start; } .attachment-btn { background-color: #17a2b8; color: #fff; padding: 10px 20px; margin: 0; display: flex; align-items: center; gap: 8px; border-radius: 4px; font-size: 14px; transition: all 0.2s; } .attachment-btn:hover { background-color: #138496; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3); } /* 附件相关样式 */ .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; } /* 附件列表布局 */ .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-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; } /* 按钮样式 */ .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-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); } </style> pages/QC/RKJ/Add.vue
@@ -197,13 +197,15 @@ <table> <thead> <tr> <th width="20%" style="text-align: center;">检验项目</th> <th width="8%" style="text-align: center;">序号</th> <th width="17%" style="text-align: center;">检验项目</th> <th width="50%" style="text-align: center;">检验描述</th> <th width="15%" style="text-align: center;">记录(点击)</th> </tr> </thead> <tbody> <tr v-for="(item, index) in tableData" :key="index"> <td style="text-align: center;">{{ item.forder || (index + 1) }}</td> <td>{{ item.projName }}</td> <td> <view v-if="item.result=='合格'" class="watermark approved"> @@ -990,16 +992,10 @@ } }).then(res1 => { let tableData = res1.data.tbBillList || []; //当已检验个数都不为空时按照检测结构排序 // 按FORDER序号排序 tableData.sort((a, b) => { if (a.result === '未完成' && b.result === '合格') { return -1; } else if (a.result === '合格' && b.result === '未完成') { return 1; } else { return 0; } return (a.forder || 0) - (b.forder || 0); }); this.tableData = tableData; @@ -2625,6 +2621,7 @@ padding: 12px 15px; border: 1px solid #ddd; text-align: left; vertical-align: middle; } .inspection-table th { @@ -2678,10 +2675,11 @@ } /* 调整表格单元格 */ .inspection-table td:nth-child(2) { .inspection-table td:nth-child(3) { position: relative; overflow: hidden; padding: 0; min-height: 80px; } /* 表单上方操作按钮区样式 */ pages/QC/RKJ/List.vue
@@ -215,6 +215,10 @@ this.isLoading = true; // 获取车间和线体筛选条件 const departmentId = uni.getStorageSync('qc_filter_departmentId') || ''; const lineId = uni.getStorageSync('qc_filter_lineId') || ''; //页面加载时调用的事件 this.$post({ url: "/RKJ/getPage", @@ -225,7 +229,9 @@ fsubmit: fsubmit, SearchValue: SearchValue, selectedIndex: this.optionsIndex, // 新增:搜索条件索引 searchField: this.selectedField // 新增:搜索字段名 searchField: this.selectedField, // 新增:搜索字段名 departmentId: departmentId, // 新增:车间ID lineId: lineId // 新增:线体ID } }).then(res => { if (this.pageIndex === 1) { pages/QC/SJ/Add.vue
@@ -78,13 +78,15 @@ <table v-if="tableData.length > 0"> <thead> <tr> <th width="20%" style="text-align: center;">检验项目</th> <th width="8%" style="text-align: center;">序号</th> <th width="17%" style="text-align: center;">检验项目</th> <th width="50%" style="text-align: center;">检验描述</th> <th width="15%" style="text-align: center;">记录(点击)</th> </tr> </thead> <tbody> <tr v-for="(item, index) in tableData" :key="index"> <td style="text-align: center;">{{ item.forder || (index + 1) }}</td> <td>{{ item.projName }}</td> <td> <view v-if="item.result=='合格'" class="watermark approved"> @@ -647,14 +649,9 @@ }).then(res => { this.tableData = res.data.tbBillList; // 按FORDE... this.tableData.sort((a, b) => { if (a.result === '未完成' && b.result === '合格') { return -1; } else if (a.result === '合格' && b.result === '未完成') { return 1; } else { return 0; } return (a.forder || 0) - (b.forder || 0); }); if (this.tableData.length <= 0) { @@ -1689,6 +1686,7 @@ border: none; text-align: left; border-bottom: 1px solid #eee; vertical-align: middle; } .inspection-table th { @@ -1717,10 +1715,10 @@ } /* 检验描述列特殊样式 */ .inspection-table td:nth-child(2) { .inspection-table td:nth-child(3) { position: relative; min-height: 80px; vertical-align: top; vertical-align: middle; padding: 16px 20px; } pages/QC/SJ/List.vue
@@ -171,6 +171,10 @@ result = "已完成"; } // 获取车间和线体筛选条件 const departmentId = uni.getStorageSync('qc_filter_departmentId') || ''; const lineId = uni.getStorageSync('qc_filter_lineId') || ''; // ===== 修改后的API调用,添加搜索字段参数 ===== //页面加载时调用的事件 this.$post({ @@ -182,7 +186,9 @@ result: result, SearchValue: SearchValue, selectedIndex: this.optionsIndex, // 新增:搜索条件索引 searchField: this.selectedField // 新增:搜索字段名 searchField: this.selectedField, // 新增:搜索字段名 departmentId: departmentId, // 新增:车间ID lineId: lineId // 新增:线体ID } }).then(res => { this.data = res.data.tbBillList; pages/QC/XJ/Add.vue
@@ -79,13 +79,15 @@ <table> <thead> <tr> <th width="20%" style="text-align: center;">检验项目</th> <th width="8%" style="text-align: center;">序号</th> <th width="17%" style="text-align: center;">检验项目</th> <th width="50%" style="text-align: center;">检验描述</th> <th width="15%" style="text-align: center;">记录(点击)</th> </tr> </thead> <tbody> <tr v-for="(item, index) in tableData" :key="index"> <td style="text-align: center;">{{ item.forder || (index + 1) }}</td> <td>{{ item.projName }}</td> <td> <view v-if="item.result=='合格'" class="watermark approved"> @@ -855,16 +857,10 @@ pid: this.formData.id } }).then(res1 => { let tableData = res1.data.tbBillList //当已检验个数都不为空时按照检测结构排序 let tableData = res1.data.tbBillList; // 按FORDER序号排序 tableData.sort((a, b) => { if (a.result === '未完成' && b.result === '合格') { return -1; } else if (a.result === '合格' && b.result === '未完成') { return 1; } else { return 0; } return (a.forder || 0) - (b.forder || 0); }); this.tableData = tableData; if (this.tableData.length === 0) { @@ -1664,6 +1660,7 @@ padding: 12px 15px; text-align: left; border: none; vertical-align: middle; } .inspection-table tr:nth-child(even) { @@ -1713,10 +1710,11 @@ } /* 调整表格单元格 */ .inspection-table td:nth-child(2) { .inspection-table td:nth-child(3) { position: relative; overflow: hidden; padding: 0; min-height: 80px; } .record-btn { pages/QC/XJ/List.vue
@@ -155,6 +155,10 @@ result = "已完成"; } // 获取车间和线体筛选条件 const departmentId = uni.getStorageSync('qc_filter_departmentId') || ''; const lineId = uni.getStorageSync('qc_filter_lineId') || ''; //页面加载时调用的事件 this.$post({ url: "/XJ/getPage", @@ -165,7 +169,9 @@ result: result, SearchValue: SearchValue, selectedIndex: this.optionsIndex, // 新增:搜索条件索引 searchField: this.selectedField // 新增:搜索字段名 searchField: this.selectedField, // 新增:搜索字段名 departmentId: departmentId, // 新增:车间ID lineId: lineId // 新增:线体ID } }).then(res => { this.data = res.data.tbBillList; store/index.js
@@ -10,9 +10,9 @@ networkFlag:'内网', serverURLInt:'http://192.168.11.251:10055',//服务器体检 10.0.1.104:10054 serverURL:'http://localhost:10055',//本地调试地址 //serverAPI:'http://localhost:5184/api',//当前正在使用的服务器,默认为外网 localhost //serverAPI:'http://192.168.1.22:10054/api',//内网 serverAPI:'http://36.26.21.214:10055/api', serverAPI:'http://localhost:5184/api',//当前正在使用的服务器,默认为外网 localhost //serverAPI:'http://192.168.1.22:10055/api',//内网 //serverAPI:'http://36.26.21.214:10055/api', ftpServer:'ftp://36.26.21.214',//FTP服务器地址 } },