huminmin
12 小时以前 0d0489ed1eeea0fa6b092923395cf75d81f01f99
Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
已修改1个文件
310 ■■■■■ 文件已修改
src/views/productionManagement/productionOrder/index.vue 310 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue
@@ -1,142 +1,180 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="生产订单号:">
          <el-input v-model="searchForm.npsNo"
          <el-input
            v-model="searchForm.npsNo"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery" />
            style="width: 160px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="产品名称:">
          <el-input v-model="searchForm.productName"
          <el-input
            v-model="searchForm.productName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery" />
            style="width: 160px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="规格:">
          <el-input v-model="searchForm.model"
          <el-input
            v-model="searchForm.model"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery" />
            style="width: 160px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="searchForm.status"
          <el-select
            v-model="searchForm.status"
                     placeholder="请选择"
                     style="width: 160px;"
                     @change="handleQuery">
            <el-option label="待开始"
                       value="1" />
            <el-option label="进行中"
                       value="2" />
            <el-option label="已完成"
                       value="3" />
            <el-option label="已取消"
                       value="4" />
            <el-option label="已结束"
                       value="5" />
            style="width: 160px"
            @change="handleQuery"
          >
            <el-option label="待开始" value="1" />
            <el-option label="进行中" value="2" />
            <el-option label="已完成" value="3" />
            <!--            <el-option label="已取消"-->
            <!--                       value="4" />-->
            <el-option label="已结束" value="5" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
          <el-button type="info"
                     @click="handleReset">重置</el-button>
          <el-button type="primary" @click="handleQuery">搜索</el-button>
          <el-button type="info" @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
      <div class="action-buttons">
        <!-- <el-button type="primary"
                   @click="isShowNewModal = true">新增</el-button> -->
        <el-button type="danger"
                   @click="handleDelete">退回</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"
      <PIMTable
        rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :tableLoading="tableLoading"
                :row-class-name="tableRowClassName"
                :isSelection="true"
                :selectable="row => !row.endOrder"
        :selectable="(row) => !row.endOrder"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        @pagination="pagination"
      >
        <template #completionStatus="{ row }">
          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
          <el-progress
            :percentage="toProgressPercentage(row?.completionStatus)"
                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
            :status="
              toProgressPercentage(row?.completionStatus) >= 100
                ? 'success'
                : ''
            "
          />
        </template>
        <template #processRouteStatus="{ row }">
          <div v-if="row.processRouteStatus && row.processRouteStatus.length"
               class="process-progress-container">
            <div v-for="(item, index) in row.processRouteStatus"
          <div
            v-if="row.processRouteStatus && row.processRouteStatus.length"
            class="process-progress-container"
          >
            <div
              v-for="(item, index) in row.processRouteStatus"
                 :key="index"
                 class="process-step">
              class="process-step"
            >
              <div class="step-content">
                <div class="step-circle"
                     :class="{ 'is-completed': item.percentage >= 100 }">
                  <span class="step-percentage"
                        :style="{ color: item.percentage >= 70 ? item.percentage >= 100 ? '#67c23a' : '#f56c6c' : '#000' }">{{ item.percentage }}%</span>
                <div
                  class="step-circle"
                  :class="{ 'is-completed': item.percentage >= 100 }"
                >
                  <span
                    class="step-percentage"
                    :style="{
                      color:
                        item.percentage >= 70
                          ? item.percentage >= 100
                            ? '#67c23a'
                            : '#f56c6c'
                          : '#000',
                    }"
                    >{{ item.percentage }}%</span
                  >
                </div>
                <div class="step-name">{{ item.name }}</div>
              </div>
              <div v-if="index < row.processRouteStatus.length - 1"
                   class="step-line"></div>
              <div
                v-if="index < row.processRouteStatus.length - 1"
                class="step-line"
              ></div>
            </div>
          </div>
          <span v-else>-</span>
        </template>
      </PIMTable>
    </div>
    <el-dialog v-model="bindRouteDialogVisible"
    <el-dialog
      v-model="bindRouteDialogVisible"
               title="绑定工艺路线"
               width="500px">
      width="500px"
    >
      <el-form label-width="90px">
        <el-form-item label="工艺路线">
          <el-select v-model="bindForm.routeId"
          <el-select
            v-model="bindForm.routeId"
                     placeholder="请选择工艺路线"
                     style="width: 100%;"
                     :loading="bindRouteLoading">
            <el-option v-for="item in routeOptions"
            style="width: 100%"
            :loading="bindRouteLoading"
          >
            <el-option
              v-for="item in routeOptions"
                       :key="item.id"
                       :label="`${item.processRouteCode || ''}`"
                       :value="item.id" />
              :value="item.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
          <el-button
            type="primary"
                     :loading="bindRouteSaving"
                     @click="handleBindRouteConfirm">确 认</el-button>
            @click="handleBindRouteConfirm"
            >确 认</el-button
          >
          <el-button @click="bindRouteDialogVisible = false">取 消</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- 来源数据弹窗 -->
    <el-dialog v-model="sourceDataDialogVisible"
    <el-dialog
      v-model="sourceDataDialogVisible"
               title="来源数据"
               width="1200px">
      <div v-if="sourceRowData"
           class="applyno-summary1">
      width="1200px"
    >
      <div v-if="sourceRowData" class="applyno-summary1">
        <div class="summary-item">
          <span class="summary-label">产品名称:</span>
          <span class="summary-value">
            <el-tag type="primary">{{ sourceRowData.productName || '-' }}</el-tag>
            <el-tag type="primary">{{
              sourceRowData.productName || "-"
            }}</el-tag>
          </span>
        </div>
        <div class="summary-item">
          <span class="summary-label">规格:</span>
          <span class="summary-value">{{ sourceRowData.model || '-' }}</span>
          <span class="summary-value">{{ sourceRowData.model || "-" }}</span>
        </div>
        <div class="summary-item">
          <span class="summary-label">订单需求数量:</span>
@@ -145,46 +183,60 @@
      </div>
      <div class="source-table-container">
        <div class="source-data-cards-container">
          <div v-for="(item, index) in sourceTableData"
          <div
            v-for="(item, index) in sourceTableData"
               :key="index"
               class="source-data-card">
            class="source-data-card"
          >
            <div class="card-body">
              <div class="info-grid">
                <div class="info-item">
                  <div class="info-label">计划号</div>
                  <div class="info-value">{{ item.mpsNo || '-' }}</div>
                  <div class="info-value">{{ item.mpsNo || "-" }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">数据来源</div>
                  <div class="info-value">
                    <el-tag :type="item.source === '销售' ? 'primary' : 'warning'">
                      {{ item.source || '未知' }}
                    <el-tag
                      :type="item.source === '销售' ? 'primary' : 'warning'"
                    >
                      {{ item.source || "未知" }}
                    </el-tag>
                  </div>
                </div>
                <div class="info-item">
                  <div class="info-label">合同号</div>
                  <div class="info-value">{{ item.salesContractNo || '-' }}</div>
                  <div class="info-value">
                    {{ item.salesContractNo || "-" }}
                  </div>
                </div>
                <div class="info-item">
                  <div class="info-label">客户名称</div>
                  <div class="info-value">{{ item.customerName || '-' }}</div>
                  <div class="info-value">{{ item.customerName || "-" }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">项目名称</div>
                  <div class="info-value">{{ item.projectName || '-' }}</div>
                  <div class="info-value">{{ item.projectName || "-" }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">计划需求数量</div>
                  <div class="info-value">{{ item.qtyRequired || 0 }} {{ item.unit || '' }}</div>
                  <div class="info-value">
                    {{ item.qtyRequired || 0 }} {{ item.unit || "" }}
                  </div>
                </div>
                <div class="info-item">
                  <div class="info-label">单位</div>
                  <div class="info-value">{{ item.unit || '-' }}</div>
                  <div class="info-value">{{ item.unit || "-" }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">需求日期</div>
                  <div class="info-value">{{ item.requiredDate ? dayjs(item.requiredDate).format('YYYY-MM-DD') : '-' }}</div>
                  <div class="info-value">
                    {{
                      item.requiredDate
                        ? dayjs(item.requiredDate).format("YYYY-MM-DD")
                        : "-"
                    }}
                  </div>
                </div>
              </div>
            </div>
@@ -192,23 +244,33 @@
        </div>
      </div>
    </el-dialog>
    <MaterialLedgerDialog v-model="materialDialogVisible"
    <MaterialLedgerDialog
      v-model="materialDialogVisible"
                          :order-row="currentMaterialOrder"
                          @saved="getList" />
    <MaterialDetailDialog v-model="materialDetailDialogVisible"
      @saved="getList"
    />
    <MaterialDetailDialog
      v-model="materialDetailDialogVisible"
                          :order-row="currentMaterialDetailOrder"
                          @confirmed="getList" />
    <MaterialSupplementDialog v-model="materialSupplementDialogVisible"
      @confirmed="getList"
    />
    <MaterialSupplementDialog
      v-model="materialSupplementDialogVisible"
                              :order-row="currentMaterialSupplementOrder"
                              @saved="getList" />
    <new-product-order v-if="isShowNewModal"
      @saved="getList"
    />
    <new-product-order
      v-if="isShowNewModal"
                       v-model:visible="isShowNewModal"
                       @completed="handleQuery" />
      @completed="handleQuery"
    />
    <!-- 打印领料单组件 -->
    <div class="print-requisition-wrapper">
      <PrintMaterialRequisition ref="printRef"
      <PrintMaterialRequisition
        ref="printRef"
                                :order-row="printOrderRow"
                                :material-list="printMaterialList" />
        :material-list="printMaterialList"
      />
    </div>
  </div>
</template>
@@ -265,7 +327,7 @@
  const processColumnWidth = computed(() => {
    if (!tableData.value || tableData.value.length === 0) return "200px";
    const maxProcesses = Math.max(
      ...tableData.value.map(row => row.processRouteStatus?.length || 0)
    ...tableData.value.map((row) => row.processRouteStatus?.length || 0)
    );
    if (maxProcesses === 0) return "100px";
    // 每个工序圆圈 36px + 线条 30px = 66px,额外加 60px 边距和文字空间
@@ -284,7 +346,7 @@
      prop: "status",
      width: "150px",
      dataType: "tag",
      formatData: val =>
    formatData: (val) =>
        val === 1
          ? "待开始"
          : val === 2
@@ -294,7 +356,7 @@
          : val === 5
          ? "已结束"
          : "已取消",
      formatType: val =>
    formatType: (val) =>
        val === 1
          ? "primary"
          : val === 2
@@ -345,19 +407,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: "planCompleteTime",
      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
    formatData: (val) => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
      width: 120,
    },
    {
@@ -370,31 +432,31 @@
        {
          name: "工艺路线",
          type: "text",
          showHide: row => row.processRouteCode,
          clickFun: row => {
        showHide: (row) => row.processRouteCode,
        clickFun: (row) => {
            showRouteItemModal(row);
          },
        },
        {
          name: "绑定工艺路线",
          type: "text",
          showHide: row => !row.processRouteCode && !row.endOrder,
          clickFun: row => {
        showHide: (row) => !row.processRouteCode && !row.endOrder,
        clickFun: (row) => {
            openBindRouteDialog(row, "add");
          },
        },
        {
          name: "更换工艺路线",
          type: "text",
          showHide: row => row.processRouteCode && !row.endOrder,
          clickFun: row => {
        showHide: (row) => row.processRouteCode && !row.endOrder,
        clickFun: (row) => {
            openBindRouteDialog(row, "change");
          },
        },
        {
          name: "来源",
          type: "text",
          clickFun: row => {
        clickFun: (row) => {
            showSourceData(row);
          },
        },
@@ -402,8 +464,8 @@
          name: "领料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder && !row.returned,
          clickFun: row => {
        showHide: (row) => !row.endOrder && !row.returned,
        clickFun: (row) => {
            openMaterialDialog(row);
          },
        },
@@ -411,8 +473,8 @@
          name: "补料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder && !row.returned,
          clickFun: row => {
        showHide: (row) => !row.endOrder && !row.returned,
        clickFun: (row) => {
            openMaterialSupplementDialog(row);
          },
        },
@@ -420,7 +482,7 @@
          name: "领料详情",
          type: "text",
          color: "#5EC7AB",
          clickFun: row => {
        clickFun: (row) => {
            openMaterialDetailDialog(row);
          },
        },
@@ -428,8 +490,8 @@
          name: "打印领料单",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder,
          clickFun: row => {
        showHide: (row) => !row.endOrder,
        clickFun: (row) => {
            handlePrint(row);
          },
        },
@@ -437,7 +499,7 @@
          name: "生产追溯",
          type: "text",
          color: "#409eff",
          clickFun: row => {
        clickFun: (row) => {
            router.push({
              path: "/productionManagement/productionTraceability",
              query: {
@@ -452,8 +514,8 @@
          name: "结束订单",
          type: "text",
          color: "red",
          showHide: row => !row.endOrder,
          clickFun: row => {
        showHide: (row) => !row.endOrder,
        clickFun: (row) => {
            handleEndOrder(row);
          },
        },
@@ -482,7 +544,7 @@
  });
  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;
@@ -491,7 +553,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";
@@ -535,7 +597,7 @@
  // 打印相关
  const printOrderRow = ref(null);
  const printMaterialList = ref([]);
  const handlePrint = async row => {
const handlePrint = async (row) => {
    printOrderRow.value = row;
    proxy.$modal.loading("正在获取领料数据...");
    try {
@@ -612,17 +674,17 @@
    }
  };
  const openMaterialDialog = row => {
const openMaterialDialog = (row) => {
    currentMaterialOrder.value = row;
    materialDialogVisible.value = true;
  };
  const openMaterialDetailDialog = async row => {
const openMaterialDetailDialog = async (row) => {
    currentMaterialDetailOrder.value = row;
    materialDetailDialogVisible.value = true;
  };
  const openMaterialSupplementDialog = row => {
const openMaterialSupplementDialog = (row) => {
    currentMaterialSupplementOrder.value = row;
    materialSupplementDialogVisible.value = true;
  };
@@ -647,12 +709,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];
@@ -668,10 +730,10 @@
    const params = { ...searchForm.value, ...page };
    params.entryDate = undefined;
    productOrderListPage(params)
      .then(async res => {
    .then(async (res) => {
        const records = res.data.records || [];
        // 为每个订单查询对应的工序进度数据
        const processPromises = records.map(async item => {
      const processPromises = records.map(async (item) => {
          if (item.npsNo) {
            try {
              const workOrderRes = await productWorkOrderPage({
@@ -681,7 +743,7 @@
              const workOrders = workOrderRes.data.records || [];
              // 按照工序顺序排序(如果有顺序字段,假设为 orderNum 或按返回顺序)
              // 转换为 processRouteStatus 格式
              const processRouteStatus = workOrders.map(wo => ({
            const processRouteStatus = workOrders.map((wo) => ({
                name: wo.operationName || "未知工序",
                percentage: wo.completionStatus > 100 ? 100 : wo.completionStatus,
              }));
@@ -703,7 +765,7 @@
      });
  };
  const showRouteItemModal = async row => {
const showRouteItemModal = async (row) => {
    const orderId = row.id;
    try {
      const res = await getOrderProcessRouteMain(orderId);
@@ -735,7 +797,7 @@
    }
  };
  const showProductStructure = row => {
const showProductStructure = (row) => {
    router.push({
      path: "/productionManagement/productStructureDetail",
      query: {
@@ -750,12 +812,12 @@
  };
  // 查看来源生产计划数据
  const showSourceData = row => {
const showSourceData = (row) => {
    // 存储点击来源按钮时传递的row参数
    sourceRowData.value = row;
    // 调用API获取来源数据
    getProductOrderSource(row.id)
      .then(res => {
    .then((res) => {
        if (res.code === 200) {
          // 直接存储返回的扁平化数据
          sourceTableData.value = res.data || [];
@@ -766,21 +828,21 @@
          proxy.$modal.msgError(res.msg || "获取来源数据失败");
        }
      })
      .catch(err => {
    .catch((err) => {
        proxy.$modal.msgError("获取来源数据失败");
        console.error(err);
      });
  };
  // 表格选择数据
  const handleSelectionChange = selection => {
const handleSelectionChange = (selection) => {
    selectedRows.value = selection;
  };
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
@@ -792,7 +854,7 @@
    })
      .then(() => {
        console.log(ids, "ids");
        delProductOrder(ids).then(res => {
      delProductOrder(ids).then((res) => {
          proxy.$modal.msgSuccess("退回成功");
          getList();
        });
@@ -822,7 +884,7 @@
  };
  // 结束订单
  const handleEndOrder = row => {
const handleEndOrder = (row) => {
    ElMessageBox.confirm(`是否确认结束订单:${row.npsNo}?`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",