<template>
  <div class="app-container">
    <el-alert
      v-if="!hasQueryPermi"
      class="mb-20"
      type="warning"
      show-icon
      :closable="false"
      title="无权限"
      description="需要权限码：system:mssql:query"
    />
    <!-- 搜索表单 -->
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="100px">
      <el-form-item label="生产令号" prop="sclh">
        <el-input
          type="textarea"
          :rows="2"
          v-model="queryParams.sclh"
          placeholder="请输入生产令号，多行或逗号隔开"
          clearable
          style="width: 300px"
        />
      </el-form-item>
      <el-form-item label="统计日" prop="boardReportDay">
        <el-date-picker
          v-model="queryParams.boardReportDay"
          type="date"
          value-format="yyyy-MM-dd"
          format="yyyy-MM-dd"
          placeholder="不填则按服务器当天"
          clearable
          style="width: 160px"
        />
      </el-form-item>
      <el-form-item label="报表起止" prop="reportDateRange">
        <el-date-picker
          v-model="queryParams.reportDateRange"
          type="daterange"
          value-format="yyyy-MM-dd"
          format="yyyy-MM-dd"
          range-separator="至"
          start-placeholder="开始"
          end-placeholder="结束"
          clearable
          style="width: 260px"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" :disabled="!hasQueryPermi" @click="handleQuery">查询</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <!-- 结果展示 -->
    <div v-loading="loading" v-if="hasQueryPermi">
      <el-empty v-if="!dataList || dataList.length === 0" description="暂无数据，请先查询"></el-empty>
      
      <!-- 按令号循环渲染卡片 -->
      <el-card v-for="(item, index) in dataList" :key="index" class="mb-20" shadow="hover">
        <div slot="header" class="card-header">
          <span class="sclh-title">生产令号: {{ item.sclh }}</span>
          <div class="header-tags">
            <el-tag size="small">生产总量: {{ formatNumber(item.totalMoQty) }}</el-tag>
            <el-tag type="success" size="small">生产入库: {{ formatNumber(item.totalProductionInstockQty) }}</el-tag>
          </div>
        </div>

        <div class="p-10">
          <el-row :gutter="12">
            <el-col v-for="card in getBoardDayKpiCards(item)" :key="card.key" :xs="24" :sm="12" :md="8" :lg="4">
              <el-card shadow="never" class="kpi-card" :class="card.className">
                <div class="kpi-title">{{ card.title }}</div>
                <div class="kpi-value" :class="card.value === '-' ? 'is-empty' : ''">{{ card.value }}</div>
              </el-card>
            </el-col>
          </el-row>
        </div>

        <el-tabs type="border-card">
          <el-tab-pane label="生产及工序明细">
            <el-empty v-if="getFlattenedProcessData(item).length === 0" description="没有"></el-empty>
            <el-table
              v-else
              :data="getFlattenedProcessData(item)"
              border
              size="small"
              :max-height="processTableMaxHeight"
              style="width: 100%"
              class="report-table process-sticky-table"
              :row-class-name="processRowClassName"
            >
              <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip fixed="left" />
              <el-table-column prop="materialName" label="物料名称" min-width="150" show-overflow-tooltip fixed="left" />
              <el-table-column prop="moInstockQty" label="入库数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.moInstockQty) }}</template>
              </el-table-column>
              <el-table-column label="总进度(%)" width="80" align="center">
                <template slot-scope="scope">
                  {{ formatNumber(scope.row.overallProgress) }}
                </template>
              </el-table-column>
              <el-table-column prop="overallStatus" label="总体状态" width="80" align="center">
                <template slot-scope="scope">
                  <el-tag size="mini" :type="overallStatusTagType(scope.row.overallStatus)">
                    {{ scope.row.overallStatus || '-' }}
                  </el-tag>
                </template>
              </el-table-column>

              <el-table-column label="工序" min-width="160" show-overflow-tooltip fixed="left">
                <template slot-scope="scope">{{ formatOperText(scope.row) }}</template>
              </el-table-column>
              <el-table-column prop="workCenter" label="工作中心" min-width="100" show-overflow-tooltip fixed="left" />
              <el-table-column label="计划数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.planQty) }}</template>
              </el-table-column>
              <el-table-column label="投入数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.inQty) }}</template>
              </el-table-column>
              <el-table-column label="合格数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.okQty) }}</template>
              </el-table-column>
              <el-table-column label="不良数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.ngQty) }}</template>
              </el-table-column>
              <el-table-column label="工序进度(%)" width="90" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.progress) }}</template>
              </el-table-column>
              <el-table-column label="当日完工" width="80" align="center">
                <template slot-scope="scope">{{ scope.row.dayReportFinishQty == null ? '-' : formatNumber(scope.row.dayReportFinishQty) }}</template>
              </el-table-column>
              <el-table-column label="当日合格" width="80" align="center">
                <template slot-scope="scope">{{ scope.row.dayReportQuaQty == null ? '-' : formatNumber(scope.row.dayReportQuaQty) }}</template>
              </el-table-column>
              <el-table-column label="当日不良" width="80" align="center">
                <template slot-scope="scope">{{ scope.row.dayReportFailQty == null ? '-' : formatNumber(scope.row.dayReportFailQty) }}</template>
              </el-table-column>
              <el-table-column label="入库数量" width="80" align="center">
                <template slot-scope="scope">{{ scope.row.operationInstockQty == null ? '-' : formatNumber(scope.row.operationInstockQty) }}</template>
              </el-table-column>

              <el-table-column label="委外(统计日前)" align="center">
                <el-table-column label="发出" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractLeaveQtyBeforeReportDay == null ? '-' : formatNumber(scope.row.subcontractLeaveQtyBeforeReportDay) }}</template>
                </el-table-column>
                <el-table-column label="接收" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractEnterQtyBeforeReportDay == null ? '-' : formatNumber(scope.row.subcontractEnterQtyBeforeReportDay) }}</template>
                </el-table-column>
                <el-table-column label="合格" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractQualifiedQtyBeforeReportDay == null ? '-' : formatNumber(scope.row.subcontractQualifiedQtyBeforeReportDay) }}</template>
                </el-table-column>
              </el-table-column>

              <el-table-column label="委外(统计日)" align="center">
                <el-table-column label="发出" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractLeaveQtyOnReportDay == null ? '-' : formatNumber(scope.row.subcontractLeaveQtyOnReportDay) }}</template>
                </el-table-column>
                <el-table-column label="接收" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractEnterQtyOnReportDay == null ? '-' : formatNumber(scope.row.subcontractEnterQtyOnReportDay) }}</template>
                </el-table-column>
                <el-table-column label="合格" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractQualifiedQtyOnReportDay == null ? '-' : formatNumber(scope.row.subcontractQualifiedQtyOnReportDay) }}</template>
                </el-table-column>
                <el-table-column label="发+收" width="80" align="center">
                  <template slot-scope="scope">{{ scope.row.subcontractLeaveEnterSumOnReportDay == null ? '-' : formatNumber(scope.row.subcontractLeaveEnterSumOnReportDay) }}</template>
                </el-table-column>
              </el-table-column>

              <el-table-column prop="transOutQty" label="转出数量" width="80" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.transOutQty) }}</template>
              </el-table-column>
              <el-table-column prop="status" label="工序状态" width="80" align="center" />
            </el-table>
          </el-tab-pane>

          <el-tab-pane label="单物料汇总">
            <el-empty v-if="getMaterialSummaryRows(item).length === 0" description="没有"></el-empty>
            <el-table v-else :data="getMaterialSummaryRows(item)" border size="small">
              <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
              <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
              <el-table-column label="生产下达" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.moQty) }}</template>
              </el-table-column>
              <el-table-column label="生产入库" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.productionInstockQty) }}</template>
              </el-table-column>
              <el-table-column label="当日完成" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.todayFinishQty) }}</template>
              </el-table-column>
              <el-table-column label="当日合格" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.todayQuaQty) }}</template>
              </el-table-column>
              <el-table-column label="当日不良" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.todayFailQty) }}</template>
              </el-table-column>
            </el-table>
          </el-tab-pane>

          <el-tab-pane label="生产跟踪明细">
            <div class="p-10">
              <div class="section-title">批次跟踪（productionTraceList）</div>
              <el-empty v-if="!item.productionTraceList || item.productionTraceList.length === 0" description="没有"></el-empty>
              <el-table v-else :data="item.productionTraceList" border size="small" class="mt-10">
                <el-table-column prop="moBillNo" label="生产订单号" min-width="140" show-overflow-tooltip />
                <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
                <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
                <el-table-column label="下达数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.qty) }}</template>
                </el-table-column>
                <el-table-column prop="orderDate" label="下达日期" min-width="160" />
                <el-table-column prop="operPlanningBillNo" label="工序计划单" min-width="140" show-overflow-tooltip />
                <el-table-column prop="planStartDate" label="计划开工" min-width="160" />
                <el-table-column prop="planFinishDate" label="计划完工" min-width="160" />
                <el-table-column prop="instockBillNo" label="入库单号" min-width="140" show-overflow-tooltip />
                <el-table-column prop="instockDate" label="入库日期" min-width="160" />
                <el-table-column label="入库数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.instockQty) }}</template>
                </el-table-column>
              </el-table>

              <div class="section-title mt-10">订单跟踪（orders.moTraceRows）</div>
              <el-empty v-if="getMoTraceRows(item.orders).length === 0" description="没有"></el-empty>
              <el-table v-else :data="getMoTraceRows(item.orders)" border size="small" class="mt-10">
                <el-table-column prop="moBillNo" label="生产订单号" min-width="140" show-overflow-tooltip />
                <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
                <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
                <el-table-column label="下达数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.qty) }}</template>
                </el-table-column>
                <el-table-column prop="orderDate" label="下达日期" min-width="160" />
                <el-table-column prop="operPlanningBillNo" label="工序计划单" min-width="140" show-overflow-tooltip />
                <el-table-column prop="planStartDate" label="计划开工" min-width="160" />
                <el-table-column prop="planFinishDate" label="计划完工" min-width="160" />
                <el-table-column prop="instockBillNo" label="入库单号" min-width="140" show-overflow-tooltip />
                <el-table-column prop="instockDate" label="入库日期" min-width="160" />
                <el-table-column label="入库数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.instockQty) }}</template>
                </el-table-column>
              </el-table>
            </div>
          </el-tab-pane>

          <el-tab-pane label="采购明细">
            <el-empty v-if="!item.purchaseList || item.purchaseList.length === 0" description="没有"></el-empty>
            <el-table v-else :data="item.purchaseList" border size="small">
              <el-table-column prop="purchaseBillNo" label="采购单号" min-width="150" show-overflow-tooltip />
              <el-table-column prop="purchaseDate" label="采购日期" min-width="160" />
              <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
              <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
              <el-table-column label="采购数量" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.purchaseQty) }}</template>
              </el-table-column>
              <el-table-column prop="instockBillNo" label="入库单号" min-width="150" show-overflow-tooltip />
              <el-table-column prop="instockDate" label="入库日期" min-width="160" />
              <el-table-column label="入库数量" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.instockQty) }}</template>
              </el-table-column>
            </el-table>
          </el-tab-pane>

          <el-tab-pane label="采购入库汇总">
            <el-empty v-if="!item.purchaseInboundSummary || item.purchaseInboundSummary.length === 0" description="没有"></el-empty>
            <el-table v-else :data="item.purchaseInboundSummary" border size="small">
              <el-table-column prop="purchaseBillNo" label="采购单号" min-width="150" show-overflow-tooltip />
              <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
              <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
              <el-table-column label="采购合计" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.sumPurchaseQty) }}</template>
              </el-table-column>
              <el-table-column label="入库合计" width="100" align="center">
                <template slot-scope="scope">{{ formatNumber(scope.row.sumInstockQty) }}</template>
              </el-table-column>
              <el-table-column prop="detailLineCount" label="明细行数" width="90" align="center" />
            </el-table>
          </el-tab-pane>

          <!-- 3. 汇报记录 -->
          <el-tab-pane label="工序汇报汇总">
            <el-empty v-if="getOperationReportSummary(item).rows.length === 0" description="没有"></el-empty>
            <div v-else class="p-10">
              <div class="summary-tags">
                <el-tag size="small">汇总完成: {{ formatNumber(getOperationReportSummary(item).totalFinishQty) }}</el-tag>
                <el-tag type="success" size="small">汇总合格: {{ formatNumber(getOperationReportSummary(item).totalQuaQty) }}</el-tag>
                <el-tag type="danger" size="small">汇总不良: {{ formatNumber(getOperationReportSummary(item).totalFailQty) }}</el-tag>
              </div>
              <el-table :data="getOperationReportSummary(item).rows" border size="small" class="mt-10">
                <el-table-column prop="reportDate" label="汇报日期" width="120" />
                <el-table-column prop="opOper" label="工序" width="100" align="center" />
                <el-table-column prop="materialNumber" label="物料编码" min-width="150" show-overflow-tooltip />
                <el-table-column prop="materialName" label="物料名称" min-width="200" show-overflow-tooltip />
                <el-table-column label="完成数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.finishQty) }}</template>
                </el-table-column>
                <el-table-column label="合格数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.quaQty) }}</template>
                </el-table-column>
                <el-table-column label="不良数量" width="100" align="center">
                  <template slot-scope="scope">{{ formatNumber(scope.row.failQty) }}</template>
                </el-table-column>
                <el-table-column prop="rowCount" label="记录数" width="80" align="center" />
              </el-table>
            </div>
          </el-tab-pane>

          <el-tab-pane label="委外转入/发出">
            <el-empty v-if="getSubcontractTransferRows(item.orders).length === 0" description="没有"></el-empty>
            <div v-else class="p-10">
              <div class="summary-tags">
                <el-tag type="warning" size="small">发出(转出): {{ formatNumber(getSubcontractInOutSummary(item.orders).outQty) }}</el-tag>
                <el-tag type="success" size="small">转入: {{ formatNumber(getSubcontractInOutSummary(item.orders).inQty) }}</el-tag>
              </div>
              <el-table :data="getSubcontractTransferRows(item.orders)" border size="small" class="mt-10">
                <el-table-column v-for="col in getDynamicColumns(getSubcontractTransferRows(item.orders))" :key="col" :prop="col" :label="col" min-width="120" show-overflow-tooltip />
              </el-table>
            </div>
          </el-tab-pane>
        </el-tabs>
      </el-card>
    </div>
  </div>
</template>

<script>
import { getProductionBoardQuery } from '@/api/system/productionBoard'
import { checkPermi } from '@/utils/permission'

export default {
  name: 'ProductionBoard',
  computed: {
    hasQueryPermi() {
      return checkPermi(['system:mssql:query'])
    }
  },
  data() {
    return {
      queryParams: {
        sclh: '',
        boardReportDay: '',
        reportDateRange: [],
      },
      loading: false,
      dataList: [],
      processTableMaxHeight: 520,
      workCenterColorCache: {}
    }
  },
  mounted() {
    this.updateProcessTableMaxHeight()
    window.addEventListener('resize', this.updateProcessTableMaxHeight)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.updateProcessTableMaxHeight)
  },
  methods: {
    updateProcessTableMaxHeight() {
      const viewport = window.innerHeight || 900
      const reserved = 84 + 20 + 56 + 160 + 120
      const h = Math.max(260, Math.min(900, viewport - reserved))
      this.processTableMaxHeight = h
    },
    toNumber(val) {
      if (val === null || val === undefined || val === '') return 0
      const n = parseFloat(val)
      return isNaN(n) ? 0 : n
    },
    overallStatusTagType(status) {
      if (status === '进行中') return 'primary'
      if (status === '已延期') return 'danger'
      if (status === '已完工') return 'success'
      if (status === '未开工') return 'info'
      return ''
    },
    getTodayStr() {
      const d = new Date()
      const y = d.getFullYear()
      const m = String(d.getMonth() + 1).padStart(2, '0')
      const day = String(d.getDate()).padStart(2, '0')
      return `${y}-${m}-${day}`
    },
    normalizeYmd(val) {
      if (!val) return ''
      if (typeof val === 'string') {
        const m = val.match(/\d{4}-\d{2}-\d{2}/)
        if (m) return m[0]
        const m2 = val.match(/\d{4}\/\d{1,2}\/\d{1,2}/)
        if (m2) {
          const parts = m2[0].split('/')
          const mm = String(parts[1]).padStart(2, '0')
          const dd = String(parts[2]).padStart(2, '0')
          return `${parts[0]}-${mm}-${dd}`
        }
        return ''
      }
      if (val instanceof Date && !isNaN(val.getTime())) {
        const y = val.getFullYear()
        const m = String(val.getMonth() + 1).padStart(2, '0')
        const d = String(val.getDate()).padStart(2, '0')
        return `${y}-${m}-${d}`
      }
      return ''
    },
    handleQuery() {
      if (!this.hasQueryPermi) {
        this.$message.error('无权限：system:mssql:query')
        return
      }
      if (!this.queryParams.sclh) {
        this.$message.warning("请输入生产令号");
        return;
      }
      this.loading = true;
      
      // 处理多行输入，转为逗号隔开的字符串
      const sclhStr = this.queryParams.sclh.replace(/\n/g, ',').replace(/\s+/g, '').replace(/,+/g, ',');

      const reportStartDate = Array.isArray(this.queryParams.reportDateRange) && this.queryParams.reportDateRange.length > 0
        ? this.queryParams.reportDateRange[0]
        : ''
      const reportEndDate = Array.isArray(this.queryParams.reportDateRange) && this.queryParams.reportDateRange.length > 1
        ? this.queryParams.reportDateRange[1]
        : ''
      
      const params = {
        sclhCsv: sclhStr,
        includePurchase: true,
        includeSnapshots: true,
        reportStartDate: reportStartDate || undefined,
        reportEndDate: reportEndDate || undefined,
        boardReportDay: this.queryParams.boardReportDay || undefined
      };

      getProductionBoardQuery(params).then(res => {
        this.loading = false;
        if (res.code === 200) {
          this.dataList = res.data || [];
          if (this.dataList.length === 0) {
            this.$message.info("未查询到相关数据");
          }
        } else {
          this.$message.error(res.msg || "查询失败");
        }
      }).catch(() => {
        this.loading = false;
        // MOCK 数据展示（用于未联调成功时可预览界面结构）
        this.$message.info("接口请求异常，已加载演示数据以便预览");
        this.loadMockData();
      })
    },
    resetQuery() {
      this.queryParams.sclh = '';
      this.queryParams.boardReportDay = '';
      this.queryParams.reportDateRange = [];
      this.dataList = [];
    },
    getBoardDayLabel() {
      return this.queryParams.boardReportDay || '服务器当天'
    },
    getBoardDayForCalc() {
      return this.queryParams.boardReportDay || this.getTodayStr()
    },
    getBoardDayInstockQty(item) {
      const day = this.getBoardDayForCalc()
      const rows = this.getMoTraceRows(item && item.orders)
      let sum = 0
      let has = false
      rows.forEach(r => {
        const ymd = this.normalizeYmd(r.instockDate)
        if (!ymd || ymd !== day) return
        const qty = this.toNumber(r.instockQty)
        sum += qty
        has = true
      })
      return has ? sum : null
    },
    getBoardDaySubcontractSummary(item) {
      const rows = this.getFlattenedProcessData(item)
      let leave = 0
      let enter = 0
      let sum = 0
      let hasLeave = false
      let hasEnter = false
      let hasSum = false

      rows.forEach(r => {
        if (r.subcontractLeaveQtyOnReportDay != null) {
          leave += this.toNumber(r.subcontractLeaveQtyOnReportDay)
          hasLeave = true
        }
        if (r.subcontractEnterQtyOnReportDay != null) {
          enter += this.toNumber(r.subcontractEnterQtyOnReportDay)
          hasEnter = true
        }
        if (r.subcontractLeaveEnterSumOnReportDay != null) {
          sum += this.toNumber(r.subcontractLeaveEnterSumOnReportDay)
          hasSum = true
        }
      })

      return {
        leaveQty: hasLeave ? leave : null,
        enterQty: hasEnter ? enter : null,
        sumQty: hasSum ? sum : (hasLeave || hasEnter ? leave + enter : null)
      }
    },
    getBoardDayKpiCards(item) {
      const dayReport = this.getDayReportSummary(item)
      const dayFinish = dayReport.rows.length > 0 ? dayReport.totalFinishQty : null
      const dayQua = dayReport.rows.length > 0 ? dayReport.totalQuaQty : null
      const dayFail = dayReport.rows.length > 0 ? dayReport.totalFailQty : null

      const sub = this.getBoardDaySubcontractSummary(item)
      const dayInstock = this.getBoardDayInstockQty(item)

      return [
        { key: 'dayFinish', title: '当日完成数量', value: dayFinish == null ? '-' : this.formatNumber(dayFinish), className: 'kpi-blue' },
        { key: 'dayQua', title: '当日合格数量', value: dayQua == null ? '-' : this.formatNumber(dayQua), className: 'kpi-green' },
        { key: 'dayFail', title: '当日不良数量', value: dayFail == null ? '-' : this.formatNumber(dayFail), className: 'kpi-red' },
        { key: 'daySubcontract', title: '当日委外', value: sub.sumQty == null ? '-' : this.formatNumber(sub.sumQty), className: 'kpi-purple' },
        { key: 'daySubLeave', title: '当日发出', value: sub.leaveQty == null ? '-' : this.formatNumber(sub.leaveQty), className: 'kpi-orange' },
        { key: 'dayInstock', title: '当日入库', value: dayInstock == null ? '-' : this.formatNumber(dayInstock), className: 'kpi-cyan' }
      ]
    },
    isOutsourceRow(row) {
      if (!row) return false
      const texts = [row.workCenter, row.processName, row.activity1Name, row.operDescription]
        .filter(Boolean)
        .map(v => `${v}`)
        .join(' ')
      return texts.includes('委外') || texts.includes('外协')
    },
    hashToIndex(str, mod) {
      const s = `${str || ''}`
      let hash = 0
      for (let i = 0; i < s.length; i++) {
        hash = (hash * 31 + s.charCodeAt(i)) >>> 0
      }
      return mod ? hash % mod : hash
    },
    getWorkCenterClass(row) {
      const wc = row && row.workCenter
      if (!wc) return ''
      if (!this.workCenterColorCache[wc]) {
        const idx = this.hashToIndex(wc, 8)
        this.workCenterColorCache[wc] = `wc-bg-${idx}`
      }
      return this.workCenterColorCache[wc]
    },
    processRowClassName({ row }) {
      const classes = []
      const wcClass = this.getWorkCenterClass(row)
      if (wcClass) classes.push(wcClass)
      if (this.isOutsourceRow(row)) classes.push('is-outsourcing-row')
      return classes.join(' ')
    },
    formatOperText(row) {
      if (!row) return '-'
      const no = row.operNo == null || row.operNo === '' ? '' : `${row.operNo}`
      const name = row.processName || ''
      if (!no && !name) return '-'
      if (!no) return name
      if (!name) return no
      return `${no}-${name}`
    },
    // 将嵌套的订单 -> 计划 -> 工序数据拍平展示
    getFlattenedProcessData(item) {
      if (!item || !item.orders || item.orders.length === 0) return [];
      
      const flatData = [];
      item.orders.forEach(order => {
        const orderBase = {
          moBillNo: order.moBillNo,
          materialNumber: order.materialNumber,
          materialName: order.materialName,
          moInstockQty: order.moInstockQty
        };

        if (order.planningList && order.planningList.length > 0) {
          order.planningList.forEach(plan => {
            const planBase = {
              ...orderBase,
              overallProgress: plan.overallProgress,
              overallStatus: plan.overallStatus
            };

            if (plan.processList && plan.processList.length > 0) {
              plan.processList.forEach(process => {
                flatData.push({
                  ...planBase,
                  ...process
                });
              });
            } else {
              // 有计划单但没有工序
              flatData.push(planBase);
            }
          });
        } else {
          // 有订单但没有计划单
          flatData.push(orderBase);
        }
      });
      return flatData;
    },
    getMoTraceRows(orders) {
      if (!orders || !Array.isArray(orders)) return []
      return orders.reduce((acc, order) => {
        const rows = order.moTraceRows
        if (Array.isArray(rows)) return acc.concat(rows)
        return acc
      }, [])
    },
    getOperationReportRows(orders) {
      if (!orders || !Array.isArray(orders)) return []
      const rows = orders.reduce((acc, order) => {
        const newRows = order.operationReportRows
        const oldRows = order.reportRows
        if (Array.isArray(newRows)) {
          return acc.concat(
            newRows.map(r => ({
              ...r,
              materialNumber: r.productNumber,
              createTime: r.createTime
            }))
          )
        }
        if (Array.isArray(oldRows)) {
          return acc.concat(oldRows)
        }
        return acc
      }, [])

      return rows.map(r => ({
        ...r,
        materialNumber: r.materialNumber || r.productNumber,
        materialName: r.materialName || r.productName
      }))
    },
    getTodayOperationReportSummary(item) {
      const today = this.getTodayStr()
      const rows = this.getOperationReportRows(item && item.orders)
        .filter(r => this.normalizeYmd(r.reportDate || r.createTime) === today)

      const map = new Map()
      let totalFinishQty = 0
      let totalQuaQty = 0
      let totalFailQty = 0

      rows.forEach(r => {
        const opOper = r.opOper || r.operNo || r.processId || '-'
        const materialNumber = r.materialNumber || '-'
        const materialName = r.materialName || '-'
        const key = `${today}|${opOper}|${materialNumber}|${materialName}`

        const finishQty = this.toNumber(r.finishQty)
        const quaQty = this.toNumber(r.quaQty)
        const failQty = this.toNumber(r.failQty)

        totalFinishQty += finishQty
        totalQuaQty += quaQty
        totalFailQty += failQty

        const cur = map.get(key) || {
          reportDate: today,
          opOper,
          materialNumber,
          materialName,
          finishQty: 0,
          quaQty: 0,
          failQty: 0,
          rowCount: 0
        }
        cur.finishQty += finishQty
        cur.quaQty += quaQty
        cur.failQty += failQty
        cur.rowCount += 1
        map.set(key, cur)
      })

      return {
        totalFinishQty,
        totalQuaQty,
        totalFailQty,
        rows: Array.from(map.values())
      }
    },
    getDayReportSummary(item) {
      const rows = this.getFlattenedProcessData(item)
      const map = new Map()
      let totalFinishQty = 0
      let totalQuaQty = 0
      let totalFailQty = 0

      rows.forEach(r => {
        const finish = r.dayReportFinishQty
        const qua = r.dayReportQuaQty
        const fail = r.dayReportFailQty

        if (finish == null && qua == null && fail == null) return

        const operNo = r.operNo || '-'
        const materialNumber = r.materialNumber || '-'
        const materialName = r.materialName || '-'
        const key = `${operNo}|${materialNumber}|${materialName}`

        const finishQty = this.toNumber(finish)
        const quaQty = this.toNumber(qua)
        const failQty = this.toNumber(fail)

        totalFinishQty += finishQty
        totalQuaQty += quaQty
        totalFailQty += failQty

        const cur = map.get(key) || {
          operNo,
          materialNumber,
          materialName,
          finishQty: 0,
          quaQty: 0,
          failQty: 0
        }
        cur.finishQty += finishQty
        cur.quaQty += quaQty
        cur.failQty += failQty
        map.set(key, cur)
      })

      const summaryRows = Array.from(map.values())
      summaryRows.sort((a, b) => `${a.operNo}` > `${b.operNo}` ? 1 : -1)

      return {
        totalFinishQty,
        totalQuaQty,
        totalFailQty,
        rows: summaryRows
      }
    },
    getOperationReportSummary(item) {
      const rows = this.getOperationReportRows(item && item.orders)
        .filter(r => this.normalizeYmd(r.reportDate || r.createTime))

      const map = new Map()
      let totalFinishQty = 0
      let totalQuaQty = 0
      let totalFailQty = 0

      rows.forEach(r => {
        const reportDate = this.normalizeYmd(r.reportDate || r.createTime) || '-'
        const opOper = r.opOper || r.operNo || r.processId || '-'
        const materialNumber = r.materialNumber || '-'
        const materialName = r.materialName || '-'
        const key = `${reportDate}|${opOper}|${materialNumber}|${materialName}`

        const finishQty = this.toNumber(r.finishQty)
        const quaQty = this.toNumber(r.quaQty)
        const failQty = this.toNumber(r.failQty)

        totalFinishQty += finishQty
        totalQuaQty += quaQty
        totalFailQty += failQty

        const cur = map.get(key) || {
          reportDate,
          opOper,
          materialNumber,
          materialName,
          finishQty: 0,
          quaQty: 0,
          failQty: 0,
          rowCount: 0
        }
        cur.finishQty += finishQty
        cur.quaQty += quaQty
        cur.failQty += failQty
        cur.rowCount += 1
        map.set(key, cur)
      })

      const summaryRows = Array.from(map.values())
      summaryRows.sort((a, b) => {
        if (a.reportDate !== b.reportDate) return a.reportDate > b.reportDate ? -1 : 1
        if (a.opOper !== b.opOper) return `${a.opOper}` > `${b.opOper}` ? 1 : -1
        if (a.materialNumber !== b.materialNumber) return `${a.materialNumber}` > `${b.materialNumber}` ? 1 : -1
        return 0
      })

      return {
        totalFinishQty,
        totalQuaQty,
        totalFailQty,
        rows: summaryRows
      }
    },
    getMaterialSummaryRows(item) {
      if (!item) return []

      const map = new Map()
      const upsert = (materialNumber, materialName) => {
        const key = materialNumber || '-'
        const cur = map.get(key) || {
          materialNumber: key,
          materialName: materialName || '-',
          moQty: 0,
          productionInstockQty: 0,
          todayFinishQty: 0,
          todayQuaQty: 0,
          todayFailQty: 0
        }
        if (!cur.materialName || cur.materialName === '-') cur.materialName = materialName || cur.materialName
        map.set(key, cur)
        return cur
      }

      ;(item.productionTraceList || []).forEach(r => {
        const cur = upsert(r.materialNumber, r.materialName)
        cur.moQty += this.toNumber(r.qty)
        cur.productionInstockQty += this.toNumber(r.instockQty)
      })

      const today = this.getTodayStr()
      this.getOperationReportRows(item.orders)
        .filter(r => this.normalizeYmd(r.reportDate || r.createTime) === today)
        .forEach(r => {
          const cur = upsert(r.materialNumber || r.productNumber, r.materialName)
          cur.todayFinishQty += this.toNumber(r.finishQty)
          cur.todayQuaQty += this.toNumber(r.quaQty)
          cur.todayFailQty += this.toNumber(r.failQty)
        })

      return Array.from(map.values())
    },
    getSubcontractTransferRows(orders) {
      if (!orders || !Array.isArray(orders)) return []
      return orders.reduce((acc, order) => {
        const rows = order.subcontractTransferRows
        const legacy = order.subcontractRows
        if (Array.isArray(rows) && rows.length) return acc.concat(rows)
        if (Array.isArray(legacy) && legacy.length) return acc.concat(legacy)
        return acc
      }, [])
    },
    getSubcontractInOutSummary(orders) {
      const rows = this.getSubcontractTransferRows(orders)
      let inQty = 0
      let outQty = 0
      rows.forEach(r => {
        if ('leaveQty' in r || 'qualifiedQty' in r) {
          outQty += this.toNumber(r.leaveQty)
          if ('enterQty' in r) inQty += this.toNumber(r.enterQty)
          else inQty += this.toNumber(r.qualifiedQty)
          return
        }

        const candidates = [
          { inKey: 'transInQty', outKey: 'transOutQty' },
          { inKey: 'inQty', outKey: 'outQty' },
          { inKey: 'qtyIn', outKey: 'qtyOut' }
        ]

        for (const c of candidates) {
          if (c.inKey in r || c.outKey in r) {
            inQty += this.toNumber(r[c.inKey])
            outQty += this.toNumber(r[c.outKey])
            return
          }
        }

        const dir = (r.direction || r.inOut || r.transType || r.type || '').toString()
        const qty = this.toNumber(r.qty || r.quantity)
        if (dir.includes('转入') || dir.toLowerCase() === 'in') inQty += qty
        else if (dir.includes('转出') || dir.includes('发出') || dir.toLowerCase() === 'out') outQty += qty
      })
      return { inQty, outQty }
    },
    getDynamicColumns(rows) {
      if (!rows || rows.length === 0) return []
      return Object.keys(rows[0])
    },
    // 格式化数值，保留一位小数
    formatNumber(num) {
      if (num === null || num === undefined || num === '') return '-';
      const parsed = parseFloat(num);
      if (isNaN(parsed)) return num; // 如果不是合法数字则原样返回
      // 检查是否为整数或者原本就没有小数位，避免强行给整数加 .0（视需求而定，目前统一强制保留1位）
      return parsed.toFixed(1);
    },
    // 加载 Mock 数据用于演示
    loadMockData() {
      this.dataList = [
        { 
          "sclh": "QB-26-026-LT", 
          "purchaseList": [ 
            { 
              "sclh": "QB-26-026-LT", 
              "purchaseBillNo": "PO202601010001", 
              "purchaseDate": "2026-04-01 08:30:00", 
              "materialNumber": "KC26022.03.01.0", 
              "materialName": "挡轮座焊件", 
              "purchaseQty": 10, 
              "instockBillNo": "RK202604110001", 
              "instockDate": "2026-04-11 16:00:00", 
              "instockQty": 10 
            } 
          ], 
          "purchaseInboundSummary": [ 
            { 
              "purchaseBillNo": "PO202601010001", 
              "materialNumber": "KC26022.03.01.0", 
              "materialName": "挡轮座焊件", 
              "sumPurchaseQty": 10, 
              "sumInstockQty": 10, 
              "detailLineCount": 1 
            } 
          ], 
          "totalPurchaseOrderQty": 10, 
          "totalPurchaseInstockQty": 10, 
          "productionTraceList": [ 
            { 
              "sclh": "QB-26-026-LT", 
              "moBillNo": "MO030013", 
              "materialNumber": "KC26022.03.01.0", 
              "materialName": "挡轮座焊件", 
              "qty": 8, 
              "orderDate": "2026-04-02 10:00:00", 
              "operPlanningBillNo": "OP000123", 
              "operPlanningId": 100012, 
              "planStartDate": "2026-04-05 08:00:00", 
              "planFinishDate": "2026-04-20 18:00:00", 
              "instockBillNo": "SCRK202604120001", 
              "instockDate": "2026-04-12 09:00:00", 
              "instockQty": 8 
            } 
          ], 
          "totalMoQty": 8, 
          "totalProductionInstockQty": 8, 
          "orders": [ 
            { 
              "moBillNo": "MO030013", 
              "materialNumber": "KC26022.03.01.0", 
              "materialName": "挡轮座焊件", 
              "planningList": [ 
                { 
                  "moNumber": "MO030013", 
                  "batchNo": "QB-26-026-LT", 
                  "projectNo": null, 
                  "productCode": "KC26022.03.01.0", 
                  "productName": "挡轮座焊件", 
                  "billNo": "OP000123", 
                  "proSpecification": "某某规格", 
                  "planStartTime": "2026-04-05 08:00:00", 
                  "planFinishTime": "2026-04-20 18:00:00", 
                  "fid": 123456789, 
                  "workCenter": "机加工段", 
                  "overallPlanQty": 100, 
                  "overallOkQty": 60, 
                  "overallProgress": 60, 
                  "overallStatus": "生产中", 
                  "processList": [ 
                    { 
                      "operNo": 10, 
                      "processName": "铣削", 
                      "workCenter": "机加", 
                      "planQty": 50, 
                      "inQty": 40, 
                      "progress": 80, 
                      "okQty": 38, 
                      "ngQty": 1, 
                      "status": "生产中", 
                      "k3Status": "开工"
                    } 
                  ] 
                } 
              ], 
              "reportRows": [ 
                { 
                  "reportDate": "2026-04-11", 
                  "moBillNo": "MO030013", 
                  "opOper": "10", 
                  "materialName": "挡轮座焊件", 
                  "finishQty": 5, 
                  "quaQty": 5, 
                  "failQty": 0, 
                  "createTime": "2026-05-10 12:00:00"
                } 
              ], 
              "subcontractRows": [ 
                { 
                  "providerName": "某某供应商", 
                  "productName": "挡轮座焊件", 
                  "documentDate": "2026/4/11", 
                  "shiftTaskName": "喷漆", 
                  "leaveQty": 8, 
                  "qualifiedQty": 8, 
                  "createTime": "2026-05-10 12:00:00"
                } 
              ], 
              "moInstockQty": 8 
            } 
          ] 
        } 
      ];
    }
  }
}
</script>

<style scoped>
.app-container {
  padding: 20px;
  min-height: calc(100vh - 84px);
}
.mb-20 {
  margin-bottom: 20px;
}
.ml-10 {
  margin-left: 10px;
}
.mt-10 {
  margin-top: 10px;
}
.p-10 {
  padding: 10px;
}
.section-title {
  font-weight: bold;
  color: #303133;
}
.summary-tags .el-tag {
  margin-right: 10px;
}
.kpi-card {
  height: 92px;
}
.kpi-card.kpi-blue {
  background: #409eff;
  border-color: #409eff;
}
.kpi-card.kpi-green {
  background: #67c23a;
  border-color: #67c23a;
}
.kpi-card.kpi-red {
  background: #f56c6c;
  border-color: #f56c6c;
}
.kpi-card.kpi-purple {
  background: #8e44ad;
  border-color: #8e44ad;
}
.kpi-card.kpi-orange {
  background: #e6a23c;
  border-color: #e6a23c;
}
.kpi-card.kpi-cyan {
  background: #2bb3b1;
  border-color: #2bb3b1;
}
.kpi-title {
  font-size: 12px;
  color: #909399;
}
.kpi-value {
  margin-top: 8px;
  font-size: 22px;
  font-weight: bold;
  color: #303133;
}
.kpi-value.is-empty {
  color: #c0c4cc;
}
.kpi-card.kpi-blue .kpi-title,
.kpi-card.kpi-green .kpi-title,
.kpi-card.kpi-red .kpi-title,
.kpi-card.kpi-purple .kpi-title,
.kpi-card.kpi-orange .kpi-title,
.kpi-card.kpi-cyan .kpi-title {
  color: rgba(255, 255, 255, 0.85);
}
.kpi-card.kpi-blue .kpi-value,
.kpi-card.kpi-green .kpi-value,
.kpi-card.kpi-red .kpi-value,
.kpi-card.kpi-purple .kpi-value,
.kpi-card.kpi-orange .kpi-value,
.kpi-card.kpi-cyan .kpi-value {
  color: #fff;
}
.kpi-card.kpi-blue .kpi-value.is-empty,
.kpi-card.kpi-green .kpi-value.is-empty,
.kpi-card.kpi-red .kpi-value.is-empty,
.kpi-card.kpi-purple .kpi-value.is-empty,
.kpi-card.kpi-orange .kpi-value.is-empty,
.kpi-card.kpi-cyan .kpi-value.is-empty {
  color: rgba(255, 255, 255, 0.65);
}

.process-sticky-table ::v-deep .el-table__body-wrapper {
  overflow-x: auto;
}

.process-sticky-table ::v-deep .el-table__body tr.is-outsourcing-row > td:first-child,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.is-outsourcing-row > td:first-child,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.is-outsourcing-row > td:first-child {
  box-shadow: inset 3px 0 0 #e6a23c;
}
.process-sticky-table ::v-deep .el-table__body tr.is-outsourcing-row > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.is-outsourcing-row > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.is-outsourcing-row > td {
  font-weight: 600;
}

.process-sticky-table ::v-deep .el-table__body tr.wc-bg-0 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-0 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-0 > td {
  background-color: #f0f9ff;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-1 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-1 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-1 > td {
  background-color: #f6ffed;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-2 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-2 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-2 > td {
  background-color: #fff7e6;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-3 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-3 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-3 > td {
  background-color: #fff0f6;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-4 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-4 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-4 > td {
  background-color: #f9f0ff;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-5 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-5 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-5 > td {
  background-color: #e6fffb;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-6 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-6 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-6 > td {
  background-color: #fff1f0;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-7 > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-7 > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-7 > td {
  background-color: #f5f5f5;
}

.process-sticky-table ::v-deep .el-table__body tr.wc-bg-0:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-0:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-0:hover > td {
  background-color: #d6efff;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-1:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-1:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-1:hover > td {
  background-color: #e5f7d8;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-2:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-2:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-2:hover > td {
  background-color: #ffe7ba;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-3:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-3:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-3:hover > td {
  background-color: #ffd6e7;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-4:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-4:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-4:hover > td {
  background-color: #efdbff;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-5:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-5:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-5:hover > td {
  background-color: #b5f5ec;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-6:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-6:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-6:hover > td {
  background-color: #ffccc7;
}
.process-sticky-table ::v-deep .el-table__body tr.wc-bg-7:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-body-wrapper tr.wc-bg-7:hover > td,
.process-sticky-table ::v-deep .el-table__fixed-right .el-table__fixed-body-wrapper tr.wc-bg-7:hover > td {
  background-color: #e6e6e6;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.sclh-title {
  font-size: 16px;
  font-weight: bold;
}
.header-tags .el-tag {
  margin-left: 10px;
}
.expand-content {
  padding: 15px 30px;
  background-color: #fafafa;
}
.order-section {
  margin-bottom: 20px;
}
.order-main-table ::v-deep .el-table__header-wrapper th {
  background-color: #f5f7fa;
}
.plan-section {
  background-color: #fff;
  padding: 15px;
  border-radius: 4px;
  border: 1px solid #ebeef5;
  margin-bottom: 15px;
}
.plan-section:last-child {
  margin-bottom: 0;
}
.plan-header {
  font-weight: bold;
  color: #303133;
  font-size: 14px;
}
.process-table ::v-deep .el-table__header-wrapper th {
  background-color: #fafafa;
}
</style>
