liding
2026-04-15 53499f59c890387d8077ff3a9e81ee18e389e0e8
fix:生产-质量-库存(合格,不合格批号,供应商)
已修改2个文件
807 ■■■■■ 文件已修改
src/views/productionManagement/productionOrder/index.vue 310 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue 497 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue
@@ -1,100 +1,104 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
        <el-form-item label="客户名称:">
          <el-input v-model="searchForm.customerName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery"/>
        </el-form-item>
        <el-form-item label="合同号:">
          <el-input v-model="searchForm.salesContractNo"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery"/>
        </el-form-item>
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="产品名称:">
          <el-input v-model="searchForm.productCategory"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.productCategory"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            style="width: 160px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="规格:">
          <el-input v-model="searchForm.specificationModel"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.specificationModel"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            style="width: 160px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索
          </el-button>
          <el-button type="primary" @click="handleQuery">搜索 </el-button>
        </el-form-item>
      </el-form>
      <div>
        <el-button type="primary" @click="isShowNewModal = true">新增</el-button>
        <el-button type="primary" @click="isShowNewModal = true"
          >新增</el-button
        >
        <el-button type="danger" @click="handleDelete">删除</el-button>
        <el-button @click="handleOut">导出</el-button>
      </div>
    </div>
    <div class="table_list">
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :tableLoading="tableLoading"
                :row-class-name="tableRowClassName"
                :isSelection="true"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
      <PIMTable
        rowKey="id"
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :tableLoading="tableLoading"
        :row-class-name="tableRowClassName"
        :isSelection="true"
        @selection-change="handleSelectionChange"
        @pagination="pagination"
      >
        <template #completionStatus="{ row }">
          <el-progress
              :percentage="toProgressPercentage(row?.completionStatus)"
              :color="progressColor(toProgressPercentage(row?.completionStatus))"
              :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
            :percentage="toProgressPercentage(row?.completionStatus)"
            :color="progressColor(toProgressPercentage(row?.completionStatus))"
            :status="
              toProgressPercentage(row?.completionStatus) >= 100
                ? 'success'
                : ''
            "
          />
        </template>
      </PIMTable>
    </div>
    <el-dialog v-model="bindRouteDialogVisible"
               title="绑定工艺路线"
               width="500px">
    <el-dialog
      v-model="bindRouteDialogVisible"
      title="绑定工艺路线"
      width="500px"
    >
      <el-form label-width="90px">
        <el-form-item label="工艺路线">
          <el-select v-model="bindForm.routeId"
                     placeholder="请选择工艺路线"
                     style="width: 100%;"
                     :loading="bindRouteLoading">
            <el-option v-for="item in routeOptions"
                       :key="item.id"
                       :label="`${item.processRouteCode || ''}`"
                       :value="item.id"/>
          <el-select
            v-model="bindForm.routeId"
            placeholder="请选择工艺路线"
            style="width: 100%"
            :loading="bindRouteLoading"
          >
            <el-option
              v-for="item in routeOptions"
              :key="item.id"
              :label="`${item.processRouteCode || ''}`"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     :loading="bindRouteSaving"
                     @click="handleBindRouteConfirm">确 认</el-button>
          <el-button
            type="primary"
            :loading="bindRouteSaving"
            @click="handleBindRouteConfirm"
            >确 认</el-button
          >
          <el-button @click="bindRouteDialogVisible = false">取 消</el-button>
        </span>
      </template>
    </el-dialog>
    <new-product-order v-if="isShowNewModal"
                       v-model:visible="isShowNewModal"
                       @completed="handleQuery"/>
    <new-product-order
      v-if="isShowNewModal"
      v-model:visible="isShowNewModal"
      @completed="handleQuery"
    />
    <!-- 清场记录弹框 -->
    <clearance-record-dialog
@@ -113,26 +117,37 @@
</template>
<script setup>
import {onMounted, ref} from "vue";
import {ElMessageBox} from "element-plus";
import { onMounted, ref } from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {useRouter} from "vue-router";
import { useRouter } from "vue-router";
import {
  productOrderListPage,
  listProcessRoute,
  bindingRoute,
  delProductOrder, finishOrder,
  delProductOrder,
  finishOrder,
  saveCleanRecord,
} from "@/api/productionManagement/productionOrder.js";
import {listMain as getOrderProcessRouteMain} from "@/api/productionManagement/productProcessRoute.js";
import {fileDel} from "@/api/financialManagement/revenueManagement.js";
import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
import { fileDel } from "@/api/financialManagement/revenueManagement.js";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
const ClearanceRecordDialog = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/ClearanceRecordDialog.vue"));
const MaterialRequisitionDialog = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue"));
const NewProductOrder = defineAsyncComponent(() =>
  import("@/views/productionManagement/productionOrder/New.vue")
);
const ClearanceRecordDialog = defineAsyncComponent(() =>
  import(
    "@/views/productionManagement/productionOrder/ClearanceRecordDialog.vue"
  )
);
const MaterialRequisitionDialog = defineAsyncComponent(() =>
  import(
    "@/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue"
  )
);
const {proxy} = getCurrentInstance();
const { proxy } = getCurrentInstance();
const router = useRouter();
const isShowNewModal = ref(false);
@@ -141,37 +156,37 @@
  {
    label: "生产订单号",
    prop: "npsNo",
    width: '120px',
    width: "120px",
  },
  {
    label: "产品名称",
    prop: "productCategory",
    width: '120px',
    width: "120px",
  },
  {
    label: "规格",
    prop: "specificationModel",
    width: '120px',
    width: "120px",
  },
  {
    label: "UID码",
    prop: "uidNo",
    width: '120px',
    width: "120px",
  },
  {
    label: "批号",
    prop: "batchNo",
    width: '120px',
    width: "120px",
  },
  {
    label: "工艺路线编号",
    prop: "processRouteCode",
    width: '200px',
    width: "200px",
  },
  {
    label: "预计生产数量",
    prop: "quantity",
    width: '140px',
    width: "140px",
  },
  {
    label: "完成数量",
@@ -187,19 +202,19 @@
  {
    label: "开始日期",
    prop: "startTime",
    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    formatData: (val) => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    width: 120,
  },
  {
    label: "结束日期",
    prop: "endTime",
    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    formatData: (val) => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    width: 120,
  },
  {
    label: "交付日期",
    prop: "deliveryDate",
    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    formatData: (val) => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    width: 120,
  },
  {
@@ -222,46 +237,46 @@
      {
        name: "工艺路线",
        type: "text",
        clickFun: row => {
        clickFun: (row) => {
          showRouteItemModal(row);
        },
      },
      {
        name: "绑定工艺路线",
        type: "text",
        showHide: row => !row.processRouteCode,
        clickFun: row => {
        showHide: (row) => !row.processRouteCode,
        clickFun: (row) => {
          openBindRouteDialog(row);
        },
      },
      {
        name: "产品结构",
        type: "text",
        clickFun: row => {
        clickFun: (row) => {
          showProductStructure(row);
        },
      },
      {
        name: "结束生产",
        type: "text",
        showHide: row => !row.isEnd,
        clickFun: row => {
        showHide: (row) => !row.isEnd,
        clickFun: (row) => {
          handleFinishOrder(row);
        },
      },
      {
        name: "清场记录",
        type: "text",
        showHide: row => !row.isEnd,
        clickFun: row => {
        showHide: (row) => !row.isEnd,
        clickFun: (row) => {
          handleClearanceRecord(row);
        },
      },
      {
        name: "领料",
        type: "text",
        showHide: row => !row.isEnd,
        clickFun: row => {
        showHide: (row) => !row.isEnd,
        clickFun: (row) => {
          handleMaterialRequisition(row);
        },
      },
@@ -286,9 +301,9 @@
    specificationModel: "",
  },
});
const {searchForm} = toRefs(data);
const { searchForm } = toRefs(data);
const toProgressPercentage = val => {
const toProgressPercentage = (val) => {
  const n = Number(val);
  if (!Number.isFinite(n)) return 0;
  if (n <= 0) return 0;
@@ -297,7 +312,7 @@
};
// 30/50/80/100 分段颜色:红/橙/蓝/绿
const progressColor = percentage => {
const progressColor = (percentage) => {
  const p = toProgressPercentage(percentage);
  if (p < 30) return "#f56c6c";
  if (p < 50) return "#e6a23c";
@@ -306,19 +321,19 @@
};
// 添加表行类名方法
const tableRowClassName = ({row}) => {
  if (!row.deliveryDate) return '';
  if (row.isFh) return '';
const tableRowClassName = ({ row }) => {
  if (!row.deliveryDate) return "";
  if (row.isFh) return "";
  const diff = row.deliveryDaysDiff;
  if (diff === 15) {
    return 'yellow';
    return "yellow";
  } else if (diff === 10) {
    return 'pink';
    return "pink";
  } else if (diff === 2) {
    return 'purple';
    return "purple";
  } else if (diff < 2) {
    return 'red';
    return "red";
  }
};
@@ -339,7 +354,7 @@
  routeId: null,
});
const openBindRouteDialog = async row => {
const openBindRouteDialog = async (row) => {
  bindForm.orderId = row.id;
  bindForm.routeId = null;
  bindRouteDialogVisible.value = true;
@@ -351,7 +366,7 @@
  }
  bindRouteLoading.value = true;
  try {
    const res = await listProcessRoute({productModelId: row.productModelId});
    const res = await listProcessRoute({ productModelId: row.productModelId });
    routeOptions.value = res.data || [];
  } catch (e) {
    console.error("获取工艺路线列表失败:", e);
@@ -389,12 +404,12 @@
  page.current = 1;
  getList();
};
const pagination = obj => {
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const changeDaterange = value => {
const changeDaterange = (value) => {
  if (value) {
    searchForm.value.entryDateStart = value[0];
    searchForm.value.entryDateEnd = value[1];
@@ -407,20 +422,20 @@
const getList = () => {
  tableLoading.value = true;
  // 构造一个新的对象,不包含entryDate字段
  const params = {...searchForm.value, ...page};
  const params = { ...searchForm.value, ...page };
  params.entryDate = undefined;
  productOrderListPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(() => {
        tableLoading.value = false;
      });
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
      page.total = res.data.total;
    })
    .catch(() => {
      tableLoading.value = false;
    });
};
const showRouteItemModal = async row => {
const showRouteItemModal = async (row) => {
  const orderId = row.id;
  try {
    const res = await getOrderProcessRouteMain(orderId);
@@ -449,7 +464,7 @@
  }
};
const showProductStructure = row => {
const showProductStructure = (row) => {
  router.push({
    path: "/productionManagement/productStructureDetail",
    query: {
@@ -481,14 +496,16 @@
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    delProductOrder(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
      getList();
  })
    .then(() => {
      delProductOrder(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
  }).catch(() => {
    proxy.$modal.msg("已取消");
  });
};
// 导出
@@ -498,16 +515,19 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        proxy.download("/productOrder/export", {...searchForm.value}, "生产订单.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
    .then(() => {
      proxy.download(
        "/productOrder/export",
        { ...searchForm.value },
        "生产订单.xlsx"
      );
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
const handleConfirmRoute = () => {
};
const handleConfirmRoute = () => {};
const handleFinishOrder = (row) => {
  ElMessageBox.confirm("是否确认结束?", "结束", {
@@ -515,15 +535,15 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        finishOrder(row.id).then(res => {
          proxy.$modal.msgSuccess("结束成功");
          getList()
        })
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
    .then(() => {
      finishOrder(row.id).then((res) => {
        proxy.$modal.msgSuccess("结束成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 打开清场记录弹框
@@ -547,7 +567,7 @@
    if (callback) callback();
    getList();
  } catch (error) {
    console.error('保存清场记录失败:', error);
    console.error("保存清场记录失败:", error);
    proxy.$modal.msgError("清场记录保存失败");
  }
};
@@ -569,11 +589,11 @@
}
::v-deep .yellow {
  background-color: #FAF0DE;
  background-color: #faf0de;
}
::v-deep .pink {
  background-color: #FAE1DE;
  background-color: #fae1de;
}
::v-deep .red {
@@ -581,6 +601,6 @@
}
::v-deep .purple {
  background-color: #F4DEFA;
  background-color: #f4defa;
}
</style>
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -1,26 +1,32 @@
<template>
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        :title="operationType === 'add' ? '新增原材料检验' : '编辑原材料检验'"
        width="70%"
        @close="closeDia"
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增原材料检验' : '编辑原材料检验'"
      width="70%"
      @close="closeDia"
    >
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
      <el-form
        :model="form"
        label-width="140px"
        label-position="top"
        :rules="rules"
        ref="formRef"
      >
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="供应商:" prop="supplier">
              <el-select
                  v-model="form.supplier"
                  placeholder="请选择"
                  clearable
                  :disabled="supplierQuantityDisabled"
                v-model="form.supplier"
                placeholder="请选择"
                clearable
                :disabled="supplierQuantityDisabled"
              >
                <el-option
                    v-for="item in supplierList"
                    :key="item.id"
                    :label="item.supplierName"
                    :value="item.supplierName"
                  v-for="item in supplierList"
                  :key="item.id"
                  :label="item.supplierName"
                  :value="item.supplierName"
                />
              </el-select>
            </el-form-item>
@@ -28,15 +34,15 @@
          <el-col :span="12">
            <el-form-item label="产品名称:" prop="productId">
              <el-tree-select
                  v-model="form.productId"
                  placeholder="请选择"
                  clearable
                  check-strictly
                  @change="getModels"
                  :data="productOptions"
                  :render-after-expand="false"
                  :disabled="operationType === 'edit'"
                  style="width: 100%"
                v-model="form.productId"
                placeholder="请选择"
                clearable
                check-strictly
                @change="getModels"
                :data="productOptions"
                :render-after-expand="false"
                :disabled="operationType === 'edit'"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
@@ -44,9 +50,21 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="规格型号:" prop="productModelId">
              <el-select v-model="form.productModelId" placeholder="请选择" clearable :disabled="operationType === 'edit'"
                         filterable readonly @change="handleChangeModel">
                <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
              <el-select
                v-model="form.productModelId"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'edit'"
                filterable
                readonly
                @change="handleChangeModel"
              >
                <el-option
                  v-for="item in modelOptions"
                  :key="item.id"
                  :label="item.model"
                  :value="item.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -72,34 +90,49 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="单位:" prop="unit">
              <el-input v-model="form.unit" disabled/>
              <el-input v-model="form.unit" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="总数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入"
                               clearable :precision="2" :disabled="supplierQuantityDisabled"/>
              <el-input-number
                :step="0.01"
                :min="0"
                style="width: 100%"
                v-model="form.quantity"
                placeholder="请输入"
                clearable
                :precision="2"
                :disabled="supplierQuantityDisabled"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检品数量:" prop="inspectedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.inspectedQuantity" placeholder="请输入,不大于总数量"
                               clearable :precision="2" :disabled="supplierQuantityDisabled"/>
              <el-input-number
                :step="0.01"
                :min="0"
                style="width: 100%"
                v-model="form.inspectedQuantity"
                placeholder="请输入,不大于总数量"
                clearable
                :precision="2"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="生产日期:" prop="productionDate">
              <el-date-picker
                  v-model="form.productionDate"
                  type="date"
                  placeholder="请选择日期"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  clearable
                  style="width: 100%"
                  @change="calculateValidityDate"
                v-model="form.productionDate"
                type="date"
                placeholder="请选择日期"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                clearable
                style="width: 100%"
                @change="calculateValidityDate"
              />
            </el-form-item>
          </el-col>
@@ -118,7 +151,7 @@
          </el-col> -->
          <el-col :span="12">
            <el-form-item label="UID码:" prop="uidNo">
              <el-input v-model="form.uidNo" disabled/>
              <el-input v-model="form.uidNo" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -135,76 +168,93 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检测单位:" prop="checkCompany">
              <el-input v-model="form.checkCompany" placeholder="请输入" clearable/>
              <el-input
                v-model="form.checkCompany"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检测结果:" prop="checkResult">
              <el-select v-model="form.checkResult">
                <el-option label="合格" value="合格"/>
                <el-option label="不合格" value="不合格"/>
                <el-option label="合格" value="合格" />
                <el-option label="不合格" value="不合格" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检验员:" prop="checkName">
              <el-select v-model="form.checkName" placeholder="请选择" clearable style="width: 100%">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
              <el-select
                v-model="form.checkName"
                placeholder="请选择"
                clearable
                style="width: 100%"
              >
                <el-option
                  v-for="item in userList"
                  :key="item.nickName"
                  :label="item.nickName"
                  :value="item.nickName"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检测日期:" prop="checkTime">
              <el-date-picker
                  v-model="form.checkTime"
                  type="date"
                  placeholder="请选择日期"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  clearable
                  style="width: 100%"
                v-model="form.checkTime"
                type="date"
                placeholder="请选择日期"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                clearable
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
<!--      <div style="margin-bottom: 10px;text-align: right">-->
<!--        <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
<!--      </div>-->
      <!--      <div style="margin-bottom: 10px;text-align: right">-->
      <!--        <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
      <!--      </div>-->
      <PIMTable
          rowKey="id"
          :column="tableColumn"
          :tableData="tableData"
          :tableLoading="tableLoading"
          height="400"
        rowKey="id"
        :column="tableColumn"
        :tableData="tableData"
        :tableLoading="tableLoading"
        height="400"
      >
        <template #instrument="{ row }">
          <el-select
              v-model="row.instrument"
              placeholder="请选择或输入"
              filterable
              allow-create
              default-first-option
              clearable
              style="width: 100%"
              @change="handleInstrumentChange(row)"
            v-model="row.instrument"
            placeholder="请选择或输入"
            filterable
            allow-create
            default-first-option
            clearable
            style="width: 100%"
            @change="handleInstrumentChange(row)"
          >
            <el-option label="目测" value="目测" />
            <el-option
                v-for="item in deviceList"
                :key="item.id"
                :label="item.deviceName + (item.deviceModel ? ' / ' + item.deviceModel : '')"
                :value="item.deviceName"
              v-for="item in deviceList"
              :key="item.id"
              :label="
                item.deviceName +
                (item.deviceModel ? ' / ' + item.deviceModel : '')
              "
              :value="item.deviceName"
            />
          </el-select>
        </template>
        <template #deviceStatus="{ row }">
          <el-select
              v-model="row.deviceStatus"
              placeholder="请选择"
              default-first-option
              clearable
              style="width: 100%"
            v-model="row.deviceStatus"
            placeholder="请选择"
            default-first-option
            clearable
            style="width: 100%"
          >
            <el-option label="正常" value="正常" />
            <el-option label="停机" value="停机" />
@@ -217,7 +267,13 @@
          <el-input v-model="row.result" placeholder="请输入" clearable />
        </template>
        <template #resultJudgment="{ row }">
          <el-select v-model="row.resultJudgment" placeholder="请选择" clearable style="width: 100%" @change="changeResult">
          <el-select
            v-model="row.resultJudgment"
            placeholder="请选择"
            clearable
            style="width: 100%"
            @change="changeResult"
          >
            <el-option label="合格" value="合格" />
            <el-option label="不合格" value="不合格" />
            <el-option label="/" value="/" />
@@ -235,24 +291,40 @@
</template>
<script setup>
import {ref, reactive, toRefs, computed, getCurrentInstance, nextTick} from "vue";
import {getOptions} from "@/api/procurementManagement/procurementLedger.js";
import {modelList, productTreeList} from "@/api/basicData/product.js";
import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js";
import {qualityInspectParamDel, qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js";
import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js";
import {deviceList as qualityInspectParamDeviceList} from "@/api/energyManagement/index.js";
import {userListNoPage} from "@/api/system/user.js";
import {
  ref,
  reactive,
  toRefs,
  computed,
  getCurrentInstance,
  nextTick,
} from "vue";
import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import {
  qualityInspectAdd,
  qualityInspectUpdate,
} from "@/api/qualityManagement/rawMaterialInspection.js";
import {
  qualityInspectParamDel,
  qualityInspectParamInfo,
} from "@/api/qualityManagement/qualityInspectParam.js";
import {
  qualityInspectDetailByProductId,
  getQualityTestStandardParamByTestStandardId,
} from "@/api/qualityManagement/metricMaintenance.js";
import { deviceList as qualityInspectParamDeviceList } from "@/api/energyManagement/index.js";
import { userListNoPage } from "@/api/system/user.js";
const {proxy} = getCurrentInstance()
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance();
const emit = defineEmits(["close"]);
const dialogFormVisible = ref(false);
const operationType = ref('')
const operationType = ref("");
const validateBatchNo = (rule, value, callback) => {
  if (value === undefined || value === null || String(value).trim() === '') {
    callback(new Error('请输入批号'));
  if (value === undefined || value === null || String(value).trim() === "") {
    callback(new Error("请输入批号"));
    return;
  }
  callback();
@@ -280,19 +352,23 @@
    checkResult: "",
  },
  rules: {
    checkTime: [{required: true, message: "请输入", trigger: "blur"},],
    supplier: [{required: true, message: "请输入", trigger: "blur"}],
    checkName: [{required: false, message: "请输入", trigger: "blur"}],
    productId: [{required: true, message: "请输入", trigger: "blur"}],
    productModelId: [{required: true, message: "请选择产品型号", trigger: "change"}],
    testStandardId: [{required: false, message: "请选择指标", trigger: "change"}],
    unit: [{required: false, message: "请输入", trigger: "blur"}],
    quantity: [{required: true, message: "请输入", trigger: "blur"}],
    checkTime: [{ required: true, message: "请输入", trigger: "blur" }],
    supplier: [{ required: true, message: "请输入", trigger: "blur" }],
    checkName: [{ required: false, message: "请输入", trigger: "blur" }],
    productId: [{ required: true, message: "请输入", trigger: "blur" }],
    productModelId: [
      { required: true, message: "请选择产品型号", trigger: "change" },
    ],
    testStandardId: [
      { required: false, message: "请选择指标", trigger: "change" },
    ],
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    inspectedQuantity: [
      {required: true, message: "请输入检品数量", trigger: "blur"},
      { required: true, message: "请输入检品数量", trigger: "blur" },
      {
        validator: (rule, value, callback) => {
          if (value !== '' && value !== null && value !== undefined) {
          if (value !== "" && value !== null && value !== undefined) {
            const qty = Number(form.value.quantity);
            const inspectedQty = Number(value);
            if (!isNaN(qty) && !isNaN(inspectedQty) && inspectedQty > qty) {
@@ -304,63 +380,65 @@
            callback();
          }
        },
        trigger: "blur"
      }
        trigger: "blur",
      },
    ],
    checkCompany: [{required: false, message: "请输入", trigger: "blur"}],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }],
    checkResult: [{required: true, message: "请选择检测结果", trigger: "change"}],
    checkResult: [
      { required: true, message: "请选择检测结果", trigger: "change" },
    ],
  },
});
const tableColumn = ref([
  {
    label: "检测项目",
    prop: "parameterItem",
    width: 150
    width: 150,
  },
  {
    label: "标准要求",
    prop: "standardValue",
    width: 180
    width: 180,
  },
  {
    label: "单位",
    prop: "unit",
    width: 70
    width: 70,
  },
  {
    label: "检测器具",
    prop: "instrument",
    dataType: 'slot',
    slot: 'instrument',
    width: 220
    dataType: "slot",
    slot: "instrument",
    width: 220,
  },
  {
    label: "设备状态",
    prop: "deviceStatus",
    dataType: 'slot',
    slot: 'deviceStatus',
    width: 120
    dataType: "slot",
    slot: "deviceStatus",
    width: 120,
  },
  {
    label: "检测结果",
    prop: "result",
    dataType: 'slot',
    slot: 'result',
    width: 150
    dataType: "slot",
    slot: "result",
    width: 150,
  },
  {
    label: "结果判断",
    prop: "resultJudgment",
    dataType: 'slot',
    slot: 'resultJudgment',
    width: 120
    dataType: "slot",
    slot: "resultJudgment",
    width: 120,
  },
]);
const tableData = ref([]);
const tableLoading = ref(false);
const {form, rules} = toRefs(data);
const { form, rules } = toRefs(data);
const supplierList = ref([]);
const productOptions = ref([]);
const currentProductId = ref(0);
@@ -393,7 +471,7 @@
  // 加载设备台账列表
  loadDeviceList();
  // 先重置表单数据(保持字段完整,避免弹窗首次渲染时触发必填红框“闪一下”)
    form.value = {
  form.value = {
    checkTime: "",
    supplier: "",
    checkName: "",
@@ -412,16 +490,16 @@
    validityDate: "",
    checkCompany: "",
    checkResult: "",
  }
  };
  testStandardOptions.value = [];
  tableData.value = [];
  // 先确保产品树已加载,否则编辑时产品/规格型号无法反显
  await getProductOptions();
  if (operationType.value === 'edit') {
  if (operationType.value === "edit") {
    // 先保存 testStandardId,避免被清空
    const savedTestStandardId = row.testStandardId;
    form.value = {...row}
    currentProductId.value = row.productId || 0
    form.value = { ...row };
    currentProductId.value = row.productId || 0;
    // 关键:编辑时加载规格型号下拉选项,才能反显 productModelId
    if (currentProductId.value) {
      try {
@@ -441,9 +519,9 @@
      // 先加载指标选项
      let params = {
        productId: currentProductId.value,
        inspectType: 0
      }
      qualityInspectDetailByProductId(params).then(res => {
        inspectType: 0,
      };
      qualityInspectDetailByProductId(params).then((res) => {
        testStandardOptions.value = res.data || [];
        // 使用 nextTick 和 setTimeout 确保选项已经渲染到 DOM
        nextTick(() => {
@@ -451,8 +529,10 @@
            // 如果编辑数据中有 testStandardId,则设置并加载对应的参数
            if (savedTestStandardId) {
              // 确保类型匹配(item.id 可能是数字或字符串)
              const matchedOption = testStandardOptions.value.find(item =>
                item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId)
              const matchedOption = testStandardOptions.value.find(
                (item) =>
                  item.id == savedTestStandardId ||
                  String(item.id) === String(savedTestStandardId)
              );
              if (matchedOption) {
                // 确保使用匹配项的 id(保持类型一致)
@@ -461,7 +541,12 @@
                getQualityInspectParamList(row.id);
              } else {
                // 如果找不到匹配项,尝试直接使用原值
                console.warn('未找到匹配的指标选项,testStandardId:', savedTestStandardId, '可用选项:', testStandardOptions.value);
                console.warn(
                  "未找到匹配的指标选项,testStandardId:",
                  savedTestStandardId,
                  "可用选项:",
                  testStandardOptions.value
                );
                form.value.testStandardId = savedTestStandardId;
                getQualityInspectParamList(row.id);
              }
@@ -481,7 +566,7 @@
  nextTick(() => {
    proxy.$refs?.formRef?.clearValidate?.();
  });
}
};
const getProductOptions = () => {
  return productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
@@ -494,25 +579,28 @@
  form.value.uidNo = undefined;
  form.value.batchNo = "";
  modelOptions.value = [];
  currentProductId.value = value
  currentProductId.value = value;
  form.value.productName = findNodeById(productOptions.value, value);
  modelList({ id: value }).then((res) => {
    modelOptions.value = res;
  })
  });
  if (currentProductId.value) {
    getList();
  }
};
const handleChangeModel = (value) => {
  form.value.model = modelOptions.value.find(item => item.id == value)?.model || '';
  form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || '';
  form.value.uidNo = modelOptions.value.find(item => item.id == value)?.uidNo || '';
  form.value.model =
    modelOptions.value.find((item) => item.id == value)?.model || "";
  form.value.unit =
    modelOptions.value.find((item) => item.id == value)?.unit || "";
  form.value.uidNo =
    modelOptions.value.find((item) => item.id == value)?.uidNo || "";
  // 选择规格型号后,如果已有生产日期则重新计算有效期
  if (form.value.productionDate) {
    calculateValidityDate();
  }
}
};
const findNodeById = (nodes, productId) => {
  for (let i = 0; i < nodes.length; i++) {
@@ -531,7 +619,7 @@
function convertIdToValue(data) {
  return data.map((item) => {
    const {id, children, ...rest} = item;
    const { id, children, ...rest } = item;
    const newItem = {
      ...rest,
      value: id, // 将 id 改为 value
@@ -546,29 +634,29 @@
// 提交产品表单
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
  proxy.$refs.formRef.validate((valid) => {
    if (valid) {
      form.value.inspectType = 0
            if (operationType.value === "add") {
                tableData.value.forEach((item) => {
                    delete item.id
                })
            }
      const data = {...form.value, qualityInspectParams: tableData.value}
      form.value.inspectType = 0;
      if (operationType.value === "add") {
        qualityInspectAdd(data).then(res => {
        tableData.value.forEach((item) => {
          delete item.id;
        });
      }
      const data = { ...form.value, qualityInspectParams: tableData.value };
      if (operationType.value === "add") {
        qualityInspectAdd(data).then((res) => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })
        });
      } else {
        qualityInspectUpdate(data).then(res => {
        qualityInspectUpdate(data).then((res) => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })
        });
      }
    }
  })
}
  });
};
const getList = () => {
  if (!currentProductId.value) {
@@ -578,17 +666,17 @@
  }
  let params = {
    productId: currentProductId.value,
    inspectType: 0
  }
  qualityInspectDetailByProductId(params).then(res => {
    inspectType: 0,
  };
  qualityInspectDetailByProductId(params).then((res) => {
    // 保存下拉框选项数据
    testStandardOptions.value = res.data || [];
    // 清空表格数据,等待用户选择指标
    tableData.value = [];
    // 清空指标选择
    form.value.testStandardId = '';
  })
}
    form.value.testStandardId = "";
  });
};
// 指标选择变化处理
const handleTestStandardChange = (testStandardId) => {
@@ -597,25 +685,28 @@
    return;
  }
  tableLoading.value = true;
  getQualityTestStandardParamByTestStandardId(testStandardId).then(res => {
    tableData.value = res.data || [];
  }).catch(error => {
    console.error('获取标准参数失败:', error);
    tableData.value = [];
  }).finally(() => {
    tableLoading.value = false;
  })
}
  getQualityTestStandardParamByTestStandardId(testStandardId)
    .then((res) => {
      tableData.value = res.data || [];
    })
    .catch((error) => {
      console.error("获取标准参数失败:", error);
      tableData.value = [];
    })
    .finally(() => {
      tableLoading.value = false;
    });
};
const getQualityInspectParamList = (id) => {
  qualityInspectParamInfo(id).then(res => {
    tableData.value = (res.data || []).map(item => ({...item}));
  })
}
  qualityInspectParamInfo(id).then((res) => {
    tableData.value = (res.data || []).map((item) => ({ ...item }));
  });
};
// 获取设备台账列表
const loadDeviceList = () => {
  qualityInspectParamDeviceList().then(res => {
  qualityInspectParamDeviceList().then((res) => {
    deviceList.value = res.data || [];
  });
};
@@ -623,49 +714,55 @@
// 设备状态颜色映射
const getDeviceStatusType = (status) => {
  const map = {
    '正常': 'success',
    '运行': 'primary',
    '停机': 'warning',
    '维修': 'danger'
    正常: "success",
    运行: "primary",
    停机: "warning",
    维修: "danger",
  };
  return map[status] || 'info';
  return map[status] || "info";
};
// 检测器具变化时,自动填充设备状态
const handleInstrumentChange = (row) => {
  if (row.instrument === '目测') {
  if (row.instrument === "目测") {
    row.deviceId = null;
    row.deviceName = '目测';
    row.deviceStatus = '';
    row.deviceName = "目测";
    row.deviceStatus = "";
    return;
  }
  const device = deviceList.value.find(d => d.deviceName === row.instrument);
  const device = deviceList.value.find((d) => d.deviceName === row.instrument);
  if (device) {
    row.deviceId = device.id;
    row.deviceName = device.deviceName;
    row.deviceStatus = device.status || '';
    row.deviceStatus = device.status || "";
  } else {
    row.deviceId = null;
    row.deviceName = row.instrument || '';
    row.deviceStatus = '';
    row.deviceName = row.instrument || "";
    row.deviceStatus = "";
  }
};
// 计算有效期(生产日期 + 规格型号中的有效期)
const calculateValidityDate = async () => {
  if (!form.value.productionDate) {
    form.value.validityDate = '';
    form.value.validityDate = "";
    return;
  }
  // 获取规格型号的有效期
  const selectedModel = modelOptions.value.find(item => item.id == form.value.productModelId);
  const selectedModel = modelOptions.value.find(
    (item) => item.id == form.value.productModelId
  );
  if (selectedModel && selectedModel.validityPeriod) {
    const productionDate = new Date(form.value.productionDate);
    const validityPeriod = parseFloat(selectedModel.validityPeriod);
    const validityDate = new Date(productionDate);
    validityDate.setFullYear(validityDate.getFullYear() + Math.floor(validityPeriod));
    validityDate.setMonth(validityDate.getMonth() + Math.round((validityPeriod % 1) * 12));
    form.value.validityDate = validityDate.toISOString().split('T')[0];
    validityDate.setFullYear(
      validityDate.getFullYear() + Math.floor(validityPeriod)
    );
    validityDate.setMonth(
      validityDate.getMonth() + Math.round((validityPeriod % 1) * 12)
    );
    form.value.validityDate = validityDate.toISOString().split("T")[0];
  }
};
@@ -674,28 +771,26 @@
  proxy.resetForm("formRef");
  tableData.value = [];
  testStandardOptions.value = [];
  form.value.testStandardId = '';
  form.value.testStandardId = "";
  dialogFormVisible.value = false;
  emit('close')
  emit("close");
};
// 修改检测结果
const changeResult = () => {
  let result = '合格'
  tableData.value.forEach(item => {
    if (item.resultJudgment !== '/') {
      if (item.resultJudgment === '不合格') {
        result = '不合格'
  let result = "合格";
  tableData.value.forEach((item) => {
    if (item.resultJudgment !== "/") {
      if (item.resultJudgment === "不合格") {
        result = "不合格";
      }
    }
  });
  form.value.checkResult = result
  form.value.checkResult = result;
};
defineExpose({
  openDialog,
});
</script>
<style scoped>
</style>
<style scoped></style>