已修改5个文件
385 ■■■■■ 文件已修改
src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrderManagement/index.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/index.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue
@@ -48,6 +48,13 @@
        <el-button :icon="RefreshRight" @click="resetSearch">重置</el-button>
      </div>
      <div class="search_actions">
        <el-button
          type="success"
          :icon="CircleCheck"
          @click="openBatchApproveDialog"
        >
          批量审批
        </el-button>
        <el-button type="primary" :icon="Plus" @click="openSubmitDialog">提交审批</el-button>
      </div>
    </div>
@@ -58,9 +65,10 @@
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="false"
        :isSelection="true"
        :tableLoading="tableLoading"
        :total="page.total"
        @selection-change="handleSelectionChange"
        @pagination="pagination"
      >
        <template #approveType="{ row }">
@@ -329,11 +337,53 @@
        </el-button>
      </template>
    </el-dialog>
    <!-- 批量审批操作 -->
    <el-dialog
      v-model="batchApproveDialog.visible"
      title="批量审批处理"
      width="560px"
      append-to-body
      destroy-on-close
      @closed="batchApproveOpinion = ''"
    >
      <el-form label-width="100px">
        <el-form-item label="审批意见">
          <el-input
            v-model="batchApproveOpinion"
            type="textarea"
            :rows="4"
            maxlength="500"
            show-word-limit
            placeholder="通过可留空;驳回请填写具体原因"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button
          type="success"
          :loading="batchApproveSubmitting"
          @click="onBatchApprove('approved')"
        >
          通 过
        </el-button>
        <el-button
          type="danger"
          :loading="batchApproveSubmitting"
          @click="onBatchApprove('rejected')"
        >
          驳 回
        </el-button>
        <el-button :disabled="batchApproveSubmitting" @click="batchApproveDialog.visible = false">
          取 消
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { Plus, RefreshRight } from "@element-plus/icons-vue";
import { CircleCheck, Plus, RefreshRight } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { computed, onMounted, ref } from "vue";
import { APPROVAL_MODULE_KEYS } from "../approve-shared/approvalModuleRegistry.js";
@@ -374,6 +424,9 @@
  approveDialog,
  approveOpinion,
  approveSubmitting,
  batchApproveDialog,
  batchApproveOpinion,
  batchApproveSubmitting,
  submitReimburseApprove,
  submitDialog,
  isSubmitEdit,
@@ -387,6 +440,8 @@
  handleQuery,
  resetSearch,
  pagination,
  handleSelectionChange,
  openBatchApproveDialog,
  resetSubmitDialogState,
  openSubmitDialog,
  openEditDialog,
@@ -394,6 +449,7 @@
  backToTemplatePick,
  submitInstanceForm,
  submitApprove,
  submitBatchApprove,
  openDetail,
  openApprove,
} = al;
@@ -435,6 +491,21 @@
  }
  if (ret?.ok) {
    ElMessage.success(result === "approved" ? "已通过" : "已驳回");
  }
}
async function onBatchApprove(result) {
  const ret = await submitBatchApprove(result);
  if (ret?.needOpinion) {
    ElMessage.warning("驳回时请填写审批意见");
    return;
  }
  if (ret?.ok) {
    if (ret.failCount > 0) {
      ElMessage.warning(`成功审批${ret.successCount}条,失败${ret.failCount}条`);
    } else {
      ElMessage.success(result === "approved" ? "批量审批已通过" : "批量审批已驳回");
    }
  }
}
@@ -611,4 +682,4 @@
  border-left: 3px solid var(--el-color-primary);
  line-height: 1.4;
}
</style>
</style>
src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
@@ -85,6 +85,10 @@
  const approveDialog = reactive({ visible: false, row: null });
  const approveOpinion = ref("");
  const approveSubmitting = ref(false);
  const selectedRows = ref([]);
  const batchApproveDialog = reactive({ visible: false });
  const batchApproveOpinion = ref("");
  const batchApproveSubmitting = ref(false);
  /** 差旅/费用报销专用详情、审批弹窗 */
  const reimburseDialog = reactive({
@@ -189,7 +193,7 @@
        {
          name: "审批",
          type: "text",
          disabled: (row) => row.approvalStatus !== "pending" || !row.isApprove,
          disabled: (row) => !canApprove(row),
          clickFun: (row) => openApprove(row),
        },
        // {
@@ -263,6 +267,28 @@
    page.current = p;
    page.size = limit;
    fetchApprovalList();
  }
  function handleSelectionChange(selection) {
    selectedRows.value = selection || [];
  }
  function canApprove(row) {
    return row?.approvalStatus === "pending" && Boolean(row?.isApprove);
  }
  function openBatchApproveDialog() {
    if (!selectedRows.value.length) {
      ElMessage.warning("请选择数据");
      return;
    }
    const approveRows = selectedRows.value.filter(canApprove);
    if (!approveRows.length) {
      ElMessage.warning("所选数据不可审批");
      return;
    }
    batchApproveOpinion.value = "";
    batchApproveDialog.visible = true;
  }
  async function openReimburseDetail(row, mode) {
@@ -636,6 +662,40 @@
    }
  }
  async function submitBatchApprove(result) {
    const approveRows = selectedRows.value.filter(canApprove);
    if (!approveRows.length) {
      ElMessage.warning("所选数据不可审批");
      return { ok: false };
    }
    if (result === "rejected" && !(batchApproveOpinion.value || "").trim()) {
      return { needOpinion: true };
    }
    if (batchApproveSubmitting.value) return { ok: false };
    batchApproveSubmitting.value = true;
    try {
      const results = await Promise.allSettled(
        approveRows.map((row) =>
          approveApprovalInstance(
            buildApproveInstanceDto(row, result, batchApproveOpinion.value)
          )
        )
      );
      const successCount = results.filter((item) => item.status === "fulfilled").length;
      const failCount = approveRows.length - successCount;
      batchApproveDialog.visible = false;
      await fetchApprovalList();
      return { ok: successCount > 0, result, successCount, failCount };
    } catch {
      ElMessage.error("批量审批失败");
      return { ok: false };
    } finally {
      batchApproveSubmitting.value = false;
    }
  }
  function approvalActionLabel(result) {
    if (result === "approved") return "通过";
    if (result === "rejected") return "驳回";
@@ -664,6 +724,10 @@
    approveDialog,
    approveOpinion,
    approveSubmitting,
    selectedRows,
    batchApproveDialog,
    batchApproveOpinion,
    batchApproveSubmitting,
    submitReimburseApprove,
    isReimburseApprovalInstance,
    submitDialog,
@@ -685,6 +749,8 @@
    handleQuery,
    resetSearch,
    pagination,
    handleSelectionChange,
    openBatchApproveDialog,
    resetSubmitDialogState,
    openSubmitDialog,
    openEditDialog,
@@ -695,8 +761,9 @@
    submitInstanceForm,
    submitNewApproval,
    submitApprove,
    submitBatchApprove,
    openDetail,
    openApprove,
    fetchApprovalList,
  };
}
}
src/views/productionManagement/workOrderManagement/index.vue
@@ -27,10 +27,17 @@
      </div>
    </div>
    <div class="table_list">
      <div style="margin-bottom: 10px; text-align: left;">
        <el-button type="primary"
                   v-hasPermi="['production:workOrder:batchReport']"
                   @click="handleBatchReport">一键报工</el-button>
      </div>
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                @selection-change="handleSelectionChange"
                :tableLoading="tableLoading"
                @pagination="pagination">
        <template #completionStatus="{ row }">
@@ -409,6 +416,7 @@
  ]);
  const tableData = ref([]);
  const tableLoading = ref(false);
  const selectedRows = ref([]);
  const transferCardVisible = ref(false);
  const transferCardData = ref([]);
  const transferCardQrUrl = ref("");
@@ -686,8 +694,7 @@
      toQuantity(planQuantity - completeQuantity)
    );
    reportForm.planQuantity = remainingQuantity;
    reportForm.quantity =
      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    reportForm.quantity = remainingQuantity;
    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
    reportForm.workOrderId = row.id;
    reportForm.reportWork = row.reportWork;
@@ -824,6 +831,79 @@
    reportForm.userName = user ? user.nickName : "";
  };
  // 表格选择变化
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  // 一键报工:勾选数据后,生产合格数量默认等于待生产数量,直接提交
  const handleBatchReport = async () => {
    if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请先勾选要报工的工单");
      return;
    }
    // 过滤出可报工的工单:未完工且待生产数量 > 0
    const validRows = selectedRows.value.filter(row => {
      if (row.endOrder) return false;
      const planQuantity = Number(row.planQuantity || 0);
      const completeQuantity = Number(row.completeQuantity || 0);
      return toQuantity(planQuantity - completeQuantity) > 0;
    });
    if (validRows.length === 0) {
      proxy.$modal.msgWarning("所选工单均无待生产数量,无法报工");
      return;
    }
    const buildSubmitParams = (row, quantity) => ({
      quantity,
      scrapQty: 0,
      userId: 329,
      userName: "孙立松",
      productionOperationTaskId: row.id,
      productProcessRouteItemId: row.productProcessRouteItemId,
      reportWork: row.reportWork,
      productMainId: row.productMainId,
      productionOrderRoutingOperationId: row.productionOrderRoutingOperationId,
      productionOrderId: row.productionOrderId,
      workHour: row.type == 0 ? row.workHour || 0 : 0,
      productionOperationParamList: [],
    });
    // 待生产数量超过一万时,每次只报 5000,拆分成多笔提交
    const tasks = [];
    validRows.forEach(row => {
      const planQuantity = Number(row.planQuantity || 0);
      const completeQuantity = Number(row.completeQuantity || 0);
      let remaining = Math.max(0, toQuantity(planQuantity - completeQuantity));
      while (remaining > 10000) {
        tasks.push(buildSubmitParams(row, 5000));
        remaining = toQuantity(remaining - 5000);
      }
      if (remaining > 0) {
        tasks.push(buildSubmitParams(row, remaining));
      }
    });
    const results = await Promise.allSettled(
      tasks.map(params => addProductMain(params))
    );
    const successCount = results.filter(r => r.status === "fulfilled").length;
    const failCount = results.filter(r => r.status === "rejected").length;
    if (failCount === 0) {
      proxy.$modal.msgSuccess(`一键报工成功,共 ${successCount} 笔`);
    } else {
      proxy.$modal.msgWarning(
        `一键报工完成:成功 ${successCount} 笔,失败 ${failCount} 笔`
      );
    }
    selectedRows.value = [];
    getList();
  };
  const getDictOptions = async dictType => {
    if (!dictType) return [];
    if (dictOptions.value[dictType]) return dictOptions.value[dictType];
src/views/qualityManagement/finalInspection/index.vue
@@ -44,6 +44,20 @@
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="提交状态"
                          prop="inspectState">
              <el-select v-model="searchForm.inspectState"
                         style="width: 240px"
                         placeholder="请选择提交状态"
                         clearable>
                <el-option label="未提交"
                           :value="0" />
                <el-option label="已提交"
                           :value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <!-- 按钮 -->
          <el-col :span="4">
            <el-form-item>
@@ -59,6 +73,10 @@
        <el-button type="primary"
                   @click="openForm('add')">新增</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="primary"
                   plain
                   :loading="batchSubmitting"
                   @click="handleBatchSubmit">批量提交</el-button>
        <el-button type="danger"
                   plain
                   @click="handleDelete">删除</el-button>
@@ -143,6 +161,7 @@
      productName: "",
      salesContractNo: "",
      workOrderNo: "",
      inspectState: "",
      entryDate: undefined, // 录入日期
      entryDateStart: undefined,
      entryDateEnd: undefined,
@@ -326,6 +345,7 @@
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const batchSubmitting = ref(false);
  const currentRow = ref(null);
  const page = reactive({
    current: 1,
@@ -391,6 +411,16 @@
  // 表格选择数据
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  const canSubmit = row => {
    // 已提交则禁用
    if (row.inspectState == 1) return false;
    // 如果检验员有值,只有当前登录用户能提交
    if (row.checkName) {
      return row.checkName === userStore.nickName;
    }
    return true;
  };
  // 打开弹框
@@ -464,6 +494,56 @@
    }
  };
  const handleBatchSubmit = () => {
    if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    const submitRows = selectedRows.value.filter(item => canSubmit(item));
    if (submitRows.length === 0) {
      proxy.$modal.msgWarning("所选数据不可提交");
      return;
    }
    ElMessageBox.confirm(
      `选中的${submitRows.length}条内容将被提交,是否确认提交?`,
      "批量提交",
      {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
      }
    )
      .then(async () => {
        batchSubmitting.value = true;
        const results = await Promise.allSettled(
          submitRows.map(item => submitQualityInspect({ id: item.id }))
        );
        const successCount = results.filter(
          item => item.status === "fulfilled" && item.value?.code === 200
        ).length;
        const failCount = submitRows.length - successCount;
        if (successCount > 0 && failCount === 0) {
          proxy.$modal.msgSuccess("批量提交成功");
        } else if (successCount > 0) {
          proxy.$modal.msgWarning(
            `成功提交${successCount}条,失败${failCount}条`
          );
        } else {
          proxy.$modal.msgError("批量提交失败");
        }
        getList();
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      })
      .finally(() => {
        batchSubmitting.value = false;
      });
  };
  // 关闭弹框
  const closeDia = () => {
    proxy.resetForm("formRef");
src/views/qualityManagement/processInspection/index.vue
@@ -34,6 +34,10 @@
        <el-button type="primary"
                   @click="openForm('add')">新增</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="primary"
                   plain
                   :loading="batchSubmitting"
                   @click="handleBatchSubmit">批量提交</el-button>
        <el-button type="danger"
                   plain
                   @click="handleDelete">删除</el-button>
@@ -302,6 +306,7 @@
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const batchSubmitting = ref(false);
  const dialogFormVisible = ref(false);
  const form = ref({
    checkName: "",
@@ -366,6 +371,16 @@
    selectedRows.value = selection;
  };
  const canSubmit = row => {
    // 已提交则禁用
    if (row.inspectState == 1) return false;
    // 如果检验员有值,只有当前登录用户能提交
    if (row.checkName) {
      return row.checkName === userStore.nickName;
    }
    return true;
  };
  // 打开弹框
  const openForm = (type, row) => {
    nextTick(() => {
@@ -392,6 +407,64 @@
      getList();
    }
  };
  const handleBatchSubmit = () => {
    if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    const submitRows = selectedRows.value.filter(item => canSubmit(item));
    const skipCount = selectedRows.value.length - submitRows.length;
    if (submitRows.length === 0) {
      proxy.$modal.msgWarning("所选数据均不可提交");
      return;
    }
    const message =
      skipCount > 0
        ? `已选择${selectedRows.value.length}条,其中${submitRows.length}条可提交,${skipCount}条已提交或无权限,将自动跳过。是否确认提交?`
        : `选中的${submitRows.length}条内容将被提交,是否确认提交?`;
    ElMessageBox.confirm(message, "批量提交", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(async () => {
        batchSubmitting.value = true;
        const results = await Promise.allSettled(
          submitRows.map(item => submitQualityInspect({ id: item.id }))
        );
        const successCount = results.filter(
          item => item.status === "fulfilled" && item.value?.code === 200
        ).length;
        const failCount = submitRows.length - successCount;
        if (failCount === 0 && skipCount === 0) {
          proxy.$modal.msgSuccess("批量提交成功");
        } else if (failCount === 0) {
          proxy.$modal.msgSuccess(
            `成功提交${successCount}条,跳过${skipCount}条`
          );
        } else if (successCount > 0) {
          proxy.$modal.msgWarning(
            `成功提交${successCount}条,失败${failCount}条,跳过${skipCount}条`
          );
        } else {
          proxy.$modal.msgError(
            `批量提交失败,失败${failCount}条,跳过${skipCount}条`
          );
        }
        getList();
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      })
      .finally(() => {
        batchSubmitting.value = false;
      });
  };
  const open = async row => {
    let userLists = await userListNoPage();
    userList.value = userLists.data;