| | |
| | | "name" : "GS-MES-AP", |
| | | "appid" : "__UNI__F08FAE3", |
| | | "description" : "", |
| | | "versionName" : "1.1.3.9", |
| | | "versionName" : "1.1.4.1", |
| | | "versionCode" : 1, |
| | | "transformPx" : false, |
| | | /* 5+App特有相关 */ |
| | |
| | | return; |
| | | } |
| | | |
| | | // 检查钉钉推送条件:PSZT为待判,且不良原因、不良描述、所属车间不为空 |
| | | const shouldPushToDingTalk = this.PSTYPE === '待判' && |
| | | this.badreason && |
| | | this.formData.fngDesc && |
| | | this.WORKSHOP; |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | this.validateUnqualifiedItems().then(() => { |
| | | // 检查钉钉推送条件:PSZT为待判,且不良原因、不良描述、所属车间不为空 |
| | | const shouldPushToDingTalk = this.PSTYPE === '待判' && |
| | | this.badreason && |
| | | this.formData.fngDesc && |
| | | this.WORKSHOP; |
| | | |
| | | let confirmMessage = '确定要提交此检验单吗?提交后将无法修改。'; |
| | | if (shouldPushToDingTalk) { |
| | | confirmMessage += '\n\n满足钉钉推送条件,将自动推送到钉钉审批流程。'; |
| | | } |
| | | |
| | | // 确认提交 |
| | | uni.showModal({ |
| | | title: '确认提交', |
| | | content: confirmMessage, |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.$post({ |
| | | url: "/RKJ/submitInspection", |
| | | data: { |
| | | id: this.formData.id, |
| | | userNo: this.$loginInfo.account |
| | | } |
| | | }).then(res => { |
| | | if (res.status == 0) { |
| | | let successMessage = "检验单提交成功!"; |
| | | if (shouldPushToDingTalk) { |
| | | successMessage += "\n已推送到钉钉审批流程。"; |
| | | } |
| | | this.$showMessage(successMessage); |
| | | // 更新本地状态 |
| | | this.formData.fsubmit = 1; |
| | | // 刷新数据 |
| | | this.init(); |
| | | } else { |
| | | this.$showMessage(res.message || "提交失败"); |
| | | } |
| | | }).catch(error => { |
| | | console.error("提交失败:", error); |
| | | this.$showMessage("提交失败,请重试"); |
| | | }); |
| | | } |
| | | let confirmMessage = '确定要提交此检验单吗?提交后将无法修改。'; |
| | | if (shouldPushToDingTalk) { |
| | | confirmMessage += '\n\n满足钉钉推送条件,将自动推送到钉钉审批流程。'; |
| | | } |
| | | |
| | | // 确认提交 |
| | | uni.showModal({ |
| | | title: '确认提交', |
| | | content: confirmMessage, |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.$post({ |
| | | url: "/RKJ/submitInspection", |
| | | data: { |
| | | id: this.formData.id, |
| | | userNo: this.$loginInfo.account |
| | | } |
| | | }).then(res => { |
| | | if (res.status == 0) { |
| | | let successMessage = "检验单提交成功!"; |
| | | if (shouldPushToDingTalk) { |
| | | successMessage += "\n已推送到钉钉审批流程。"; |
| | | } |
| | | this.$showMessage(successMessage); |
| | | // 更新本地状态 |
| | | this.formData.fsubmit = 1; |
| | | // 刷新数据 |
| | | this.init(); |
| | | } else { |
| | | this.$showMessage(res.message || "提交失败"); |
| | | } |
| | | }).catch(error => { |
| | | console.error("提交失败:", error); |
| | | this.$showMessage("提交失败,请重试"); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }).catch(error => { |
| | | this.$showMessage(error); |
| | | }); |
| | | }, |
| | | |
| | | // 验证不合格检验项目 |
| | | async validateUnqualifiedItems() { |
| | | const unqualifiedItems = this.tableData.filter(item => item.result === '不合格'); |
| | | |
| | | if (unqualifiedItems.length === 0) { |
| | | return Promise.resolve(); |
| | | } |
| | | |
| | | // 检查每个不合格项目是否有图片和描述 |
| | | for (const item of unqualifiedItems) { |
| | | try { |
| | | const detail = await this.getInspectionItemDetail(item.id); |
| | | if (!detail.hasImage || !detail.hasRemarks) { |
| | | const missingItems = []; |
| | | if (!detail.hasImage) missingItems.push('图片'); |
| | | if (!detail.hasRemarks) missingItems.push('不良描述'); |
| | | |
| | | throw new Error(`检验项目"${item.projName}"不合格,但缺少:${missingItems.join('、')},请完善后重新提交!`); |
| | | } |
| | | } catch (error) { |
| | | throw error; |
| | | } |
| | | } |
| | | |
| | | return Promise.resolve(); |
| | | }, |
| | | |
| | | // 获取检验项目详细信息 |
| | | getInspectionItemDetail(itemId) { |
| | | return new Promise((resolve, reject) => { |
| | | this.$post({ |
| | | url: "/RKJ/getXjDetail02ById", |
| | | data: { id: itemId } |
| | | }).then(res => { |
| | | const itemData = res.data.tbBillList.itemXj01; |
| | | resolve({ |
| | | hasImage: itemData.imageData && itemData.imageData.length > 0, |
| | | hasRemarks: itemData.remarks && itemData.remarks.trim() !== '' |
| | | }); |
| | | }).catch(error => { |
| | | reject('获取检验项目详情失败'); |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | viewAttachmentInfo() { |
| | | this.showAttachmentPopup = true; // 先弹窗 |
| | | this.attachmentsLoading = true; |
| | |
| | | onLoad() { |
| | | //页面加载时调用的事件 |
| | | this.init(); |
| | | // 同时获取未提交和已提交的数量 |
| | | this.getCounts(); |
| | | }, |
| | | methods: { |
| | | // ===== 新增查询条件选择方法 ===== |
| | |
| | | this.selectedField = fieldMap[this.optionsIndex]; |
| | | }, |
| | | |
| | | // ===== 新增获取数量统计方法 ===== |
| | | getCounts() { |
| | | // 获取未提交数量 - fsubmit = 0 或空值 |
| | | this.$post({ |
| | | url: "/RKJ/getPage", |
| | | data: { |
| | | pageIndex: 1, |
| | | limit: 1, // 只需要获取总数,不需要具体数据 |
| | | createUser: this.$loginInfo.account, |
| | | fsubmit: "0" // 未提交:fsubmit = 0 或空值 |
| | | } |
| | | }).then(res => { |
| | | this.unsubmittedCount = res.data.totalCount || 0; |
| | | }).catch(() => { |
| | | this.unsubmittedCount = 0; |
| | | }); |
| | | |
| | | // 获取已提交数量 - fsubmit = 1 |
| | | this.$post({ |
| | | url: "/RKJ/getPage", |
| | | data: { |
| | | pageIndex: 1, |
| | | limit: 1, // 只需要获取总数,不需要具体数据 |
| | | createUser: this.$loginInfo.account, |
| | | fsubmit: "1" // 已提交:fsubmit = 1 |
| | | } |
| | | }).then(res => { |
| | | this.submittedCount = res.data.totalCount || 0; |
| | | }).catch(() => { |
| | | this.submittedCount = 0; |
| | | }); |
| | | }, |
| | | |
| | | //搜索框点击事件 |
| | | btnclicked() { |
| | | this.pageIndex = 1; |
| | | this.data = []; |
| | | this.init(); |
| | | // 搜索后重新获取数量统计 |
| | | this.getCounts(); |
| | | }, |
| | | |
| | | init() { |
| | | //获取搜索条件内容 |
| | | let SearchValue = this.searchValue; |
| | | |
| | | let fsubmit = null; // 默认查询所有未提交的记录(包括fsubmit = 0和fsubmit为空) |
| | | let fsubmit = "0"; // 默认查询未提交的记录(fsubmit = 0或空值) |
| | | if (this.current == 1) { |
| | | fsubmit = "1"; // 已提交 |
| | | } |
| | |
| | | } |
| | | this.totalCount = res.data.totalCount; |
| | | this.totalPage = Math.ceil(this.totalCount / this.limit); |
| | | |
| | | // 设置数量统计 - 参考XJ的实现方式 |
| | | if (this.current === 1) { |
| | | this.submittedCount = res.data.totalCount; |
| | | } else { |
| | | this.unsubmittedCount = res.data.totalCount; |
| | | } |
| | | |
| | | this.noData = this.pageIndex >= this.totalPage; |
| | | this.isLoading = false; // 结束加载 |
| | |
| | | this.data = []; |
| | | this.pageIndex = 1; |
| | | this.init(); |
| | | // 切换标签后重新获取数量统计 |
| | | this.getCounts(); |
| | | } |
| | | }, |
| | | navigateToDetail(item) { |
| | |
| | | this.data = []; |
| | | //this.current = 0 |
| | | this.init(); |
| | | // 页面显示时重新获取数量统计 |
| | | this.getCounts(); |
| | | } |
| | | }; |
| | | </script> |
| | |
| | | <view class="inspection-hint"> |
| | | <view class="hint-text">没有最大值和最小值时填写0(未通过检验)或1(通过检验)</view> |
| | | </view> |
| | | |
| | | <!-- 不合格检验项目提示 --> |
| | | <view class="validation-hint" v-if="isUnqualifiedResult()"> |
| | | <view class="validation-icon">⚠️</view> |
| | | <view class="validation-text"> |
| | | <view class="validation-title">检验项目不合格,必须完成以下操作:</view> |
| | | <view class="validation-requirements"> |
| | | <view class="requirement-item" :class="{ 'completed': hasImage(), 'required': !hasImage() }"> |
| | | <text class="requirement-icon">{{ hasImage() ? '✅' : '❌' }}</text> |
| | | <text class="requirement-text">上传图片</text> |
| | | </view> |
| | | <view class="requirement-item" :class="{ 'completed': hasRemarks(), 'required': !hasRemarks() }"> |
| | | <text class="requirement-icon">{{ hasRemarks() ? '✅' : '❌' }}</text> |
| | | <text class="requirement-text">填写不良描述</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="input-group"> |
| | | <view class="input-wrapper"> |
| | | <input v-if="tableData.length < formData.levelNum" |
| | |
| | | </view> |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <view class="section-header">相关图片</view> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | |
| | | <view class="action-buttons"> |
| | | <button class="action-btn warning" @click="saveRemarks">添加不合格描述</button> |
| | | <button class="action-btn primary" @click="viewAttachmentInfo">查看检验项目</button> |
| | | <button class="action-btn success tablet-upload-btn" @click="uploadImage"> |
| | | <view class="btn-content"> |
| | | <view class="btn-icon">📷</view> |
| | | <view class="btn-text">拍照/上传图片</view> |
| | | </view> |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 修改检验结果弹出框 --> |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | // 判断当前检验结果是否为不合格 |
| | | isUnqualifiedResult() { |
| | | if (!this.formData.fcheckResu) return false; |
| | | |
| | | // 如果有最大值和最小值,检查是否超出范围 |
| | | if (this.formData.maxValue && this.formData.minValue) { |
| | | return this.formData.fcheckResu < this.formData.minValue || |
| | | this.formData.fcheckResu > this.formData.maxValue; |
| | | } |
| | | |
| | | // 如果没有最大值和最小值,检查是否为0(不合格) |
| | | return this.formData.fcheckResu == 0; |
| | | }, |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | | hasRemarks() { |
| | | return this.formData.remarks && this.formData.remarks.trim() !== ''; |
| | | }, |
| | | |
| | | previewImage() { |
| | | uni.previewImage({ |
| | |
| | | count = count - this.tableData.length; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.formData.updater = this.$loginInfo.account; |
| | | |
| | | this.$post({ |
| | |
| | | |
| | | this.tableData = res.data.tbBillList.itemXj02s; |
| | | |
| | | if (this.formData.imageData) { |
| | | // 处理图片显示状态 |
| | | if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | // 如果没有图片数据,隐藏图片显示区域 |
| | | this.isShowImg = false; |
| | | this.base64Image = ''; |
| | | } |
| | | |
| | | //maxValue minValue standardValue |
| | |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.editData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.editData.updater = this.$loginInfo.account; |
| | | |
| | | this.$post({ |
| | |
| | | if (item.fcheckResu == '1') { |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.$post({ |
| | |
| | | current: this.previewContent |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | // 上传图片方法 - 保存到当前检验项目的PICTURE字段(LONG RAW类型) |
| | | // 后端会自动生成时间戳文件名,格式:1746945271304.jpg |
| | | uploadImage() { |
| | | // 显示选择弹窗,让用户选择拍照或从相册选择 |
| | | uni.showActionSheet({ |
| | | itemList: ['拍照', '从相册选择'], |
| | | success: (res) => { |
| | | const sourceType = res.tapIndex === 0 ? ['camera'] : ['album']; |
| | | this.chooseImageWithSource(sourceType); |
| | | }, |
| | | fail: (error) => { |
| | | console.log('用户取消选择:', error); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 根据选择的来源选择图片 |
| | | chooseImageWithSource(sourceType) { |
| | | uni.chooseImage({ |
| | | count: 1, // 最多选择1张图片 |
| | | sizeType: ['compressed', 'original'], // 提供压缩和原图选项 |
| | | sourceType: sourceType, // 根据用户选择设置来源 |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | |
| | | // 如果是拍照,显示预览确认 |
| | | if (sourceType.includes('camera')) { |
| | | this.showImagePreview(tempFilePath); |
| | | } else { |
| | | this.uploadImageToServer(tempFilePath); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | | console.error('选择图片失败:', error); |
| | | let errorMessage = '选择图片失败'; |
| | | if (sourceType.includes('camera')) { |
| | | errorMessage = '拍照失败,请检查相机权限'; |
| | | } |
| | | uni.showToast({ |
| | | title: errorMessage, |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 显示图片预览确认(主要用于拍照后的确认) |
| | | showImagePreview(imagePath) { |
| | | uni.previewImage({ |
| | | urls: [imagePath], |
| | | current: imagePath, |
| | | success: () => { |
| | | // 用户查看图片后,询问是否使用此图片 |
| | | uni.showModal({ |
| | | title: '确认使用此图片', |
| | | content: '是否使用刚才拍摄的图片?', |
| | | confirmText: '使用', |
| | | cancelText: '重新拍摄', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.uploadImageToServer(imagePath); |
| | | } else if (res.cancel) { |
| | | // 用户选择重新拍摄 |
| | | this.chooseImageWithSource(['camera']); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | fail: () => { |
| | | // 预览失败,直接上传 |
| | | this.uploadImageToServer(imagePath); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 上传图片到服务器并保存到数据库PICTURE字段(LONG RAW类型) |
| | | // 后端会自动生成时间戳文件名存储到TPICTURENAME字段 |
| | | uploadImageToServer(filePath) { |
| | | uni.showLoading({ |
| | | title: '上传中...' |
| | | }); |
| | | |
| | | // 构建上传URL |
| | | const uploadUrl = this.$store.state.serverInfo.serverAPI + "/RKJ/UploadImageToPicture"; |
| | | |
| | | uni.uploadFile({ |
| | | url: uploadUrl, |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id, // 当前检验项目ID |
| | | gid: this.gid, |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (uploadRes) => { |
| | | uni.hideLoading(); |
| | | try { |
| | | const result = JSON.parse(uploadRes.data); |
| | | if (result.status === 0) { |
| | | uni.showToast({ |
| | | title: '图片保存成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新页面数据 |
| | | this.refreshResult(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: result.message || '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | console.error('解析上传结果失败:', error); |
| | | uni.showToast({ |
| | | title: '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | | uni.hideLoading(); |
| | | console.error('上传失败:', error); |
| | | uni.showToast({ |
| | | title: '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 删除图片 |
| | | deleteImage() { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除当前图片吗?删除后无法恢复。', |
| | | confirmText: '删除', |
| | | cancelText: '取消', |
| | | confirmColor: '#e74c3c', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/RKJ/DeleteImageFromPicture", |
| | | data: { |
| | | id: this.id // 当前检验项目ID |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | | uni.showToast({ |
| | | title: '图片删除成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新页面数据 |
| | | this.refreshResult(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.message || '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(error => { |
| | | uni.hideLoading(); |
| | | console.error('删除图片失败:', error); |
| | | uni.showToast({ |
| | | title: '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | }); |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | |
| | | background-color: $bg-color; |
| | | border-bottom: 1px solid $border-color; |
| | | font-weight: bold; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | &-title { |
| | | flex: 1; |
| | | } |
| | | |
| | | &-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | &-body { |
| | |
| | | .hint-text { |
| | | font-size: 12px; |
| | | color: #856404; |
| | | } |
| | | |
| | | /* 验证提示样式 */ |
| | | .validation-hint { |
| | | background: linear-gradient(135deg, #ffe6e6 0%, #ffcccc 100%); |
| | | border: 2px solid #ff6b6b; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | box-shadow: 0 2px 8px rgba(255, 107, 107, 0.2); |
| | | } |
| | | |
| | | .validation-icon { |
| | | font-size: 24px; |
| | | flex-shrink: 0; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .validation-text { |
| | | flex: 1; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #d63031; |
| | | margin-bottom: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | .validation-requirements { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 6px 10px; |
| | | border-radius: 6px; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .requirement-item.completed { |
| | | background-color: #d4edda; |
| | | border: 1px solid #c3e6cb; |
| | | } |
| | | |
| | | .requirement-item.required { |
| | | background-color: #f8d7da; |
| | | border: 1px solid #f5c6cb; |
| | | } |
| | | |
| | | .requirement-icon { |
| | | font-size: 16px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | .input-group { |
| | |
| | | background-color: $warning-color; |
| | | color: white; |
| | | } |
| | | |
| | | &.success { |
| | | background-color: $success-color; |
| | | color: white; |
| | | } |
| | | } |
| | | |
| | | .delete-image-btn { |
| | | padding: 6px 12px; |
| | | border: 1px solid #e74c3c; |
| | | border-radius: 4px; |
| | | background-color: #e74c3c; |
| | | color: white; |
| | | font-size: 12px; |
| | | font-weight: 500; |
| | | cursor: pointer; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .delete-image-btn:hover { |
| | | background-color: #c0392b; |
| | | border-color: #c0392b; |
| | | } |
| | | |
| | | .delete-image-btn:active { |
| | | background-color: #a93226; |
| | | border-color: #a93226; |
| | | } |
| | | |
| | | /* 平板上传按钮样式 */ |
| | | .tablet-upload-btn { |
| | | position: relative; |
| | | overflow: hidden; |
| | | background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%); |
| | | box-shadow: 0 4px 15px rgba(46, 204, 113, 0.3); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .tablet-upload-btn:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 6px 20px rgba(46, 204, 113, 0.4); |
| | | } |
| | | |
| | | .tablet-upload-btn:active { |
| | | transform: translateY(0); |
| | | box-shadow: 0 2px 10px rgba(46, 204, 113, 0.3); |
| | | } |
| | | |
| | | .btn-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | padding: 8px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 24px; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | line-height: 1.2; |
| | | text-align: center; |
| | | } |
| | | |
| | | .overlay { |
| | |
| | | flex-direction: column; |
| | | } |
| | | } |
| | | |
| | | /* 平板优化样式 */ |
| | | @media (min-width: 768px) and (max-width: 1024px) { |
| | | .action-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 15px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .action-btn { |
| | | padding: 20px 16px; |
| | | font-size: 16px; |
| | | min-height: 80px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .tablet-upload-btn { |
| | | min-height: 100px; |
| | | } |
| | | |
| | | .btn-content { |
| | | gap: 12px; |
| | | padding: 12px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 32px; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .info-grid { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | gap: 20px; |
| | | } |
| | | |
| | | .section-body { |
| | | padding: 30px; |
| | | } |
| | | } |
| | | |
| | | /* 大屏平板优化 */ |
| | | @media (min-width: 1024px) { |
| | | .action-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 20px; |
| | | margin-bottom: 40px; |
| | | } |
| | | |
| | | .action-btn { |
| | | padding: 25px 20px; |
| | | font-size: 18px; |
| | | min-height: 100px; |
| | | } |
| | | |
| | | .tablet-upload-btn { |
| | | min-height: 120px; |
| | | } |
| | | |
| | | .btn-content { |
| | | gap: 15px; |
| | | padding: 15px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 36px; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .info-grid { |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 25px; |
| | | } |
| | | |
| | | .section-body { |
| | | padding: 40px; |
| | | } |
| | | |
| | | .validation-hint { |
| | | padding: 25px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | padding: 12px 18px; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 15px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | this.SJ_MJIndex = e.mp.detail.value; |
| | | this.formData.SJ_MJ = this.SJ_MJList[this.SJ_MJIndex]; |
| | | }, |
| | | submitInspection() { |
| | | async submitInspection() { |
| | | if (this.formData.id) { |
| | | // 显示确认提示框 |
| | | uni.showModal({ |
| | | title: '确认提交', |
| | | content: '确定要提交检验结果吗?提交后将无法修改。', |
| | | confirmText: '确定提交', |
| | | cancelText: '取消', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | // 用户确认后执行提交 |
| | | this.$post({ |
| | | url: "/SJ/SjSubmit", |
| | | data: { |
| | | id: this.formData.id, |
| | | userNo: this.$loginInfo.account |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList) { |
| | | this.$showMessage("提交成功"); |
| | | this.init(); |
| | | } |
| | | }); |
| | | try { |
| | | // 验证不合格检验项目 |
| | | await this.validateUnqualifiedItems(); |
| | | |
| | | // 显示确认提示框 |
| | | uni.showModal({ |
| | | title: '确认提交', |
| | | content: '确定要提交检验结果吗?提交后将无法修改。', |
| | | confirmText: '确定提交', |
| | | cancelText: '取消', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | // 用户确认后执行提交 |
| | | this.$post({ |
| | | url: "/SJ/SjSubmit", |
| | | data: { |
| | | id: this.formData.id, |
| | | userNo: this.$loginInfo.account |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList) { |
| | | this.$showMessage("提交成功"); |
| | | this.init(); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | } catch (error) { |
| | | this.$showMessage(error.message); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // 验证不合格检验项目 |
| | | async validateUnqualifiedItems() { |
| | | const unqualifiedItems = this.tableData.filter(item => item.result === '不合格'); |
| | | |
| | | if (unqualifiedItems.length === 0) { |
| | | return Promise.resolve(); |
| | | } |
| | | |
| | | // 检查每个不合格项目是否有图片和描述 |
| | | for (const item of unqualifiedItems) { |
| | | try { |
| | | const detail = await this.getInspectionItemDetail(item.id); |
| | | if (!detail.hasImage || !detail.hasRemarks) { |
| | | const missingItems = []; |
| | | if (!detail.hasImage) missingItems.push('图片'); |
| | | if (!detail.hasRemarks) missingItems.push('不良描述'); |
| | | |
| | | throw new Error(`检验项目"${item.projName}"不合格,但缺少:${missingItems.join('、')},请完善后重新提交!`); |
| | | } |
| | | } catch (error) { |
| | | throw error; |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // 获取检验项目详细信息 |
| | | async getInspectionItemDetail(itemId) { |
| | | return new Promise((resolve, reject) => { |
| | | this.$post({ |
| | | url: "/SJ/getQSItems", |
| | | data: { |
| | | pid: this.formData.id, |
| | | id: itemId |
| | | } |
| | | }).then(res => { |
| | | const item = res.data.tbBillList[0]; |
| | | if (item) { |
| | | resolve({ |
| | | hasImage: item.imageData && item.imageData.length > 0, |
| | | hasRemarks: item.remarks && item.remarks.trim() !== '' |
| | | }); |
| | | } else { |
| | | reject(new Error('无法获取检验项目详情')); |
| | | } |
| | | }).catch(err => { |
| | | reject(err); |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | drawingConfirm() { |
| | | this.drawingShow = false |
| | | this.imageShow = false |
| | |
| | | <view class="section"> |
| | | <view class="section-header">检验结果录入</view> |
| | | <view class="section-body"> |
| | | <!-- 验证提示 --> |
| | | <view v-if="isUnqualifiedResult()" class="validation-hint"> |
| | | <view class="validation-icon">⚠️</view> |
| | | <view class="validation-text"> |
| | | <view class="validation-title">检验项目不合格,必须完成以下操作:</view> |
| | | <view class="validation-requirements"> |
| | | <view class="requirement-item" :class="{ 'completed': hasImage() }"> |
| | | <view class="requirement-icon">{{ hasImage() ? '✅' : '❌' }}</view> |
| | | <view class="requirement-text">上传图片</view> |
| | | </view> |
| | | <view class="requirement-item" :class="{ 'completed': hasRemarks() }"> |
| | | <view class="requirement-icon">{{ hasRemarks() ? '✅' : '❌' }}</view> |
| | | <view class="requirement-text">填写不良描述</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="input-group"> |
| | | <view class="input-wrapper"> |
| | | <button class="btn upload-btn" @tap="saveRemarks"> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="action-buttons"> |
| | | <button class="action-btn success tablet-upload-btn" @click="uploadImage"> |
| | | <view class="btn-content"> |
| | | <view class="btn-icon">📷</view> |
| | | <view class="btn-text">拍照/上传图片</view> |
| | | </view> |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 结果表格 --> |
| | |
| | | |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <view class="section-header">相关图片</view> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | // 判断当前检验结果是否为不合格 |
| | | isUnqualifiedResult() { |
| | | if (!this.formData.fcheckResu) return false; |
| | | |
| | | // 如果有最大值和最小值,检查是否超出范围 |
| | | if (this.formData.maxValue && this.formData.minValue) { |
| | | return this.formData.fcheckResu < this.formData.minValue || |
| | | this.formData.fcheckResu > this.formData.maxValue; |
| | | } |
| | | |
| | | // 如果没有最大值和最小值,检查是否为0(不合格) |
| | | return this.formData.fcheckResu == 0; |
| | | }, |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | | hasRemarks() { |
| | | return this.formData.remarks && this.formData.remarks.trim() !== ''; |
| | | }, |
| | | |
| | | getResultClass(fcheckResu, fstand, index) { |
| | | // 检查是否被堵穴 |
| | | if (this.isHoleBlocked(index)) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.formData.updater = this.$loginInfo.account; |
| | | |
| | | |
| | | // 直接执行保存,不显示确认弹窗 |
| | | this.$post({ |
| | | url: "/SJ/SetQSItemDetail", |
| | |
| | | if (this.formData.imageData) { |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | this.isShowImg = false; |
| | | this.base64Image = ''; |
| | | } |
| | | if (this.formData.maxValue && this.formData.minValue && this.formData.standardValue) { |
| | | this.isNumber = true; |
| | |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.editData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.editData.updater = this.$loginInfo.account; |
| | | |
| | | |
| | | // 显示确认提示框 |
| | | uni.showModal({ |
| | | title: '确认修改', |
| | |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | } |
| | | |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.$post({ |
| | | url: "/SJ/UpdateQSItemDetail", |
| | | data: { |
| | |
| | | current: this.previewContent |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | // 图片上传方法 |
| | | uploadImage() { |
| | | uni.showActionSheet({ |
| | | itemList: ['拍照', '从相册选择'], |
| | | success: (res) => { |
| | | if (res.tapIndex === 0) { |
| | | this.chooseImageWithSource('camera'); |
| | | } else if (res.tapIndex === 1) { |
| | | this.chooseImageWithSource('album'); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 选择图片来源 |
| | | chooseImageWithSource(source) { |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | sizeType: ['compressed'], |
| | | sourceType: [source], |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | if (source === 'camera') { |
| | | // 拍照后显示预览确认 |
| | | this.showImagePreview(tempFilePath); |
| | | } else { |
| | | // 相册选择直接上传 |
| | | this.uploadImageToServer(tempFilePath); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error('选择图片失败:', err); |
| | | this.$showMessage('选择图片失败'); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 显示图片预览 |
| | | showImagePreview(tempFilePath) { |
| | | uni.previewImage({ |
| | | urls: [tempFilePath], |
| | | current: tempFilePath, |
| | | success: () => { |
| | | // 预览后询问是否上传 |
| | | uni.showModal({ |
| | | title: '确认上传', |
| | | content: '是否上传此图片?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.uploadImageToServer(tempFilePath); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 上传图片到服务器 |
| | | uploadImageToServer(tempFilePath) { |
| | | uni.showLoading({ |
| | | title: '上传中...' |
| | | }); |
| | | |
| | | uni.uploadFile({ |
| | | url: this.$store.state.serverInfo.serverAPI + '/SJ/UploadImageToPicture', |
| | | filePath: tempFilePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id.toString(), |
| | | gid: this.gid.toString(), |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (res) => { |
| | | uni.hideLoading(); |
| | | try { |
| | | const result = JSON.parse(res.data); |
| | | if (result.status === 0) { |
| | | this.$showMessage('图片上传成功'); |
| | | this.refreshResult(); // 刷新页面数据 |
| | | } else { |
| | | this.$showMessage(result.message || '上传失败'); |
| | | } |
| | | } catch (e) { |
| | | this.$showMessage('上传失败,请重试'); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | uni.hideLoading(); |
| | | console.error('上传失败:', err); |
| | | this.$showMessage('上传失败,请重试'); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 删除图片 |
| | | deleteImage() { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除此图片吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: '/SJ/DeleteImageFromPicture', |
| | | data: { |
| | | id: this.id |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | | this.$showMessage('图片删除成功'); |
| | | this.refreshResult(); // 刷新页面数据 |
| | | } else { |
| | | this.$showMessage(res.message || '删除失败'); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('删除失败:', err); |
| | | this.$showMessage('删除失败,请重试'); |
| | | }); |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | |
| | | margin: 20px 0; |
| | | border: 1px solid $border-color; |
| | | border-radius: 4px; |
| | | |
| | | |
| | | &-header { |
| | | padding: 12px 16px; |
| | | background-color: $bg-color; |
| | | border-bottom: 1px solid $border-color; |
| | | font-weight: bold; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | |
| | | &-title { |
| | | flex: 1; |
| | | } |
| | | |
| | | &-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | &-body { |
| | | padding: 16px; |
| | | } |
| | |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 2px 8px rgba(0,0,0,0.15); |
| | | } |
| | | |
| | | /* 验证提示样式 */ |
| | | .validation-hint { |
| | | background: linear-gradient(135deg, #ffe6e6 0%, #ffcccc 100%); |
| | | border: 2px solid #ff6b6b; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | box-shadow: 0 2px 8px rgba(255, 107, 107, 0.2); |
| | | } |
| | | |
| | | .validation-icon { |
| | | font-size: 24px; |
| | | flex-shrink: 0; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .validation-text { |
| | | flex: 1; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #d63031; |
| | | margin-bottom: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | .validation-requirements { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 8px 12px; |
| | | background: rgba(255, 255, 255, 0.7); |
| | | border-radius: 6px; |
| | | border: 1px solid rgba(255, 107, 107, 0.3); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .requirement-item.completed { |
| | | background: rgba(46, 204, 113, 0.1); |
| | | border-color: rgba(46, 204, 113, 0.3); |
| | | } |
| | | |
| | | .requirement-icon { |
| | | font-size: 16px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 13px; |
| | | color: #2c3e50; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .requirement-item.completed .requirement-text { |
| | | color: #27ae60; |
| | | } |
| | | |
| | | /* 删除图片按钮样式 */ |
| | | .delete-image-btn { |
| | | padding: 6px 12px; |
| | | border: 1px solid #e74c3c; |
| | | border-radius: 4px; |
| | | background-color: #e74c3c; |
| | | color: white; |
| | | font-size: 12px; |
| | | font-weight: 500; |
| | | cursor: pointer; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .delete-image-btn:hover { |
| | | background-color: #c0392b; |
| | | border-color: #c0392b; |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | /* 上传图片按钮样式 */ |
| | | .tablet-upload-btn { |
| | | background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%); |
| | | border: none; |
| | | border-radius: 8px; |
| | | padding: 12px 20px; |
| | | color: white; |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | box-shadow: 0 4px 12px rgba(46, 204, 113, 0.3); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | min-height: 48px; |
| | | } |
| | | |
| | | .tablet-upload-btn:hover { |
| | | background: linear-gradient(135deg, #27ae60 0%, #229954 100%); |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 6px 16px rgba(46, 204, 113, 0.4); |
| | | } |
| | | |
| | | .btn-content { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | /* 响应式设计 */ |
| | | @media (min-width: 768px) { |
| | | .section-body { |
| | | padding: 40px; |
| | | } |
| | | |
| | | .validation-hint { |
| | | padding: 25px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | padding: 12px 18px; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 15px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | position: absolute; |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | opacity: 0.3; |
| | | opacity: 0.8; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | transform: rotate(-15deg); |
| | |
| | | <view class="inspection-hint"> |
| | | <view class="hint-text">没有最大值和最小值时填写0(未通过检验)或1(通过检验)</view> |
| | | </view> |
| | | |
| | | <!-- 不合格检验项目提示 --> |
| | | <view class="validation-hint" v-if="isUnqualifiedResult()"> |
| | | <view class="validation-icon">⚠️</view> |
| | | <view class="validation-text"> |
| | | <view class="validation-title">检验项目不合格,必须完成以下操作:</view> |
| | | <view class="validation-requirements"> |
| | | <view class="requirement-item" :class="{ 'completed': hasImage(), 'required': !hasImage() }"> |
| | | <text class="requirement-icon">{{ hasImage() ? '✅' : '❌' }}</text> |
| | | <text class="requirement-text">上传图片</text> |
| | | </view> |
| | | <view class="requirement-item" :class="{ 'completed': hasRemarks(), 'required': !hasRemarks() }"> |
| | | <text class="requirement-icon">{{ hasRemarks() ? '✅' : '❌' }}</text> |
| | | <text class="requirement-text">填写不良描述</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="input-group"> |
| | | <view class="input-wrapper"> |
| | | <input v-if="tableData.length < formData.levelNum" |
| | |
| | | |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <view class="section-header">相关图片</view> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | |
| | | <view class="action-buttons"> |
| | | <button class="action-btn warning" @click="saveRemarks">添加不合格描述</button> |
| | | <button class="action-btn primary" @click="viewAttachmentInfo">查看附件信息</button> |
| | | <button class="action-btn success tablet-upload-btn" @click="uploadImage"> |
| | | <view class="btn-content"> |
| | | <view class="btn-icon">📷</view> |
| | | <view class="btn-text">拍照/上传图片</view> |
| | | </view> |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 修改不合格描述弹出框 --> |
| | |
| | | return 'result-pending'; |
| | | }, |
| | | |
| | | // 判断当前检验结果是否为不合格 |
| | | isUnqualifiedResult() { |
| | | if (!this.formData.fcheckResu) return false; |
| | | |
| | | // 如果有最大值和最小值,检查是否超出范围 |
| | | if (this.formData.maxValue && this.formData.minValue) { |
| | | return this.formData.fcheckResu < this.formData.minValue || |
| | | this.formData.fcheckResu > this.formData.maxValue; |
| | | } |
| | | |
| | | // 如果没有最大值和最小值,检查是否为0(不合格) |
| | | return this.formData.fcheckResu == 0; |
| | | }, |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | | hasRemarks() { |
| | | return this.formData.remarks && this.formData.remarks.trim() !== ''; |
| | | }, |
| | | |
| | | |
| | | previewImage() { |
| | | uni.previewImage({ |
| | |
| | | count = count - this.tableData.length; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.formData.updater = this.$loginInfo.account; |
| | | |
| | | this.$post({ |
| | |
| | | |
| | | this.tableData = res.data.tbBillList.itemXj02s; |
| | | |
| | | if (this.formData.imageData) { |
| | | // 处理图片显示状态 |
| | | if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | // 如果没有图片数据,隐藏图片显示区域 |
| | | this.isShowImg = false; |
| | | this.base64Image = ''; |
| | | } |
| | | |
| | | if (this.formData.maxValue && this.formData.minValue && this.formData.standardValue) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.editData.fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.editData.updater = this.$loginInfo.account; |
| | | |
| | | this.$post({ |
| | |
| | | if (item.fcheckResu == '1') { |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否已填写不良描述 |
| | | if (!this.formData.remarks || this.formData.remarks.trim() === '') { |
| | | this.$showMessage("检验项目不合格,必须填写不良描述!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | this.$post({ |
| | |
| | | current: this.previewContent |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | // 上传图片方法 - 保存到当前检验项目的PICTURE字段(LONG RAW类型) |
| | | // 后端会自动生成时间戳文件名,格式:1746945271304.jpg |
| | | uploadImage() { |
| | | // 显示选择弹窗,让用户选择拍照或从相册选择 |
| | | uni.showActionSheet({ |
| | | itemList: ['拍照', '从相册选择'], |
| | | success: (res) => { |
| | | const sourceType = res.tapIndex === 0 ? ['camera'] : ['album']; |
| | | this.chooseImageWithSource(sourceType); |
| | | }, |
| | | fail: (error) => { |
| | | console.log('用户取消选择:', error); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 根据选择的来源选择图片 |
| | | chooseImageWithSource(sourceType) { |
| | | uni.chooseImage({ |
| | | count: 1, // 最多选择1张图片 |
| | | sizeType: ['compressed', 'original'], // 提供压缩和原图选项 |
| | | sourceType: sourceType, // 根据用户选择设置来源 |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | |
| | | // 如果是拍照,显示预览确认 |
| | | if (sourceType.includes('camera')) { |
| | | this.showImagePreview(tempFilePath); |
| | | } else { |
| | | this.uploadImageToServer(tempFilePath); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | | console.error('选择图片失败:', error); |
| | | let errorMessage = '选择图片失败'; |
| | | if (sourceType.includes('camera')) { |
| | | errorMessage = '拍照失败,请检查相机权限'; |
| | | } |
| | | uni.showToast({ |
| | | title: errorMessage, |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 显示图片预览确认(主要用于拍照后的确认) |
| | | showImagePreview(imagePath) { |
| | | uni.previewImage({ |
| | | urls: [imagePath], |
| | | current: imagePath, |
| | | success: () => { |
| | | // 用户查看图片后,询问是否使用此图片 |
| | | uni.showModal({ |
| | | title: '确认使用此图片', |
| | | content: '是否使用刚才拍摄的图片?', |
| | | confirmText: '使用', |
| | | cancelText: '重新拍摄', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.uploadImageToServer(imagePath); |
| | | } else if (res.cancel) { |
| | | // 用户选择重新拍摄 |
| | | this.chooseImageWithSource(['camera']); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | fail: () => { |
| | | // 预览失败,直接上传 |
| | | this.uploadImageToServer(imagePath); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 上传图片到服务器并保存到数据库PICTURE字段(LONG RAW类型) |
| | | // 后端会自动生成时间戳文件名存储到PICTURENAME字段 |
| | | uploadImageToServer(filePath) { |
| | | uni.showLoading({ |
| | | title: '上传中...' |
| | | }); |
| | | |
| | | // 构建上传URL |
| | | const uploadUrl = this.$store.state.serverInfo.serverAPI + "/XJ/UploadImageToPicture"; |
| | | |
| | | uni.uploadFile({ |
| | | url: uploadUrl, |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id, // 当前检验项目ID |
| | | gid: this.gid, |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (uploadRes) => { |
| | | uni.hideLoading(); |
| | | try { |
| | | const result = JSON.parse(uploadRes.data); |
| | | if (result.status === 0) { |
| | | uni.showToast({ |
| | | title: '图片保存成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新页面数据 |
| | | this.refreshResult(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: result.message || '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | console.error('解析上传结果失败:', error); |
| | | uni.showToast({ |
| | | title: '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | | uni.hideLoading(); |
| | | console.error('上传失败:', error); |
| | | uni.showToast({ |
| | | title: '图片保存失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 删除图片 |
| | | deleteImage() { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除当前图片吗?删除后无法恢复。', |
| | | confirmText: '删除', |
| | | cancelText: '取消', |
| | | confirmColor: '#e74c3c', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/XJ/DeleteImageFromPicture", |
| | | data: { |
| | | id: this.id // 当前检验项目ID |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | | uni.showToast({ |
| | | title: '图片删除成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新页面数据 |
| | | this.refreshResult(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.message || '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(error => { |
| | | uni.hideLoading(); |
| | | console.error('删除图片失败:', error); |
| | | uni.showToast({ |
| | | title: '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | }); |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .section-title { |
| | | flex: 1; |
| | | } |
| | | |
| | | .section-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .delete-image-btn { |
| | | padding: 6px 12px; |
| | | border: 1px solid #e74c3c; |
| | | border-radius: 4px; |
| | | background-color: #e74c3c; |
| | | color: white; |
| | | font-size: 12px; |
| | | font-weight: 500; |
| | | cursor: pointer; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .delete-image-btn:hover { |
| | | background-color: #c0392b; |
| | | border-color: #c0392b; |
| | | } |
| | | |
| | | .delete-image-btn:active { |
| | | background-color: #a93226; |
| | | border-color: #a93226; |
| | | } |
| | | |
| | | .section-body { |
| | |
| | | .hint-text { |
| | | font-size: 12px; |
| | | color: #856404; |
| | | } |
| | | |
| | | /* 验证提示样式 */ |
| | | .validation-hint { |
| | | background: linear-gradient(135deg, #ffe6e6 0%, #ffcccc 100%); |
| | | border: 2px solid #ff6b6b; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | box-shadow: 0 2px 8px rgba(255, 107, 107, 0.2); |
| | | } |
| | | |
| | | .validation-icon { |
| | | font-size: 24px; |
| | | flex-shrink: 0; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .validation-text { |
| | | flex: 1; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #d63031; |
| | | margin-bottom: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | .validation-requirements { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 6px 10px; |
| | | border-radius: 6px; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .requirement-item.completed { |
| | | background-color: #d4edda; |
| | | border: 1px solid #c3e6cb; |
| | | } |
| | | |
| | | .requirement-item.required { |
| | | background-color: #f8d7da; |
| | | border: 1px solid #f5c6cb; |
| | | } |
| | | |
| | | .requirement-icon { |
| | | font-size: 16px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | .input-group { |
| | |
| | | color: white; |
| | | } |
| | | |
| | | .action-btn.success { |
| | | background-color: #2ecc71; |
| | | color: white; |
| | | } |
| | | |
| | | /* 平板上传按钮样式 */ |
| | | .tablet-upload-btn { |
| | | position: relative; |
| | | overflow: hidden; |
| | | background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%); |
| | | box-shadow: 0 4px 15px rgba(46, 204, 113, 0.3); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .tablet-upload-btn:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 6px 20px rgba(46, 204, 113, 0.4); |
| | | } |
| | | |
| | | .tablet-upload-btn:active { |
| | | transform: translateY(0); |
| | | box-shadow: 0 2px 10px rgba(46, 204, 113, 0.3); |
| | | } |
| | | |
| | | .btn-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | padding: 8px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 24px; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | line-height: 1.2; |
| | | text-align: center; |
| | | } |
| | | |
| | | /* 弹出框样式 */ |
| | | .overlay { |
| | | position: fixed; |
| | |
| | | } |
| | | } |
| | | |
| | | /* 平板优化样式 */ |
| | | @media (min-width: 768px) and (max-width: 1024px) { |
| | | .action-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 15px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .action-btn { |
| | | padding: 20px 16px; |
| | | font-size: 16px; |
| | | min-height: 80px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .tablet-upload-btn { |
| | | min-height: 100px; |
| | | } |
| | | |
| | | .btn-content { |
| | | gap: 12px; |
| | | padding: 12px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 32px; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .info-grid { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | gap: 20px; |
| | | } |
| | | |
| | | .section-body { |
| | | padding: 30px; |
| | | } |
| | | |
| | | .validation-hint { |
| | | padding: 20px; |
| | | margin-bottom: 25px; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | padding: 10px 15px; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | /* 大屏平板优化 */ |
| | | @media (min-width: 1024px) { |
| | | .action-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 20px; |
| | | margin-bottom: 40px; |
| | | } |
| | | |
| | | .action-btn { |
| | | padding: 25px 20px; |
| | | font-size: 18px; |
| | | min-height: 100px; |
| | | } |
| | | |
| | | .tablet-upload-btn { |
| | | min-height: 120px; |
| | | } |
| | | |
| | | .btn-content { |
| | | gap: 15px; |
| | | padding: 15px; |
| | | } |
| | | |
| | | .btn-icon { |
| | | font-size: 36px; |
| | | } |
| | | |
| | | .btn-text { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .info-grid { |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 25px; |
| | | } |
| | | |
| | | .section-body { |
| | | padding: 40px; |
| | | } |
| | | |
| | | .validation-hint { |
| | | padding: 25px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .validation-title { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .requirement-item { |
| | | padding: 12px 18px; |
| | | } |
| | | |
| | | .requirement-text { |
| | | font-size: 15px; |
| | | } |
| | | } |
| | | |
| | | /* 附件相关样式 */ |
| | | .attachment-list-popup { |
| | | width: 80vw; |
| | |
| | | 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://localhost:5184/api',//当前正在使用的服务器,默认为外网 localhost |
| | | //serverAPI:'http://192.168.1.22:10054/api',//内网 |
| | | //serverAPI:'http://36.26.21.214:10055/api', |
| | | serverAPI:'http://36.26.21.214:10055/api', |
| | | ftpServer:'ftp://36.26.21.214',//FTP服务器地址 |
| | | } |
| | | }, |