﻿<template>
    <div class="table-box waveform-page">
        <div class="page-header">
            <div class="page-title">波形查看</div>

            <div class="action-row">
                <div class="file-select-row">
                    <el-input
                        :model-value="selectedWaveformFileName"
                        readonly
                        placeholder="请选择同一组.cfg和.dat文件"
                        class="file-input"
                    />
                    <el-button type="primary" :loading="isParsing" @click="openWaveformFilePicker">选择波形</el-button>
                    <input
                        ref="waveformFileInputRef"
                        type="file"
                        :accept="waveformFileAccept"
                        multiple
                        class="waveform-file-input"
                        @change="handleWaveformFileChange"
                    />
                </div>

                <div class="toolbar-actions">
                    <div v-if="channelOptions.length" class="toolbar-item">
                        <div class="toolbar-label">波形通道</div>
                        <el-select v-model="activeChannelIndex" class="channel-select" placeholder="选择通道">
                            <el-option
                                v-for="item in channelOptions"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                            />
                        </el-select>
                    </div>

                    <div class="toolbar-item">
                        <div class="toolbar-label">功能显示</div>
                        <el-select v-model="activeDisplayMode" class="display-mode-select" placeholder="选择显示模式">
                            <el-option
                                v-for="item in displayModeOptions"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                            />
                        </el-select>
                    </div>

                    <div class="toolbar-item">
                        <div class="toolbar-label">数值类型</div>
                        <el-radio-group v-model="activeValueMode" class="value-mode-switch">
                            <el-radio-button
                                v-for="item in valueModeOptions"
                                :key="item.value"
                                :label="item.value"
                            >
                                {{ item.label }}
                            </el-radio-button>
                        </el-radio-group>
                    </div>

                    <el-button type="primary" :icon="Download" :disabled="!hasWaveformData" @click="downloadTrendData">
                        下载数据
                    </el-button>
                </div>
            </div>
        </div>

        <div class="waveform-layout">
            <section class="waveform-panel">
                <div class="panel-header">
                    <el-tabs v-model="activeTrendTab" class="trend-tabs">
                        <el-tab-pane v-for="item in trendTabs" :key="item.value" :label="item.label" :name="item.value" />
                    </el-tabs>
                </div>

                <div class="panel-body">
                    <div v-if="hasWaveformData && activeDisplayMode === 'multi-channel'" class="chart-container">
                        <LineChart :options="activeTrendOptions" />
                    </div>
                    <div v-else-if="hasWaveformData" class="single-channel-list">
                        <div v-for="item in singleChannelTrendOptionsList" :key="item.key" class="single-channel-card">
                            <div class="single-channel-chart">
                                <LineChart :options="item.options" :group="item.group" />
                            </div>
                        </div>
                    </div>
                    <div v-else class="empty-block">
                        <div class="empty-title">暂无波形数据</div>
                        <div class="empty-text">请选择同一组 `.cfg` 和 `.dat` 文件后自动解析并展示。</div>
                        <div v-if="lastParseErrorMessage" class="empty-text error-text">最近一次解析失败：{{ lastParseErrorMessage }}</div>
                    </div>
                </div>
            </section>

            <section class="waveform-panel">
                <div class="panel-header">
                    <div class="section-title">波形信息</div>
                </div>

                <div v-if="hasParsedWaveform" class="panel-body info-body">
                    <div class="panel-tip">当前接口未返回向量图坐标，右侧展示解析摘要与特征值结果。</div>

                    <div class="summary-grid">
                        <div v-for="item in summaryItems" :key="item.label" class="summary-item">
                            <div class="summary-label">{{ item.label }}</div>
                            <div class="summary-value">{{ item.value }}</div>
                        </div>
                    </div>

                    <div class="feature-header">特征值</div>
                    <div v-if="eigenvalueList.length" class="feature-grid">
                        <div v-for="(item, index) in eigenvalueList" :key="index" class="feature-card">
                            <div class="feature-card-title">特征值 {{ index + 1 }}</div>
                            <div class="feature-row">
                                <span>幅值占比</span>
                                <span>{{ formatPercentage(item.amplitude) }}</span>
                            </div>
                            <div class="feature-row">
                                <span>残余电压</span>
                                <span>{{ formatNumber(item.residualVoltage) }}</span>
                            </div>
                            <div class="feature-row">
                                <span>额定电压</span>
                                <span>{{ formatNumber(item.ratedVoltage) }}</span>
                            </div>
                            <div class="feature-row">
                                <span>持续时间</span>
                                <span>{{ formatDuration(item.durationTime) }}</span>
                            </div>
                        </div>
                    </div>
                    <div v-else class="empty-inline">当前文件未返回特征值结果。</div>
                </div>

                <div v-else class="panel-body">
                    <div class="empty-block">
                        <div class="empty-title">暂无解析信息</div>
                        <div class="empty-text">接口联调完成后，右侧会展示波形摘要和特征值。</div>
                        <div v-if="lastParseErrorMessage" class="empty-text error-text">最近一次解析失败：{{ lastParseErrorMessage }}</div>
                    </div>
                </div>
            </section>
        </div>
    </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Download } from '@element-plus/icons-vue'
import LineChart from '@/components/echarts/line/index.vue'
import { parseComtradeApi } from '@/api/tools/waveform'
import type { Waveform } from '@/api/tools/waveform/interface'

defineOptions({
    name: 'WaveformView'
})

type TrendTabValue = 'instant' | 'rms'
type ValueMode = 'primary' | 'secondary'
type DisplayMode = 'single-channel' | 'multi-channel'

interface WaveformDetailOption {
    label: string
    value: number
}

interface WaveformSeriesItem {
    name: string
    data: number[]
}

interface WaveformTrendPayload {
    timeLabels: string[]
    unit: string
    min?: number
    max?: number
    series: WaveformSeriesItem[]
}

interface TrendChartLayoutOptions {
    showTimeAxis?: boolean
}

const activeTrendTab = ref<TrendTabValue>('instant')
const activeValueMode = ref<ValueMode>('primary')
const activeDisplayMode = ref<DisplayMode>('single-channel')
const activeChannelIndex = ref(0)
const singleChannelTrendChartGroup = 'waveform-single-channel-sync'
const isParsing = ref(false)
const waveformFileInputRef = ref<HTMLInputElement>()
const selectedCfgFile = ref<File | null>(null)
const selectedDatFile = ref<File | null>(null)
const waveformParseResult = ref<Waveform.WaveComtradeResultVO | null>(null)
const lastParseErrorMessage = ref('')
const waveformFileAccept = '.cfg,.dat'

const trendTabs = [
    { value: 'instant' as const, label: '瞬时波形' },
    { value: 'rms' as const, label: 'RMS 波形' }
]

const valueModeOptions = [
    { label: '一次值', value: 'primary' },
    { label: '二次值', value: 'secondary' }
]

const displayModeOptions = [
    { label: '单通道', value: 'single-channel' as const },
    { label: '多通道', value: 'multi-channel' as const }
]

const trendLabelMap = {
    instant: '瞬时波形',
    rms: 'RMS 波形'
} as const

const valueModeLabelMap = {
    primary: '一次值',
    secondary: '二次值'
} as const

const readThemeColor = (name: string, fallback: string) => {
    if (typeof window === 'undefined') return fallback
    const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim()
    return value || fallback
}

const phaseColors = {
    a: readThemeColor('--cn-color-phase-a', '#daa520'),
    b: readThemeColor('--cn-color-phase-b', '#2e8b57'),
    c: readThemeColor('--cn-color-phase-c', '#a52a2a')
}

const defaultPhaseColors = [phaseColors.a, phaseColors.b, phaseColors.c]

const selectedWaveformFileName = computed(() => {
    const fileNames = [selectedCfgFile.value?.name, selectedDatFile.value?.name].filter(Boolean)
    return fileNames.join(' / ')
})

const getWaveformParseErrorMessage = (error: unknown) => {
    if (!error || typeof error !== 'object') {
        return '波形解析失败，请检查 cfg 和 dat 文件内容'
    }

    const businessError = error as {
        message?: string
        response?: {
            data?: {
                message?: string
            }
        }
    }

    return businessError.response?.data?.message || businessError.message || '波形解析失败，请检查 cfg 和 dat 文件内容'
}

const hasParsedWaveform = computed(() => !!waveformParseResult.value?.waveData)

const buildSeriesPoints = (list: number[][] | undefined, valueIndex: number) => {
    return (list || []).map(item => [Number(item[0]), Number(item[valueIndex] ?? 0)])
}

const normalizedWaveDetails = computed<Waveform.WaveDataDetail[]>(() => {
    const waveData = waveformParseResult.value?.waveData
    const detailList = waveformParseResult.value?.waveDataDetails || []
    const instantList = waveData?.listWaveData
    const rmsList = waveData?.listRmsData
    const waveTitles = waveData?.waveTitle || []
    const groupCount = Math.max(Math.floor(Math.max(waveTitles.length - 1, 0) / 3), detailList.length)

    if (!groupCount) return []

    return Array.from({ length: groupCount }, (_, index) => {
        const startColumnIndex = index * 3 + 1
        const detail = detailList[index]
        const titleSlice = waveTitles.slice(startColumnIndex, startColumnIndex + 3)

        return {
            channelName: detail?.channelName || waveData?.channelNames?.[startColumnIndex] || `通道${index + 1}`,
            title: detail?.title || titleSlice.join(' / ') || `三相波形 ${index + 1}`,
            unit: detail?.unit || '',
            a: detail?.a || waveTitles[startColumnIndex] || 'A相',
            b: detail?.b || waveTitles[startColumnIndex + 1] || 'B相',
            c: detail?.c || waveTitles[startColumnIndex + 2] || 'C相',
            isOpen: detail?.isOpen || false,
            // 三相颜色统一读取全局主题变量，避免被接口返回的局部颜色覆盖。
            colors: [...defaultPhaseColors],
            instantData: {
                aValue: buildSeriesPoints(instantList, startColumnIndex),
                bValue: buildSeriesPoints(instantList, startColumnIndex + 1),
                cValue: buildSeriesPoints(instantList, startColumnIndex + 2)
            },
            rmsData: {
                aValue: buildSeriesPoints(rmsList, startColumnIndex),
                bValue: buildSeriesPoints(rmsList, startColumnIndex + 1),
                cValue: buildSeriesPoints(rmsList, startColumnIndex + 2)
            }
        }
    })
})

const channelOptions = computed<WaveformDetailOption[]>(() => {
    return normalizedWaveDetails.value.map((item, index) => ({
        label: buildChannelLabel(item, index),
        value: index
    }))
})

const activeWaveDetail = computed(() => {
    return normalizedWaveDetails.value[activeChannelIndex.value] || normalizedWaveDetails.value[0] || null
})

const activeWaveData = computed(() => waveformParseResult.value?.waveData)
const eigenvalueList = computed(() => waveformParseResult.value?.eigenvalues || [])

const normalizeRatio = (value?: number) => {
    const ratio = Number(value)
    return Number.isFinite(ratio) && ratio > 0 ? ratio : 1
}

const isCurrentChannel = (channelName?: string) => {
    return (channelName || '').toUpperCase().startsWith('I')
}

const activeValueScale = computed(() => {
    if (activeValueMode.value === 'secondary') return 1

    const waveData = activeWaveData.value
    const ratio = isCurrentChannel(activeWaveDetail.value?.channelName) ? waveData?.ct : waveData?.pt
    return normalizeRatio(ratio)
})

const safeNumber = (value: unknown) => {
    const numberValue = Number(value)
    return Number.isFinite(numberValue) ? numberValue : 0
}

const formatNumber = (value: unknown, fractionDigits = 3) => {
    const numberValue = Number(value)

    if (!Number.isFinite(numberValue)) return '--'
    if (Number.isInteger(numberValue)) return `${numberValue}`

    return `${Number(numberValue.toFixed(fractionDigits))}`
}

const formatPercentage = (value?: number) => {
    const numberValue = Number(value)
    if (!Number.isFinite(numberValue)) return '--'
    return `${Number((numberValue * 100).toFixed(2))}%`
}

const formatDuration = (value?: number) => {
    const numberValue = Number(value)
    if (!Number.isFinite(numberValue)) return '--'
    return `${Number(numberValue.toFixed(3))} ms`
}

const buildChannelLabel = (detail: Waveform.WaveDataDetail, index: number) => {
    if (detail.title) return detail.title
    if (detail.channelName && detail.unit) return `${detail.channelName} (${detail.unit})`
    if (detail.channelName) return detail.channelName
    return `通道 ${index + 1}`
}

const buildTrendPayload = (detail: Waveform.WaveDataDetail | null, trendTab: TrendTabValue, scale: number): WaveformTrendPayload => {
    const trendData = trendTab === 'instant' ? detail?.instantData : detail?.rmsData
    const aName = detail?.a || 'A相'
    const bName = detail?.b || 'B相'
    const cName = detail?.c || 'C相'
    const aValue = trendData?.aValue || []
    const bValue = trendData?.bValue || []
    const cValue = trendData?.cValue || []
    const timeSource = aValue.length ? aValue : bValue.length ? bValue : cValue
    const seriesConfigs = [
        { name: aName, source: aValue },
        { name: bName, source: bValue },
        { name: cName, source: cValue }
    ]

    const series = seriesConfigs
        .filter(item => item.source.length)
        .map(item => ({
            name: item.name,
            data: item.source.map(point => safeNumber(point[1]) * scale)
        }))

    const flatSeriesData = series.flatMap(item => item.data)
    const min = flatSeriesData.length ? Math.min(...flatSeriesData) : undefined
    const max = flatSeriesData.length ? Math.max(...flatSeriesData) : undefined

    return {
        timeLabels: timeSource.map(point => formatNumber(point[0])),
        unit: detail?.unit || '',
        min,
        max,
        series
    }
}

const activeTrendPayload = computed(() => {
    return buildTrendPayload(activeWaveDetail.value, activeTrendTab.value, activeValueScale.value)
})

const currentTrendColors = computed(() => {
    const customColors = activeWaveDetail.value?.colors?.filter(Boolean) || []
    return customColors.length >= 3 ? customColors.slice(0, 3) : defaultPhaseColors
})

const hasWaveformData = computed(() => activeTrendPayload.value.series.length > 0)

const buildTrendAxisConfig = (trendPayload: WaveformTrendPayload) => {
    const min = trendPayload.min
    const max = trendPayload.max
    const valueGap = Number.isFinite(min) && Number.isFinite(max) ? Math.max((max! - min!) * 0.1, 1) : undefined

    return {
        name: trendPayload.unit || '',
        ...(valueGap !== undefined && min !== undefined && max !== undefined
            ? {
                  min: min - valueGap,
                  max: max + valueGap
              }
            : {})
    }
}

const buildTrendChartOptions = (
    trendPayload: WaveformTrendPayload,
    seriesList: WaveformSeriesItem[],
    chartColors = currentTrendColors.value,
    layoutOptions: TrendChartLayoutOptions = {}
) => {
    const { showTimeAxis = true } = layoutOptions

    return {
        tooltip: {
            valueFormatter: (value: number) => {
                return trendPayload.unit ? `${formatNumber(value)} ${trendPayload.unit}` : formatNumber(value)
            }
        },
        legend: {
            top: 10,
            right: 12
        },
        grid: {
            top: '18px',
            left: '24px',
            right: showTimeAxis ? '32px' : '24px',
            bottom: showTimeAxis ? '22px' : '12px'
        },
        xAxis: {
            data: trendPayload.timeLabels,
            boundaryGap: false,
            name: showTimeAxis ? 'ms' : '',
            nameLocation: 'end',
            nameGap: showTimeAxis ? 10 : 0,
            axisLabel: {
                show: showTimeAxis,
                hideOverlap: true,
                interval: 'auto',
                margin: showTimeAxis ? 6 : 0,
                formatter: (value: string | number) => formatNumber(value, 2)
            },
            axisTick: {
                show: showTimeAxis
            }
        },
        yAxis: buildTrendAxisConfig(trendPayload),
        dataZoom: [],
        color: chartColors,
        series: seriesList.map(item => ({
            name: item.name,
            type: 'line',
            smooth: true,
            symbol: 'none',
            data: item.data
        }))
    }
}

const activeTrendOptions = computed(() => {
    const trendPayload = activeTrendPayload.value
    return buildTrendChartOptions(trendPayload, trendPayload.series)
})

// 单通道模式按相别拆成多个图，便于分别观察各通道波形。
const singleChannelTrendOptionsList = computed(() => {
    const trendPayload = activeTrendPayload.value

    // 单通道下每张图只保留一个 series，需要单独指定对应相色。
    return trendPayload.series.map((item, index) => ({
        key: item.name,
        group: singleChannelTrendChartGroup,
        options: buildTrendChartOptions(
            trendPayload,
            [item],
            [currentTrendColors.value[index] || defaultPhaseColors[index]],
            {
                // 仅最后一张图显示时间轴，既保留时间信息，又避免多图重复挤占高度。
                showTimeAxis: index === trendPayload.series.length - 1
            }
        )
    }))
})

const summaryItems = computed(() => {
    const waveData = activeWaveData.value
    const cfgData = waveData?.comtradeCfgDTO
    const detail = activeWaveDetail.value

    return [
        { label: '测点名称', value: waveData?.monitorName || '--' },
        { label: '事件时间', value: waveData?.time || '--' },
        { label: '录波开始', value: cfgData?.timeStart || '--' },
        { label: '触发时间', value: cfgData?.timeTrige || '--' },
        { label: '采样率', value: cfgData?.finalSampleRate ? `${cfgData.finalSampleRate} Hz` : '--' },
        { label: '总通道数', value: cfgData?.nChannelNum ?? '--' },
        { label: '当前通道', value: detail ? buildChannelLabel(detail, activeChannelIndex.value) : '--' },
        { label: '单位', value: detail?.unit || '--' },
        { label: '相别数量', value: waveData?.iPhasic ?? '--' },
        { label: 'PT / CT', value: `${formatNumber(waveData?.pt, 2)} / ${formatNumber(waveData?.ct, 2)}` },
        { label: '数据类型', value: valueModeLabelMap[activeValueMode.value] },
        { label: '文件编码', value: cfgData?.strBinType || '--' }
    ]
})

const openWaveformFilePicker = () => {
    if (!waveformFileInputRef.value) return

    waveformFileInputRef.value.value = ''
    waveformFileInputRef.value.click()
}

const getFileBaseName = (fileName: string) => {
    return fileName.replace(/\.[^.]+$/, '').toLowerCase()
}

const resetSelectedWaveformFiles = () => {
    selectedCfgFile.value = null
    selectedDatFile.value = null
    waveformParseResult.value = null
    lastParseErrorMessage.value = ''
}

const handleWaveformFileChange = async (event: Event) => {
    const input = event.target as HTMLInputElement
    const fileList = Array.from(input.files || [])

    if (!fileList.length) return

    const cfgFiles = fileList.filter(item => item.name.toLowerCase().endsWith('.cfg'))
    const datFiles = fileList.filter(item => item.name.toLowerCase().endsWith('.dat'))

    if (cfgFiles.length !== 1 || datFiles.length !== 1 || fileList.length !== 2) {
        resetSelectedWaveformFiles()
        ElMessage.warning('请选择一组同名的.cfg和.dat文件')
        return
    }

    const [cfgFile] = cfgFiles
    const [datFile] = datFiles

    if (!cfgFile || !datFile) {
        resetSelectedWaveformFiles()
        ElMessage.warning('请选择同一组.cfg和.dat文件')
        return
    }

    if (getFileBaseName(cfgFile.name) !== getFileBaseName(datFile.name)) {
        resetSelectedWaveformFiles()
        ElMessage.warning('请选择同名的.cfg和.dat文件')
        return
    }

    selectedCfgFile.value = cfgFile
    selectedDatFile.value = datFile

    await loadWaveformData(cfgFile, datFile)
}

const loadWaveformData = async (cfgFile: File, datFile: File) => {
    try {
        isParsing.value = true
        activeChannelIndex.value = 0
        lastParseErrorMessage.value = ''

        const result = await parseComtradeApi({
            cfgFile,
            datFile
        })

        waveformParseResult.value = result.data
    } catch (error) {
        waveformParseResult.value = null
        lastParseErrorMessage.value = getWaveformParseErrorMessage(error)

        console.error('[waveform] parseComtrade failed', {
            cfgFileName: cfgFile.name,
            cfgFileSize: cfgFile.size,
            datFileName: datFile.name,
            datFileSize: datFile.size,
            error
        })
    } finally {
        isParsing.value = false
    }
}

const downloadTrendData = () => {
    if (!hasWaveformData.value) {
        ElMessage.warning('暂无可导出的波形数据')
        return
    }

    const trendPayload = activeTrendPayload.value
    const header = ['时间', ...trendPayload.series.map(item => item.name)]
    const rows = trendPayload.timeLabels.map((time, index) => {
        return [time, ...trendPayload.series.map(item => item.data[index] ?? '')]
    })

    const csvContent = [header, ...rows].map(row => row.join(',')).join('\n')
    const blob = new Blob([`\uFEFF${csvContent}`], { type: 'text/csv;charset=utf-8;' })
    const blobUrl = URL.createObjectURL(blob)
    const exportFile = document.createElement('a')
    const channelLabel = activeWaveDetail.value ? buildChannelLabel(activeWaveDetail.value, activeChannelIndex.value) : '波形'
    const fileName = `波形查看_${channelLabel}_${valueModeLabelMap[activeValueMode.value]}_${trendLabelMap[activeTrendTab.value]}.csv`

    exportFile.style.display = 'none'
    exportFile.download = fileName
    exportFile.href = blobUrl
    document.body.appendChild(exportFile)
    exportFile.click()
    document.body.removeChild(exportFile)
    URL.revokeObjectURL(blobUrl)

    ElMessage.success('趋势图数据下载成功')
}
</script>

<style scoped lang="scss">
.waveform-page {
    gap: 12px;
    overflow: hidden;
}

.page-header {
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex-shrink: 0;
}

.page-title {
    font-size: 18px;
    font-weight: 600;
    line-height: 1.5;
    color: var(--el-text-color-primary);
}

.action-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.file-select-row,
.toolbar-actions,
.toolbar-item {
    display: flex;
    gap: 12px;
    align-items: center;
    min-width: 0;
}

.toolbar-actions {
    flex-shrink: 0;
}

.toolbar-label,
.file-select-row :deep(.el-input__inner),
.file-select-row :deep(.el-button),
.toolbar-actions :deep(.el-radio-button__inner),
.toolbar-actions :deep(.el-button),
.toolbar-actions :deep(.el-input__inner),
.toolbar-actions :deep(.el-select__placeholder),
.toolbar-actions :deep(.el-select__selected-item),
.trend-tabs :deep(.el-tabs__item) {
    font-size: 13px;
}

.file-input {
    width: 360px;
    max-width: 100%;
}

.channel-select {
    width: 220px;
}

.display-mode-select {
    width: 160px;
}

.value-mode-switch {
    min-width: 150px;
}

.waveform-file-input {
    display: none;
}

.waveform-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(360px, 0.95fr);
    gap: 16px;
    width: 100%;
    height: 100%;
    overflow: hidden;
}


.waveform-panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    padding: 16px;
    overflow: hidden;
    background: var(--el-bg-color);
    border: 1px solid var(--el-border-color-light);
    border-radius: 4px;
}


.panel-header {
    margin-bottom: 16px;
    flex-shrink: 0;
}

.trend-tabs {
    width: 100%;
    flex-shrink: 0;
}

.trend-tabs :deep(.el-tabs__header) {
    margin-bottom: 0;
}

.trend-tabs :deep(.el-tabs__nav-wrap::after) {
    background-color: var(--el-border-color-light);
}

.panel-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}


.section-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.chart-container,
.empty-block {
    display: flex;
    flex: 1;
    min-height: 0;
    padding: 12px;
    overflow: hidden;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
}

.empty-block {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: var(--cn-color-canvas-bg);
}

.single-channel-list {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
    overflow: hidden;
}

.single-channel-card {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
    padding: 12px;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
    background: var(--cn-color-canvas-bg);
    overflow: hidden;
}

.single-channel-chart {
    flex: 1;
    min-height: 0;
}

.empty-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.empty-text,
.empty-inline,
.panel-tip {
    font-size: 13px;
    line-height: 1.6;
    color: var(--el-text-color-regular);
}

.error-text {
    color: var(--el-color-danger);
    word-break: break-all;
}

.info-body {
    gap: 12px;
    overflow: auto;
}

.summary-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

.summary-item,
.feature-card {
    padding: 12px;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
    background: var(--cn-color-canvas-bg);
}

.summary-label,
.feature-card-title,
.feature-header {
    font-size: 13px;
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.summary-value {
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--el-text-color-regular);
    word-break: break-all;
}

.feature-header {
    margin-top: 4px;
}

.feature-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

.feature-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.feature-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
    color: var(--el-text-color-regular);
}

@media (max-width: 1280px) {
    .waveform-layout {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 992px) {
    .action-row,
    .toolbar-actions {
        flex-direction: column;
        align-items: stretch;
    }

    .toolbar-item,
    .file-select-row {
        width: 100%;
    }

    .channel-select,
    .display-mode-select,
    .file-input,
    .value-mode-switch {
        width: 100%;
        max-width: none;
    }

    .summary-grid,
    .feature-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 768px) {
    .page-title {
        font-size: 17px;
    }

    .trend-tabs {
        width: 100%;
    }

    .trend-tabs :deep(.el-tabs__nav) {
        width: 100%;
    }

    .trend-tabs :deep(.el-tabs__item) {
        flex: 1;
        justify-content: center;
    }
}
</style>

