<template>
    <div class="oee-report-page">
      <!-- 左侧：报告主体 -->
      <div class="oee-report-main">
        <!-- 条件概览（报告式，不要大标题） -->
        <header class="oee-report-header">
          <div class="oee-report-meta">
            <div>报告日期区间：{{ query.startDate }} 至 {{ query.endDate }}</div>
            <div>产线：{{ lineNamesText }}</div>
          </div>
          <div v-if="bgLoading.active" class="oee-bg-progress">
            <el-progress
              :percentage="bgLoading.percent"
              :stroke-width="10"
              status="success"
              :text-inside="false"
            />
            <div class="oee-bg-progress-text">{{ bgLoading.text }}</div>
          </div>
          <!-- 简洁查询区：更像“报告参数选择”，而不是大屏搜索栏 -->
          <el-form
            ref="queryForm"
            :inline="true"
            size="mini"
            class="oee-report-query-form"
          >
            <el-form-item label="日期范围">
              <el-date-picker
                v-model="dateRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
                :picker-options="pickerOptions"
              />
            </el-form-item>
            <el-form-item label="产线">
              <el-select
                v-model="selectedLineIds"
                multiple
                collapse-tags
                style="min-width: 220px"
              >
                <el-option
                  v-for="line in allLines"
                  :key="line.lineId"
                  :label="line.lineName"
                  :value="line.lineId"
                />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleQuery">生成报告</el-button>
            <el-button :disabled="!query.startDate || !query.endDate" @click="handleExportWord">导出 Word</el-button>
            </el-form-item>
          </el-form>
        </header>
  
        <!-- 生成中占位：先展示框架 + 进度条，数据到达后再填充表格 -->
        <section class="oee-section" v-if="loading && summaryLines.length === 0">
          <h2 class="oee-section-title">正在生成报告数据…</h2>
          <p class="oee-paragraph">
            当前进度：{{ bgLoading.percent }}%（{{ bgLoading.text }}）
          </p>
          <p class="oee-paragraph">
            汇总数据就绪后会立即显示表格；事件明细与理论节拍回归会在后台继续补全。
          </p>
        </section>

        <!-- 报告内容：按“章节”布局，模拟 Word 报告结构 -->
        <section class="oee-section" v-if="summaryLines.length">
          <h2 class="oee-section-title">一、关键指标总览（按产线）</h2>
          <el-table
            :data="summaryLines"
            border
            size="mini"
            class="oee-kpi-table"
          >
            <el-table-column prop="lineName" label="产线" fixed="left" />
            <el-table-column prop="oeeText" label="OEE" />
            <el-table-column prop="availabilityText" label="时间稼动率" />
            <el-table-column prop="performanceText" label="性能稼动率" />
            <el-table-column prop="qualityText" label="良品率" />
            <el-table-column prop="loadingTimeH" label="负荷时间(h)" />
            <el-table-column prop="downtimeH" label="停机时间(h)" />
            <el-table-column prop="runTimeH" label="实际运转时间(h)" />
            <el-table-column prop="totalOutput" label="总产量" />
            <el-table-column prop="goodOutput" label="良品量" />
            <el-table-column prop="defectOutput" label="不良量" />
          </el-table>
        </section>

      <section class="oee-section" v-if="trendDates.length">
        <h2 class="oee-section-title">二、趋势（按日）</h2>
        <div class="oee-charts">
          <div class="oee-chart-card">
            <div class="oee-chart-title">OEE 日趋势</div>
            <div ref="oeeTrendChart" class="oee-chart"></div>
          </div>
          <div class="oee-chart-card">
            <div class="oee-chart-title">时间稼动率 / 性能稼动率 / 良品率（日趋势）</div>
            <div ref="apqTrendChart" class="oee-chart"></div>
          </div>
        </div>
      </section>
  
        <section class="oee-section" v-if="summaryLines.length">
        <h2 class="oee-section-title">三、指标日明细（用于报告点评）</h2>
          <p class="oee-paragraph">
            本节展示所选日期范围内，各产线每日的 OEE 及三大构成指标（时间稼动率、性能稼动率、良品率）。
            页面以文字+表格形式呈现，便于在 Word 报告中直接使用和点评。
          </p>
          <div
            v-for="line in summaryLines"
            :key="line.lineId"
            class="oee-subsection"
          >
            <h3 class="oee-subsection-title">
              产线：{{ line.lineName }}
            </h3>
            <el-table
              :data="line.daily || []"
              border
              size="mini"
              class="oee-daily-table"
            >
              <el-table-column prop="statDate" label="日期" width="110" />
              <el-table-column prop="oeeText" label="OEE" width="90" />
              <el-table-column prop="availabilityText" label="时间稼动率" width="110" />
              <el-table-column prop="performanceText" label="性能稼动率" width="110" />
              <el-table-column prop="qualityText" label="良品率" width="90" />
              <el-table-column prop="loadingTimeH" label="负荷时间(h)" width="120" />
              <el-table-column prop="downtimeH" label="停机时间(h)" width="120" />
              <el-table-column prop="runTimeH" label="实际运转时间(h)" width="140" />
              <el-table-column prop="totalOutput" label="总产量" width="100" />
              <el-table-column prop="goodOutput" label="良品量" width="100" />
              <el-table-column prop="defectOutput" label="不良量" width="100" />
            </el-table>
          </div>
        </section>
  
        <section class="oee-section" v-if="lossByLine.length">
        <h2 class="oee-section-title">四、7 大损失分类汇总</h2>
          <p class="oee-paragraph">
            本节按照 7 大损失分类，统计各类别的时间损失与占比，帮助识别 OEE 损失的主要来源。
          </p>
          <div
            v-for="item in lossByLine"
            :key="item.lineId"
            class="oee-subsection"
          >
            <h3 class="oee-subsection-title">
              产线：{{ item.lineName }}
            </h3>
            <el-table
              :data="item.losses || []"
              border
              size="mini"
              class="oee-loss-table"
            >
              <el-table-column prop="lossCategoryName" label="损失类别" />
              <el-table-column prop="lossTimeH" label="损失时间(h)" />
              <el-table-column prop="lossTimeRateText" label="占比" />
              <el-table-column prop="count" label="次数" />
              <el-table-column prop="avgDurationH" label="平均时长(h)" />
            </el-table>
          </div>
        </section>
  
        <section class="oee-section">
        <h2 class="oee-section-title">五、停机/损失事件明细（节选）</h2>
          <p class="oee-paragraph">
            下表为当前条件下的部分停机/损失事件明细（默认展示前 50 条），便于在报告中引用典型案例。
          </p>
          <el-table
            :data="eventRows"
            border
            size="mini"
            class="oee-events-table"
          >
            <el-table-column prop="eventStartTime" label="开始时间" width="160" />
            <el-table-column prop="eventEndTime" label="结束时间" width="160" />
            <el-table-column prop="lineName" label="产线" width="90" />
            <el-table-column prop="lossCategoryName" label="损失类别" width="120" />
            <el-table-column prop="rawReasonName" label="原因" min-width="180" />
            <el-table-column prop="durationMin" label="时长(min)" width="90" />
            <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
          </el-table>
        </section>
      </div>

      <!-- 右侧：理论依据 / 公式（MathType 风格，使用 LaTeX + MathJax 渲染） -->
      <aside class="oee-report-aside">
        <div class="oee-formula-card">
          <h3 class="oee-formula-title">OEE 计算公式与理论依据</h3>
          <div class="oee-formula-body">
            <!-- 总公式 -->
            <div class="math-block" v-html="renderMath('OEE = A \\\\times P \\\\times Q')" />
  
            <!-- 时间稼动率 -->
            <div class="oee-formula-caption">时间稼动率 A：</div>
            <div
              class="math-block"
              v-html="renderMath('A = \\frac{T_{\\text{load}} - T_{\\text{down}}}{T_{\\text{load}}}')"
            />
  
            <!-- 性能稼动率 -->
            <div class="oee-formula-caption">性能稼动率 P（按标准节拍）：</div>
            <div
              class="math-block"
              v-html="renderMath('P = \\frac{t_{\\text{ideal}} \\times Q_{\\text{out}}}{T_{\\text{run}}}')"
            />
  
            <!-- 良品率 -->
            <div class="oee-formula-caption">良品率 Q：</div>
            <div
              class="math-block"
              v-html="renderMath('Q = \\frac{Q_{\\text{good}}}{Q_{\\text{total}}}')"
            />
  
            <div class="oee-formula-footnote">
              说明：公式采用 TeX 语法并由 MathJax（SVG 输出）渲染，显示效果接近 Word/MathType。
            </div>
          </div>
        </div>

        <div class="oee-formula-card" style="margin-top: 12px">
          <h3 class="oee-formula-title">理论节拍回归（用于性能口径）</h3>
          <div class="oee-formula-body">
            <div v-if="regressionStatus.refreshing" class="oee-formula-footnote">
              理论节拍回归正在后台计算中，稍后可点击“生成报告”再次刷新查看结果。
            </div>
            <div v-else-if="regressionLines.length === 0" class="oee-formula-footnote">
              暂无回归数据（可稍后重试或检查近 6 个月是否有足够样本）。
            </div>
            <div v-for="r in regressionLines" :key="r.lineId" class="oee-regression-item">
              <div class="oee-regression-title">{{ r.lineName }}（{{ r.lineId }}）</div>
              <div class="oee-regression-row">
                <span>斜率(分钟/吨)：{{ r.slopeMinPerTon }}</span>
                <span>R²：{{ r.r2 }}</span>
                <span>样本数：{{ r.sampleCount }}</span>
              </div>
            </div>
          </div>
        </div>
      </aside>
    </div>
  </template>
  
  <script>
  import { fetchOeeSummary, fetchOeeLoss7, fetchOeeEvents, createOeeTheoryCycleRegressionJob, exportOeeWord } from '@/api/da/oee'
  import WebSocketManager from '@/utils/websocketManager'
  import * as echarts from 'echarts'
  
  // 组件内加载 MathJax（不依赖全局 index.html），并使用 SVG 输出接近 MathType 的显示效果
  function ensureMathJaxLoaded() {
    if (window.MathJax && window.MathJax.typesetPromise) {
      return Promise.resolve()
    }
    if (window.__KLP_MATHJAX_LOADING__) {
      return window.__KLP_MATHJAX_LOADING__
    }
    window.MathJax = {
      tex: { inlineMath: [['\\\\(', '\\\\)']], displayMath: [['\\\\[', '\\\\]']] },
      svg: { fontCache: 'global' }
    }
    window.__KLP_MATHJAX_LOADING__ = new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.async = true
      script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js'
      script.onload = () => resolve()
      script.onerror = (e) => reject(e)
      document.head.appendChild(script)
    })
    return window.__KLP_MATHJAX_LOADING__
  }

  function typesetMath() {
    if (window.MathJax && window.MathJax.typesetPromise) {
      return window.MathJax.typesetPromise()
    }
    return Promise.resolve()
  }
  
  export default {
    name: 'DaOeeReport',
    data() {
      const today = this.parseTime(new Date(), '{y}-{m}-{d}')
      const d = new Date()
      d.setDate(d.getDate() - 29)
      const monthAgo = this.parseTime(d, '{y}-{m}-{d}')
      return {
        query: {
          startDate: monthAgo,
          endDate: today
        },
        dateRange: [monthAgo, today],
        pickerOptions: {
          disabledDate(time) {
            return time.getTime() > Date.now()
          }
        },
        allLines: [
          // 与后端约定好的 lineId/lineName，后续也可以从接口动态获取
          { lineId: 'SY', lineName: '酸轧线' },
          { lineId: 'DX1', lineName: '镀锌一线' }
        ],
        selectedLineIds: ['SY', 'DX1'],
        summaryLines: [],
        lossByLine: [],
        eventRows: [],
        regressionLines: [],
        regressionStatus: {},
        trendDates: [],
        charts: {
          oee: null,
          apq: null
        },
        loading: false,
        loadStage: 'idle', // idle | base | events | regression | done
        loadMessage: '',
        bgLoading: { active: true, percent: 10, text: '正在准备加载 OEE 报告…' },
        wsManager: null,
        regressionWsType: null
      }
    },
    computed: {
      lineNamesText() {
        const names = this.allLines
          .filter(l => this.selectedLineIds.includes(l.lineId))
          .map(l => l.lineName)
        return names.length ? names.join('、') : '（未选择）'
      }
    },
    mounted() {
      ensureMathJaxLoaded()
        .then(() => this.handleQuery())
        .then(() => this.$nextTick(() => typesetMath()))
        .catch(() => {
          // MathJax 加载失败也不影响数据展示
          this.handleQuery()
        })
    },
    beforeDestroy() {
      this.disposeCharts()
      // 断开 websocket，避免页面离开后仍在推送
      if (this.wsManager) {
        try {
          if (this.regressionWsType) {
            this.wsManager.disconnect(this.regressionWsType)
          } else {
            this.wsManager.disconnectAll()
          }
        } catch (e) {
          // ignore
        }
      }
    },
    methods: {
      getWsBaseUrl() {
        const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
        return `${protocol}://${window.location.host}/websocket`
      },
      // 将 TeX 字符串包装成 MathJax 识别的行内/块级格式
      renderMath(tex) {
        const escaped = tex
        this.$nextTick(() => {
          typesetMath()
        })
        // 注意：这里返回的是“可被 MathJax 识别的文本”，不是直接插 SVG
        return `\\\\[${escaped}\\\\]`
      },
      buildQueryParams() {
        const [start, end] = this.dateRange || []
        return {
          startDate: start,
          endDate: end,
          lineIds: (this.selectedLineIds || []).join(',')
        }
      },
      async handleQuery() {
        this.loading = true
        this.loadStage = 'base'
        this.loadMessage = '正在加载汇总指标与趋势…'
        this.bgLoading = { active: true, percent: 10, text: '正在获取基础数据…' }
        const params = this.buildQueryParams()
        this.query.startDate = params.startDate
        this.query.endDate = params.endDate
  
        try {
          // 0) 事件明细不依赖 summary，提前拉取，避免 summary 卡住导致第五节永远空
          ;(async () => {
            try {
              const eventsRes = await fetchOeeEvents({
                startTime: params.startDate + ' 00:00:00',
                endTime: params.endDate + ' 23:59:59',
                pageNum: 1,
                pageSize: 50
              })
              this.eventRows = (eventsRes.data && eventsRes.data.rows) || []
            } catch (e) {
              console.warn('加载事件明细失败（不影响主报表）', e)
              this.eventRows = []
            }
          })()

          // 1) 先加载“报表主体”所必需的数据（summary(http) + loss7(http)）
          const [summaryRes, lossRes] = await Promise.all([
            fetchOeeSummary(params),
            fetchOeeLoss7({ ...params, topN: 10 })
          ])

          const rawSummary = summaryRes && summaryRes.data ? summaryRes.data : summaryRes
          const lines = (rawSummary && rawSummary.lines) || rawSummary || []
          this.summaryLines = lines.map(l => {
            const total = l.total || {}
            return {
              lineId: l.lineId,
              lineName: l.lineName,
              // 区间汇总
              loadingTimeH: this.formatHours(total.loadingTimeMin),
              downtimeH: this.formatHours(total.downtimeMin),
              runTimeH: this.formatHours(total.runTimeMin),
              totalOutput: total.totalOutput,
              goodOutput: total.goodOutput,
              defectOutput: total.defectOutput,
              availabilityText: this.formatPercent(total.availability),
              performanceText: this.formatPercent(total.performance),
              qualityText: this.formatPercent(total.quality),
              oeeText: this.formatPercent(total.oee),
              // 日明细
              daily: (l.daily || []).map(d => ({
                ...d,
                availabilityText: this.formatPercent(d.availability),
                performanceText: this.formatPercent(d.performance),
                qualityText: this.formatPercent(d.quality),
                oeeText: this.formatPercent(d.oee),
                loadingTimeH: this.formatHours(d.loadingTimeMin),
                downtimeH: this.formatHours(d.downtimeMin),
                runTimeH: this.formatHours(d.runTimeMin)
              }))
            }
          })
  
          const byLine = (lossRes.data && lossRes.data.byLine) || []
          this.lossByLine = byLine.map(b => ({
            ...b,
            losses: (b.losses || []).map(x => ({
              ...x,
              lossTimeRateText: this.formatPercent(x.lossTimeRate),
              lossTimeH: this.formatHours(x.lossTimeMin),
              avgDurationH: this.formatHours(x.avgDurationMin)
            }))
          }))
          this.buildTrendData()
          // 主体已就绪：先展示报表，再后台补全
          this.loading = false
          this.bgLoading = { active: true, percent: 70, text: '主体已生成：正在加载事件明细…' }
          this.loadStage = 'events'
          this.loadMessage = ''

          this.loadStage = 'regression'
          this.bgLoading = { active: true, percent: 85, text: '正在获取理论节拍回归…' }
          // 3) 回归（异步任务 + WebSocket 推送进度/结果；失败不影响主体）
          try {
            // 创建任务
            const jobRes = await createOeeTheoryCycleRegressionJob({
              startTime: params.startDate + ' 00:00:00',
              endTime: params.endDate + ' 23:59:59',
              lineIds: params.lineIds
            })
            const jobInfo = jobRes.data || {}
            const wsType = jobInfo.wsType
            this.regressionWsType = wsType
            this.regressionStatus = { refreshing: true, ...jobInfo }
            this.regressionLines = []

            // 订阅 WS
            const wsBase = this.getWsBaseUrl()
            this.wsManager = new WebSocketManager(wsBase)
            if (wsType) {
              this.wsManager.connect(wsType, {
                onMessage: (msg) => {
                  if (!msg) return
                  // 统一显示进度
                  if (typeof msg.progress === 'number') {
                    this.bgLoading = {
                      active: true,
                      percent: Math.max(0, Math.min(100, msg.progress)),
                      text: msg.text || this.bgLoading.text
                    }
                  }

                  if (msg.status === 'success') {
                    const data = msg.data || {}
                    this.regressionStatus = { ...(data || {}), refreshing: false }
                    this.regressionLines = (data && data.lines) || []
                    this.bgLoading = { active: false, percent: 100, text: '报告生成完成' }
                    try { this.wsManager.disconnect(wsType) } catch (e) {}
                  } else if (msg.status === 'failed') {
                    this.regressionStatus = { refreshing: false, errorMsg: msg.errorMsg || '回归计算失败' }
                    this.regressionLines = []
                    this.bgLoading = { active: false, percent: 100, text: '报告生成完成' }
                    try { this.wsManager.disconnect(wsType) } catch (e) {}
                  } else {
                    // running
                    this.regressionStatus = { refreshing: true, ...this.regressionStatus }
                  }
                }
              })
            } else {
              // wsType 缺失：退化为不展示回归
              this.regressionStatus = {}
              this.regressionLines = []
            }
          } catch (e) {
            console.warn('加载理论节拍回归失败（不影响主报表）', e)
            this.regressionStatus = {}
            this.regressionLines = []
          }

          this.loadStage = 'done'
          this.loadMessage = ''
          this.bgLoading = { active: false, percent: 100, text: '报告生成完成' }
        } catch (e) {
          console.error('加载 OEE 报表数据失败', e)
        } finally {
          this.loading = false
          this.$nextTick(() => {
            typesetMath()
            this.renderCharts()
          })
        }
      },
      buildTrendData() {
        // 统一 X 轴日期：取所有产线 daily 的 statDate 并去重排序
        const set = new Set()
        this.summaryLines.forEach(l => {
          ;(l.daily || []).forEach(d => {
            if (d && d.statDate) set.add(d.statDate)
          })
        })
        this.trendDates = Array.from(set).sort()
      },
      disposeCharts() {
        if (this.charts.oee) {
          this.charts.oee.dispose()
          this.charts.oee = null
        }
        if (this.charts.apq) {
          this.charts.apq.dispose()
          this.charts.apq = null
        }
      },
      renderCharts() {
        if (!this.trendDates || this.trendDates.length === 0) return
        if (!this.$refs.oeeTrendChart || !this.$refs.apqTrendChart) return

        // init
        if (!this.charts.oee) {
          this.charts.oee = echarts.init(this.$refs.oeeTrendChart)
        }
        if (!this.charts.apq) {
          this.charts.apq = echarts.init(this.$refs.apqTrendChart)
        }

        // 样式池：纯黑线+不同线型/点形状，用于区分所有图例
        const stylePool = [
          { lineType: 'solid',  symbol: 'circle' },
          { lineType: 'dashed', symbol: 'rect' },
          { lineType: 'dotted', symbol: 'triangle' },
          { lineType: 'solid',  symbol: 'diamond' },
          { lineType: 'dashed', symbol: 'pin' },
          { lineType: 'dotted', symbol: 'arrow' }
        ]
        let styleIndex = 0
        const nextStyle = () => {
          const s = stylePool[styleIndex % stylePool.length]
          styleIndex += 1
          return s
        }

        const buildSeries = (key, nameSuffix) => {
          return this.summaryLines.map(line => {
            const dailyMap = new Map((line.daily || []).map(d => [d.statDate, d]))
            const style = nextStyle()
            return {
              name: `${line.lineName}${nameSuffix}`,
              type: 'line',
              smooth: false,
               symbol: style.symbol,
               lineStyle: { type: style.lineType },
               itemStyle: { color: '#000000' },
              data: this.trendDates.map(dt => {
                const d = dailyMap.get(dt) || {}
                const v = d[key]
                if (v === null || v === undefined || isNaN(v)) return null
                const n = Number(v)
                return n <= 1 ? +(n * 100).toFixed(3) : +n.toFixed(3)
              })
            }
          })
        }

        this.charts.oee.setOption({
          grid: { left: 12, right: 16, top: 36, bottom: 18, containLabel: true },
          tooltip: { trigger: 'axis' },
          legend: { top: 6 },
          xAxis: { type: 'category', data: this.trendDates },
          yAxis: { type: 'value', axisLabel: { formatter: '{value}%' } },
          series: buildSeries('oee', '')
        })

        const apqSeries = [
          ...buildSeries('availability', ' A'),
          ...buildSeries('performance', ' P'),
          ...buildSeries('quality', ' Q')
        ]
        this.charts.apq.setOption({
          grid: { left: 12, right: 16, top: 36, bottom: 18, containLabel: true },
          tooltip: { trigger: 'axis' },
          legend: { top: 6, type: 'scroll' },
          xAxis: { type: 'category', data: this.trendDates },
          yAxis: { type: 'value', axisLabel: { formatter: '{value}%' } },
          series: apqSeries
        })

        // resize once
        this.charts.oee.resize()
        this.charts.apq.resize()
      },
      async handleExportWord() {
        const params = this.buildQueryParams()
        // 统一文件名：OEE_yyyyMMdd_yyyyMMdd.docx
        const filename = `OEE_${(params.startDate || '').replace(/-/g, '')}_${(params.endDate || '').replace(/-/g, '')}.docx`
        try {
          const blobData = await exportOeeWord(params)
          // request.js 对 blob 会直接返回 res.data，这里 blobData 就是 Blob/ArrayBuffer
          const blob = blobData instanceof Blob ? blobData : new Blob([blobData])
          const link = document.createElement('a')
          link.href = URL.createObjectURL(blob)
          link.download = filename
          document.body.appendChild(link)
          link.click()
          document.body.removeChild(link)
          URL.revokeObjectURL(link.href)
        } catch (e) {
          console.error('导出 Word 失败', e)
        }
      },
      formatPercent(value) {
        if (value === null || value === undefined || isNaN(value)) {
          return ''
        }
        let v = Number(value)
        if (v <= 1) {
          v = v * 100
        }
        return v.toFixed(3) + '%'
      },
      formatHours(min) {
        if (min === null || min === undefined || min === '') return ''
        const v = Number(min)
        if (isNaN(v)) return ''
        return (v / 60).toFixed(2)
      }
    }
  }
  </script>
  
  <style lang="scss" scoped>
  .oee-report-page {
    display: flex;
    padding: 16px 24px;
    box-sizing: border-box;
    background: #f5f7fa;
    font-family: 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, 'Segoe UI',
      'Helvetica Neue', Arial, sans-serif;
  }
  
  .oee-report-main {
    flex: 1;
    background: #ffffff;
    padding: 24px 28px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
    border-radius: 4px;
    margin-right: 16px;
  }

  .oee-loading-main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .oee-loading-card {
    max-width: 520px;
    padding: 24px 28px;
    background: #ffffff;
    border-radius: 4px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
    text-align: left;
  }

  .oee-loading-title {
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 8px;
  }

  .oee-loading-text {
    font-size: 13px;
    color: #606266;
    line-height: 1.6;
    margin-bottom: 12px;
  }
  
  .oee-report-header {
    border-bottom: 1px solid #ebeef5;
    padding-bottom: 12px;
    margin-bottom: 16px;
  }
  
  .oee-report-meta {
    display: flex;
    justify-content: flex-start;
    column-gap: 24px;
    font-size: 12px;
    color: #606266;
    margin-bottom: 6px;
  }
  
  .oee-report-query-form {
    display: flex;
    justify-content: flex-end;
  }
  
  .oee-section {
    margin-top: 18px;
  }
  
  .oee-section-title {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 8px;
  }

  .oee-charts {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .oee-chart-card {
    border: 1px solid #ebeef5;
    border-radius: 4px;
    padding: 10px 12px;
  }

  .oee-chart-title {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 6px;
  }

  .oee-chart {
    width: 100%;
    height: 260px;
  }
  
  .oee-paragraph {
    font-size: 13px;
    line-height: 1.6;
    color: #606266;
    margin-bottom: 8px;
  }
  
  .oee-subsection {
    margin-top: 10px;
  }
  
  .oee-subsection-title {
    font-size: 14px;
    font-weight: 500;
    margin-bottom: 6px;
  }
  
  .oee-kpi-table,
  .oee-daily-table,
  .oee-loss-table,
  .oee-events-table {
    font-size: 12px;
  }
  
  .oee-report-aside {
    width: 320px;
    position: sticky;
    top: 72px;
    align-self: flex-start;
  }
  
  .oee-formula-card {
    background: #ffffff;
    padding: 16px 18px;
    border-radius: 4px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  }
  
  .oee-formula-title {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 8px;
  }
  
  .oee-formula-body {
    font-size: 12px;
    color: #606266;
  }
  
  .oee-formula-caption {
    margin-top: 10px;
    margin-bottom: 2px;
    font-weight: 500;
  }
  
  .math-block {
    margin: 4px 0;
  }
  
  .oee-formula-footnote {
    margin-top: 10px;
    font-size: 11px;
    color: #909399;
  }

  .oee-bg-progress {
    margin-top: 8px;
    width: 100%;
  }

  .oee-bg-progress-text {
    margin-top: 4px;
    font-size: 12px;
    color: #909399;
  }

  /* 让进度数字在条外侧显示，避免被遮挡 */
  .oee-bg-progress :deep(.el-progress__text) {
    margin-left: 8px;
    color: #606266;
    font-weight: 500;
  }

  .oee-regression-item {
    padding: 8px 0;
    border-top: 1px dashed #ebeef5;
  }

  .oee-regression-title {
    font-weight: 600;
    margin-bottom: 4px;
  }

  .oee-regression-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 12px;
  }
  </style>
  
  