<template>
  <div v-loading="loading" class="app-container line-report">
    <!-- 查询条件 -->
    <div class="filter-area">
      <el-form label-width="70px" inline class="filter-form">
        <el-form-item label="产线">
          <el-select v-model="actionTypes" style="width: 150px;" placeholder="产线" clearable size="small" @change="handleQuery">
            <el-option label="全部" value="" />
            <el-option v-for="line in lineOptions" :key="line.value" :label="line.label" :value="line.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="品质">
          <muti-select
            v-model="queryParams.qualityStatusCsv"
            :options="dict.type.coil_quality_status"
            placeholder="品质"
            clearable
            style="width: 150px;"
            size="small"
          />
        </el-form-item>
        <el-form-item label="规格">
          <memo-input
            v-model="queryParams.itemSpecification"
            style="width: 130px;"
            storage-key="coilSpec"
            placeholder="规格"
            clearable
            size="small"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="材质">
          <muti-select
            v-model="queryParams.itemMaterial"
            style="width: 150px;"
            :options="dict.type.coil_material"
            placeholder="材质"
            clearable
            size="small"
          />
        </el-form-item>
        <el-form-item label="厂家">
          <muti-select
            v-model="queryParams.itemManufacturer"
            style="width: 150px;"
            :options="dict.type.coil_manufacturer"
            placeholder="厂家"
            clearable
            size="small"
          />
        </el-form-item>
        <el-form-item label="入场号">
          <el-input
            v-model="queryParams.enterCoilNo"
            style="width: 150px;"
            placeholder="入场钢卷号"
            clearable
            size="small"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
      </el-form>
      <div class="time-row">
        <span class="time-label">时间范围</span>
        <el-date-picker
          v-model="startTime"
          style="width: 170px;"
          type="datetime"
          value-format="yyyy-MM-dd HH:mm:ss"
          placeholder="开始"
          size="small"
        />
        <span class="time-sep">—</span>
        <el-date-picker
          v-model="endTime"
          style="width: 170px;"
          type="datetime"
          value-format="yyyy-MM-dd HH:mm:ss"
          placeholder="结束"
          size="small"
        />
        <span class="time-label period-label">周期</span>
        <el-select v-model="periodType" style="width: 90px;" size="small" @change="recalcPeriod">
          <el-option label="按日" value="day" />
          <el-option label="按周" value="week" />
          <el-option label="按月" value="month" />
        </el-select>
        <el-button-group size="small" class="quick-btns">
          <el-button @click="setQuickPeriod('thisMonth')">本月</el-button>
          <el-button @click="setQuickPeriod('lastMonth')">上月</el-button>
          <el-button @click="setQuickPeriod('thisQuarter')">本季</el-button>
          <el-button @click="setQuickPeriod('thisYear')">今年</el-button>
          <el-button @click="setQuickPeriod('lastYear')">去年</el-button>
        </el-button-group>
        <el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">查询</el-button>
      </div>
    </div>

    <!-- 口径说明 -->
    <div class="explain-bar">
      <span class="explain-icon">i</span>
      <span class="explain-text">
        <strong>统计口径：</strong>按{{ periodLabel }}周期拆分，统计各期产出量与消耗量。
        <span class="explain-divider" />
        <strong>M卷定义：</strong>钢卷经部分加工后剩余部分返回原料库并重新编号，新钢卷号中包含字母"M"（且"M"不在前5位）的钢卷定义为M卷，不计入产出统计。
        <span class="explain-divider" />
        <strong>成品率</strong> = 产出总重 / 消耗总重 × 100%
        <strong>正品率</strong> = (1 - 异常率) × 100%
        <strong>损耗率</strong> = 1 - 成品率
        <strong>异常率</strong> = (异常库位钢卷数 + 特殊品质状态钢卷数) / 产出总数 × 100%
      </span>
    </div>

    <!-- 周期数据摘要 -->
    <div v-if="periodData.length > 0" class="summary-bar">
      <div class="summary-item">
        <span class="summary-label">周期数</span>
        <span class="summary-value">{{ periodData.length }}</span>
      </div>
      <div class="summary-item">
        <span class="summary-label">产出合计</span>
        <span class="summary-value">{{ totalOutCount }}卷 / {{ totalOutWeight }}t</span>
      </div>
      <div class="summary-item">
        <span class="summary-label">消耗合计</span>
        <span class="summary-value">{{ totalLossCount }}卷 / {{ totalLossWeight }}t</span>
      </div>
    </div>

    <!-- 折线图区域 -->
    <div class="chart-grid">
      <div v-for="(cfg, idx) in chartConfigs" :key="idx" class="chart-group">
        <div class="group-title">{{ cfg.title }}</div>
        <div :ref="'chart_' + idx" class="chart-container" :style="{ height: cfg.height || '280px' }" />
      </div>
    </div>

    <!-- 明细表格 -->
    <div v-if="periodData.length > 0" class="detail-section">
      <div class="group-title">各期明细</div>
      <div class="table-wrapper">
        <el-table :data="periodData" border size="small" stripe height="400px" style="width: 100%">
          <el-table-column prop="periodLabel" label="周期" min-width="100" fixed />
          <el-table-column label="产出统计" align="center">
            <el-table-column prop="outCount" label="数量" min-width="70" />
            <el-table-column prop="outTotalWeight" label="总重(t)" min-width="90" />
            <el-table-column prop="outAvgWeight" label="均重(t)" min-width="90" />
          </el-table-column>
          <el-table-column label="消耗统计" align="center">
            <el-table-column prop="lossCount" label="数量" min-width="70" />
            <el-table-column prop="lossTotalWeight" label="总重(t)" min-width="90" />
            <el-table-column prop="lossAvgWeight" label="均重(t)" min-width="90" />
          </el-table-column>
          <el-table-column label="品质比率" align="center">
            <el-table-column prop="passRate" label="成品率" min-width="75" />
            <el-table-column prop="passRate2" label="正品率" min-width="75" />
            <el-table-column prop="lossRate" label="损耗率" min-width="75" />
            <el-table-column prop="abRate" label="异常率" min-width="75" />
          </el-table-column>
          <el-table-column label="M卷统计" align="center">
            <el-table-column prop="mOutCount" label="产出数量" min-width="70" />
            <el-table-column prop="mOutTotalWeight" label="产出总重(t)" min-width="90" />
            <el-table-column prop="mOutAvgWeight" label="产出均重(t)" min-width="90" />
            <el-table-column prop="mLossCount" label="消耗数量" min-width="70" />
            <el-table-column prop="mLossTotalWeight" label="消耗总重(t)" min-width="90" />
            <el-table-column prop="mLossAvgWeight" label="消耗均重(t)" min-width="90" />
            <el-table-column prop="mPassRate" label="成品率" min-width="75" />
            <el-table-column prop="mLossRate" label="损耗率" min-width="75" />
            <el-table-column prop="mPassRate2" label="正品率" min-width="75" />
            <el-table-column prop="mAbRate" label="异常率" min-width="75" />
          </el-table-column>
          <el-table-column label="异常库位" align="center">
            <el-table-column prop="abTechCount" label="技术部" min-width="70" />
            <el-table-column prop="abMiniCount" label="小钢卷库" min-width="75" />
            <el-table-column prop="abRubbishCount" label="废品库" min-width="70" />
            <el-table-column prop="abReturnCount" label="退货库" min-width="70" />
            <el-table-column prop="abTechRate" label="技术部占比" min-width="85" />
            <el-table-column prop="abMiniRate" label="小钢卷占比" min-width="85" />
            <el-table-column prop="abRubbishRate" label="废品库占比" min-width="85" />
            <el-table-column prop="abReturnRate" label="退货库占比" min-width="85" />
          </el-table-column>
          <el-table-column label="M异常库位" align="center">
            <el-table-column prop="mAbTechCount" label="技术部" min-width="70" />
            <el-table-column prop="mAbMiniCount" label="小钢卷库" min-width="75" />
            <el-table-column prop="mAbRubbishCount" label="废品库" min-width="70" />
            <el-table-column prop="mAbReturnCount" label="退货库" min-width="70" />
            <el-table-column prop="mAbTechRate" label="技术部占比" min-width="85" />
            <el-table-column prop="mAbMiniRate" label="小钢卷占比" min-width="85" />
            <el-table-column prop="mAbRubbishRate" label="废品库占比" min-width="85" />
            <el-table-column prop="mAbReturnRate" label="退货库占比" min-width="85" />
          </el-table-column>
        </el-table>
      </div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import { listLightCoil } from '@/api/wms/coil'
import { listLightPendingAction } from '@/api/wms/pendingAction'
import MemoInput from '@/components/MemoInput'
import MutiSelect from '@/components/MutiSelect'
import { calcSummary, calcMSummary, calcAbSummary } from '@/views/wms/report/js/calc'

export default {
  name: 'LineReport',
  components: { MemoInput, MutiSelect },
  dicts: ['coil_material', 'coil_manufacturer', 'coil_quality_status'],
  data() {
    const addZero = (num) => num.toString().padStart(2, '0')
    const now = new Date()
    const monthStart = `${now.getFullYear()}-${addZero(now.getMonth() + 1)}-01 00:00:00`
    const monthEnd = `${now.getFullYear()}-${addZero(now.getMonth() + 1)}-${addZero(now.getDate())} 23:59:59`

    return {
      chartInstances: [],
      loading: false,
      startTime: monthStart,
      endTime: monthEnd,
      periodType: 'day',
      queryParams: {
        enterCoilNo: '', currentCoilNo: '', itemName: '', itemSpecification: '',
        itemMaterial: '', itemManufacturer: '', qualityStatusCsv: ''
      },
      actionTypes: '',
      lineOptions: [
        { label: '酸轧线', value: '11,120,201,520' }, { label: '镀锌线', value: '202,501,521' },
        { label: '双机架', value: '205,504,524' }, { label: '镀铬线', value: '206,505,525' },
        { label: '拉矫线', value: '204,503,523' }, { label: '脱脂线', value: '203,502,522' }
      ],
      allOutList: [],
      allLossList: [],
      periodData: []
    }
  },
  computed: {
    periodLabel() {
      const map = { day: '日', week: '周', month: '月' }
      return map[this.periodType] || '日'
    },
    totalOutCount() {
      return this.periodData.reduce((s, i) => s + (i.outCount || 0), 0)
    },
    totalOutWeight() {
      return this.periodData.reduce((s, i) => s + (parseFloat(i.outTotalWeight) || 0), 0).toFixed(2)
    },
    totalLossCount() {
      return this.periodData.reduce((s, i) => s + (i.lossCount || 0), 0)
    },
    totalLossWeight() {
      return this.periodData.reduce((s, i) => s + (parseFloat(i.lossTotalWeight) || 0), 0).toFixed(2)
    },
    chartConfigs() {
      return [
        // ====== Row 1: 数量/总重 ======
        {
          title: '产出与消耗数量/总重',
          series: [
            { key: 'outCount', label: '产出数量(卷)', color: '#409eff', yAxisIndex: 0 },
            { key: 'lossCount', label: '消耗数量(卷)', color: '#f56c6c', yAxisIndex: 0 },
            { key: 'outTotalWeight', label: '产出总重(t)', color: '#67c23a', yAxisIndex: 1 },
            { key: 'lossTotalWeight', label: '消耗总重(t)', color: '#909399', yAxisIndex: 1 }
          ],
          yAxis: [
            { type: 'value', name: '数量(卷)' },
            { type: 'value', name: '重量(t)' }
          ],
          height: '280px'
        },
        {
          title: 'M-卷产出与消耗数量/总重',
          series: [
            { key: 'mOutCount', label: 'M-产出数量(卷)', color: '#409eff', yAxisIndex: 0 },
            { key: 'mLossCount', label: 'M-消耗数量(卷)', color: '#f56c6c', yAxisIndex: 0 },
            { key: 'mOutTotalWeight', label: 'M-产出总重(t)', color: '#67c23a', yAxisIndex: 1 },
            { key: 'mLossTotalWeight', label: 'M-消耗总重(t)', color: '#909399', yAxisIndex: 1 }
          ],
          yAxis: [
            { type: 'value', name: '数量(卷)' },
            { type: 'value', name: '重量(t)' }
          ],
          height: '280px'
        },
        // ====== Row 2: 均重 ======
        {
          title: '产出与消耗均重',
          series: [
            { key: 'outAvgWeight', label: '产出均重(t)', color: '#e6a23c' },
            { key: 'lossAvgWeight', label: '消耗均重(t)', color: '#b37feb' }
          ],
          yAxis: [{ type: 'value', name: '均重(t)' }],
          height: '280px'
        },
        {
          title: 'M-卷均重',
          series: [
            { key: 'mOutAvgWeight', label: 'M-产出均重(t)', color: '#e6a23c' },
            { key: 'mLossAvgWeight', label: 'M-消耗均重(t)', color: '#b37feb' }
          ],
          yAxis: [{ type: 'value', name: '均重(t)' }],
          height: '280px'
        },
        // ====== Row 3: 品质比率 ======
        {
          title: '品质比率',
          series: [
            { key: 'passRate', label: '成品率', color: '#67c23a', percent: true },
            { key: 'passRate2', label: '正品率', color: '#409eff', percent: true },
            { key: 'lossRate', label: '损耗率', color: '#f56c6c', percent: true },
            { key: 'abRate', label: '异常率', color: '#e6a23c', percent: true }
          ],
          yAxis: [{ type: 'value', name: '%', axisLabel: { formatter: '{value}%' }}],
          height: '280px'
        },
        {
          title: 'M-卷品质比率',
          series: [
            { key: 'mPassRate', label: 'M-成品率', color: '#67c23a', percent: true },
            { key: 'mPassRate2', label: 'M-正品率', color: '#409eff', percent: true },
            { key: 'mLossRate', label: 'M-损耗率', color: '#f56c6c', percent: true },
            { key: 'mAbRate', label: 'M-异常率', color: '#e6a23c', percent: true }
          ],
          yAxis: [{ type: 'value', name: '%', axisLabel: { formatter: '{value}%' }}],
          height: '280px'
        },
        // ====== Row 4: 异常库位 ======
        {
          title: '异常库位分布（钢卷数与占比）',
          series: [
            { key: 'abTechCount', label: '技术部', color: '#409eff', yAxisIndex: 0 },
            { key: 'abMiniCount', label: '小钢卷库', color: '#67c23a', yAxisIndex: 0 },
            { key: 'abRubbishCount', label: '废品库', color: '#e6a23c', yAxisIndex: 0 },
            { key: 'abReturnCount', label: '退货库', color: '#f56c6c', yAxisIndex: 0 },
            { key: 'abTechRate', label: '技术部占比', color: '#409eff', yAxisIndex: 1, percent: true, dash: true },
            { key: 'abMiniRate', label: '小钢卷占比', color: '#67c23a', yAxisIndex: 1, percent: true, dash: true },
            { key: 'abRubbishRate', label: '废品库占比', color: '#e6a23c', yAxisIndex: 1, percent: true, dash: true },
            { key: 'abReturnRate', label: '退货库占比', color: '#f56c6c', yAxisIndex: 1, percent: true, dash: true }
          ],
          yAxis: [
            { type: 'value', name: '钢卷数' },
            { type: 'value', name: '占比(%)', axisLabel: { formatter: '{value}%' }}
          ],
          height: '280px'
        },
        {
          title: 'M-异常库位分布（钢卷数与占比）',
          series: [
            { key: 'mAbTechCount', label: '技术部', color: '#409eff', yAxisIndex: 0 },
            { key: 'mAbMiniCount', label: '小钢卷库', color: '#67c23a', yAxisIndex: 0 },
            { key: 'mAbRubbishCount', label: '废品库', color: '#e6a23c', yAxisIndex: 0 },
            { key: 'mAbReturnCount', label: '退货库', color: '#f56c6c', yAxisIndex: 0 },
            { key: 'mAbTechRate', label: '技术部占比', color: '#409eff', yAxisIndex: 1, percent: true, dash: true },
            { key: 'mAbMiniRate', label: '小钢卷占比', color: '#67c23a', yAxisIndex: 1, percent: true, dash: true },
            { key: 'mAbRubbishRate', label: '废品库占比', color: '#e6a23c', yAxisIndex: 1, percent: true, dash: true },
            { key: 'mAbReturnRate', label: '退货库占比', color: '#f56c6c', yAxisIndex: 1, percent: true, dash: true }
          ],
          yAxis: [
            { type: 'value', name: '钢卷数' },
            { type: 'value', name: '占比(%)', axisLabel: { formatter: '{value}%' }}
          ],
          height: '280px'
        }
      ]
    }
  },
  watch: {
    periodData: {
      deep: true,
      handler() {
        this.$nextTick(() => this.renderCharts())
      }
    }
  },
  created() {
    this.handleQuery()
  },
  mounted() {
    this.$nextTick(() => this.renderCharts())
  },
  beforeDestroy() {
    this.disposeCharts()
  },
  methods: {
    // ====== 时间快捷选择 ======
    setQuickPeriod(type) {
      const now = new Date(); const addZero = n => n.toString().padStart(2, '0')
      const fd = d => `${d.getFullYear()}-${addZero(d.getMonth() + 1)}-${addZero(d.getDate())}`
      switch (type) {
        case 'thisMonth':
          this.startTime = `${fd(new Date(now.getFullYear(), now.getMonth(), 1))} 00:00:00`
          this.endTime = `${fd(now)} 23:59:59`
          this.periodType = 'day'
          break
        case 'lastMonth': {
          const lm = new Date(now.getFullYear(), now.getMonth() - 1, 1)
          const lme = new Date(now.getFullYear(), now.getMonth(), 0)
          this.startTime = `${fd(lm)} 00:00:00`
          this.endTime = `${fd(lme)} 23:59:59`
          this.periodType = 'day'
          break
        }
        case 'thisQuarter': {
          const qs = Math.floor(now.getMonth() / 3) * 3
          this.startTime = `${fd(new Date(now.getFullYear(), qs, 1))} 00:00:00`
          this.endTime = `${fd(now)} 23:59:59`
          this.periodType = 'month'
          break
        }
        case 'thisYear':
          this.startTime = `${now.getFullYear()}-01-01 00:00:00`
          this.endTime = `${fd(now)} 23:59:59`
          this.periodType = 'month'
          break
        case 'lastYear':
          this.startTime = `${now.getFullYear() - 1}-01-01 00:00:00`
          this.endTime = `${now.getFullYear() - 1}-12-31 23:59:59`
          this.periodType = 'month'
          break
      }
      this.handleQuery()
    },

    // ====== 数据获取 ======
    handleQuery() {
      this.fetchData()
    },
    // 切换周期类型时仅前端重新汇总，无需重新请求接口
    recalcPeriod() {
      if (this.allOutList.length === 0 && this.allLossList.length === 0) return
      this.disposeCharts()
      this.chartInstances = []
      this.splitByPeriod()
      this.$nextTick(() => this.renderCharts())
    },
    async fetchData() {
      this.loading = true
      this.disposeCharts()
      this.chartInstances = []
      this.periodData = []

      try {
        const baseQuery = {
          enterCoilNo: this.queryParams.enterCoilNo,
          currentCoilNo: this.queryParams.currentCoilNo,
          itemName: this.queryParams.itemName,
          itemSpecification: this.queryParams.itemSpecification,
          itemMaterial: this.queryParams.itemMaterial,
          itemManufacturer: this.queryParams.itemManufacturer,
          qualityStatusCsv: this.queryParams.qualityStatusCsv
        }

        // 1. 获取整个时间范围内的所有待处理操作
        const actionRes = await listLightPendingAction({
          ...baseQuery,
          startTime: this.startTime,
          endTime: this.endTime,
          actionTypes: this.actionTypes,
          actionStatus: 2
        })

        const actions = actionRes.data || []
        if (actions.length === 0) {
          this.loading = false
          return
        }

        // 2. 提取产出和消耗的钢卷ID
        const outIds = actions.map(i => i.processedCoilIds).filter(Boolean).join(',')
        const lossIds = actions.filter(i => i.coilId).map(i => i.coilId).join(',')

        if (!outIds) {
          this.loading = false
          return
        }

        // 3. 批量获取产出和消耗钢卷数据
        const mapItems = list => (list || []).map(item => {
          const [th, w] = item.specification?.split('*') || []
          return { ...item, computedThickness: parseFloat(th), computedWidth: parseFloat(w) }
        })

        const [outRes, lossRes] = await Promise.all([
          listLightCoil({
            ...baseQuery, coilIds: outIds, startTime: '', endTime: '',
            selectType: 'product', pageSize: 99999, pageNum: 1
          }),
          lossIds ? listLightCoil({
            ...baseQuery, coilIds: lossIds, startTime: '', endTime: '',
            selectType: 'raw_material', pageSize: 99999, pageNum: 1
          }) : Promise.resolve({ data: [] })
        ])

        this.allOutList = mapItems(outRes)
        this.allLossList = mapItems(lossRes)

        // 4. 按周期拆分数据
        this.splitByPeriod()

        // 5. 渲染图表
        this.$nextTick(() => this.renderCharts())
      } catch (e) {
        console.error('数据获取失败:', e)
        this.$message.error('数据获取失败')
      }

      this.loading = false
    },

    // ====== 周期拆分 ======
    splitByPeriod() {
      const periods = this.generatePeriods()
      this.periodData = periods.map(p => {
        const st = p.start.getTime(); const et = p.end.getTime()

        const outList = this.allOutList.filter(c => {
          const t = new Date(c.createTime || c.createDate).getTime()
          return t >= st && t <= et
        })
        const lossList = this.allLossList.filter(c => {
          const t = new Date(c.createTime || c.createDate).getTime()
          return t >= st && t <= et
        })

        const summary = calcSummary(outList, lossList)
        const mSummary = calcMSummary(outList, lossList)
        const abSummary = calcAbSummary(outList)
        const abMap = {}
        abSummary.forEach(i => { abMap[i.label] = i.value })
        // M-异常库位（处理M后的非M卷产出）
        const isMcoil = c => c.currentCoilNo && c.currentCoilNo.includes('M') && c.currentCoilNo.indexOf('M') > 4
        const nonMOut = outList.filter(c => !isMcoil(c))
        const mAbSummary = calcAbSummary(nonMOut)
        const mAbMap = {}
        mAbSummary.forEach(i => { mAbMap[i.label] = i.value })

        return {
          periodLabel: p.label,
          // 基础统计
          ...summary,
          // M卷统计
          mOutCount: mSummary.outCount,
          mOutTotalWeight: mSummary.outTotalWeight,
          mLossCount: mSummary.lossCount,
          mLossTotalWeight: mSummary.lossTotalWeight,
          mOutAvgWeight: mSummary.outAvgWeight,
          mLossAvgWeight: mSummary.lossAvgWeight,
          mPassRate: mSummary.passRate,
          mLossRate: mSummary.lossRate,
          mPassRate2: mSummary.passRate2,
          mAbRate: mSummary.abRate,
          // 异常库位统计
          abTechCount: abMap['技术部钢卷数'] || 0,
          abMiniCount: abMap['小钢卷库钢卷数'] || 0,
          abRubbishCount: abMap['废品库钢卷数'] || 0,
          abReturnCount: abMap['退货库钢卷数'] || 0,
          abTechRate: abMap['技术部占比'] || '0.00%',
          abMiniRate: abMap['小钢卷库占比'] || '0.00%',
          abRubbishRate: abMap['废品库占比'] || '0.00%',
          abReturnRate: abMap['退货库占比'] || '0.00%',
          // M异常库位统计
          mAbTechCount: mAbMap['技术部钢卷数'] || 0,
          mAbMiniCount: mAbMap['小钢卷库钢卷数'] || 0,
          mAbRubbishCount: mAbMap['废品库钢卷数'] || 0,
          mAbReturnCount: mAbMap['退货库钢卷数'] || 0,
          mAbTechRate: mAbMap['技术部占比'] || '0.00%',
          mAbMiniRate: mAbMap['小钢卷库占比'] || '0.00%',
          mAbRubbishRate: mAbMap['废品库占比'] || '0.00%',
          mAbReturnRate: mAbMap['退货库占比'] || '0.00%'
        }
      })
    },
    generatePeriods() {
      const periods = []
      const start = new Date(this.startTime)
      const end = new Date(this.endTime)

      if (this.periodType === 'day') {
        const endMs = end.getTime()
        const cur = new Date(start)
        while (cur.getTime() <= endMs) {
          const dayEnd = new Date(cur)
          dayEnd.setHours(23, 59, 59, 999)
          periods.push({
            label: `${cur.getFullYear()}-${String(cur.getMonth() + 1).padStart(2, '0')}-${String(cur.getDate()).padStart(2, '0')}`,
            start: new Date(cur),
            end: new Date(Math.min(dayEnd.getTime(), endMs))
          })
          cur.setDate(cur.getDate() + 1)
          cur.setHours(0, 0, 0, 0)
        }
      } else if (this.periodType === 'week') {
        const endMs = end.getTime()
        const cur = new Date(start)
        const day = cur.getDay()
        const diff = day === 0 ? -6 : 1 - day
        cur.setDate(cur.getDate() + diff)
        cur.setHours(0, 0, 0, 0)

        while (cur.getTime() <= endMs) {
          const weekEnd = new Date(cur)
          weekEnd.setDate(weekEnd.getDate() + 6)
          weekEnd.setHours(23, 59, 59, 999)
          periods.push({
            label: `${cur.getFullYear()}-W${this.getWeekNumber(cur)}`,
            start: new Date(Math.max(cur.getTime(), start.getTime())),
            end: new Date(Math.min(weekEnd.getTime(), endMs))
          })
          cur.setDate(cur.getDate() + 7)
        }
      } else if (this.periodType === 'month') {
        const endMs = end.getTime()
        const cur = new Date(start.getFullYear(), start.getMonth(), 1)
        while (cur.getTime() <= endMs) {
          const monthEnd = new Date(cur.getFullYear(), cur.getMonth() + 1, 0, 23, 59, 59, 999)
          periods.push({
            label: `${cur.getFullYear()}-${String(cur.getMonth() + 1).padStart(2, '0')}`,
            start: new Date(Math.max(cur.getTime(), start.getTime())),
            end: new Date(Math.min(monthEnd.getTime(), endMs))
          })
          cur.setMonth(cur.getMonth() + 1)
        }
      }

      return periods
    },
    getWeekNumber(d) {
      const temp = new Date(d.getFullYear(), d.getMonth(), d.getDate())
      temp.setDate(temp.getDate() + 3 - (temp.getDay() + 6) % 7)
      const week1 = new Date(temp.getFullYear(), 0, 4)
      return Math.round(((temp - week1) / 86400000 + week1.getDay() + 1) / 7)
    },

    // ====== 图表渲染 ======
    renderCharts() {
      this.disposeCharts()
      if (this.periodData.length === 0) return

      const xLabels = this.periodData.map(p => p.periodLabel)

      this.chartConfigs.forEach((cfg, idx) => {
        const dom = this.$refs['chart_' + idx]
        if (!dom || !dom[0]) return

        const chart = echarts.init(dom[0])
        this.chartInstances.push(chart)

        const yAxis = cfg.yAxis || [{ type: 'value' }]
        const series = cfg.series.map(s => ({
          name: s.label,
          type: 'line',
          smooth: true,
          symbol: s.dash ? 'diamond' : 'circle',
          symbolSize: 6,
          lineStyle: { width: 2, color: s.color, type: s.dash ? 'dashed' : 'solid' },
          itemStyle: { color: s.color },
          yAxisIndex: s.yAxisIndex || 0,
          data: this.periodData.map(p => {
            const raw = p[s.key]
            if (s.percent) {
              return parseFloat(raw || '0') || 0
            }
            return raw !== undefined && raw !== null ? parseFloat(raw) || raw : 0
          })
        }))

        const option = {
          tooltip: {
            trigger: 'axis',
            formatter: function(params) {
              let html = params[0].axisValue + '<br/>'
              params.forEach(p => {
                const val = typeof p.value === 'number' ? p.value.toFixed(2) : p.value
                html += p.marker + ' ' + p.seriesName + '：' + val + '<br/>'
              })
              return html
            }
          },
          legend: { data: cfg.series.map(s => s.label), top: 5 },
          grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
          xAxis: { type: 'category', data: xLabels, axisLabel: { rotate: xLabels.length > 15 ? 45 : 0, fontSize: 11 }},
          yAxis: yAxis,
          dataZoom: [
            { type: 'inside', start: 0, end: 100 },
            { type: 'slider', start: 0, end: 100, height: 20, bottom: 5 }
          ],
          series: series
        }

        chart.setOption(option)

        const handler = () => chart.resize()
        window.addEventListener('resize', handler)
        chart._resizeHandler = handler
      })
    },
    disposeCharts() {
      this.chartInstances.forEach(chart => {
        if (chart._resizeHandler) {
          window.removeEventListener('resize', chart._resizeHandler)
        }
        chart.dispose()
      })
      this.chartInstances = []
    }
  }
}
</script>

<style scoped>
.line-report { min-width: 900px; }
.filter-area { background: #fff; padding: 8px 12px; margin-bottom: 8px; border-bottom: 1px solid #e4e7ed; }
.filter-form { margin-bottom: 0; }
.filter-form .el-form-item { margin-bottom: 6px; margin-right: 4px; }
.filter-form >>> .el-form-item__label { font-size: 12px; }
.time-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding-top: 6px; border-top: 1px solid #ebeef5; }
.time-label { font-size: 12px; color: #909399; font-weight: 600; white-space: nowrap; }
.period-label { color: #409eff; margin-left: 4px; }
.time-sep { color: #c0c4cc; font-size: 12px; }
.quick-btns { margin-left: auto; }
.explain-bar { display: flex; align-items: flex-start; gap: 6px; padding: 6px 12px; margin-bottom: 8px; background: #f0f9ff; border-radius: 4px; font-size: 12px; color: #606266; line-height: 1.6; }
.explain-icon { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; min-width: 16px; border-radius: 50%; background: #909399; color: #fff; font-size: 11px; font-weight: 700; font-style: normal; margin-top: 2px; }
.explain-text { flex: 1; }
.explain-divider { display: inline-block; width: 0; height: 0; margin: 0 2px; border-left: 1px solid #c0c4cc; }

.summary-bar { display: flex; gap: 16px; padding: 10px 12px; background: #f5f7fa; border-radius: 4px; margin-bottom: 10px; flex-wrap: wrap; }
.summary-item { display: flex; flex-direction: column; align-items: center; min-width: 100px; }
.summary-label { font-size: 12px; color: #909399; white-space: nowrap; }
.summary-value { font-size: 16px; font-weight: 600; color: #303133; margin-top: 2px; white-space: nowrap; }

.chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.group-title { font-size: 13px; font-weight: 600; color: #303133; padding: 5px 0; margin-bottom: 6px; border-bottom: 2px solid #409eff; }
.chart-container { width: 100%; background: #fff; border: 1px solid #ebeef5; border-radius: 4px; }

.detail-section { margin-top: 8px; }
.table-wrapper { overflow-x: auto; }
.detail-section >>> .el-table th { background-color: #f5f7fa; font-size: 12px; }
.detail-section >>> .el-table td { font-size: 12px; }
</style>
