spring
2 天以前 87bf944a61068a47f56cd2f27b585c70437ef1f7
src/views/productionManagement/productionOrder/Detail/index.vue
@@ -36,13 +36,21 @@
                  <div
                    class="step-title"
                    :class="{ selected: idx === selectedIndex }"
                    @click="selectProcess(idx)"
                    @click.stop="selectProcess(idx)"
                  >
                    {{ `${idx + 1}. ${p.processName || "-"}` }}
                  </div>
                </template>
                <template #description>
                  <div class="step-panel" :class="{ 'step-panel-active': idx === active }">
                  <div
                    class="step-panel"
                    :class="{
                      'step-panel-selected': idx === selectedIndex,
                      'step-panel-current': idx === active,
                    }"
                    @click="selectProcess(idx)"
                  >
                    <span v-if="idx === active" class="step-current-badge">生产中</span>
                    <div v-if="p.status !== 'wait'" class="current-progress">
                      <div class="current-progress-head">
                        <span class="current-progress-title">工序进度</span>
@@ -100,7 +108,7 @@
            </div>
            <div v-if="!selectedProcess" class="right-empty">
              点击左侧某个工序,右侧展示该工序的报工明细。
              暂无工序数据。
            </div>
            <div v-else class="right-content">
@@ -110,20 +118,43 @@
                <el-table-column label="报工人员" prop="reportUser" min-width="120" show-overflow-tooltip />
                <el-table-column label="报工时间" prop="reportTime" min-width="160" show-overflow-tooltip />
                <el-table-column label="产出数量" prop="outputQty" min-width="110" />
                <el-table-column label="合格数量" prop="qualifiedQty" min-width="110" />
                <el-table-column label="不良数量" prop="badQty" min-width="110" />
                <el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip />
                <el-table-column label="操作" width="150" fixed="right">
                  <template #default="{ row }">
                    <el-button type="primary" link @click="viewReportRecord(row)">
                      生产记录
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </div>
        </div>
      </div>
    </el-card>
    <el-dialog
      v-model="reportRecordDialogVisible"
      title="报工生产记录"
      width="680px"
      destroy-on-close
    >
      <div class="report-record-placeholder">
        <div>报工单号:{{ currentReportRow?.reportNo || "-" }}</div>
        <div>工序:{{ selectedProcess?.processName || "-" }}</div>
        <div class="placeholder-tip">弹框内容待定(后续补充详细生产记录)。</div>
      </div>
      <template #footer>
        <el-button @click="reportRecordDialogVisible = false">关闭</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { computed, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { computed, ref, watch } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
@@ -175,15 +206,31 @@
  },
]);
const selectedIndex = ref(null);
// 默认选中第一道序(接口数据就绪后仍可从 0 开始)
const selectedIndex = ref(0);
const selectProcess = (idx) => {
  selectedIndex.value = idx;
};
watch(
  () => (processes.value || []).length,
  (len) => {
    if (!len) return;
    if (selectedIndex.value >= len) selectedIndex.value = len - 1;
    if (selectedIndex.value < 0) selectedIndex.value = 0;
  }
);
const selectedProcess = computed(() => {
  if (selectedIndex.value === null || selectedIndex.value === undefined) return null;
  return (processes.value || [])[selectedIndex.value] || null;
  const list = processes.value || [];
  if (!list.length) return null;
  const raw = selectedIndex.value;
  const idx =
    raw === null || raw === undefined
      ? 0
      : Math.min(Math.max(0, raw), list.length - 1);
  return list[idx] || null;
});
// 模拟报工信息(后续用接口替换)
@@ -191,7 +238,7 @@
  const p = selectedProcess.value;
  if (!p) return [];
  const code = p.processCode || "GX";
  return [
  const reports = [
    {
      reportNo: `${code}-BG-0001`,
      reportUser: "张三",
@@ -217,7 +264,20 @@
      remark: "收尾",
    },
  ];
  return reports.map((item) => ({
    ...item,
    qualifiedQty: Math.max(0, Number(item.outputQty ?? 0) - Number(item.badQty ?? 0)),
  }));
});
const viewReportRecord = (row) => {
  if (!row?.reportNo) return;
  currentReportRow.value = row;
  reportRecordDialogVisible.value = true;
};
const reportRecordDialogVisible = ref(false);
const currentReportRow = ref(null);
const clampPercentage = (val) => {
  const n = Number(val);
@@ -331,13 +391,15 @@
    align-items: center;
    padding: 2px 6px;
    border-radius: 6px;
    transition: background-color 0.15s ease;
    transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
    &:hover {
      background: #f5f7fa;
      transform: translateX(2px);
    }
    &.selected {
      background: rgba(64, 158, 255, 0.12);
      background: rgba(64, 158, 255, 0.18);
      color: #409eff;
      font-weight: 700;
    }
  }
@@ -375,6 +437,8 @@
  }
  .step-panel {
    position: relative;
    cursor: pointer;
    background: #f6f8fb;
    border: 1px solid #ebeef5;
    border-radius: 10px;
@@ -382,11 +446,60 @@
    width: 100%;
    max-width: none;
    box-sizing: border-box;
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease,
      background 0.25s ease;
    &:hover {
      border-color: #c6e2ff;
      box-shadow: 0 4px 14px rgba(64, 158, 255, 0.12);
      transform: translateY(-1px);
    }
  }
  .step-panel-active {
  /* 被选中:沿用原「高亮」语义并加呼吸动画 */
  .step-panel-selected {
    background: #ecf5ff;
    border-color: #79bbff;
    box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.15);
    border-color: #409eff;
    animation: step-panel-selected-pulse 2.2s ease-in-out infinite;
    &:hover {
      transform: translateY(-1px);
    }
  }
  @keyframes step-panel-selected-pulse {
    0%,
    100% {
      box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.22);
    }
    50% {
      box-shadow: 0 0 0 6px rgba(64, 158, 255, 0.12);
    }
  }
  /* 当前生产中的工序:橙色主题,与选中区分;若同时选中则以选中为主,仅保留角标 */
  .step-panel-current:not(.step-panel-selected) {
    background: #fdf6ec;
    border-color: #e6a23c;
    border-left: 4px solid #e6a23c;
    padding-left: 9px;
    &:hover {
      box-shadow: 0 4px 14px rgba(230, 162, 60, 0.18);
    }
  }
  .step-current-badge {
    position: absolute;
    top: 8px;
    right: 10px;
    z-index: 1;
    font-size: 11px;
    font-weight: 600;
    color: #b88230;
    background: rgba(230, 162, 60, 0.18);
    border: 1px solid rgba(230, 162, 60, 0.45);
    border-radius: 4px;
    padding: 2px 8px;
    line-height: 1.2;
    pointer-events: none;
  }
  .right-panel {
@@ -448,6 +561,17 @@
    }
  }
  .report-record-placeholder {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 120px;
    color: #303133;
    .placeholder-tip {
      color: #909399;
    }
  }
  .step-meta {
    display: flex;
    gap: 16px;