zhangwencui
8 天以前 fa7202c95f80c76c334e98c034910443395e5f0e
生产追溯修改
已修改2个文件
388 ■■■■■ 文件已修改
src/api/productionManagement/productionOrder.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionTraceability/index.vue 379 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionOrder.js
@@ -102,6 +102,15 @@
    data,
  });
}
// 生产订单溯源详情
export function getOrderDetail(npsNo) {
  return request({
    url: "/productionOrder/ordeDetail",
    method: "get",
    params: { npsNo },
  });
}
// 生产订单-领料详情列表
// export function listMaterialPickingDetail(query) {
//   return request({
src/views/productionManagement/productionTraceability/index.vue
@@ -22,9 +22,6 @@
                           :value="option.id" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button @click="handleBack">返回</el-button>
            </el-form-item>
          </el-form>
        </div>
      </template>
@@ -37,7 +34,7 @@
          <el-descriptions-item label="生产订单号">{{ rowData.productionOrderDto?.npsNo || '-' }}</el-descriptions-item>
          <el-descriptions-item label="产品名称">{{ rowData.productionOrderDto?.productName || '-' }}</el-descriptions-item>
          <el-descriptions-item label="产品规格">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item>
          <el-descriptions-item label="物料编码">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item>
          <!-- <el-descriptions-item label="物料编码">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item> -->
          <el-descriptions-item label="计划数量">{{ rowData.productionOrderDto?.quantity || 0 }} <span class="unit">{{ rowData.productionOrderDto?.unit || '-' }}</span></el-descriptions-item>
          <el-descriptions-item label="当前状态">
            <el-tag :type="getStatusType(rowData.productionOrderDto?.status)">
@@ -45,12 +42,12 @@
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="客户名称">{{ rowData.productionOrderDto?.customerName || '-' }}</el-descriptions-item>
          <el-descriptions-item label="开始日期">{{ rowData.productionOrderDto?.startTime || '-' }}</el-descriptions-item>
          <el-descriptions-item label="开始日期">{{ parseTime(rowData.productionOrderDto?.startTime) || '-' }}</el-descriptions-item>
          <el-descriptions-item label="完成进度">
            <el-progress :percentage="rowData.productionOrderDto?.completionStatus"
            <el-progress :percentage="rowData.productionOrderDto?.completionStatus>=100?100:rowData.productionOrderDto?.completionStatus"
                         :color="customColors(rowData.productionOrderDto?.completionStatus)"
                         :status="rowData.productionOrderDto?.completionStatus === 100 ? 'success' : ''"
                         style="width: 120px;" />
                         :status="rowData.productionOrderDto?.completionStatus >= 100 ? 'success' : ''"
                         style="width: 80%;" />
          </el-descriptions-item>
        </el-descriptions>
      </div>
@@ -65,23 +62,26 @@
            <el-table :data="rowData.productionRecords"
                      border
                      style="width: 100%">
              <el-table-column prop="productNo"
              <el-table-column prop="workOrder.workOrderNo"
                               label="工单编号"
                               align="center">
              </el-table-column>
              <el-table-column prop="productName"
                               label="产品名称"
                               align="center" />
              <el-table-column prop="model"
                               label="规格"
                               align="center" />
              <el-table-column prop="processName"
                               label="工序名称"
                               align="center" />
              <el-table-column prop="requiredQuantity"
              <el-table-column label="产品名称"
                               align="center">
                <template #default>
                  {{ rowData.productionOrderDto?.productName || '-' }}
                </template>
              </el-table-column>
              <el-table-column label="规格"
                               align="center">
                <template #default>
                  {{ rowData.productionOrderDto?.model || '-' }}
                </template>
              </el-table-column>
              <el-table-column prop="workOrder.planQuantity"
                               label="需求数量"
                               align="center" />
              <el-table-column prop="completedQuantity"
              <el-table-column prop="workOrder.completeQuantity"
                               label="完成数量"
                               align="center" />
              <el-table-column label="详情"
@@ -111,39 +111,36 @@
      <div class="detail-container">
        <!-- 基础信息 -->
        <div class="detail-section">
          <h3 class="section-title">基础信息</h3>
          <h3 class="section-title">工单基础信息</h3>
          <el-descriptions :column="3"
                           border>
            <el-descriptions-item label="生产工单号">{{ detailData.npsNo || '-' }}</el-descriptions-item>
            <el-descriptions-item label="班组">
              <el-tag :type="detailData.schedule === '白班' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag>
            <el-descriptions-item label="生产工单号">{{ detailData.workOrder.workOrderNo || '-' }}</el-descriptions-item>
            <el-descriptions-item label="计划数量">{{ detailData.workOrder.planQuantity || 0 }}</el-descriptions-item>
            <el-descriptions-item label="完成数量">{{ detailData.workOrder.completeQuantity || 0 }}</el-descriptions-item>
            <el-descriptions-item label="实际开始时间">{{ parseTime(detailData.workOrder.actualStartTime) || '-' }}</el-descriptions-item>
            <el-descriptions-item label="实际结束时间">{{ parseTime(detailData.workOrder.actualEndTime) || '-' }}</el-descriptions-item>
            <el-descriptions-item label="状态">
              <el-tag :type="getStatusType(detailData.workOrder.status)">{{ getStatusText(detailData.workOrder.status) }}</el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="产品编码">{{ detailData.materialCode || '-' }}</el-descriptions-item>
            <el-descriptions-item label="产品名称">{{ detailData.productName || '-' }}</el-descriptions-item>
            <el-descriptions-item label="规格">{{ detailData.model || '-' }}</el-descriptions-item>
            <el-descriptions-item label="合格数量"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
            <el-descriptions-item label="不合格数量"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
            <el-descriptions-item label="总数量"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
            <el-descriptions-item label="开始时间">{{ detailData.reportingTime || '-' }}</el-descriptions-item>
          </el-descriptions>
        </div>
        <div class="detail-section">
          <h3 class="section-title">报工明细</h3>
          <el-table :data="[detailData]"
          <el-table :data="detailData.reports"
                    border
                    style="width: 100%">
            <el-table-column label="报工单号"
                             prop="productNo"
                             align="center" />
            <el-table-column label="产出数量"
                             prop="qualifiedQuantity"
                             align="center" />
            <el-table-column label="报废数量"
                             prop="unqualifiedQuantity"
            <el-table-column label="创建人"
                             prop="userName"
                             align="center" />
            <el-table-column label="创建时间"
                             prop="reportingTime"
                             align="center" />
                             align="center">
              <template #default="{ row }">
                {{ parseTime(row.createTime) }}
              </template>
            </el-table-column>
            <el-table-column label="操作"
                             align="center"
                             width="200">
@@ -205,25 +202,24 @@
             :key="record.id"
             class="quality-record-block">
          <div class="detail-section">
            <h3 class="section-title">检测记录 {{ index + 1 }} - {{ record.checkTime }}</h3>
            <h3 class="section-title">检测记录 {{ index + 1 }} - {{ parseTime(record.createTime) }}</h3>
            <el-descriptions :column="3"
                             border>
              <el-descriptions-item label="检测日期">{{ record.checkTime || '-' }}</el-descriptions-item>
              <el-descriptions-item label="生产工单号">{{ record.workOrderNo || '-' }}</el-descriptions-item>
              <el-descriptions-item label="工序">{{ record.process || '-' }}</el-descriptions-item>
              <el-descriptions-item label="检验员">{{ record.checkName || '-' }}</el-descriptions-item>
              <el-descriptions-item label="检测日期">{{ parseTime(record.createTime) || '-' }}</el-descriptions-item>
              <el-descriptions-item label="报工单号">{{ record.reportNo || '-' }}</el-descriptions-item>
              <el-descriptions-item label="检验员">{{ record.userName || '-' }}</el-descriptions-item>
              <el-descriptions-item label="产品名称">{{ record.productName || '-' }}</el-descriptions-item>
              <el-descriptions-item label="规格型号">{{ record.model || '-' }}</el-descriptions-item>
              <el-descriptions-item label="数量">{{ record.quantity || 0 }} {{ record.unit || '-' }}</el-descriptions-item>
              <el-descriptions-item label="检测单位">{{ record.checkCompany || '-' }}</el-descriptions-item>
              <el-descriptions-item label="检测结果">
                <el-tag :type="record.checkResult === '合格' ? 'success' : 'danger'">
                  {{ record.checkResult || '-' }}
                  {{ record.checkResult || '待检测' }}
                </el-tag>
              </el-descriptions-item>
            </el-descriptions>
            <h4 class="sub-section-title">检验指标列表</h4>
            <el-table :data="record.inspectItems"
            <el-table :data="record.inspectParamList"
                      border
                      style="width: 100%">
              <el-table-column label="序号"
@@ -231,7 +227,7 @@
                               width="60"
                               align="center" />
              <el-table-column label="指标"
                               prop="itemName"
                               prop="paramName"
                               align="center" />
              <el-table-column label="单位"
                               prop="unit"
@@ -239,17 +235,11 @@
              <el-table-column label="标准值"
                               prop="standardValue"
                               align="center" />
              <el-table-column label="内控值"
                               prop="controlValue"
                               align="center" />
              <el-table-column label="实际值"
                               prop="actualValue"
                               prop="inputValue"
                               align="center" />
            </el-table>
          </div>
          <!-- <div class="detail-section">
          </div> -->
          <el-divider v-if="index < qualityRecords.length - 1" />
        </div>
      </div>
@@ -266,7 +256,12 @@
  import { ref, reactive, onMounted } from "vue";
  import { useRoute, useRouter } from "vue-router";
  import { ElMessage } from "element-plus";
  import { parseTime } from "@/utils/ruoyi";
  import InputModal from "@/views/productionManagement/productionReporting/Input.vue";
  import {
    getOrderDetail,
    productOrderListPage,
  } from "@/api/productionManagement/productionOrder";
  const route = useRoute();
  const router = useRouter();
@@ -277,47 +272,7 @@
  });
  const selectedNpsNo = ref(null);
  const npsNoLoading = ref(false);
  const npsNoOptions = ref([
    {
      id: 1,
      npsNo: "PO20240301001",
      productName: "精密液压缸",
      model: "HG-100/50-500",
      materialCode: "MAT-2024-001",
      quantity: 500,
      unit: "件",
      status: 1,
      customerName: "重工机械有限公司",
      startTime: "2024-03-01",
      completionStatus: 65,
    },
    {
      id: 2,
      npsNo: "PO20240301002",
      productName: "工业伺服电机",
      model: "SV-400W-3000",
      materialCode: "MAT-2024-002",
      quantity: 200,
      unit: "台",
      status: 2,
      customerName: "自动化设备科技公司",
      startTime: "2024-03-02",
      completionStatus: 100,
    },
    {
      id: 3,
      npsNo: "PO20240301003",
      productName: "高压密封圈",
      model: "SR-80-5",
      materialCode: "MAT-2024-003",
      quantity: 5000,
      unit: "个",
      status: 0,
      customerName: "密封系统配件厂",
      startTime: "2024-03-05",
      completionStatus: 0,
    },
  ]);
  const npsNoOptions = ref([]);
  // 详情数据
  const rowData = reactive({
@@ -327,7 +282,10 @@
  // 报工详情弹窗
  const detailDialogVisible = ref(false);
  const detailData = ref({});
  const detailData = ref({
    workOrder: {},
    reports: [],
  });
  // 投入模态框
  const isShowInput = ref(false);
@@ -351,12 +309,12 @@
  // 状态处理
  const getStatusType = status => {
    const typeMap = { 0: "info", 1: "primary", 2: "success" };
    const typeMap = { 1: "primary", 2: "warning", 3: "success", 5: "danger" };
    return typeMap[status] || "info";
  };
  const getStatusText = status => {
    const statusMap = { 0: "未开始", 1: "生产中", 2: "已完成" };
    return statusMap[status] || "未知";
    const statusMap = { 1: "待开始", 2: "进行中", 3: "已完成", 5: "已结束" };
    return statusMap[status] || "已取消";
  };
  const customColors = percentage => {
    if (percentage < 30) return "#f56c6c";
@@ -365,51 +323,41 @@
  };
  // 模拟搜索方法
  const handleNpsNoSearch = query => {
    if (query) {
  const handleNpsNoSearch = async query => {
      npsNoLoading.value = true;
      setTimeout(() => {
    try {
      const res = await productOrderListPage({
        npsNo: query || "",
        pageNum: 1,
        pageSize: 50,
      });
      // 参照 productionOrder/index.vue 的数据结构 res.data.records
      npsNoOptions.value = res.data?.records || res.rows || [];
    } catch (error) {
      console.error(error);
    } finally {
        npsNoLoading.value = false;
      }, 300);
    }
  };
  const handleSearch = id => {
  const handleSearch = async id => {
    const selected = npsNoOptions.value.find(item => item.id === id);
    if (selected) {
      try {
        const res = await getOrderDetail(selected.npsNo);
        if (res.code === 200) {
          const { productionOrder, workOrderList } = res.data;
          rowData.productionOrderDto = productionOrder || selected;
          rowData.productionRecords = workOrderList || [];
        } else {
      rowData.productionOrderDto = selected;
      rowData.productionRecords = [
        {
          id: 1001,
          productNo: "MO-2024-001-01",
          productName: selected.productName,
          model: selected.model,
          processName: "毛坯加工",
          requiredQuantity: selected.quantity,
          completedQuantity: Math.floor(selected.quantity * 0.4),
          qualifiedQuantity: Math.floor(selected.quantity * 0.4) - 2,
          unqualifiedQuantity: 2,
          reportingTime: "2024-03-01 10:00:00",
          schedule: "白班",
          postName: "张三",
          unit: selected.unit,
        },
        {
          id: 1002,
          productNo: "MO-2024-001-02",
          productName: selected.productName,
          model: selected.model,
          processName: "精加工",
          requiredQuantity: Math.floor(selected.quantity * 0.4),
          completedQuantity: Math.floor(selected.quantity * 0.25),
          qualifiedQuantity: Math.floor(selected.quantity * 0.25),
          unqualifiedQuantity: 0,
          reportingTime: "2024-03-01 16:00:00",
          schedule: "白班",
          postName: "李四",
          unit: selected.unit,
        },
      ];
          rowData.productionRecords = [];
        }
      } catch (error) {
        console.error(error);
        ElMessage.error("获取订单详情失败");
        rowData.productionOrderDto = selected;
      }
    }
  };
@@ -418,121 +366,34 @@
  };
  const handleClickStep = row => {
    // row 是 workOrderList 中的一项,包含 workOrder, reportList, inspectList
    detailData.value = {
      id: row.id || Math.floor(Math.random() * 1000),
      productNo: row.productNo,
      npsNo: rowData.productionOrderDto.npsNo,
      schedule: row.schedule,
      postName: row.postName,
      materialCode: rowData.productionOrderDto.materialCode,
      productName: row.productName,
      model: row.model,
      qualifiedQuantity: row.qualifiedQuantity,
      unqualifiedQuantity: row.unqualifiedQuantity || 0,
      quantity: row.completedQuantity,
      unit: row.unit,
      reportingTime: row.reportingTime,
      productionOperationParamList: [
        { id: 1, paramName: "主轴转速", inputValue: "2400", unit: "rpm" },
        { id: 2, paramName: "进给速度", inputValue: "120", unit: "mm/min" },
        { id: 3, paramName: "切削深度", inputValue: "0.5", unit: "mm" },
        { id: 4, paramName: "冷却液压力", inputValue: "0.6", unit: "Mpa" },
      ],
      workOrder: row.workOrder || {},
      reports: (row.reportList || []).map(r => ({
        ...r.reportMain,
        productionOperationParamList: r.reportParamList || [],
      })),
    };
    detailDialogVisible.value = true;
  };
  const handleClickQuality = row => {
    qualityRecords.value = [
      {
        id: 2001,
        checkTime: "2024-03-01 11:30:00",
        workOrderNo: row.productNo,
        process: row.processName,
        checkName: "质量部-王建国",
        productName: row.productName,
        model: row.model,
        unit: row.unit,
        quantity: row.completedQuantity,
        checkCompany: "内部实验室",
        checkResult: "合格",
        inspectItems: [
          {
            id: 1,
            itemName: "外径尺寸",
            unit: "mm",
            standardValue: "100.00±0.05",
            controlValue: "100.00±0.03",
            actualValue: "100.01",
            result: "合格",
          },
          {
            id: 2,
            itemName: "内径尺寸",
            unit: "mm",
            standardValue: "50.00+0.02/-0",
            controlValue: "50.00+0.01/-0",
            actualValue: "50.01",
            result: "合格",
          },
          {
            id: 3,
            itemName: "表面粗糙度",
            unit: "Ra",
            standardValue: "≤1.6",
            controlValue: "≤1.2",
            actualValue: "0.8",
            result: "合格",
          },
        ],
      },
      {
        id: 2001,
        checkTime: "2024-03-01 11:30:00",
        workOrderNo: row.productNo,
        process: row.processName,
        checkName: "质量部-王建国",
        productName: row.productName,
        model: row.model,
        unit: row.unit,
        quantity: row.completedQuantity,
        checkCompany: "内部实验室",
        checkResult: "合格",
        inspectItems: [
          {
            id: 1,
            itemName: "外径尺寸",
            unit: "mm",
            standardValue: "100.00±0.05",
            controlValue: "100.00±0.03",
            actualValue: "100.01",
            result: "合格",
          },
          {
            id: 2,
            itemName: "内径尺寸",
            unit: "mm",
            standardValue: "50.00+0.02/-0",
            controlValue: "50.00+0.01/-0",
            actualValue: "50.01",
            result: "合格",
          },
          {
            id: 3,
            itemName: "表面粗糙度",
            unit: "Ra",
            standardValue: "≤1.6",
            controlValue: "≤1.2",
            actualValue: "0.8",
            result: "合格",
          },
        ],
      },
    ];
    // row 是 workOrderList 中的一项
    const inspects = row.inspectList || [];
    qualityRecords.value = inspects.map(i => ({
      ...i.inspect,
      reportNo: i.reportNo,
      userName: i.reportMain?.userName || "-",
      inspectParamList: i.inspectParamList || [],
      inspectFileList: i.inspectFileList || [],
    }));
    qualityDialogVisible.value = true;
  };
  onMounted(() => {
  onMounted(async () => {
    // 初始加载列表
    await handleNpsNoSearch();
    if (route.query.npsNo) {
      const npsNo = route.query.npsNo;
      const found = npsNoOptions.value.find(item => item.npsNo === npsNo);
@@ -540,23 +401,23 @@
        selectedNpsNo.value = found.id;
        handleSearch(found.id);
      } else {
        // 如果没找到,创建一个临时的
        const mockItem = {
          id: Date.now(),
          npsNo: npsNo,
          productName: route.query.productName || "精密液压缸",
          model: route.query.model || "HG-100/50-500",
          materialCode: "MAT-2024-MOCK",
          quantity: 100,
          unit: "件",
          status: 1,
          customerName: "模拟客户",
          startTime: "2024-03-01",
          completionStatus: 50,
        };
        npsNoOptions.value.push(mockItem);
        selectedNpsNo.value = mockItem.id;
        handleSearch(mockItem.id);
        // 如果列表中没有(可能是分页原因),则根据 npsNo 再次精准搜索
        try {
          const res = await productOrderListPage({
            npsNo,
            pageNum: -1,
            pageSize: -1,
          });
          const records = res.data?.records || res.rows || [];
          if (records.length > 0) {
            const item = records[0];
            npsNoOptions.value.unshift(item);
            selectedNpsNo.value = item.id;
            handleSearch(item.id);
          }
        } catch (error) {
          console.error("获取路由参数对应的订单失败", error);
        }
      }
    }
  });