<script lang="ts" setup>
import { computed, ref } from 'vue'
import { useRoute } from 'vue-router'
import { IotDeviceApi } from '@/api/pms/device'
import {
  Odometer,
  CircleCheckFilled,
  CircleCloseFilled,
  DataLine,
  Crop,
  FullScreen,
  Setting
} from '@element-plus/icons-vue'
import { AnimatedCountTo } from '@/components/AnimatedCountTo'
import { neonColors } from '@/utils/td-color'
import dayjs from 'dayjs'
import * as echarts from 'echarts'
import { cancelAllRequests, IotStatApi } from '@/api/pms/stat'
import { Dimensions, formatIotValue, HeaderItem } from '@/utils/useSocketBus'
import { rangeShortcuts } from '@/utils/formatTime'
import { useFullscreen } from '@vueuse/core'
import { snapdom } from '@zumer/snapdom'
import { ElMessage } from 'element-plus'
import { useMqtt } from '@/utils/useMqtt'

const { query } = useRoute()

const data = ref({
  deviceCode: query.code || '',
  deviceName: query.name || '',
  lastInlineTime: query.time || '',
  ifInline: query.ifInline === '3',
  dept: query.dept || '',
  vehicle: query.vehicle || '',
  carOnline: query.carOnline === 'true',
  mqttUrl: query.mqttUrl || ''
})

const { connect, destroy, isConnected, subscribe } = useMqtt()

const handleMessageUpdate = (_topic: string, data: any) => {
  const valueMap = new Map<string, number>()

  for (const item of data) {
    const { id: identity, value: logValue, remark } = item

    const value = logValue ? Number(logValue) : 0

    if (identity) {
      valueMap.set(identity, value)
    }

    const modelName = dimensions.value.find((item) => item.identifier === identity)?.name

    if (modelName && chartData.value[modelName]) {
      chartData.value[modelName].push({
        ts: dayjs.unix(remark).valueOf(),
        value
      })

      updateSingleSeries(modelName)
    }
  }

  const updateDimensions = (list) => {
    list.forEach((item) => {
      const v = valueMap.get(item.identifier)
      if (v !== undefined) {
        item.value = v
      }
    })
  }

  updateDimensions(dimensions.value)
  updateDimensions(gatewayDimensions.value)
  updateDimensions(carDimensions.value)

  genderIntervalArr()
}

watch(isConnected, (newVal) => {
  if (newVal) {
    subscribe(data.value.mqttUrl as string)
  }
})

// const { open: connect, onAny, close } = useSocketBus(data.value.deviceCode as string)

// onAny((msg) => {
//   if (!Array.isArray(msg) || msg.length === 0) return

//   const valueMap = new Map<string, number>()

//   for (const item of msg) {
//     const { identity, modelName, readTime, logValue } = item

//     const value = logValue ? Number(logValue) : 0

//     if (identity) {
//       valueMap.set(identity, value)
//     }

//     if (modelName && chartData.value[modelName]) {
//       chartData.value[modelName].push({
//         ts: dayjs(readTime).valueOf(),
//         value
//       })

//       updateSingleSeries(modelName)
//     }
//   }

//   const updateDimensions = (list) => {
//     list.forEach((item) => {
//       const v = valueMap.get(item.identifier)
//       if (v !== undefined) {
//         item.value = v
//       }
//     })
//   }

//   updateDimensions(dimensions.value)
//   updateDimensions(gatewayDimensions.value)
//   updateDimensions(carDimensions.value)

//   // 3️⃣ 统一一次调用
//   genderIntervalArr()
// })

function hexToRgba(hex: string, alpha: number) {
  const r = parseInt(hex.slice(1, 3), 16)
  const g = parseInt(hex.slice(3, 5), 16)
  const b = parseInt(hex.slice(5, 7), 16)
  return `rgba(${r}, ${g}, ${b}, ${alpha})`
}

const headerCenterContent: HeaderItem[] = [
  { label: '设备名称', key: 'deviceName' },
  { label: '所属部门', key: 'dept' },
  { label: '车牌号码', key: 'vehicle', judgment: true },
  { label: '最后上报时间', key: 'lastInlineTime' }
]

const tagProps = { size: 'default', round: true } as const

const headerTagContent: HeaderItem[] = [
  { label: '网关', key: 'ifInline' },
  { label: '北斗', key: 'carOnline', judgment: true }
]

const dimensions = ref<Dimensions[]>([])
const gatewayDimensions = ref<Dimensions[]>([])
const carDimensions = ref<Dimensions[]>([])

const dimensionsContent = computed(() => [
  {
    label: '网关数采',
    icon: DataLine,
    value: gatewayDimensions.value,
    countColor: 'text-blue-600',
    countBg: 'bg-blue-50',
    judgment: false
  }
  // {
  //   label: '中航北斗',
  //   icon: TrendCharts,
  //   value: carDimensions.value,
  //   countColor: 'text-indigo-600',
  //   countBg: 'bg-indigo-50',
  //   judgment: true
  // }
])

const disabledDimensions = ref<string[]>(['online', 'vehicle_name'])
const selectedDimension = ref<Record<string, boolean>>({})
const dimensionLoading = ref(false)

async function loadDimensions() {
  if (!query.id) return
  dimensionLoading.value = true
  try {
    const gateway = (((await IotDeviceApi.getIotDeviceTds(Number(query.id))) as any[]) ?? [])
      .sort((a, b) => b.modelOrder - a.modelOrder)
      .map((item) => {
        const { value, suffix, isText } = formatIotValue(item.value)
        return {
          identifier: item.identifier,
          name: item.modelName,
          value: value,
          suffix: suffix,
          isText: isText,
          response: false,
          id: item.alarmSettingId,
          maxValue: Number(item.maxValue),
          minValue: Number(item.minValue)
        }
      })

    // const car = (((await IotDeviceApi.getIotDeviceZHBDTds(Number(query.id))) as any[]) ?? [])
    //   .sort((a, b) => b.modelOrder - a.modelOrder)
    //   .map((item) => {
    //     const { value, suffix, isText } = formatIotValue(item.value)
    //     console.log(`${item.modelName} :>> `, value)
    //     return {
    //       identifier: item.identifier,
    //       name: item.modelName,
    //       value: value,
    //       suffix: suffix,
    //       isText: isText,
    //       response: false
    //     }
    //   })

    // const rawList = [...gateway, ...car]
    const rawList = [...gateway]

    const uniqueMap = new Map()

    rawList.forEach((item) => {
      const uniqueKey = `${item.identifier}|${item.name}`

      // if (!uniqueMap.has(uniqueKey)) {
      uniqueMap.set(uniqueKey, item)
      // }
    })

    dimensions.value = Array.from(uniqueMap.values()).map((item, index) => {
      const color = neonColors[index % neonColors.length]
      return {
        ...item,
        color: color,
        bgHover: hexToRgba(color, 0.08),
        bgActive: hexToRgba(color, 0.12)
      }
    })

    gatewayDimensions.value = dimensions.value.filter((d) =>
      gateway.some((g) => g.identifier === d.identifier)
    )
    // carDimensions.value = dimensions.value.filter((d) =>
    //   car.some((c) => c.identifier === d.identifier)
    // )

    selectedDimension.value = Object.fromEntries(dimensions.value.map((item) => [item.name, false]))
    if (dimensions.value.length > 0) {
      selectedDimension.value[dimensions.value[0].name] = true
    }
  } catch (e) {
    console.error(e)
  } finally {
    dimensionLoading.value = false
  }
}

const selectedDate = ref<string[]>([
  dayjs().subtract(5, 'minute').format('YYYY-MM-DD HH:mm:ss'),
  dayjs().format('YYYY-MM-DD HH:mm:ss')
])

interface ChartData {
  [key: Dimensions['name']]: { ts: number; value: number }[]
}

const chartData = ref<ChartData>({})

let intervalArr = ref<number[]>([])
let maxInterval = ref(0)
let minInterval = ref(0)

const chartRef = ref<HTMLDivElement | null>(null)
let chart: echarts.ECharts | null = null

function genderIntervalArr(init: boolean = false) {
  const values: number[] = []

  for (const [key, value] of Object.entries(selectedDimension.value)) {
    if (value) {
      values.push(...(chartData.value[key]?.map((item) => item.value) ?? []))
    }
  }

  const maxVal = values.length === 0 ? 10000 : Math.max(...values)
  const minVal = values.length === 0 ? 0 : Math.min(...values) > 0 ? 0 : Math.min(...values)

  const maxDigits = (Math.floor(maxVal) + '').length
  const minDigits = minVal === 0 ? 0 : (Math.floor(Math.abs(minVal)) + '').length

  const interval = Math.max(maxDigits, minDigits)

  maxInterval.value = interval
  minInterval.value = minDigits

  intervalArr.value = [0]
  for (let i = 1; i <= interval; i++) {
    intervalArr.value.push(Math.pow(10, i))
  }

  if (!init) {
    chart?.setOption({
      yAxis: {
        min: -minInterval.value,
        max: maxInterval.value
      }
    })
  }
}

function chartInit() {
  if (!chart) return

  chart.on('legendselectchanged', (params: any) => {
    selectedDimension.value = params.selected
  })

  window.addEventListener('resize', () => {
    if (chart) chart.resize()
  })
}

function render() {
  if (!chartRef.value) return

  if (!chart) chart = echarts.init(chartRef.value, undefined, { renderer: 'canvas' })

  chartInit()

  genderIntervalArr(true)

  chart.setOption({
    animation: true,
    animationDuration: 200,
    animationEasing: 'linear',
    animationDurationUpdate: 200,
    animationEasingUpdate: 'linear',
    grid: {
      left: '0%',
      top: '5%',
      right: '5%',
      bottom: '12%'
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'line'
      },
      formatter: (params) => {
        let d = `${params[0].axisValueLabel}<br>`
        const exist: string[] = []
        params = params.filter((el) => {
          if (exist.includes(el.seriesName)) return false
          exist.push(el.seriesName)
          return true
        })
        let item = params.map(
          (el) => `<div class="flex items-center justify-between mt-1">
            <span>${el.marker} ${el.seriesName}</span>
            <span>${el.value[2]?.toFixed(2)}</span>
          </div>`
        )

        return d + item.join('')
      }
    },
    xAxis: {
      type: 'time',
      boundaryGap: ['0%', '25%'],
      axisLabel: {
        formatter: (v) => dayjs(v).format('YYYY-MM-DD\nHH:mm:ss'),
        rotate: 0,
        align: 'left'
      }
    },
    dataZoom: [
      { type: 'inside', xAxisIndex: 0 },
      { type: 'slider', xAxisIndex: 0 }
    ],
    yAxis: {
      type: 'value',
      min: -minInterval.value,
      max: maxInterval.value,
      interval: 1,
      axisLabel: {
        formatter: (v) => {
          const num = v === 0 ? 0 : v > 0 ? Math.pow(10, v) : -Math.pow(10, -v)

          return num.toLocaleString()
        }
      },
      show: false
    },
    legend: {
      data: dimensions.value.map((item) => item.name),
      selected: selectedDimension.value,
      show: false
    },
    series: dimensions.value.map((item) => ({
      name: item.name,
      type: 'line',

      smooth: 0.2,

      showSymbol: false,

      endLabel: {
        show: true,
        formatter: (params) => params.value[2]?.toFixed(2),
        offset: [6, 0],
        color: item.color,
        fontSize: 12
      },

      emphasis: {
        focus: 'series'
      },

      lineStyle: {
        width: 2
      },

      color: item.color,
      data: [] // 占位数组
    }))
  })
}

function mapData({ value, ts }) {
  if (value === null || value === undefined || value === 0) return [ts, 0, 0]

  const isPositive = value > 0
  const absItem = Math.abs(value)

  if (!intervalArr.value.length) return [ts, 0, value]

  const min_value = Math.max(...intervalArr.value.filter((v) => v <= absItem))
  const min_index = intervalArr.value.findIndex((v) => v === min_value)

  let denominator = 1
  if (min_index < intervalArr.value.length - 1) {
    denominator = intervalArr.value[min_index + 1] - intervalArr.value[min_index]
  } else {
    denominator = intervalArr.value[min_index] || 1
  }

  const new_value = (absItem - min_value) / denominator + min_index

  return [ts, isPositive ? new_value : -new_value, value]
}

function updateSingleSeries(name: string) {
  if (!chart) render()
  if (!chart) return

  const idx = dimensions.value.findIndex((item) => item.name === name)
  if (idx === -1) return

  const data = chartData.value[name].map((v) => mapData(v))

  chart.setOption({
    series: [{ name, data }]
  })
}

const lastTsMap = ref<Record<Dimensions['name'], number>>({})

const chartLoading = ref(false)

const token = ref('')

async function getToken() {
  const res = await IotDeviceApi.getToken()

  token.value = res
}

onMounted(() => {
  getToken()
})

async function initLoadChartData(real_time: boolean = true) {
  if (!dimensions.value.length) return

  chartData.value = Object.fromEntries(dimensions.value.map((item) => [item.name, []]))

  chartLoading.value = true

  dimensions.value = dimensions.value.map((item) => {
    item.response = true
    return item
  })

  for (const item of dimensions.value) {
    const { identifier, name } = item
    try {
      const res = await IotStatApi.getDeviceInfoChart(
        data.value.deviceCode,
        identifier,
        selectedDate.value[0],
        selectedDate.value[1]
      )

      const sorted = res
        .sort((a, b) => a.ts - b.ts)
        .map((item) => ({ ts: item.ts, value: item.value }))

      chartData.value[name] = sorted

      lastTsMap.value[name] = sorted.at(-1)?.ts ?? 0

      genderIntervalArr()

      updateSingleSeries(name)

      chartLoading.value = false
    } finally {
      item.response = false
    }
  }

  if (real_time) {
    connect(`wss://aims.deepoil.cc/mqtt`, { password: token.value }, handleMessageUpdate)
  }
}

async function initfn(load: boolean = true, real_time: boolean = true) {
  if (load) await loadDimensions()
  render()
  initLoadChartData(real_time)
}

onMounted(() => {
  initfn()
})

function reset() {
  cancelAllRequests().then(() => {
    selectedDate.value = [
      dayjs().subtract(5, 'minute').format('YYYY-MM-DD HH:mm:ss'),
      dayjs().format('YYYY-MM-DD HH:mm:ss')
    ]

    destroy()
    if (chart) chart.clear()
    initfn(false)
  })
}

function handleDateChange() {
  cancelAllRequests().then(() => {
    destroy()
    // stopAutoFetch()
    if (chart) chart.clear()
    initfn(false, false)
  })
}

function handleClickSpec(modelName: string) {
  selectedDimension.value[modelName] = !selectedDimension.value[modelName]
  chart?.setOption({
    legend: {
      selected: selectedDimension.value
    }
  })

  genderIntervalArr()

  if (selectedDimension.value[modelName]) {
    updateSingleSeries(modelName)
  }

  nextTick(() => {
    chart?.resize()
  })
}

const downloadRef = ref(null)

const exportChart = async () => {
  try {
    if (!downloadRef.value) return

    const result = await snapdom(downloadRef.value, {
      scale: 2,
      backgroundColor: '#fff'
    })

    await result.download({
      filename: `${data.value.deviceName}-设备监控`,
      type: 'png'
    })
  } catch (error) {
    console.error(error)
    ElMessage.error('导出图表失败')
  }
}

const maxmin = computed(() => {
  if (!dimensions.value.length) return []
  return dimensions.value
    .filter((v) => selectedDimension.value[v.name])
    .map((v) => ({
      name: v.name,
      color: v.color,
      bgHover: v.bgHover,
      max: Math.max(...(chartData.value[v.name]?.map((v) => v.value) ?? [])).toFixed(2),
      min: Math.min(...(chartData.value[v.name]?.map((v) => v.value) ?? [])).toFixed(2)
    }))
})

onUnmounted(() => {
  destroy()

  window.removeEventListener('resize', () => {
    if (chart) chart.resize()
  })
})

const targetArea = ref(null)

const { toggle, isFullscreen } = useFullscreen(targetArea)

const message = useMessage()

async function handleSave(item: Dimensions) {
  const { minValue, maxValue } = item

  // 1. 判断是否为空 (包括空字符串、null、undefined)
  if (!minValue || !maxValue) {
    return message.warning('最大值和最小值不能为空')
  }

  // 2. 判断是否为有效的数字
  // Number() 处理字符串数字，isNaN 排除非数字字符
  const min = Number(minValue)
  const max = Number(maxValue)

  if (isNaN(min) || isNaN(max)) {
    return message.warning('请输入有效的数字')
  }

  // 3. (附加逻辑) 比较大小
  if (min > max) {
    return message.warning('最小值不能大于最大值')
  }

  const body = {
    minValue: min,
    maxValue: max,
    deviceId: query.id,
    propertyCode: item.identifier,
    alarmProperty: item.name,
    deviceName: data.value.deviceName,
    id: item.id
  }

  const res = await IotDeviceApi.saveMaxMin(body)

  if (res.id) item.id = res.id

  message.success('设置成功')
}
async function handleReset(item: Dimensions) {
  item.minValue = undefined
  item.maxValue = undefined

  await IotDeviceApi.deleteMaxMin({ id: item.id })
  item.id = undefined

  message.success('清除重置成功')
}
</script>

<template>
  <div
    class="grid grid-rows-[80px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
  >
    <div
      class="rounded-xl shadow-sm border border-gray-100 border-solid px-6 flex items-center justify-between shrink-0 bg-gradient-to-r from-blue-100 to-white"
    >
      <div class="flex items-center gap-4">
        <div
          class="size-12 rounded-lg bg-blue-50 text-blue-600 flex items-center justify-center shadow-inner"
        >
          <el-icon :size="24"><Odometer /></el-icon>
        </div>
        <div>
          <div class="text-xs text-gray-400 font-medium tracking-wider">资产编码</div>
          <div class="text-xl font-bold font-mono text-gray-800">{{ data.deviceCode }}</div>
        </div>
      </div>
      <div class="flex-1 flex justify-center divide-x divide-gray-100">
        <template v-for="item in headerCenterContent" :key="item.key">
          <div
            class="px-8 flex flex-col items-center"
            v-if="item.judgment ? Boolean(query[item.key]) : true"
          >
            <span class="text-xs text-gray-400 mb-1">{{ item.label }}</span>
            <span class="font-semibold text-gray-700">{{ data[item.key] }}</span>
          </div>
        </template>
      </div>
      <div class="flex items-center gap-6">
        <template v-for="item in headerTagContent" :key="item.key">
          <div class="text-center" v-if="item.judgment ? Boolean(query[item.key]) : true">
            <div class="text-xs text-gray-400 mb-1">{{ item.label }}</div>
            <el-tag v-if="data[item.key]" type="success" v-bind="tagProps">
              <el-icon class="mr-1"><CircleCheckFilled /></el-icon>在线
            </el-tag>
            <el-tag v-else type="danger" v-bind="tagProps">
              <el-icon class="mr-1"><CircleCloseFilled /></el-icon>离线
            </el-tag>
          </div>
        </template>
      </div>
    </div>
    <div ref="targetArea" class="relative">
      <div class="flex flex-col gap-4 h-full">
        <template v-for="citem in dimensionsContent" :key="citem.label">
          <template v-if="citem.judgment ? Boolean(citem.value.length) : true">
            <div
              class="rounded-xl shadow-sm border border-gray-100 border-solid overflow-hidden bg-gradient-to-b from-blue-100 to-white p-4 flex flex-col gap-2"
              v-loading="dimensionLoading"
            >
              <div class="flex justify-center items-center gap-2 border-0 border-solid">
                <span class="font-bold text-gray-700! flex items-center gap-2">
                  <el-icon><component :is="citem.icon" /></el-icon>
                  {{ citem.label }}
                </span>
                <span
                  class="text-xs px-2 py-0.5 rounded-full font-mono bg-gray-200"
                  :class="[citem.countBg, citem.countColor]"
                >
                  {{ citem.value.length }}
                </span>
              </div>

              <div class="grid grid-cols-4 gap-2">
                <div
                  :data-disabled="disabledDimensions.includes(item.identifier)"
                  v-for="item in citem.value"
                  :key="item.identifier"
                  @click="handleClickSpec(item.name)"
                  class="dimension-card group relative p-3 rounded-lg border border-solid bg-transparent border-gray-300 transition-all duration-300 cursor-pointer select-none data-[disabled=true]:pointer-events-none"
                  :class="{ 'is-active': selectedDimension[item.name] }"
                  :style="{
                    '--theme-color': item.color,
                    '--theme-bg-hover': item.bgHover,
                    '--theme-bg-active': item.bgActive
                  }"
                >
                  <div class="flex justify-between items-center mb-1">
                    <span
                      class="text-xs font-medium text-gray-500 transition-colors truncate pr-2 group-hover:text-[var(--theme-color)]"
                      :class="{ 'text-[var(--theme-color)]!': selectedDimension[item.name] }"
                    >
                      {{ item.name }}
                    </span>
                    <el-popover placement="bottom" :width="280" trigger="click">
                      <template #reference>
                        <el-button class="group" link>
                          <el-icon
                            class="transition-transform duration-500 group-hover:rotate-180"
                            :size="16"
                          >
                            <Setting />
                          </el-icon>
                        </el-button>
                      </template>

                      <div class="flex flex-col gap-3">
                        <div class="text-sm font-bold text-gray-700 pb-1 border-b border-gray-100">
                          设置范围
                        </div>

                        <div class="grid grid-cols-[auto_1fr] gap-y-3 gap-x-2 items-center">
                          <span class="text-xs text-gray-500 text-right">最小值:</span>
                          <el-input-number
                            v-model="item.minValue"
                            size="default"
                            class="!w-full"
                            placeholder="Min"
                            :controls="false"
                            align="left"
                          />

                          <span class="text-xs text-gray-500 text-right">最大值:</span>
                          <el-input-number
                            v-model="item.maxValue"
                            size="default"
                            class="!w-full"
                            placeholder="Max"
                            :controls="false"
                            align="left"
                          />
                        </div>

                        <div class="flex justify-end gap-2 pt-1">
                          <el-button size="small" text bg @click="handleReset(item)">
                            清除重置
                          </el-button>
                          <el-button size="small" type="primary" @click="handleSave(item)">
                            保存
                          </el-button>
                        </div>
                      </div>
                    </el-popover>
                    <!-- <div
                      class="size-2 rounded-full transition-all duration-300 shadow-sm"
                      :class="selectedDimension[item.name] ? 'scale-100' : 'scale-0'"
                      :style="{ backgroundColor: item.color, boxShadow: `0 0 6px ${item.color}` }"
                    ></div> -->
                  </div>

                  <!-- <div class="flex items-baseline justify-between relative z-9">
                    <animated-count-to
                      v-if="!item.isText"
                      :value="Number(item.value)"
                      :duration="500"
                      :suffix="item.suffix"
                      class="text-lg font-bold font-mono tracking-tight text-slate-800"
                    />
                    <span v-else class="text-lg font-bold font-mono tracking-tight text-slate-800">
                      {{ item.value }}
                    </span>
                  </div> -->

                  <div class="flex items-center justify-between relative z-9 mt-1">
                    <div class="flex-1 mr-2">
                      <animated-count-to
                        v-if="!item.isText"
                        :value="Number(item.value)"
                        :duration="500"
                        :suffix="item.suffix"
                        class="text-2xl font-black font-mono tracking-tight text-slate-800 leading-none"
                      />
                      <span
                        v-else
                        class="text-2xl font-black font-mono tracking-tight text-slate-800 leading-none"
                      >
                        {{ item.value }}
                      </span>
                    </div>

                    <div v-if="item.minValue || item.maxValue" class="flex gap-1.5 items-center">
                      <div
                        v-if="item.maxValue"
                        class="flex items-center px-2 py-1 rounded-md bg-emerald-50/80 border border-solid border-emerald-100/80 shadow-sm transition-all duration-300 hover:bg-emerald-100 hover:border-emerald-200"
                      >
                        <div
                          class="flex items-center justify-center w-4 h-4 mr-1 rounded-full bg-emerald-100 text-emerald-600 group-hover/max:bg-white group-hover/max:scale-110 transition-all"
                        >
                          <div class="i-material-symbols:arrow-upward-alt-rounded"></div>
                        </div>
                        <span class="text-[10px] font-bold text-emerald-400/80 mr-1.5">MAX</span>
                        <span class="text-sm font-bold font-mono text-emerald-700">{{
                          item.maxValue
                        }}</span>
                      </div>

                      <div
                        v-if="item.minValue"
                        class="flex items-center px-2 py-0.5 rounded-md bg-rose-50/80 border border-solid border-rose-100/80 shadow-sm transition-all duration-300 hover:bg-rose-100 hover:border-rose-200"
                      >
                        <div
                          class="flex items-center justify-center w-4 h-4 mr-1 rounded-full bg-rose-100 text-rose-600 group-hover/min:bg-white group-hover/min:scale-110 transition-all"
                        >
                          <div class="i-material-symbols:arrow-downward-alt-rounded"></div>
                        </div>
                        <span class="text-[10px] font-bold text-rose-400/80 mr-1.5">MIN</span>
                        <span class="text-sm font-bold font-mono text-rose-700">{{
                          item.minValue
                        }}</span>
                      </div>
                    </div>
                  </div>
                  <div
                    class="absolute left-0 top-3 bottom-3 w-1 rounded-r transition-all duration-300"
                    :class="
                      selectedDimension[item.name]
                        ? 'opacity-100 shadow-[0_0_8px_currentColor]'
                        : 'opacity-0'
                    "
                    :style="{ backgroundColor: item.color, color: item.color }"
                  >
                  </div>
                </div>
              </div>
            </div>
          </template>
        </template>
        <div
          class="flex-1 min-h-200 rounded-xl shadow-sm border border-gray-100 border-solid p-4 flex flex-col bg-gradient-to-b from-blue-100 to-white"
        >
          <header class="flex items-center justify-between mb-4">
            <h3 class="flex items-center gap-2">
              <div
                class="i-material-symbols:area-chart-outline-rounded text-sky size-6"
                text-sky
              ></div>
              数据趋势
            </h3>
            <div class="flex gap-4">
              <el-button type="primary" size="default" @click="exportChart">导出为图片</el-button>
              <el-button size="default" @click="reset">重置</el-button>
              <el-date-picker
                v-model="selectedDate"
                value-format="YYYY-MM-DD HH:mm:ss"
                type="datetimerange"
                unlink-panels
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                :shortcuts="rangeShortcuts"
                size="default"
                class="w-100!"
                placement="bottom-end"
                @change="handleDateChange"
              />
              <el-button
                size="default"
                :type="isFullscreen ? 'info' : 'primary'"
                :icon="isFullscreen ? Crop : FullScreen"
                @click="toggle"
              >
                {{ isFullscreen ? '退出全屏' : '全屏' }}
              </el-button>
            </div>
          </header>

          <div ref="downloadRef" class="flex flex-1">
            <div class="flex gap-1 select-none">
              <div
                v-for="item of maxmin"
                :key="item.name"
                :style="{
                  '--theme-bg-hover': item.bgHover
                }"
                class="w-8 h-full flex flex-col items-center justify-between py-2 gap-1 rounded-full group relative bg-transparent border border-solid border-transparent transition-all duration-300 hover:bg-[var(--theme-bg-hover)] hover-border-gray-200 hover:shadow-md cursor-pointer active:scale-95"
                @click="handleClickSpec(item.name)"
              >
                <span class="[writing-mode:sideways-lr] text-xs text-gray-400">{{ item.max }}</span>
                <div
                  class="flex-1 w-0.5 rounded-full opacity-40 group-hover:opacity-100 transition-opacity duration-300"
                  :style="{ backgroundColor: item.color }"
                ></div>
                <span
                  class="[writing-mode:sideways-lr] text-sm font-bold tracking-widest"
                  :style="{ color: item.color }"
                >
                  {{ item.name }}
                </span>
                <div
                  class="flex-1 w-0.5 rounded-full opacity-40 group-hover:opacity-100 transition-opacity duration-300"
                  :style="{ backgroundColor: item.color }"
                ></div>
                <span class="[writing-mode:sideways-lr] text-xs text-gray-400">{{ item.min }}</span>
              </div>
            </div>
            <div
              class="flex flex-1 min-w-0 bg-gray-50/30 rounded-lg border border-dashed border-gray-200 ml-2 relative overflow-hidden bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:20px_20px]"
            >
              <div
                v-loading="chartLoading"
                element-loading-background="transparent"
                ref="chartRef"
                class="w-full h-full"
              >
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- <div ref="targetArea" class="h-full min-h-0 relative">
      <div class="grid grid-cols-[260px_1fr] gap-4 h-full">
        <el-scrollbar
          class="rounded-xl shadow-sm border border-gray-100 border-solid overflow-hidden bg-gradient-to-b from-blue-100 to-white"
          view-class="flex flex-col min-h-full"
          v-loading="dimensionLoading"
        >
          <template v-for="citem in dimensionsContent" :key="citem.label">
            <template v-if="citem.judgment ? Boolean(citem.value.length) : true">
              <div
                class="sticky-title bg-blue-100 z-10 flex justify-between items-center py-3 px-4 border-0 border-solid"
              >
                <span class="font-bold text-sm text-gray-700! flex items-center gap-2">
                  <el-icon><component :is="citem.icon" /></el-icon>
                  {{ citem.label }}
                </span>
                <span
                  class="text-xs px-2 py-0.5 rounded-full font-mono"
                  :class="[citem.countBg, citem.countColor]"
                >
                  {{ citem.value.length }}
                </span>
              </div>

              <div class="px-3 pb-4 pt-2 space-y-3">
                <div
                  :data-disabled="disabledDimensions.includes(item.identifier)"
                  v-for="item in citem.value"
                  :key="item.identifier"
                  @click="handleClickSpec(item.name)"
                  class="dimension-card group relative p-3 rounded-lg border border-solid bg-transparent border-gray-300 transition-all duration-300 cursor-pointer select-none data-[disabled=true]:pointer-events-none"
                  :class="{ 'is-active': selectedDimension[item.name] }"
                  :style="{
                    '--theme-color': item.color,
                    '--theme-bg-hover': item.bgHover,
                    '--theme-bg-active': item.bgActive
                  }"
                >
                  <div class="flex justify-between items-center mb-1">
                    <span
                      class="text-xs font-medium text-gray-500 transition-colors truncate pr-2 group-hover:text-[var(--theme-color)]"
                      :class="{ 'text-[var(--theme-color)]!': selectedDimension[item.name] }"
                    >
                      {{ item.name }}
                    </span>
                    <div
                      class="size-2 rounded-full transition-all duration-300 shadow-sm"
                      :class="selectedDimension[item.name] ? 'scale-100' : 'scale-0'"
                      :style="{ backgroundColor: item.color, boxShadow: `0 0 6px ${item.color}` }"
                    ></div>
                  </div>

                  <div class="flex items-baseline justify-between relative z-9">
                    <animated-count-to
                      v-if="!item.isText"
                      :value="Number(item.value)"
                      :duration="500"
                      :suffix="item.suffix"
                      class="text-lg font-bold font-mono tracking-tight text-slate-800"
                    />
                    <span v-else class="text-lg font-bold font-mono tracking-tight text-slate-800">
                      {{ item.value }}
                    </span>
                  </div>
                  <div
                    class="absolute left-0 top-3 bottom-3 w-1 rounded-r transition-all duration-300"
                    :class="
                      selectedDimension[item.name]
                        ? 'opacity-100 shadow-[0_0_8px_currentColor]'
                        : 'opacity-0'
                    "
                    :style="{ backgroundColor: item.color, color: item.color }"
                  >
                  </div>
                </div>
              </div>
            </template>
          </template>
        </el-scrollbar>

        <div
          class="rounded-xl shadow-sm border border-gray-100 border-solid p-4 flex flex-col bg-gradient-to-b from-blue-100 to-white"
        >
          <header class="flex items-center justify-between mb-4">
            <h3 class="flex items-center gap-2">
              <div
                class="i-material-symbols:area-chart-outline-rounded text-sky size-6"
                text-sky
              ></div>
              数据趋势
            </h3>
            <div class="flex gap-4">
              <el-button type="primary" size="default" @click="exportChart">导出为图片</el-button>
              <el-button size="default" @click="reset">重置</el-button>
              <el-date-picker
                v-model="selectedDate"
                value-format="YYYY-MM-DD HH:mm:ss"
                type="datetimerange"
                unlink-panels
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                :shortcuts="rangeShortcuts"
                size="default"
                class="w-100!"
                placement="bottom-end"
                @change="handleDateChange"
              />
              <el-button
                size="default"
                :type="isFullscreen ? 'info' : 'primary'"
                :icon="isFullscreen ? Crop : FullScreen"
                @click="toggle"
              >
                {{ isFullscreen ? '退出全屏' : '全屏' }}
              </el-button>
            </div>
          </header>

          <div ref="downloadRef" class="flex flex-1">
            <div class="flex gap-1 select-none">
              <div
                v-for="item of maxmin"
                :key="item.name"
                :style="{
                  '--theme-bg-hover': item.bgHover
                }"
                class="w-8 h-full flex flex-col items-center justify-between py-2 gap-1 rounded-full group relative bg-transparent border border-solid border-transparent transition-all duration-300 hover:bg-[var(--theme-bg-hover)] hover-border-gray-200 hover:shadow-md cursor-pointer active:scale-95"
                @click="handleClickSpec(item.name)"
              >
                <span class="[writing-mode:sideways-lr] text-xs text-gray-400">{{ item.max }}</span>
                <div
                  class="flex-1 w-0.5 rounded-full opacity-40 group-hover:opacity-100 transition-opacity duration-300"
                  :style="{ backgroundColor: item.color }"
                ></div>
                <span
                  class="[writing-mode:sideways-lr] text-sm font-bold tracking-widest"
                  :style="{ color: item.color }"
                >
                  {{ item.name }}
                </span>
                <div
                  class="flex-1 w-0.5 rounded-full opacity-40 group-hover:opacity-100 transition-opacity duration-300"
                  :style="{ backgroundColor: item.color }"
                ></div>
                <span class="[writing-mode:sideways-lr] text-xs text-gray-400">{{ item.min }}</span>
              </div>
            </div>
            <div
              class="flex flex-1 min-w-0 bg-gray-50/30 rounded-lg border border-dashed border-gray-200 ml-2 relative overflow-hidden bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:20px_20px]"
            >
              <div
                v-loading="chartLoading"
                element-loading-background="transparent"
                ref="chartRef"
                class="w-full h-full"
              >
              </div>
            </div>
          </div>
        </div>
      </div>
    </div> -->
  </div>
</template>

<style scoped>
:deep(.el-tag__content) {
  display: flex;
  align-items: center;
  gap: 2px;
}

.sticky-title {
  position: sticky;
  top: 0;
}

.dimension-card:hover {
  background-color: var(--theme-bg-hover);
  border-color: var(--theme-bg-active);
  box-shadow: 0 4px 12px -2px rgb(0 0 0 / 5%);
}

.dimension-card.is-active {
  background-color: var(--theme-bg-active);
  border-color: var(--theme-color);
  box-shadow:
    0 0 0 1px var(--theme-bg-active),
    0 4px 12px -2px var(--theme-bg-active);
}

:deep(.el-scrollbar__bar.is-vertical) {
  right: 2px;
  width: 4px;
}

:deep(.el-scrollbar__thumb) {
  background-color: #cbd5e1;
  opacity: 0.6;
}

:deep(.el-scrollbar__thumb:hover) {
  background-color: #94a3b8;
  opacity: 1;
}

:fullscreen {
  padding: 16px;
  background-color: #fff;
}

/* 兼容写法 */
::backdrop {
  background-color: #fff;
}
</style>
