ZN
6 天以前 5fc4e0f0cd2554eeaa911384ed87373aa4ee3c5f
src/views/productionManagement/workOrder/index.vue
@@ -24,10 +24,12 @@
                :page="page"
                :tableLoading="tableLoading"
                @pagination="pagination">
                <template #completionStatus="{ row }">
                  <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
                </template>
              </PIMTable>
        <template #completionStatus="{ row }">
          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
        </template>
      </PIMTable>
    </div>
    <el-dialog v-model="editDialogVisible"
               title="编辑时间"
@@ -104,7 +106,6 @@
                transferCardRowData.status 
              }}</span>
            </div> -->
            <div class="info-item">
              <span class="info-label">计划开始时间</span>
              <span class="info-value">{{ transferCardRowData.planStartTime }}</span>
@@ -166,26 +167,34 @@
    <el-dialog v-model="reportDialogVisible"
               title="报工"
               width="500px">
      <el-form :model="reportForm"
      <el-form ref="reportFormRef"
               :model="reportForm"
               :rules="reportFormRules"
               label-width="120px">
        <el-form-item label="待生产数量">
          <el-input v-model="reportForm.planQuantity"
                    readonly
                    style="width: 300px" />
        </el-form-item>
        <el-form-item label="本次生产数量">
        <el-form-item label="本次生产数量"
                      prop="quantity">
          <el-input v-model.number="reportForm.quantity"
                    type="number"
                    min="1"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入本次生产数量" />
                    placeholder="请输入本次生产数量"
                    @input="handleQuantityInput" />
        </el-form-item>
        <el-form-item label="报废数量">
        <el-form-item label="报废数量"
                      prop="scrapQty">
          <el-input v-model.number="reportForm.scrapQty"
                    type="number"
                    min="1"
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入报废数量" />
                    placeholder="请输入报废数量"
                    @input="handleScrapQtyInput" />
        </el-form-item>
        <el-form-item label="班组信息">
          <el-select v-model="reportForm.userId"
@@ -196,7 +205,20 @@
                     @change="handleUserChange">
            <el-option v-for="user in userOptions"
                       :key="user.userId"
                       :label="user.userName"
                       :label="user.nickName"
                       :value="user.userId" />
          </el-select>
        </el-form-item>
        <el-form-item label="审核人" prop="auditUserId">
          <el-select v-model="reportForm.auditUserId"
                     style="width: 300px"
                     placeholder="请选择审核人"
                     clearable
                     filterable
                     @change="handleReviewerIdChange">
            <el-option v-for="user in userOptions"
                       :key="user.userId"
                       :label="user.nickName"
                       :value="user.userId" />
          </el-select>
        </el-form-item>
@@ -209,13 +231,46 @@
        </span>
      </template>
    </el-dialog>
    <el-dialog
      v-model="auditDialogVisible"
      title="审核"
      width="1000px"
      :close-on-click-modal="false"
    >
      <el-table :data="auditTableData" border style="width: 100%" v-loading="auditLoading">
        <el-table-column label="产品名称" prop="productName" min-width="140" show-overflow-tooltip />
        <el-table-column label="规格" prop="model" min-width="120" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" width="80" />
        <el-table-column label="工序名称" prop="processName" min-width="120" show-overflow-tooltip />
        <el-table-column label="需求数量" prop="planQuantity" width="110" />
        <el-table-column label="完成数量" prop="completeQuantity" width="110" />
        <el-table-column label="完成进度" prop="completionStatus" width="140">
          <template #default="{ row }">
            <el-progress
              :percentage="toProgressPercentage(row?.completionStatus)"
              :color="progressColor(toProgressPercentage(row?.completionStatus))"
              :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
            />
          </template>
        </el-table-column>
        <el-table-column label="计划开始时间" prop="planStartTime" width="140" />
        <el-table-column label="计划结束时间" prop="planEndTime" width="140" />
      </el-table>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" :loading="auditLoading" @click="submitAudit(1)">通过</el-button>
          <el-button type="danger" :loading="auditLoading" @click="submitAudit(2)">不通过</el-button>
          <el-button :disabled="auditLoading" @click="auditDialogVisible = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
    <FilesDia ref="workOrderFilesRef" />
  </div>
</template>
<script setup>
  import { onMounted, ref } from "vue";
  import { ElMessageBox } from "element-plus";
  import { onMounted, ref, nextTick } from "vue";
  import { ElMessageBox, ElMessage } from "element-plus";
  import dayjs from "dayjs";
  import {
    productWorkOrderPage,
@@ -230,6 +285,11 @@
  const { proxy } = getCurrentInstance();
  const tableColumn = ref([
    {
      label: "工单类型",
      prop: "workOrderType",
      width: "80",
    },
    {
      label: "工单编号",
      prop: "workOrderNo",
@@ -306,6 +366,8 @@
          clickFun: row => {
            handleEdit(row);
          },
          // 当需求数量等于完成数量的时候,按钮不可点击
          disabled: row => Number(row?.planQuantity) === Number(row?.completeQuantity),
        },
        {
          name: "流转卡",
@@ -324,8 +386,16 @@
          clickFun: row => {
            showReportDialog(row);
          },
          disabled: row => row.planQuantity <= 0,
          disabled: row => Number(row?.planQuantity) <= Number(row?.completeQuantity) || row.planQuantity <= 0,
        },
        // {
        //   name:"审核",
        //   color: "#f56c6c",
        //   clickFun: row => {
        //     handleAudit(row);
        //   },
        //   disabled: row => Number(row?.auditStatus) === 1,
        // }
      ],
    },
  ]);
@@ -339,11 +409,17 @@
  const transferCardQrUrl = ref("");
  const transferCardRowData = ref(null);
  const reportDialogVisible = ref(false);
  const auditDialogVisible = ref(false);
  const auditRowData = ref(null);
  const auditTableData = ref([]);
  const auditLoading = ref(false);
  const workOrderFilesRef = ref(null);
  const reportFormRef = ref(null);
  const userOptions = ref([]);
  const reportForm = reactive({
    planQuantity: 0,
    quantity: 0,
    quantity: null,
    scrapQty: null,
    userName: "",
    workOrderId: "",
    reportWork: "",
@@ -351,6 +427,153 @@
    userId: "",
    productMainId: null,
  });
  // 本次生产数量验证规则
  const validateQuantity = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback(new Error("请输入本次生产数量"));
      return;
    }
    const num = Number(value);
    // 整数且大于等于1
    if (isNaN(num) || !Number.isInteger(num) || num < 1) {
      callback(new Error("本次生产数量必须大于等于1"));
      return;
    }
    callback();
  };
  // 报废数量验证规则
  const validateScrapQty = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback();
      return;
    }
    const num = Number(value);
    // 整数且大于等于0
    if (isNaN(num) || !Number.isInteger(num) || num < 0) {
      callback(new Error("报废数量必须大于等于0"));
      return;
    }
    callback();
  };
  // 审核
  const handleAudit = (row) => {
    if (Number(row?.auditStatus) === 1) {
      ElMessage.warning("该工单已审核");
      return;
    }
    auditRowData.value = row;
    const workOrderNo = row?.workOrderNo;
    const related = workOrderNo
      ? tableData.value.filter(r => r?.workOrderNo === workOrderNo)
      : [];
    auditTableData.value = related.length > 0 ? related : [row];
    auditDialogVisible.value = true;
  };
  const submitAudit = async (result) => {
    const current = auditRowData.value;
    if (!current) return;
    if (auditLoading.value) return;
    const confirmText = result === 1 ? "确定审核通过吗?" : "确定审核不通过吗?";
    try {
      await ElMessageBox.confirm(confirmText, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      });
    } catch {
      return;
    }
    auditLoading.value = true;
    try {
      const updates = auditTableData.value.map(item => {
        const id = item?.id;
        if (!id) return Promise.resolve();
        return updateProductWorkOrder({ id, auditStatus: result });
      });
      await Promise.all(updates);
      ElMessage.success("审核成功");
      auditDialogVisible.value = false;
      getList();
    } finally {
      auditLoading.value = false;
    }
  };
  // 查看详情
  const handleView = (row) => {
    const { workOrderId } = row;
    router.push({
      path: "/productionManagement/workOrderDetail",
      query: { workOrderId },
    });
  }
  // 验证规则
  const reportFormRules = {
    quantity: [{ required: true, validator: validateQuantity, trigger: "blur" }],
    scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
    auditUserId: [{ required: true, message: "请选择审核人", trigger: "change" }],
  };
  // 处理本次生产数量输入,限制必须大于等于1
  const handleQuantityInput = value => {
    if (value === "" || value === null || value === undefined) {
      reportForm.quantity = null;
      return;
    }
    const num = Number(value);
    if (isNaN(num)) {
      return;
    }
    // 如果小于1,清除
    if (num < 1) {
      reportForm.quantity = null;
      return;
    }
    // 如果是小数取整数部分
    if (!Number.isInteger(num)) {
      const intValue = Math.floor(num);
      // 如果取整后小于1,清除
      if (intValue < 1) {
        reportForm.quantity = null;
        return;
      }
      reportForm.quantity = intValue;
      return;
    }
    reportForm.quantity = num;
  };
  // 处理报废数量
  const handleScrapQtyInput = value => {
    if (value === "" || value === null || value === undefined) {
      reportForm.scrapQty = null;
      return;
    }
    const num = Number(value);
    // 如果是NaN,保持原值
    if (isNaN(num)) {
      return;
    }
    // 如果是负数,清除输入
    if (num < 0) {
      reportForm.scrapQty = null;
      return;
    }
    // 如果是小数,取整数部分
    if (!Number.isInteger(num)) {
      reportForm.scrapQty = Math.floor(num);
      return;
    }
    // 有效的非负整数(包括0)
    reportForm.scrapQty = num;
  };
  const currentReportRowData = ref(null);
  const page = reactive({
    current: 1,
@@ -425,7 +648,9 @@
      // 创建 Blob URL
      const fileBlob =
        blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" });
        blob instanceof Blob
          ? blob
          : new Blob([blob], { type: blob.type || "application/octet-stream" });
      const url = window.URL.createObjectURL(fileBlob);
      // 创建隐藏 iframe,用于触发浏览器打印
@@ -488,19 +713,24 @@
  const showReportDialog = row => {
    currentReportRowData.value = row;
    reportForm.planQuantity = row.planQuantity;
    reportForm.quantity = row.quantity;
    reportForm.planQuantity = row.planQuantity - row.completeQuantity;
    reportForm.quantity =
      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
    reportForm.workOrderId = row.id;
    reportForm.reportWork = row.reportWork;
    reportForm.productMainId = row.productMainId;
    reportForm.scrapQty = row.scrapQty;
    reportForm.scrapQty =
      row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
    nextTick(() => {
      reportFormRef.value?.clearValidate();
    });
    // 获取当前登录用户信息,设置为默认选中
    getUserProfile()
      .then(res => {
        if (res.code === 200) {
          reportForm.userId = res.data.userId;
          reportForm.userName = res.data.userName;
          reportForm.userName = res.data.nickName;
        }
      })
      .catch(err => {
@@ -515,35 +745,79 @@
  };
  const handleReport = () => {
    if (reportForm.planQuantity <= 0) {
      ElMessageBox.alert("待生产数量为0,无法报工", "提示", {
        confirmButtonText: "确定",
      });
      return;
    }
    if (!reportForm.quantity || reportForm.quantity <= 0) {
      ElMessageBox.alert("请输入有效的本次生产数量", "提示", {
        confirmButtonText: "确定",
      });
      return;
    }
    if (reportForm.quantity > reportForm.planQuantity) {
      ElMessageBox.alert("本次生产数量不能超过待生产数量", "提示", {
        confirmButtonText: "确定",
      });
      return;
    }
    // console.log(reportForm);
    addProductMain(reportForm).then(res => {
      if (res.code === 200) {
        proxy.$modal.msgSuccess("报工成功");
        reportDialogVisible.value = false;
        getList();
      } else {
        ElMessageBox.alert(res.msg || "报工失败", "提示", {
    reportFormRef.value?.validate(valid => {
      if (!valid) {
        return false;
      }
      if (reportForm.planQuantity <= 0) {
        ElMessageBox.alert("待生产数量为0,无法报工", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // 验证本次生产数量
      if (
        reportForm.quantity === null ||
        reportForm.quantity === undefined ||
        reportForm.quantity === ""
      ) {
        ElMessageBox.alert("请输入本次生产数量", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      const quantity = Number(reportForm.quantity);
      const scrapQty =
        reportForm.scrapQty === null ||
        reportForm.scrapQty === undefined ||
        reportForm.scrapQty === ""
          ? 0
          : Number(reportForm.scrapQty);
      // 本次生产数量
      if (isNaN(quantity) || !Number.isInteger(quantity) || quantity < 1) {
        ElMessageBox.alert("本次生产数量必须大于等于1", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // 报废数量必须是整数且大于等于0
      if (isNaN(scrapQty) || !Number.isInteger(scrapQty) || scrapQty < 0) {
        ElMessageBox.alert("报废数量必须大于等于0", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      if (quantity > reportForm.planQuantity) {
        ElMessageBox.alert("本次生产数量不能超过待生产数量", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      const submitData = {
        ...reportForm,
        quantity: quantity,
        scrapQty: scrapQty,
      };
      // console.log(submitData);
      addProductMain(submitData).then(res => {
        if (res.code === 200) {
          proxy.$modal.msgSuccess("报工成功");
          reportDialogVisible.value = false;
          getList();
        } else {
          ElMessageBox.alert(res.msg || "报工失败", "提示", {
            confirmButtonText: "确定",
          });
        }
      });
    });
  };
@@ -561,16 +835,27 @@
  };
  // 用户选择变化时更新 userName
  const handleUserChange = (userId) => {
  const handleUserChange = userId => {
    if (userId) {
      const selectedUser = userOptions.value.find(user => user.userId === userId);
      if (selectedUser) {
        reportForm.userName = selectedUser.userName;
        reportForm.userName = selectedUser.nickName;
      }
    } else {
      reportForm.userName = "";
    }
  };
  // 审核人
  const handleReviewerIdChange = userId => {
    if (userId) {
      const selectedUser = userOptions.value.find(user => user.userId === userId);
      if (selectedUser) {
        reportForm.auditUserName = selectedUser.nickName;
      }
    } else {
      reportForm.auditUserName = "";
    }
  }
  onMounted(() => {
    getList();