| | |
| | | "name" : "GS-MES-AP", |
| | | "appid" : "__UNI__F08FAE3", |
| | | "description" : "", |
| | | "versionName" : "1.1.4.6", |
| | | "versionName" : "1.1.4.9", |
| | | "versionCode" : 1, |
| | | "transformPx" : false, |
| | | /* 5+App特有相关 */ |
| | |
| | | |
| | | <view class="form-row"> |
| | | <label class="form-label required">送检数量:</label> |
| | | <input type="number" v-model="formData.quantity" placeholder="请输入送检数量" class="large-quantity-input" |
| | | @input="onQuantityChange" /> |
| | | <input type="number" v-model="formData.sjqty" placeholder="请输入送检数量" class="large-quantity-input" |
| | | @input="onSjqtyChange" /> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | |
| | | <view class="form-actions"> |
| | | <button class="btn-primary" |
| | | v-if="!isShowTable && formData.workShop && formData.lineName && formData.rBillNo && formData.quantity" |
| | | v-if="!isShowTable && formData.workShop && formData.lineName && formData.rBillNo && formData.sjqty" |
| | | @click="getItem"> |
| | | <text class="btn-icon">✓</text> |
| | | 生成检验单 |
| | |
| | | <view class="info-value">{{formData.itemModel}}</view> |
| | | </view> |
| | | <view class="info-block"> |
| | | <view class="info-label">工单数量:</view> |
| | | <view class="info-value">{{formData.quantity || formData.planQty}}</view> |
| | | </view> |
| | | <view class="info-block"> |
| | | <view class="info-label">送检数量:</view> |
| | | <view class="info-value highlight">{{formData.quantity}}</view> |
| | | <view class="info-value highlight">{{formData.sjqty}}</view> |
| | | </view> |
| | | <view class="info-block" v-if="formData.remarks"> |
| | | <view class="info-label">不合格描述:</view> |
| | |
| | | rbillNo: "", |
| | | workShop: "", // 工作车间 |
| | | lineName: "", // 线体名称 |
| | | quantity: "", // 送检数量 |
| | | quantity: "", // 工单数量(原送检数量字段) |
| | | sjqty: "", // 送检数量(新增字段) |
| | | planQty: "", // 工单计划数量 |
| | | fngDesc: "" // 不良描述 |
| | | }, |
| | |
| | | data: { |
| | | from: this.formData, |
| | | userNo: this.$loginInfo.account, |
| | | quantity: this.formData.quantity, |
| | | //moidNum: this.formData.moidNum |
| | | quantity: this.formData.quantity, // 工单数量 |
| | | sjqty: this.formData.sjqty, // 送检数量 |
| | | items: this.tableData |
| | | } |
| | | }).then(res => { |
| | |
| | | this.formData.billNo = data.daa001; // 工单号作为billNo |
| | | this.formData.rbillNo = "无源单"; // 送检批次号(使用默认值) |
| | | this.formData.itemModel = data.daa004 || ""; // 产品规格 |
| | | this.formData.planQty = data.daa008 || ""; // 工单数量 |
| | | this.formData.planQty = data.daa008 || ""; // 工单数量(仅显示) |
| | | this.formData.quantity = data.daa008 || ""; // 工单数量(保存到数据库) |
| | | // 不清空送检数量,保持用户已输入的值 |
| | | this.tableData = []; |
| | | }, |
| | | // 送检数量变化事件 |
| | | onQuantityChange(event) { |
| | | onSjqtyChange(event) { |
| | | // 如果输入为空,不进行验证 |
| | | if (!this.formData.quantity || this.formData.quantity === "") { |
| | | if (!this.formData.sjqty || this.formData.sjqty === "") { |
| | | return; |
| | | } |
| | | |
| | | const quantity = parseFloat(this.formData.quantity); |
| | | const sjqty = parseFloat(this.formData.sjqty); |
| | | |
| | | // 检查是否为有效数字 |
| | | if (isNaN(quantity)) { |
| | | if (isNaN(sjqty)) { |
| | | this.$showMessage("请输入有效的数字"); |
| | | this.formData.quantity = ""; |
| | | this.formData.sjqty = ""; |
| | | return; |
| | | } |
| | | |
| | | // 只有在输入完成且数量大于0时才进行验证 |
| | | if (quantity <= 0) { |
| | | if (sjqty <= 0) { |
| | | this.$showMessage("送检数量必须大于0"); |
| | | this.formData.quantity = ""; |
| | | this.formData.sjqty = ""; |
| | | return; |
| | | } |
| | | |
| | | // 只有在已选择工单且有工单数量时才进行数量比较 |
| | | if (this.formData.planQty) { |
| | | const planQty = parseFloat(this.formData.planQty); |
| | | if (!isNaN(planQty) && quantity > planQty) { |
| | | if (this.formData.quantity || this.formData.planQty) { |
| | | const planQty = parseFloat(this.formData.quantity || this.formData.planQty); |
| | | if (!isNaN(planQty) && sjqty > planQty) { |
| | | this.$showMessage("送检数量不能大于工单数量"); |
| | | this.formData.quantity = ""; |
| | | this.formData.sjqty = ""; |
| | | return; |
| | | } |
| | | } |
| | |
| | | this.formData.itemNo = data.itemNo; |
| | | this.formData.itemId = data.itemId; |
| | | this.formData.lineNo = data.lineNo; |
| | | this.formData.quantity = data.quantity; |
| | | this.formData.quantity = data.quantity; // 工单数量 |
| | | this.formData.sjqty = data.sjqty; // 送检数量 |
| | | this.formData.fcheckResu = data.fcheckResu; |
| | | this.formData.fcheckBy = data.fcheckBy; |
| | | this.formData.fcheckDate = data.fcheckDate; |
| | |
| | | }); |
| | | }, |
| | | getTable() { |
| | | // 确保quantity有值 |
| | | if (!this.formData.quantity || parseFloat(this.formData.quantity) <= 0) { |
| | | // 确保sjqty有值 |
| | | if (!this.formData.sjqty || parseFloat(this.formData.sjqty) <= 0) { |
| | | this.$showMessage("请先输入有效的送检数量"); |
| | | return; |
| | | } |
| | |
| | | url: "/RKJ/setJYItem", |
| | | data: { |
| | | itemNo: this.formData.itemNo, |
| | | quantity: this.formData.quantity |
| | | quantity: this.formData.sjqty |
| | | } |
| | | }).then(res => { |
| | | |
| | |
| | | |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <text class="info-label">送检数量</text> |
| | | <text class="info-content highlight">{{item.quantity}}</text> |
| | | <text class="info-label">工单数量</text> |
| | | <text class="info-content">{{item.quantity}}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">创建人</text> |
| | | <text class="info-content">{{item.createBy}}</text> |
| | | <text class="info-label">送检数量</text> |
| | | <text class="info-content highlight">{{item.sjqty}}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <text class="info-label">创建人</text> |
| | | <text class="info-content">{{item.createBy}}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">送检批次</text> |
| | | <text class="info-content">{{item.rbillNo}}</text> |
| | | </view> |
| | |
| | | v-model="formData.fcheckResu" |
| | | type="text" |
| | | class="result-input" |
| | | placeholder="没有最大值和最小值时填写0(未通过检验)或1(通过检验)" |
| | | placeholder="无上下限时填写OK(合格)或NG(不合格)" |
| | | placeholder-class="placeholder" /> |
| | | <button v-if="(tableData.length < formData.levelNum)" |
| | | style="margin: 0px;background-color: #3498db;color:#ffffff ;" class="btn primary-btn" |
| | |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <!-- 图片预览 - 支持多图片 --> |
| | | <view v-if="imageList && imageList.length > 0" class="section"> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | <view class="section-title">相关图片 ({{ imageList.length }}张)</view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | | <view class="image-list"> |
| | | <view v-for="(img, index) in imageList" :key="img.id" class="image-item"> |
| | | <view class="image-preview" @click="previewMultiImage(index)"> |
| | | <image :src="'data:image/jpeg;base64,' + img.base64Data" mode="aspectFill" class="preview-image"/> |
| | | </view> |
| | | <view class="image-actions"> |
| | | <button class="delete-image-btn" @click="deleteSingleImage(img)"> |
| | | <text class="delete-icon">🗑️</text> |
| | | <text>删除</text> |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | <view class="td"> |
| | | <view class="result-badge" :class="item.fcheckResu === '1' ? 'OK' : 'NG'"> |
| | | <view class="result-badge" :class="(item.fcheckResu === 'OK' || item.fcheckResu === '1' || item.fcheckResu == 1) ? 'OK' : 'NG'"> |
| | | {{ item.fcheckResu }} |
| | | </view> |
| | | </view> |
| | |
| | | tableData: [], |
| | | isShowImg: false, |
| | | base64Image: "", |
| | | imageList: [], // 多图片列表 |
| | | remarks: "", |
| | | remarksPopup: false, |
| | | fcheckResu: null, |
| | |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | return this.imageList && this.imageList.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | |
| | | }, |
| | | |
| | | editResult(fcheckResu) { |
| | | if (fcheckResu == '1') { |
| | | // 1 或 OK 都表示合格 |
| | | if (fcheckResu == '1' || fcheckResu == 'OK' || fcheckResu == 1) { |
| | | return "改为不合格"; |
| | | } else { |
| | | return "改为合格"; |
| | |
| | | } else { |
| | | |
| | | if (!this.formData.fcheckResu) { |
| | | this.formData.fcheckResu = 1 |
| | | this.formData.fcheckResu = 'OK'; // 默认合格 |
| | | } |
| | | |
| | | if (this.formData.fcheckResu == 0 || this.formData.fcheckResu == 1) { |
| | | this.formData.isPass = this.formData.fcheckResu |
| | | // 统一使用 OK/NG |
| | | const upperValue = String(this.formData.fcheckResu).toUpperCase(); |
| | | if (upperValue === 'OK' || upperValue === 'NG') { |
| | | this.formData.fcheckResu = upperValue; // 统一转为大写 |
| | | if (upperValue === 'NG') { |
| | | fstand = "×"; |
| | | } |
| | | } else { |
| | | this.$showMessage("无标准值时,检验结果只能为0或1!"); |
| | | this.$showMessage("无上下限时,检验结果只能为OK或NG!"); |
| | | return; |
| | | } |
| | | count = count - this.tableData.length; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | if (fstand === "×" || this.formData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | |
| | | this.tableData = res.data.tbBillList.itemXj02s; |
| | | |
| | | // 处理图片显示状态 |
| | | if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | // 处理多图片列表 |
| | | if (this.formData.imageList && this.formData.imageList.length > 0) { |
| | | this.imageList = this.formData.imageList; |
| | | this.isShowImg = true; |
| | | if (this.imageList.length > 0) { |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.imageList[0].base64Data; |
| | | } |
| | | } else if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | // 向后兼容:如果没有imageList但有imageData |
| | | this.imageList = [{ |
| | | id: 0, |
| | | base64Data: this.formData.imageData, |
| | | fileName: '', |
| | | createDate: null, |
| | | createBy: '' |
| | | }]; |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | // 如果没有图片数据,隐藏图片显示区域 |
| | | this.imageList = []; |
| | | this.isShowImg = false; |
| | | this.base64Image = ''; |
| | | } |
| | |
| | | } else { |
| | | |
| | | if (!this.editData.fcheckResu) { |
| | | this.editData.fcheckResu = 1 |
| | | this.editData.fcheckResu = 'OK'; // 默认合格 |
| | | } |
| | | |
| | | if (this.editData.fcheckResu == 0 || this.editData.fcheckResu == 1) { |
| | | if (this.editData.fcheckResu == 0) { |
| | | // 统一使用 OK/NG |
| | | const upperValue = String(this.editData.fcheckResu).toUpperCase(); |
| | | if (upperValue === 'OK' || upperValue === 'NG') { |
| | | this.editData.fcheckResu = upperValue; // 统一转为大写 |
| | | if (upperValue === 'NG') { |
| | | fstand = "×"; |
| | | } |
| | | } else { |
| | | this.$showMessage("无标准值时,检验结果只能为0或1!"); |
| | | this.$showMessage("无上下限时,检验结果只能为OK或NG!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.editData.fcheckResu == 0) { |
| | | if (fstand === "×" || this.editData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | numberEdit(item) { |
| | | |
| | | let fstand = "√"; |
| | | let fcheckResu = 1; |
| | | let fcheckResu = 'OK'; // 合格用OK |
| | | |
| | | if (item.fcheckResu == '1') { |
| | | // 判断当前是否为合格状态(OK 或 1 都表示合格) |
| | | if (item.fcheckResu == '1' || item.fcheckResu == 'OK' || item.fcheckResu == 1) { |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | fcheckResu = 'NG'; // 不合格用NG |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | if (fstand === "×" || fcheckResu == 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 根据选择的来源选择图片 |
| | | // 根据选择的来源选择图片(支持多选) |
| | | chooseImageWithSource(sourceType) { |
| | | // 计算还可以上传多少张图片 |
| | | const currentCount = this.imageList ? this.imageList.length : 0; |
| | | const maxCount = 9; |
| | | const remainCount = maxCount - currentCount; |
| | | |
| | | if (remainCount <= 0) { |
| | | uni.showToast({ |
| | | title: '最多只能上传' + maxCount + '张图片', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.chooseImage({ |
| | | count: 1, // 最多选择1张图片 |
| | | sizeType: ['compressed', 'original'], // 提供压缩和原图选项 |
| | | sourceType: sourceType, // 根据用户选择设置来源 |
| | | count: sourceType.includes('camera') ? 1 : remainCount, // 拍照只能一张,相册可多选 |
| | | sizeType: ['compressed', 'original'], |
| | | sourceType: sourceType, |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | const tempFilePaths = res.tempFilePaths; |
| | | |
| | | // 如果是拍照,显示预览确认 |
| | | if (sourceType.includes('camera')) { |
| | | this.showImagePreview(tempFilePath); |
| | | this.showImagePreview(tempFilePaths[0]); |
| | | } else { |
| | | this.uploadImageToServer(tempFilePath); |
| | | // 多图片批量上传 |
| | | this.uploadMultipleImages(tempFilePaths); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | |
| | | } |
| | | uni.showToast({ |
| | | title: errorMessage, |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 批量上传图片 |
| | | uploadMultipleImages(tempFilePaths) { |
| | | if (!tempFilePaths || tempFilePaths.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | uni.showLoading({ |
| | | title: '上传中... (0/' + tempFilePaths.length + ')' |
| | | }); |
| | | |
| | | const uploadUrl = this.$store.state.serverInfo.serverAPI + "/RKJ/UploadImageToPicture"; |
| | | let successCount = 0; |
| | | let failCount = 0; |
| | | const total = tempFilePaths.length; |
| | | |
| | | const uploadPromises = tempFilePaths.map((filePath, index) => { |
| | | return new Promise((resolve) => { |
| | | uni.uploadFile({ |
| | | url: uploadUrl, |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id, |
| | | gid: this.gid, |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (uploadRes) => { |
| | | try { |
| | | const result = JSON.parse(uploadRes.data); |
| | | if (result.status === 0) { |
| | | successCount++; |
| | | } else { |
| | | failCount++; |
| | | } |
| | | } catch (error) { |
| | | failCount++; |
| | | } |
| | | uni.showLoading({ |
| | | title: '上传中... (' + (successCount + failCount) + '/' + total + ')' |
| | | }); |
| | | resolve(); |
| | | }, |
| | | fail: () => { |
| | | failCount++; |
| | | uni.showLoading({ |
| | | title: '上传中... (' + (successCount + failCount) + '/' + total + ')' |
| | | }); |
| | | resolve(); |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | |
| | | Promise.all(uploadPromises).then(() => { |
| | | uni.hideLoading(); |
| | | if (successCount > 0) { |
| | | uni.showToast({ |
| | | title: '成功上传' + successCount + '张图片', |
| | | icon: 'success' |
| | | }); |
| | | this.refreshResult(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: '图片上传失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 预览多图片 |
| | | previewMultiImage(index) { |
| | | const urls = this.imageList.map(img => 'data:image/jpeg;base64,' + img.base64Data); |
| | | uni.previewImage({ |
| | | urls: urls, |
| | | current: index |
| | | }); |
| | | }, |
| | | |
| | | // 删除单张图片 |
| | | deleteSingleImage(img) { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除这张图片吗?', |
| | | confirmText: '删除', |
| | | cancelText: '取消', |
| | | confirmColor: '#e74c3c', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(img.id); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | deleteImageFromServer(imageId = null) { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | const data = { id: this.id }; |
| | | if (imageId !== null && imageId !== undefined && imageId !== 0) { |
| | | data.imageId = imageId; |
| | | } |
| | | |
| | | this.$post({ |
| | | url: "/RKJ/DeleteImageFromPicture", |
| | | data: { |
| | | id: this.id // 当前检验项目ID |
| | | } |
| | | data: data |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | |
| | | } |
| | | } |
| | | |
| | | /* 多图片列表样式 */ |
| | | .image-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .image-item { |
| | | width: 150px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | |
| | | .image-preview { |
| | | width: 150px; |
| | | height: 150px; |
| | | border: 1px solid $border-color; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | |
| | | .preview-image { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | } |
| | | } |
| | | |
| | | .image-actions { |
| | | margin-top: 8px; |
| | | |
| | | .delete-image-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | padding: 6px 12px; |
| | | background-color: $danger-color; |
| | | color: #fff; |
| | | border: none; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | cursor: pointer; |
| | | |
| | | .delete-icon { |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .info-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | |
| | | v-model="formData.fcheckResu" |
| | | type="text" |
| | | class="result-input" |
| | | placeholder="没有最大值和最小值时填写0(未通过检验)或1(通过检验)" |
| | | placeholder="无上下限时填写OK(合格)或NG(不合格)" |
| | | placeholder-class="placeholder" /> |
| | | <button v-if="!isAllCompleted" |
| | | style="margin: 0px;background-color: #3498db;color:#ffffff ;" class="btn primary-btn" |
| | |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <!-- 图片预览 - 支持多图片 --> |
| | | <view v-if="imageList && imageList.length > 0" class="section"> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | <view class="section-title">相关图片 ({{ imageList.length }}张)</view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | | <view class="image-list"> |
| | | <view v-for="(img, index) in imageList" :key="img.id" class="image-item"> |
| | | <view class="image-preview" @click="previewMultiImage(index)"> |
| | | <image :src="'data:image/jpeg;base64,' + img.base64Data" mode="aspectFill" class="preview-image"/> |
| | | </view> |
| | | <view class="image-actions"> |
| | | <button class="delete-image-btn" @click="deleteSingleImage(img)"> |
| | | <text class="delete-icon">🗑️</text> |
| | | <text>删除</text> |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | tableData: [], |
| | | base64Image: "", |
| | | isShowImg: false, |
| | | imageList: [], // 多图片列表 |
| | | remarks: "", |
| | | remarksPopup: false, |
| | | // ===== 新增LLJ样式相关数据 ===== |
| | |
| | | this.formData.fcheckResu > this.formData.maxValue; |
| | | } |
| | | |
| | | // 如果没有最大值和最小值,检查是否为0(不合格) |
| | | return this.formData.fcheckResu == 0; |
| | | // 如果没有上下限,检查是否为NG(不合格)或兼容旧的06 |
| | | return this.formData.fcheckResu == 0 || this.formData.fcheckResu === 'NG'; |
| | | }, |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | return this.imageList && this.imageList.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | |
| | | return 'NG'; |
| | | } else { |
| | | // 如果没有fstand,根据fcheckResu的值判断 |
| | | if (fcheckResu === '1' || fcheckResu === 1) { |
| | | if (fcheckResu === '1' || fcheckResu === 1 || fcheckResu === 'OK') { |
| | | return 'OK'; |
| | | } else if (fcheckResu === '0' || fcheckResu === 0) { |
| | | } else if (fcheckResu === '0' || fcheckResu === 0 || fcheckResu === 'NG') { |
| | | return 'NG'; |
| | | } else { |
| | | // 对于有上下限的数值检验,根据fcheckResu是否在范围内判断 |
| | |
| | | return '不合格'; |
| | | } else { |
| | | // 如果没有fstand,根据fcheckResu的值判断 |
| | | if (fcheckResu === '1' || fcheckResu === 1) { |
| | | if (fcheckResu === '1' || fcheckResu === 1 || fcheckResu === 'OK') { |
| | | return '合格'; |
| | | } else if (fcheckResu === '0' || fcheckResu === 0) { |
| | | } else if (fcheckResu === '0' || fcheckResu === 0 || fcheckResu === 'NG') { |
| | | return '不合格'; |
| | | } else { |
| | | // 对于有上下限的数值检验,根据fcheckResu是否在范围内判断 |
| | |
| | | urls: [this.base64Image], |
| | | }); |
| | | }, |
| | | |
| | | // 多图片预览 |
| | | previewMultiImage(index) { |
| | | const urls = this.imageList.map(img => 'data:image/jpeg;base64,' + img.base64Data); |
| | | uni.previewImage({ |
| | | urls: urls, |
| | | current: index |
| | | }); |
| | | }, |
| | | |
| | | // 删除单张图片 |
| | | deleteSingleImage(img) { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除这张图片吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(img.id); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | editResult(fcheckResu) { |
| | | if (fcheckResu == '1') { |
| | | // 1 或 OK 都表示合格 |
| | | if (fcheckResu == '1' || fcheckResu == 'OK' || fcheckResu == 1) { |
| | | return "改为不合格"; |
| | | } else { |
| | | return "改为合格"; |
| | |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | if (fstand === "×" || this.formData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | console.log("获取到的 formData:", this.formData); |
| | | console.log("itemNo 值:", this.formData.itemNo); |
| | | |
| | | if (this.formData.imageData) { |
| | | // 处理多图片列表 |
| | | if (this.formData.imageList && this.formData.imageList.length > 0) { |
| | | this.imageList = this.formData.imageList; |
| | | this.isShowImg = true; |
| | | // 保持向后兼容 |
| | | if (this.imageList.length > 0) { |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.imageList[0].base64Data; |
| | | } |
| | | } else if (this.formData.imageData) { |
| | | // 向后兼容:如果只有单张图片数据 |
| | | this.imageList = [{ |
| | | id: 0, |
| | | base64Data: this.formData.imageData, |
| | | fileName: '', |
| | | createDate: null, |
| | | createBy: '' |
| | | }]; |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | this.imageList = []; |
| | | 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 (fstand === "×" || this.editData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | |
| | | numberEdit(item) { |
| | | |
| | | let fstand = "√"; |
| | | let fcheckResu = 1; |
| | | let fcheckResu = 'OK'; // 合格用OK |
| | | |
| | | if (item.fcheckResu == '1') { |
| | | // 判断当前是否为合格状态(OK 或 1 都表示合格) |
| | | if (item.fcheckResu == '1' || item.fcheckResu == 'OK' || item.fcheckResu == 1) { |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | fcheckResu = 'NG'; // 不合格用NG |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | if (fstand === "×" || fcheckResu == 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 选择图片来源 |
| | | // 选择图片来源 - 支持多选 |
| | | chooseImageWithSource(source) { |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | count: 9, // 支持最多选择9张图片 |
| | | sizeType: ['compressed'], |
| | | sourceType: [source], |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | const tempFilePaths = res.tempFilePaths; |
| | | if (source === 'camera') { |
| | | // 拍照后显示预览确认 |
| | | this.showImagePreview(tempFilePath); |
| | | // 拍照后直接上传(单张) |
| | | this.uploadImageToServer(tempFilePaths[0]); |
| | | } else { |
| | | // 相册选择直接上传 |
| | | this.uploadImageToServer(tempFilePath); |
| | | // 相册选择,批量上传 |
| | | this.uploadMultipleImages(tempFilePaths); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error('选择图片失败:', err); |
| | | this.$showMessage('选择图片失败'); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 批量上传图片 |
| | | uploadMultipleImages(tempFilePaths) { |
| | | if (!tempFilePaths || tempFilePaths.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | uni.showLoading({ |
| | | title: `上传中(0/${tempFilePaths.length})...` |
| | | }); |
| | | |
| | | let successCount = 0; |
| | | let failCount = 0; |
| | | const total = tempFilePaths.length; |
| | | |
| | | // 使用 Promise.all 并行上传 |
| | | const uploadPromises = tempFilePaths.map((filePath, index) => { |
| | | return new Promise((resolve) => { |
| | | uni.uploadFile({ |
| | | url: this.$store.state.serverInfo.serverAPI + '/SJ/UploadImageToPicture', |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id.toString(), |
| | | gid: this.gid.toString(), |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (res) => { |
| | | try { |
| | | const result = JSON.parse(res.data); |
| | | if (result.status === 0) { |
| | | successCount++; |
| | | } else { |
| | | failCount++; |
| | | } |
| | | } catch (e) { |
| | | failCount++; |
| | | } |
| | | uni.showLoading({ |
| | | title: `上传中(${successCount + failCount}/${total})...` |
| | | }); |
| | | resolve(); |
| | | }, |
| | | fail: (err) => { |
| | | failCount++; |
| | | console.error('上传失败:', err); |
| | | resolve(); |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | |
| | | Promise.all(uploadPromises).then(() => { |
| | | uni.hideLoading(); |
| | | if (failCount === 0) { |
| | | this.$showMessage(`${successCount}张图片上传成功`); |
| | | } else { |
| | | this.$showMessage(`上传完成:成功${successCount}张,失败${failCount}张`); |
| | | } |
| | | this.refreshResult(); |
| | | }); |
| | | }, |
| | | |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | // 从服务器删除图片 - 支持删除单张或所有图片 |
| | | deleteImageFromServer(imageId = null) { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | const data = { |
| | | id: this.id |
| | | }; |
| | | |
| | | // 如果传入了 imageId,则删除单张图片 |
| | | if (imageId !== null && imageId !== undefined && imageId !== 0) { |
| | | data.imageId = imageId; |
| | | } |
| | | |
| | | this.$post({ |
| | | url: '/SJ/DeleteImageFromPicture', |
| | | data: { |
| | | id: this.id |
| | | } |
| | | data: data |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | /* 多图片列表样式 */ |
| | | .image-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 12px; |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .image-item { |
| | | position: relative; |
| | | width: calc(33.33% - 8px); |
| | | min-width: 100px; |
| | | max-width: 150px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | background: #fff; |
| | | box-shadow: 0 2px 12px rgba(0,0,0,0.08); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .image-item:hover { |
| | | box-shadow: 0 4px 20px rgba(0,0,0,0.12); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | width: 100%; |
| | | height: 100px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | position: relative; |
| | | } |
| | | |
| | | .image-item .preview-image { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | } |
| | | |
| | | .image-actions { |
| | | padding: 8px 6px; |
| | | text-align: center; |
| | | background: linear-gradient(to bottom, #fafafa, #f5f5f5); |
| | | } |
| | | |
| | | .image-actions .delete-image-btn { |
| | | width: 100%; |
| | | padding: 8px 12px; |
| | | font-size: 13px; |
| | | border-radius: 20px; |
| | | background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%); |
| | | border: none; |
| | | color: white; |
| | | font-weight: 500; |
| | | box-shadow: 0 2px 8px rgba(238, 90, 90, 0.3); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 4px; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .image-actions .delete-image-btn:active { |
| | | transform: scale(0.95); |
| | | box-shadow: 0 1px 4px rgba(238, 90, 90, 0.3); |
| | | } |
| | | |
| | | .delete-icon { |
| | | font-size: 14px; |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | /* 移动端优化 */ |
| | | @media (max-width: 480px) { |
| | | .image-list { |
| | | gap: 10px; |
| | | } |
| | | |
| | | .image-item { |
| | | width: calc(50% - 5px); |
| | | min-width: 0; |
| | | max-width: none; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | height: 90px; |
| | | } |
| | | |
| | | .image-actions { |
| | | padding: 6px 5px; |
| | | } |
| | | |
| | | .image-actions .delete-image-btn { |
| | | padding: 6px 10px; |
| | | font-size: 12px; |
| | | border-radius: 16px; |
| | | } |
| | | } |
| | | |
| | | @media (min-width: 768px) { |
| | | .image-item { |
| | | width: calc(25% - 9px); |
| | | max-width: 160px; |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | height: 120px; |
| | | } |
| | | } |
| | | |
| | | /* 上传图片按钮样式 */ |
| | | .tablet-upload-btn { |
| | | background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%); |
| | |
| | | v-model="formData.fcheckResu" |
| | | type="text" |
| | | class="result-input" |
| | | placeholder="没有最大值和最小值时填写0(未通过检验)或1(通过检验)" |
| | | placeholder="无上下限时填写OK(合格)或NG(不合格)" |
| | | placeholder-class="placeholder" /> |
| | | <button v-if="(tableData.length < formData.levelNum)" |
| | | style="margin: 0px;background-color: #3498db;color:#ffffff ;" class="btn primary-btn" |
| | |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 图片预览 --> |
| | | <view v-if="isShowImg" class="section"> |
| | | <!-- 图片预览 - 支持多图片 --> |
| | | <view v-if="imageList && imageList.length > 0" class="section"> |
| | | <view class="section-header"> |
| | | <view class="section-title">相关图片</view> |
| | | <view class="section-actions"> |
| | | <button class="delete-image-btn" @click="deleteImage">删除图片</button> |
| | | </view> |
| | | <view class="section-title">相关图片 ({{ imageList.length }}张)</view> |
| | | </view> |
| | | <view class="section-body"> |
| | | <view class="image-preview" @click="previewImage"> |
| | | <image :src="base64Image" mode="aspectFit" class="preview-image"/> |
| | | <view class="image-list"> |
| | | <view v-for="(img, index) in imageList" :key="img.id" class="image-item"> |
| | | <view class="image-preview" @click="previewMultiImage(index)"> |
| | | <image :src="'data:image/jpeg;base64,' + img.base64Data" mode="aspectFill" class="preview-image"/> |
| | | </view> |
| | | <view class="image-actions"> |
| | | <button class="delete-image-btn" @click="deleteSingleImage(img)"> |
| | | <text class="delete-icon">🗑️</text> |
| | | <text>删除</text> |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | <view v-for="(item, index) in tableData" :key="index" class="table-row"> |
| | | <view class="td">{{ index + 1 }}</view> |
| | | <view class="td"> |
| | | <view :class="['result-badge', item.fstand === '√' ? 'OK' : 'NG']"> |
| | | <view class="result-badge" :class="(item.fcheckResu === 'OK' || item.fcheckResu === '1' || item.fcheckResu == 1) ? 'OK' : 'NG'"> |
| | | {{ item.fcheckResu }} |
| | | </view> |
| | | </view> |
| | |
| | | editData: {}, |
| | | tableData: [], |
| | | isShowImg: false, |
| | | base64Image:"", |
| | | base64Image: "", |
| | | imageList: [], // 多图片列表 |
| | | remarks: "", |
| | | remarksPopup: false, |
| | | |
| | |
| | | |
| | | // 判断是否已上传图片 |
| | | hasImage() { |
| | | return this.formData.imageData && this.formData.imageData.length > 0; |
| | | return this.imageList && this.imageList.length > 0; |
| | | }, |
| | | |
| | | // 判断是否已填写不良描述 |
| | |
| | | urls: [this.base64Image], |
| | | }); |
| | | }, |
| | | |
| | | // 多图片预览 |
| | | previewMultiImage(index) { |
| | | const urls = this.imageList.map(img => 'data:image/jpeg;base64,' + img.base64Data); |
| | | uni.previewImage({ |
| | | urls: urls, |
| | | current: index |
| | | }); |
| | | }, |
| | | |
| | | // 删除单张图片 |
| | | deleteSingleImage(img) { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除这张图片吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.deleteImageFromServer(img.id); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | editResult(fcheckResu) { |
| | | if (fcheckResu == '1') { |
| | | // 1 或 OK 都表示合格 |
| | | if (fcheckResu == '1' || fcheckResu == 'OK' || fcheckResu == 1) { |
| | | return "改为不合格"; |
| | | } else { |
| | | return "改为合格"; |
| | |
| | | } |
| | | count = 1; |
| | | } else { |
| | | |
| | | if (!this.formData.fcheckResu) { |
| | | this.formData.fcheckResu = 1 |
| | | this.formData.fcheckResu = 'OK'; // 默认合格 |
| | | } |
| | | |
| | | if (this.formData.fcheckResu == 0 || this.formData.fcheckResu == 1) { |
| | | this.formData.isPass = this.formData.fcheckResu |
| | | // 统一使用 OK/NG |
| | | const upperValue = String(this.formData.fcheckResu).toUpperCase(); |
| | | if (upperValue === 'OK' || upperValue === 'NG') { |
| | | this.formData.fcheckResu = upperValue; // 统一转为大写 |
| | | if (upperValue === 'NG') { |
| | | fstand = "×"; |
| | | } |
| | | } else { |
| | | this.$showMessage("无标准值时,检验结果只能为0或1!"); |
| | | this.$showMessage("无上下限时,检验结果只能为OK或NG!"); |
| | | return; |
| | | } |
| | | count = count - this.tableData.length; |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.formData.fcheckResu == 0) { |
| | | if (fstand === "×" || this.formData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | |
| | | this.tableData = res.data.tbBillList.itemXj02s; |
| | | |
| | | // 处理图片显示状态 |
| | | if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | // 处理多图片列表 |
| | | if (this.formData.imageList && this.formData.imageList.length > 0) { |
| | | this.imageList = this.formData.imageList; |
| | | this.isShowImg = true; |
| | | // 保持向后兼容 |
| | | if (this.imageList.length > 0) { |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.imageList[0].base64Data; |
| | | } |
| | | } else if (this.formData.imageData && this.formData.imageData.length > 0) { |
| | | // 向后兼容:如果只有单张图片数据 |
| | | this.imageList = [{ |
| | | id: 0, |
| | | base64Data: this.formData.imageData, |
| | | fileName: '', |
| | | createDate: null, |
| | | createBy: '' |
| | | }]; |
| | | this.isShowImg = true; |
| | | this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData; |
| | | } else { |
| | | // 如果没有图片数据,隐藏图片显示区域 |
| | | this.imageList = []; |
| | | this.isShowImg = false; |
| | | this.base64Image = ''; |
| | | } |
| | |
| | | fstand = "×"; |
| | | } |
| | | } else { |
| | | |
| | | if (!this.editData.fcheckResu) { |
| | | this.editData.fcheckResu = 1 |
| | | this.editData.fcheckResu = 'OK'; // 默认合格 |
| | | } |
| | | |
| | | if (this.editData.fcheckResu == 0 || this.editData.fcheckResu == 1) { |
| | | if (this.editData.fcheckResu == 0) { |
| | | // 统一使用 OK/NG |
| | | const upperValue = String(this.editData.fcheckResu).toUpperCase(); |
| | | if (upperValue === 'OK' || upperValue === 'NG') { |
| | | this.editData.fcheckResu = upperValue; // 统一转为大写 |
| | | if (upperValue === 'NG') { |
| | | fstand = "×"; |
| | | } |
| | | } else { |
| | | this.$showMessage("无标准值时,检验结果只能为0或1!"); |
| | | this.$showMessage("无上下限时,检验结果只能为OK或NG!"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || this.editData.fcheckResu == 0) { |
| | | if (fstand === "×" || this.editData.fcheckResu === 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | numberEdit(item) { |
| | | |
| | | let fstand = "√"; |
| | | let fcheckResu = 1; |
| | | let fcheckResu = 'OK'; // 合格用OK |
| | | |
| | | if (item.fcheckResu == '1') { |
| | | // 判断当前是否为合格状态(OK 或 1 都表示合格) |
| | | if (item.fcheckResu == '1' || item.fcheckResu == 'OK' || item.fcheckResu == 1) { |
| | | fstand = "×"; |
| | | fcheckResu = 0; |
| | | fcheckResu = 'NG'; // 不合格用NG |
| | | } |
| | | |
| | | // 验证不合格检验项目必须上传图片并填写不良描述 |
| | | if (fstand === "×" || fcheckResu == 0) { |
| | | if (fstand === "×" || fcheckResu == 'NG') { |
| | | // 检查是否已上传图片 |
| | | if (!this.formData.imageData || this.formData.imageData.length === 0) { |
| | | if (!this.imageList || this.imageList.length === 0) { |
| | | this.$showMessage("检验项目不合格,必须上传图片!"); |
| | | return; |
| | | } |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 根据选择的来源选择图片 |
| | | // 根据选择的来源选择图片 - 支持多选 |
| | | chooseImageWithSource(sourceType) { |
| | | uni.chooseImage({ |
| | | count: 1, // 最多选择1张图片 |
| | | sizeType: ['compressed', 'original'], // 提供压缩和原图选项 |
| | | count: 9, // 最多选择9张图片 |
| | | sizeType: ['compressed'], // 压缩图片 |
| | | sourceType: sourceType, // 根据用户选择设置来源 |
| | | success: (res) => { |
| | | const tempFilePath = res.tempFilePaths[0]; |
| | | const tempFilePaths = res.tempFilePaths; |
| | | |
| | | // 如果是拍照,显示预览确认 |
| | | // 如果是拍照,直接上传(单张) |
| | | if (sourceType.includes('camera')) { |
| | | this.showImagePreview(tempFilePath); |
| | | this.uploadImageToServer(tempFilePaths[0]); |
| | | } else { |
| | | this.uploadImageToServer(tempFilePath); |
| | | // 相册选择,批量上传 |
| | | this.uploadMultipleImages(tempFilePaths); |
| | | } |
| | | }, |
| | | fail: (error) => { |
| | |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 批量上传图片 |
| | | uploadMultipleImages(tempFilePaths) { |
| | | if (!tempFilePaths || tempFilePaths.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | uni.showLoading({ |
| | | title: `上传中(0/${tempFilePaths.length})...` |
| | | }); |
| | | |
| | | let successCount = 0; |
| | | let failCount = 0; |
| | | const total = tempFilePaths.length; |
| | | |
| | | // 使用 Promise.all 并行上传 |
| | | const uploadPromises = tempFilePaths.map((filePath, index) => { |
| | | return new Promise((resolve) => { |
| | | uni.uploadFile({ |
| | | url: this.$store.state.serverInfo.serverAPI + '/XJ/UploadImageToPicture', |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | id: this.id.toString(), |
| | | gid: this.gid.toString(), |
| | | billNo: this.billNo, |
| | | createBy: this.$loginInfo.account |
| | | }, |
| | | success: (res) => { |
| | | try { |
| | | const result = JSON.parse(res.data); |
| | | if (result.status === 0) { |
| | | successCount++; |
| | | } else { |
| | | failCount++; |
| | | } |
| | | } catch (e) { |
| | | failCount++; |
| | | } |
| | | uni.showLoading({ |
| | | title: `上传中(${successCount + failCount}/${total})...` |
| | | }); |
| | | resolve(); |
| | | }, |
| | | fail: (err) => { |
| | | failCount++; |
| | | console.error('上传失败:', err); |
| | | resolve(); |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | |
| | | Promise.all(uploadPromises).then(() => { |
| | | uni.hideLoading(); |
| | | if (failCount === 0) { |
| | | this.$showMessage(`${successCount}张图片上传成功`); |
| | | } else { |
| | | this.$showMessage(`上传完成:成功${successCount}张,失败${failCount}张`); |
| | | } |
| | | this.refreshResult(); |
| | | }); |
| | | }, |
| | | |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 从服务器删除图片 |
| | | deleteImageFromServer() { |
| | | // 从服务器删除图片 - 支持删除单张或所有图片 |
| | | deleteImageFromServer(imageId = null) { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | const data = { |
| | | id: this.id |
| | | }; |
| | | |
| | | // 如果传入了 imageId,则删除单张图片 |
| | | if (imageId !== null && imageId !== undefined && imageId !== 0) { |
| | | data.imageId = imageId; |
| | | } |
| | | |
| | | this.$post({ |
| | | url: "/XJ/DeleteImageFromPicture", |
| | | data: { |
| | | id: this.id // 当前检验项目ID |
| | | } |
| | | url: '/XJ/DeleteImageFromPicture', |
| | | data: data |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | | uni.showToast({ |
| | | title: '图片删除成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新页面数据 |
| | | this.refreshResult(); |
| | | this.$showMessage('图片删除成功'); |
| | | this.refreshResult(); // 刷新页面数据 |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.message || '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | this.$showMessage(res.message || '删除失败'); |
| | | } |
| | | }).catch(error => { |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('删除图片失败:', error); |
| | | uni.showToast({ |
| | | title: '图片删除失败', |
| | | icon: 'none' |
| | | }); |
| | | console.error('删除图片失败:', err); |
| | | this.$showMessage('删除失败,请重试'); |
| | | }); |
| | | } |
| | | }, |
| | |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 2px 8px rgba(0,0,0,0.15); |
| | | } |
| | | |
| | | /* 多图片列表样式 */ |
| | | .image-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 12px; |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .image-item { |
| | | position: relative; |
| | | width: calc(33.33% - 8px); |
| | | min-width: 100px; |
| | | max-width: 150px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | background: #fff; |
| | | box-shadow: 0 2px 12px rgba(0,0,0,0.08); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .image-item:hover { |
| | | box-shadow: 0 4px 20px rgba(0,0,0,0.12); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | width: 100%; |
| | | height: 100px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | position: relative; |
| | | } |
| | | |
| | | .image-item .preview-image { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | } |
| | | |
| | | .image-actions { |
| | | padding: 8px 6px; |
| | | text-align: center; |
| | | background: linear-gradient(to bottom, #fafafa, #f5f5f5); |
| | | } |
| | | |
| | | .image-actions .delete-image-btn { |
| | | width: 100%; |
| | | padding: 8px 12px; |
| | | font-size: 13px; |
| | | border-radius: 20px; |
| | | background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%); |
| | | border: none; |
| | | color: white; |
| | | font-weight: 500; |
| | | box-shadow: 0 2px 8px rgba(238, 90, 90, 0.3); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 4px; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .image-actions .delete-image-btn:active { |
| | | transform: scale(0.95); |
| | | box-shadow: 0 1px 4px rgba(238, 90, 90, 0.3); |
| | | } |
| | | |
| | | .delete-icon { |
| | | font-size: 14px; |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | /* 移动端优化 */ |
| | | @media (max-width: 480px) { |
| | | .image-list { |
| | | gap: 10px; |
| | | } |
| | | |
| | | .image-item { |
| | | width: calc(50% - 5px); |
| | | min-width: 0; |
| | | max-width: none; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | height: 90px; |
| | | } |
| | | |
| | | .image-actions { |
| | | padding: 6px 5px; |
| | | } |
| | | |
| | | .image-actions .delete-image-btn { |
| | | padding: 6px 10px; |
| | | font-size: 12px; |
| | | border-radius: 16px; |
| | | } |
| | | } |
| | | |
| | | @media (min-width: 768px) { |
| | | .image-item { |
| | | width: calc(25% - 9px); |
| | | max-width: 160px; |
| | | } |
| | | |
| | | .image-item .image-preview { |
| | | height: 120px; |
| | | } |
| | | } |
| | | </style> |