src/pages/qualityManagement/finalInspection/index.vue
@@ -26,6 +26,17 @@
                   color="#999"></up-icon>
        </view>
      </view>
      <!-- 检验状态筛选 -->
      <view class="filter-row">
        <view class="filter-item"
              @click="showStateSheet = true">
          <text class="filter-label">检验状态</text>
          <text class="filter-value">{{ stateFilterLabel }}</text>
          <up-icon name="arrow-down"
                   size="14"
                   color="#999"></up-icon>
        </view>
      </view>
      <!-- 日期选择 -->
      <!-- <view class="date-range"
            v-if="searchForm.entryDate">
@@ -85,7 +96,7 @@
              <u-tag :type="getStateTagType(item.inspectState)"
                     size="mini"
                     class="status-tag">
                {{ item.inspectState ? '已提交' : '未提交' }}
                {{ item.inspectState ? '已提交' : '待提交' }}
              </u-tag>
            </view>
          </view>
@@ -114,6 +125,18 @@
            <view class="detail-row">
              <text class="detail-label">检测单位</text>
              <text class="detail-value">{{ item.checkCompany || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">合格数量</text>
              <text class="detail-value">{{ item.qualifiedQuantity != null ? item.qualifiedQuantity : '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">不合格数量</text>
              <text class="detail-value">{{ item.unqualifiedQuantity != null ? item.unqualifiedQuantity : '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">检验结论</text>
              <text class="detail-value">{{ item.checkResult || '-' }}</text>
            </view>
          </view>
          <!-- 操作按钮 -->
@@ -152,6 +175,15 @@
                      :disabled="item.inspectState || item.checkName !== ''"
                      @click.stop="assignInspector(item)">
              分配检验员
            </u-button>
          </view>
          <view class="action-buttons">
            <u-button type="error"
                      size="small"
                      class="action-btn"
                      :disabled="!(Number(item.unqualifiedQuantity) > 0)"
                      @click.stop="openUnqualified(item)">
              不合格处理
            </u-button>
          </view>
        </view>
@@ -223,6 +255,56 @@
                     :actions="userSheetOptions"
                     @select="selectInspector"
                     title="选择检验员" />
    <!-- 检验状态筛选 -->
    <up-action-sheet :show="showStateSheet"
                     :actions="stateSheetOptions"
                     @select="selectState"
                     @close="showStateSheet = false"
                     title="选择检验状态" />
    <!-- 不合格处理弹窗 -->
    <up-popup v-model:show="showUnqualifiedPopup"
              mode="bottom"
              round>
      <view class="unqualified-dialog">
        <view class="dialog-header">
          <text class="dialog-title">不合格处理</text>
          <up-icon name="close"
                   size="20"
                   color="#999"
                   @click="showUnqualifiedPopup = false"></up-icon>
        </view>
        <view class="dialog-content">
          <view v-if="unqualifiedLoading"
                class="unqualified-empty">加载中...</view>
          <view v-else-if="unqualifiedList.length === 0"
                class="unqualified-empty">暂无待处理不合格记录</view>
          <view v-for="(row, idx) in unqualifiedList"
                :key="idx"
                class="unqualified-item">
            <view class="unqualified-info">
              <text class="unqualified-label">不合格现象</text>
              <text class="unqualified-value">{{ row.defectivePhenomena || '-' }}</text>
            </view>
            <view class="unqualified-info">
              <text class="unqualified-label">数量</text>
              <text class="unqualified-value">{{ row.quantity != null ? row.quantity : '-' }}</text>
            </view>
            <u-button type="primary"
                      size="small"
                      class="unqualified-btn"
                      @click="openDealSheet(row)">
              处理
            </u-button>
          </view>
        </view>
      </view>
    </up-popup>
    <!-- 处理结果选择 -->
    <up-action-sheet :show="showDealSheet"
                     :actions="dealSheetOptions"
                     @select="selectDeal"
                     @close="showDealSheet = false"
                     title="选择处理结果" />
  </view>
</template>
@@ -235,8 +317,13 @@
    submitQualityInspect,
    qualityInspectUpdate,
    qualityInspectListPage,
    qualityUnqualifiedListPage,
    qualityUnqualifiedDeal,
  } from "@/api/qualityManagement/materialInspection.js";
  import { userListNoPage } from "@/api/system/user.js";
  // 出厂/成品检验 inspectType=2
  const currentInspectType = 2;
  // 显示提示信息
  const showToast = message => {
@@ -294,6 +381,121 @@
      value: item.nickName,
    }));
  });
  // 检验状态筛选
  const showStateSheet = ref(false);
  const stateFilter = ref("");
  const stateSheetOptions = [
    { name: "全部", value: "" },
    { name: "待提交", value: 0 },
    { name: "已提交", value: 1 },
  ];
  const stateFilterLabel = computed(() => {
    const hit = stateSheetOptions.find(o => o.value === stateFilter.value);
    return hit ? hit.name : "全部";
  });
  const selectState = e => {
    stateFilter.value = e.value;
    showStateSheet.value = false;
    getList();
  };
  // 不合格处理相关
  const showUnqualifiedPopup = ref(false);
  const unqualifiedLoading = ref(false);
  const unqualifiedList = ref([]);
  const currentInspectRow = ref(null);
  const showDealSheet = ref(false);
  const currentUnqualifiedRow = ref(null);
  // 过程/成品类支持 返修/返工/报废/让步放行
  const dealSheetOptions = computed(() => {
    return ["返修", "返工", "报废", "让步放行"].map(name => ({
      name,
      value: name,
    }));
  });
  // 打开不合格处理弹窗:按检验单id拉取待处理不合格记录
  const openUnqualified = async item => {
    currentInspectRow.value = item;
    showUnqualifiedPopup.value = true;
    unqualifiedLoading.value = true;
    unqualifiedList.value = [];
    try {
      const res = await qualityUnqualifiedListPage({
        inspectType: currentInspectType,
        inspectState: 0,
        inspectId: item.id,
        current: -1,
        size: -1,
      });
      let records = res.data?.records || res.data || [];
      // 若后端未按检验单过滤,前端兜底按检验单id过滤
      const hasInspectRef = records.some(
        r => r.inspectId != null || r.qualityInspectId != null
      );
      if (hasInspectRef) {
        records = records.filter(
          r => (r.inspectId ?? r.qualityInspectId) == item.id
        );
      }
      // 只保留待处理记录
      unqualifiedList.value = records.filter(
        r => Number(r.inspectState) !== 1
      );
    } catch (error) {
      // request.ts 已统一 toast 后端 msg,这里只记录
      console.error("获取不合格记录失败:", error);
      unqualifiedList.value = [];
    } finally {
      unqualifiedLoading.value = false;
    }
  };
  // 打开处理结果选择
  const openDealSheet = row => {
    currentUnqualifiedRow.value = row;
    showDealSheet.value = true;
  };
  // 选择处理结果
  const selectDeal = e => {
    showDealSheet.value = false;
    if (!currentUnqualifiedRow.value) return;
    const result = e.value;
    // 返修/返工会自动创建返工生产订单,先二次确认
    if (result === "返修" || result === "返工") {
      uni.showModal({
        title: "提示",
        content: "将自动创建返工生产订单(FG单号),是否继续?",
        success: res => {
          if (res.confirm) {
            doDeal(currentUnqualifiedRow.value, result);
          }
        },
      });
      return;
    }
    doDeal(currentUnqualifiedRow.value, result);
  };
  // 提交不合格处理
  const doDeal = async (row, dealResult) => {
    try {
      await qualityUnqualifiedDeal({ id: row.id, dealResult });
      showToast("处理成功");
      if (currentInspectRow.value) {
        await openUnqualified(currentInspectRow.value);
      }
      if (unqualifiedList.value.length === 0) {
        showUnqualifiedPopup.value = false;
      }
      getList();
    } catch (error) {
      // request.ts 已统一 toast 后端 msg,这里只记录
      console.error("不合格处理失败:", error);
    }
  };
  // 返回上一页
  const goBack = () => {
@@ -371,7 +573,9 @@
    tableLoading.value = true;
    const params = { ...searchForm.value, ...page.value };
    params.entryDate = undefined;
    qualityInspectListPage({ ...params, inspectType: 2 })
    params.inspectState =
      stateFilter.value === "" ? undefined : stateFilter.value;
    qualityInspectListPage({ ...params, inspectType: currentInspectType })
      .then(res => {
        tableLoading.value = false;
        inspectionList.value = res.data.records || [];
@@ -430,25 +634,30 @@
  };
  // 提交检验
  const submitInspection = async item => {
  const submitInspection = item => {
    if (!item) {
      showToast("参数错误");
      return;
    }
    try {
      const res = await submitQualityInspect({ id: item.id });
      if (res.code === 200) {
        showToast("提交成功");
        setTimeout(() => {
          getList();
        }, 1000);
      } else {
        showToast("提交失败:" + (res.msg || "未知错误"));
      }
    } catch (error) {
      console.error("提交失败:", error);
      showToast("提交失败,请重试");
    }
    uni.showModal({
      title: "提示",
      content: "提交后将生成入库记录且不可修改,是否继续?",
      success: async res => {
        if (!res.confirm) return;
        try {
          await submitQualityInspect({ id: item.id });
          showToast(
            "提交成功,合格部分已生成入库记录(待审核),不合格部分已生成处理单"
          );
          setTimeout(() => {
            getList();
          }, 1500);
        } catch (error) {
          // request.ts 已统一 toast 后端 msg,这里只记录
          console.error("提交失败:", error);
        }
      },
    });
  };
  // 分配检验员
@@ -551,6 +760,78 @@
    padding: 5px;
  }
  // 检验状态筛选
  .filter-row {
    display: flex;
    align-items: center;
    margin-top: 10px;
  }
  .filter-item {
    display: flex;
    align-items: center;
    padding: 4px 10px;
    background: #f2f3f5;
    border-radius: 12px;
  }
  .filter-label {
    font-size: 12px;
    color: #666;
    margin-right: 4px;
  }
  .filter-value {
    font-size: 12px;
    color: #2979ff;
    margin-right: 4px;
  }
  // 不合格处理弹窗
  .unqualified-dialog {
    background: #ffffff;
    border-radius: 16px 16px 0 0;
    padding: 20px;
    max-height: 70vh;
    overflow-y: auto;
  }
  .unqualified-empty {
    padding: 30px 0;
    text-align: center;
    font-size: 13px;
    color: #999;
  }
  .unqualified-item {
    display: flex;
    align-items: center;
    padding: 12px 0;
    border-bottom: 1px solid #f0f0f0;
  }
  .unqualified-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    margin-right: 10px;
  }
  .unqualified-label {
    font-size: 12px;
    color: #999;
  }
  .unqualified-value {
    font-size: 13px;
    color: #333;
    margin-top: 2px;
  }
  .unqualified-btn {
    width: 70px;
  }
  // 统计卡片
  .stats-cards {
    display: flex;