zhangwencui
15 小时以前 91dec349aa88c58c587199d9601529d60824e1d0
src/pages/productionManagement/productionOrder/index.vue
@@ -55,8 +55,16 @@
              <text class="detail-value">{{ item.model || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">订单数量</text>
              <text class="detail-label">工艺路线编号</text>
              <text class="detail-value">{{ item.processRouteCode || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">需求数量</text>
              <text class="detail-value">{{ item.quantity || 0 }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">完成数量</text>
              <text class="detail-value">{{ item.completeQuantity || 0 }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">完成进度</text>
@@ -67,6 +75,39 @@
                <text class="progress-text">{{ item.completeQuantity || 0 }} / {{ item.quantity || 0 }}</text>
              </view>
            </view>
            <!-- 工序生产进度展示 -->
            <view class="detail-row process-row">
              <text class="detail-label">工序进度</text>
              <scroll-view scroll-x
                           class="process-scroll">
                <view class="process-container">
                  <view v-for="(process, pIdx) in item.processRouteStatus"
                        :key="pIdx"
                        class="process-item">
                    <view class="process-node">
                      <view class="node-circle"
                            :class="{ 'is-complete': process.percentage >= 100 }">
                        <text class="node-percentage"
                              :style="{ color: process.percentage >= 100 ? '#52c41a' : (process.percentage >= 70 ? '#f56c6c' : '#3c9cff') }">{{ process.percentage }}%</text>
                      </view>
                      <text class="node-name">{{ process.name }}</text>
                    </view>
                    <view v-if="pIdx < item.processRouteStatus.length - 1"
                          class="node-line"></view>
                  </view>
                  <view v-if="!item.processRouteStatus || !item.processRouteStatus.length"
                        class="no-process">-</view>
                </view>
              </scroll-view>
            </view>
            <view class="detail-row">
              <text class="detail-label">开始日期</text>
              <text class="detail-value">{{ formatDate(item.startTime) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">结束日期</text>
              <text class="detail-value">{{ formatDate(item.endTime) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">计划完成</text>
              <text class="detail-value">{{ formatDate(item.planCompleteTime) }}</text>
@@ -75,17 +116,22 @@
          <view class="item-footer">
            <view class="action-btns">
              <up-button type="info"
                         size="mini"
                         size="small"
                         plain
                         text="生产追溯"
                         @click="goTraceability(item)"></up-button>
              <up-button type="info"
                         size="small"
                         plain
                         text="工艺路线"
                         @click="goProcessRoute(item)"></up-button>
              <up-button type="primary"
                         size="mini"
                         size="small"
                         plain
                         text="来源"
                         @click="goSource(item)"></up-button>
              <up-button type="success"
                         size="mini"
                         size="small"
                         plain
                         text="领料详情"
                         @click="goPickingDetail(item)"></up-button>
@@ -112,6 +158,7 @@
    productOrderListPage,
    getOrderProcessRouteMain,
  } from "@/api/productionManagement/productionOrder.js";
  import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
  import PageHeader from "@/components/PageHeader.vue";
  const { proxy } = getCurrentInstance();
@@ -166,7 +213,7 @@
      2: "warning",
      3: "success",
      4: "info",
      5: "danger",
      5: "error",
    };
    return typeMap[status] || "info";
  };
@@ -216,16 +263,44 @@
    };
    productOrderListPage(params)
      .then(res => {
        loading.value = false;
      .then(async res => {
        const records = res.data.records || [];
        // 为每个订单并行查询工序进度
        const processPromises = records.map(async item => {
          if (item.npsNo) {
            try {
              const workOrderRes = await productWorkOrderPage({
                npsNo: item.npsNo,
                size: 100,
              });
              const workOrders = workOrderRes.data.records || [];
              const processRouteStatus = workOrders.map(wo => ({
                name: wo.operationName || "未知工序",
                percentage:
                  Number(wo.completionStatus) > 100
                    ? 100
                    : Number(wo.completionStatus || 0),
              }));
              return { ...item, processRouteStatus };
            } catch (error) {
              console.error(`获取工单 ${item.npsNo} 进度失败:`, error);
              return { ...item, processRouteStatus: [] };
            }
          }
          return { ...item, processRouteStatus: [] };
        });
        const updatedRecords = await Promise.all(processPromises);
        loading.value = false;
        if (page.current === 1) {
          tableData.value = records;
          tableData.value = updatedRecords;
        } else {
          tableData.value = [...tableData.value, ...records];
          tableData.value = [...tableData.value, ...updatedRecords];
        }
        if (records.length < page.size) {
        if (updatedRecords.length < page.size) {
          loadStatus.value = "nomore";
        } else {
          loadStatus.value = "loadmore";
@@ -283,6 +358,13 @@
  const goPickingDetail = item => {
    uni.navigateTo({
      url: `/pages/productionManagement/productionOrder/pickingDetail?id=${item.id}&npsNo=${item.npsNo}`,
    });
  };
  // 跳转生产追溯
  const goTraceability = item => {
    uni.navigateTo({
      url: `/pages/productionManagement/productionTraceability/index?npsNo=${item.npsNo}`,
    });
  };
@@ -380,6 +462,84 @@
            text-align: right;
          }
        }
        &.process-row {
          flex-direction: column;
          margin: 20rpx 0;
          .process-scroll {
            width: 100%;
            margin-top: 16rpx;
            .process-container {
              display: flex;
              align-items: flex-start;
              padding: 10rpx 0;
              min-height: 120rpx;
              .process-item {
                display: flex;
                align-items: center;
                .process-node {
                  display: flex;
                  flex-direction: column;
                  align-items: center;
                  width: 100rpx;
                  .node-circle {
                    width: 60rpx;
                    height: 60rpx;
                    border-radius: 50%;
                    border: 2rpx solid #3c9cff;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    background: #fff;
                    margin-bottom: 8rpx;
                    .node-percentage {
                      font-size: 18rpx;
                      color: #3c9cff;
                      font-weight: bold;
                    }
                    &.is-complete {
                      border-color: #52c41a;
                      background: #f6ffed;
                      .node-percentage {
                        color: #52c41a;
                      }
                    }
                  }
                  .node-name {
                    font-size: 20rpx;
                    color: #666;
                    text-align: center;
                    width: 120rpx;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                  }
                }
                .node-line {
                  width: 40rpx;
                  height: 2rpx;
                  background: #e8e8e8;
                  margin: -30rpx 0 0 0;
                }
              }
              .no-process {
                font-size: 24rpx;
                color: #ccc;
              }
            }
          }
        }
      }
    }