xwt
2025-09-18 688505dded0a49ee685abcb980bd0dc521df4241
pages/QC/RKJ/detail.vue
@@ -12,10 +12,21 @@
          <view class="tabs">
            <view v-for="(tab, index) in tabs" :key="index" class="tab" :class="{active: currentTab === index}"
              @tap="switchTab(index, tab.id)">
              <view class="tab-text">{{ tab.projName || tab.fcheckItem || '项目' + (index + 1) }}</view>
              <view class="tab-text">{{ getTabDisplayName(tab, index) }}</view>
            </view>
          </view>
        </scroll-view>
        <!-- 加载状态 -->
        <view v-if="loading" class="loading-indicator">
          <text>加载中...</text>
        </view>
        <!-- 错误提示 -->
        <view v-if="errorMessage" class="error-message">
          <text>{{ errorMessage }}</text>
          <button class="retry-btn" @tap="retryLoad">重试</button>
        </view>
      </view>
  
      <view class="tab-content">
@@ -44,30 +55,24 @@
                <view class="info-label">检验数</view>
                <view class="info-value">{{formData.levelNum}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">检验标准编码</view>
                <view class="info-value">{{formData.qsCode}}</view>
              </view>
            </view>
          </view>
        </view>
  
        <!-- 检验标准 -->
        <!-- 结果信息 -->
        <view class="section">
          <view class="section-header">检验标准</view>
          <view class="section-header">结果信息</view>
          <view class="section-body">
            <view class="info-grid">
              <view class="info-item">
                <view class="info-label">检验标准名称</view>
                <view class="info-value">{{formData.qsName}}</view>
                <view class="info-label">不合格数</view>
                <view class="info-value">{{formData.unqualified}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">检验水平</view>
                <view class="info-value">{{formData.fcheckLevel}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">接收水平</view>
                <view class="info-value">{{formData.facLevel}}</view>
                <view class="info-label">预览结果</view>
                <view class="info-value" :class="{danger: formData.result === '不合格'}">{{formData.result}}</view>
              </view>
              <view class="info-item" v-if="formData.minValue">
                <view class="info-label">下限</view>
@@ -82,31 +87,6 @@
                <view class="info-value">{{formData.maxValue}}</view>
              </view>
            </view>
          </view>
        </view>
        <!-- 结果信息 -->
        <view class="section">
          <view class="section-header">结果信息</view>
          <view class="section-body">
            <view class="info-grid">
              <view class="info-item">
                <view class="info-label">AC数</view>
                <view class="info-value">{{formData.freQty ? (formData.freQty - 1) : ''}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">RE数</view>
                <view class="info-value">{{formData.freQty}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">不合格数</view>
                <view class="info-value">{{formData.unqualified}}</view>
              </view>
              <view class="info-item">
                <view class="info-label">预览结果</view>
                <view class="info-value" :class="{danger: formData.result === '不合格'}">{{formData.result}}</view>
              </view>
            </view>
            
            <view v-if="formData.remarks" class="result-remarks">
              <view class="info-label">不合格描述</view>
@@ -116,55 +96,20 @@
            <view class="hint-text" v-if="!formData.maxValue || !formData.minValue">
              <view class="danger">没有最大值和最小值时填写0(未通过检验)或1(通过检验)</view>
            </view>
            <!-- 填写检验结果 -->
            <view v-if="current && tableData.length < formData.levelNum" class="input-group input1">
              <view class="input-wrapper llj-flex-row">
                <input class="result-input"
                       :type="isNumber ? 'number' : 'text'"
                       v-model="formData.fcheckResu"
                       :placeholder="isNumber ? '请输入检验数值...' : '请输入检验结果...'"/>
                <button class="llj-btn llj-btn-save" @click="submit">保存结果</button>
              </view>
            </view>
          </view>
        </view>
  
        <!-- 检验结果录入 -->
        <view class="section">
          <view class="section-header">检验结果录入</view>
          <view class="section-body">
            <view class="input-group input1">
              <view class="input-wrapper">
                <button class="btn upload-btn" @tap="chooseImage">
                  <uni-icons type="upload" size="16" color="#fff"></uni-icons>
                  上传/查看图片
                </button>
                <button v-if="this.current" class="btn upload-btn" @tap="saveRemarks">
                  <uni-icons type="compose" size="16" color="#fff"></uni-icons>
                  不合格描述
                </button>
                <input v-if="(tableData.length < formData.levelNum)"
                  v-model="formData.fcheckResu" type="text" class="result-input"
                  placeholder="请输入检验结果..." />
                <button v-if="(tableData.length < formData.levelNum)"
                  style="margin: 0px;background-color: #3498db;color:#ffffff ;"
                  class="btn primary-btn" @tap="submit">保存结果</button>
              </view>
            </view>
            <!-- 移动端适配的输入区 -->
            <view class="input-group input2">
              <view class="input-wrapper">
                <button class="btn upload-btn" @tap="chooseImage">
                  <uni-icons type="upload" size="16" color="#fff"></uni-icons>
                  上传/查看图片
                </button>
                <button v-if="this.current" class="btn upload-btn" @tap="saveRemarks">
                  <uni-icons type="compose" size="16" color="#fff"></uni-icons>
                  不合格描述
                </button>
              </view>
              <view class="input-wrapper" style="margin-top: 15px;">
                <input v-if="(tableData.length < formData.levelNum)"
                  v-model="formData.fcheckResu" type="text" class="result-input"
                  placeholder="请输入检验结果..." />
                <button v-if="(tableData.length < formData.levelNum)"
                  style="margin: 0px;background-color: #3498db;color:#ffffff ;"
                  class="btn primary-btn" @tap="submit">保存结果</button>
              </view>
            </view>
          </view>
        </view>
  
        <!-- 结果表格 -->
        <view v-if="tableData.length>0" class="simple-table-container">
@@ -188,18 +133,18 @@
              </view>
              <view class="simple-data-cell simple-result">
                <!-- 数字结果样式 -->
                <view v-if="isNumber && !isNaN(parseFloat(item.fstand))" class="simple-number-result">
                  <view class="result-value">{{ item.fstand }}</view>
                <view v-if="isNumber && !isNaN(parseFloat(item.fcheckResu))" class="simple-number-result">
                  <view class="result-value">{{ item.fcheckResu }}</view>
                  <view v-if="formData.unitName" class="result-unit">{{ formData.unitName }}</view>
                  <view class="result-status" :class="{'pass': isInRange(item.fstand), 'fail': !isInRange(item.fstand)}">
                    {{ isInRange(item.fstand) ? '合格' : '不合格' }}
                  <view class="result-status" :class="{'pass': isInRange(item.fcheckResu), 'fail': !isInRange(item.fcheckResu)}">
                    {{ isInRange(item.fcheckResu) ? '合格' : '不合格' }}
                  </view>
                </view>
                
                <!-- NG/OK状态样式 -->
                <view v-else class="simple-status-result">
                  <view class="simple-status" :class="{'pass': item.fcheckResu === '1', 'fail': item.fcheckResu !== '1'}">
                    {{ item.fcheckResu === '1' ? '合格' : '不合格' }}
                  <view class="simple-status" :class="{'pass': isPassResult(item.fcheckResu), 'fail': !isPassResult(item.fcheckResu)}">
                    {{ isPassResult(item.fcheckResu) ? '合格' : '不合格' }}
                  </view>
                </view>
              </view>
@@ -241,7 +186,7 @@
          <form>
            <view class="form-group">
              <label class="form-label">不合格描述:</label>
              <input class="form-input" type="text" v-model="remarks"/>
              <input class="form-input" type="text" v-model="remarks" placeholder="请输入不合格描述,留空表示清除描述"/>
            </view>
            <view class="popup-buttons">
              <button class="btn primary-btn" @click="editRemarks">修改</button>
@@ -273,13 +218,40 @@
        remarksPopup: false,
        currentTab: 0,
        tabs: [],
        current: true // 添加current属性,默认为true
        current: true, // 添加current属性,默认为true
        loading: false, // 添加加载状态
        errorMessage: '' // 添加错误信息
      }
    },
    methods: {
      switchTab(index, id) {
        // 验证索引和ID的有效性
        if (index < 0 || index >= this.tabs.length) {
          console.warn('Invalid tab index:', index);
          return;
        }
        if (!id) {
          console.warn('Invalid tab id:', id);
          return;
        }
        // 如果点击的是当前标签,不需要切换
        if (this.currentTab === index && this.id === id) {
          return;
        }
        this.currentTab = index;
        this.id = id;
        // 清空当前表单数据,避免显示上一个项目的数据
        this.formData = {};
        this.tableData = [];
        this.isShowImg = false;
        this.base64Image = "";
        this.isNumber = false;
        // 刷新当前项目的数据
        this.refreshResult();
      },
  
@@ -290,7 +262,7 @@
      },
  
      editResult(fcheckResu) {
        if (fcheckResu == '1') {
        if (this.isPassResult(fcheckResu)) {
          return "改为不合格";
        } else {
          return "改为合格";
@@ -340,12 +312,12 @@
        this.$post({
          url: "/RKJ/SetQSItemDetail",
          data: {
            pid: this.id,
            gid: this.gid,
            fstand: fstand,
            fcheckResu: this.formData.fcheckResu,
            isPass: isPass, // 添加合格状态
            updateBy: this.formData.updater,
            Pid: this.id,
            Gid: this.gid,
            Fstand: fstand,
            FcheckResu: this.formData.fcheckResu,
            IsPass: isPass, // 添加合格状态
            UpdateBy: this.formData.updater,
            count: count
          }
        }).then(res => {
@@ -371,8 +343,8 @@
            this.base64Image = 'data:image/jpeg;base64,' + this.formData.imageData;
          }
  
          //maxValue  minValue  standardValue
          if (this.formData.maxValue && this.formData.minValue && this.formData.standardValue) {
          //maxValue  minValue 只要有上下限就按数字类型处理
          if (this.formData.maxValue && this.formData.minValue) {
            this.isNumber = true;
          }
  
@@ -428,12 +400,12 @@
          url: "/RKJ/UpdateQSItemDetail",
          data: {
            id: this.editData.id,
            pid: this.id,
            gid: this.gid,
            fstand: fstand,
            fcheckResu: this.editData.fcheckResu,
            isPass: isPass, // 添加合格状态
            updateBy: this.editData.updater,
            Pid: this.id,
            Gid: this.gid,
            Fstand: fstand,
            FcheckResu: this.editData.fcheckResu,
            IsPass: isPass, // 添加合格状态
            UpdateBy: this.editData.updater,
          }
        }).then(res => {
          this.showPopup = !this.showPopup;
@@ -447,7 +419,7 @@
        let fstand = "√";
        let fcheckResu = 1;
  
        if (item.fcheckResu == '1') {
        if (this.isPassResult(item.fcheckResu)) {
          fstand = "×";
          fcheckResu = 0;
        }
@@ -456,11 +428,11 @@
          url: "/RKJ/UpdateQSItemDetail",
          data: {
            id: item.id,
            pid: item.pid,
            gid: item.gid,
            fstand: fstand,
            fcheckResu: fcheckResu,
            updateBy: this.$loginInfo.account,
            Pid: item.pid,
            Gid: item.gid,
            Fstand: fstand,
            FcheckResu: fcheckResu,
            UpdateBy: this.$loginInfo.account,
          }
        }).then(res => {
          this.$showMessage("修改成功");
@@ -472,33 +444,44 @@
        this.remarks = this.formData.remarks;
      },
      editRemarks() {
        if (this.remarks) {
          //saveRemarksGid
        // 允许留空,留空代表清除描述
          this.$post({
            url: "/RKJ/saveRemarksPid",
            data: {
              pid: this.formData.id,
              remarks: this.remarks
            Pid: this.formData.id,
            remarks: this.remarks || "" // 留空时传递空字符串
            }
          }).then(res => {
            if(res.data.tbBillList > 0){
              this.formData.remarks = this.remarks;
            this.formData.remarks = this.remarks || ""; // 更新本地数据
              this.remarksPopup = !this.remarksPopup;
              this.$showMessage("保存成功");
            this.$showMessage(this.remarks ? "保存成功" : "描述已清除");
            }
          })
        }
        }).catch(error => {
          this.$showMessage("保存失败,请重试");
        });
      },
      // 加载检验项目列表
      loadTabItems() {
        if (!this.gid) {
          console.warn('gid is empty, cannot load tab items');
          this.errorMessage = '缺少必要参数,无法加载检验项目';
          return;
        }
        this.loading = true;
        this.errorMessage = '';
        // 使用与Add.vue完全相同的参数格式和调用方式
        this.$post({
          url: "/RKJ/getItems",
          data: {
            pid: this.gid,
            pid: this.gid  // 与Add.vue中的pid: this.formData.id保持一致
          }
        }).then(res => {
          if(res.data && res.data.tbBillList) {
          if(res.data && res.data.tbBillList && res.data.tbBillList.length > 0) {
            this.tabs = res.data.tbBillList;
            // 按检测结果排序,未完成的排在前面
            this.tabs.sort((a, b) => {
              if (a.result === '未完成' && b.result !== '未完成') {
@@ -509,10 +492,31 @@
                return 0;
              }
            });
            // 确保当前选中的标签存在
            if (this.currentTab >= this.tabs.length) {
              this.currentTab = 0;
            }
            // 如果当前ID不在标签列表中,更新为第一个标签的ID
            const currentTabExists = this.tabs.some(tab => tab.id === this.id);
            if (!currentTabExists && this.tabs.length > 0) {
              this.id = this.tabs[this.currentTab].id;
              this.refreshResult();
            }
          } else {
            // 没有项目时至少添加当前项目到标签
            this.tabs = [{id: this.id, projName: this.formData.projName || '当前项目'}];
            this.currentTab = 0;
          }
          this.loading = false;
        }).catch(error => {
          console.error('加载检验项目列表失败:', error);
          this.loading = false;
          this.errorMessage = '加载检验项目失败,请检查网络连接';
          // 发生错误时至少添加当前项目到标签
          this.tabs = [{id: this.id, projName: this.formData.projName || '当前项目'}];
          this.currentTab = 0;
        })
      },
      // 判断数字是否在范围内
@@ -521,6 +525,15 @@
        const numValue = parseFloat(value);
        return numValue >= parseFloat(this.formData.minValue) && 
               numValue <= parseFloat(this.formData.maxValue);
      },
      // 判断检验结果是否合格
      isPassResult(fcheckResu) {
        // 支持多种合格状态的表示方式
        if (fcheckResu === '1' || fcheckResu === 'OK' || fcheckResu === 'ok' || fcheckResu === '合格') {
          return true;
        }
        return false;
      },
      // 获取数字结果的样式类
      getNumberResultClass(value) {
@@ -537,6 +550,26 @@
        uni.navigateTo({
          url: 'ImageItem?id=' + this.formData.id
        });
      },
      // 获取标签显示名称
      getTabDisplayName(tab, index) {
        // 优先使用项目名称
        if (tab.projName && tab.projName.trim()) {
          return tab.projName.trim();
        }
        // 其次使用检验项目名称
        if (tab.fcheckItem && tab.fcheckItem.trim()) {
          return tab.fcheckItem.trim();
        }
        // 最后使用默认名称
        return '项目' + (index + 1);
      },
      // 重试加载
      retryLoad() {
        this.errorMessage = '';
        this.loadTabItems();
      }
    },
    onLoad(options) {
@@ -594,6 +627,39 @@
          background-color: $bg-color;
          border-bottom: 1px solid $border-color;
          position: relative;
      }
      .loading-indicator {
          padding: 10px;
          text-align: center;
          color: #666;
          font-size: 14px;
      }
      .error-message {
          padding: 10px;
          background-color: #fef0f0;
          border: 1px solid #fbc4c4;
          border-radius: 4px;
          margin: 10px;
          display: flex;
          justify-content: space-between;
          align-items: center;
          text {
              color: #f56c6c;
              font-size: 14px;
          }
          .retry-btn {
              padding: 4px 12px;
              background-color: #f56c6c;
              color: white;
              border: none;
              border-radius: 4px;
              font-size: 12px;
              cursor: pointer;
          }
      }
  
      .tabs-scroll {
@@ -654,6 +720,7 @@
                  word-break: break-word;
                  display: -webkit-box;
                  -webkit-line-clamp: 2;
                  line-clamp: 2;
                  -webkit-box-orient: vertical;
                  overflow: hidden;
                  font-size: 14px;
@@ -718,29 +785,82 @@
  
  .input-group {
    margin: 16px 0;
  }
  
  .input-wrapper {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
  }
  
  .result-input {
    flex: 1;
    height: 45px;
    padding: 0 12px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
        border: 1px solid $border-color;
        border-radius: 4px;
    font-size: 14px;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
    min-width: 0; /* 防止flex子项溢出 */
        box-sizing: border-box;
        min-width: 120px;
        -webkit-appearance: none; /* 移除移动端默认样式 */
        -moz-appearance: none;
        appearance: none;
  }
  
  .result-input:focus {
    outline: none;
    border-color: #409EFF;
    box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
      .upload-btn {
        background-color: #909399;
        color: #fff;
        padding: 0 10px;
        margin: 0;
      }
    }
  }
  /* llj按钮样式 - 与SJ和XJ保持一致 */
  .llj-flex-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
  }
  .llj-btn {
    display: flex;
    align-items: center;
    border: none;
    border-radius: 24px;
    font-size: 16px;
    font-weight: 500;
    height: 45px;
    line-height: 1;
    padding: 0 28px;
    margin: 0;
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    user-select: none;
    touch-action: manipulation;
  }
  .llj-btn-save {
    background: linear-gradient(90deg, #27ae60 0%, #43e97b 100%);
    color: #fff;
    margin-right: 12px;
  }
  .llj-btn-save:active {
    background: linear-gradient(90deg, #43e97b 0%, #27ae60 100%);
  }
  .llj-btn, .llj-btn-save {
    height: 45px;
    line-height: 1;
    padding: 0 24px;
    min-width: 90px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
  }
  
  .btn {
@@ -1134,30 +1254,6 @@
                 display: none;
      }
  
      .input-group {
          margin: 16px 0;
          .input-wrapper {
              display: flex;
              gap: 12px;
              .result-input {
                  flex: 1;
                  height: 45px;
                  padding: 0 12px;
                  border: 1px solid $border-color;
                  border-radius: 4px;
                  font-size: 14px;
              }
              .upload-btn {
                  background-color: #909399;
                  color: #fff;
                  padding: 0 10px;
                  margin: 0;
              }
          }
      }
  
      .result-preview {
          .info-label {
@@ -1451,4 +1547,54 @@
          }
      }
      
      /* 移动端按钮和输入框样式调整 */
      @media (max-width: 768px) {
        .llj-btn {
          font-size: 14px;
          padding: 0 20px;
          height: 40px;
          border-radius: 20px;
        }
        .llj-btn, .llj-btn-save {
          height: 40px;
          padding: 0 20px;
          min-width: 80px;
        }
        .result-input {
          height: 40px;
          font-size: 14px;
        }
      }
      @media (max-width: 500px) {
        .llj-btn {
          -webkit-tap-highlight-color: transparent;
          -webkit-touch-callout: none;
          -webkit-user-select: none;
          -khtml-user-select: none;
          -moz-user-select: none;
          -ms-user-select: none;
          user-select: none;
        }
        .btn {
          height: 40px;
          padding: 0 20px;
          min-width: 80px;
        }
        .result-input {
          height: 40px;
          font-size: 14px;
        }
      }
      /* 移动端按钮点击效果优化 */
      .llj-btn:active {
        transform: scale(0.98);
        transition: transform 0.1s ease;
      }
  </style>