xwt
2025-10-16 f63e51553b520b5dd760ba186d9b274ed246a64a
SJ,XJ,RKJ单独检验项目拍照+提交限制
已修改9个文件
1807 ■■■■■ 文件已修改
manifest.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/RKJ/Add.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/RKJ/List.vue 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/RKJ/detail.vue 540 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/SJ/Add.vue 105 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/SJ/detail.vue 413 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/XJ/Add.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/XJ/detail.vue 558 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json
@@ -2,7 +2,7 @@
    "name" : "GS-MES-AP",
    "appid" : "__UNI__F08FAE3",
    "description" : "",
    "versionName" : "1.1.3.9",
    "versionName" : "1.1.4.1",
    "versionCode" : 1,
    "transformPx" : false,
    /* 5+App特有相关 */
pages/QC/RKJ/Add.vue
@@ -1191,51 +1191,102 @@
                    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;
pages/QC/RKJ/List.vue
@@ -142,6 +142,8 @@
    onLoad() {
      //页面加载时调用的事件
      this.init();
      // 同时获取未提交和已提交的数量
      this.getCounts();
    },
    methods: {
      // ===== 新增查询条件选择方法 =====
@@ -158,18 +160,53 @@
        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"; // 已提交
        }
@@ -204,13 +241,6 @@
          }
          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; // 结束加载
@@ -230,6 +260,8 @@
          this.data = [];
          this.pageIndex = 1;
          this.init();
          // 切换标签后重新获取数量统计
          this.getCounts();
        }
      },
      navigateToDetail(item) {
@@ -267,6 +299,8 @@
      this.data = [];
      //this.current = 0
      this.init();
      // 页面显示时重新获取数量统计
      this.getCounts();
    }
  };
  </script>
pages/QC/RKJ/detail.vue
@@ -101,6 +101,25 @@
        <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"
@@ -118,7 +137,12 @@
    </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"/>
@@ -163,6 +187,12 @@
    <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>
    <!-- 修改检验结果弹出框 -->
@@ -395,6 +425,29 @@
    }
  },
  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({
@@ -444,6 +497,21 @@
        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({
@@ -474,9 +542,14 @@
        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
@@ -534,6 +607,21 @@
        }
      }
      // 验证不合格检验项目必须上传图片并填写不良描述
      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({
@@ -567,6 +655,21 @@
      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({
@@ -870,6 +973,189 @@
          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) {
@@ -926,6 +1212,18 @@
    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 {
@@ -964,6 +1262,73 @@
.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 {
@@ -1154,6 +1519,73 @@
    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 {
@@ -1670,4 +2102,108 @@
    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>
pages/QC/SJ/Add.vue
@@ -873,35 +873,92 @@
                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
pages/QC/SJ/detail.vue
@@ -115,6 +115,24 @@
      <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">
@@ -139,6 +157,16 @@
            </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>
 
      <!-- 结果表格 -->
@@ -180,7 +208,12 @@
 
      <!-- 图片预览 -->
      <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"/>
@@ -520,6 +553,30 @@
    }
  },
  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)) {
@@ -694,8 +751,23 @@
        }
      }
 
      // 验证不合格检验项目必须上传图片并填写不良描述
      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",
@@ -732,6 +804,9 @@
        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;
@@ -798,8 +873,23 @@
        }
      }
 
      // 验证不合格检验项目必须上传图片并填写不良描述
      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: '确认修改',
@@ -837,7 +927,22 @@
        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: {
@@ -1128,6 +1233,140 @@
          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) {
@@ -1212,14 +1451,26 @@
  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;
  }
@@ -2036,4 +2287,154 @@
  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>
pages/QC/XJ/Add.vue
@@ -1681,7 +1681,7 @@
    position: absolute;
    font-size: 32px;
    font-weight: bold;
    opacity: 0.3;
    opacity: 0.8;
    z-index: 1;
    pointer-events: none;
    transform: rotate(-15deg);
pages/QC/XJ/detail.vue
@@ -85,6 +85,25 @@
        <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"
@@ -103,7 +122,12 @@
    <!-- 图片预览 -->
    <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"/>
@@ -141,6 +165,12 @@
    <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>
    <!-- 修改不合格描述弹出框 -->
@@ -383,6 +413,30 @@
      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({
@@ -431,6 +485,21 @@
        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({
@@ -461,9 +530,14 @@
        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) {
@@ -518,6 +592,21 @@
        }
      }
      // 验证不合格检验项目必须上传图片并填写不良描述
      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({
@@ -544,6 +633,21 @@
      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({
@@ -819,6 +923,189 @@
          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) {
@@ -880,6 +1167,40 @@
  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 {
@@ -946,6 +1267,73 @@
.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 {
@@ -1093,6 +1481,51 @@
  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;
@@ -1182,6 +1615,127 @@
  }
}
/* 平板优化样式 */
@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;
store/index.js
@@ -10,9 +10,9 @@
            networkFlag:'内网', 
            serverURLInt:'http://192.168.11.251:10055',//服务器体检 10.0.1.104:10054
            serverURL:'http://localhost:10055',//本地调试地址
            serverAPI:'http://localhost:5184/api',//当前正在使用的服务器,默认为外网  localhost
            //serverAPI:'http://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服务器地址
        }
    },