<template>
  <div
    class="warehouse-dashboard"
    :style="{ width: `${style.width}px`, height: `${style.height}px`, transform: style.transform }"
  >
    <div class="dashboard-shell">
      <header class="dashboard-header">
        <div class="brand">
          <img class="brand-logo" :src="clientLogoUrl" alt="RENLY" />
        </div>
        <h1>仓库任务大屏</h1>
        <div class="time-block">
          <div class="current-time">{{ currentTime }}</div>
          <!-- <div class="refresh-time">数据刷新 {{ refreshTimeText }}</div> -->
        </div>
      </header>

      <main class="dashboard-content">
        <section class="chart-grid">
          <article class="panel chart-panel">
            <div class="chart-panel-head">
              <div class="chart-title">入库任务</div>
              <div class="chart-summary">
                <div class="chart-summary-value">
                  <span>{{ chartSummaries.inbound.value }}</span>
                  <small>条</small>
                </div>
                <div class="chart-summary-sub">加急 <span>{{ chartSummaries.inbound.urgent }}</span> 条</div>
              </div>
            </div>
            <div ref="inboundChartRef" class="chart-box"></div>
          </article>
          <article class="panel chart-panel">
            <div class="chart-panel-head">
              <div class="chart-title">拣配任务</div>
              <div class="chart-summary">
                <div class="chart-summary-value">
                  <span>{{ chartSummaries.picking.value }}</span>
                  <small>条</small>
                </div>
                <div class="chart-summary-sub">加急 <span>{{ chartSummaries.picking.urgent }}</span> 条</div>
              </div>
            </div>
            <div ref="pickingChartRef" class="chart-box"></div>
          </article>
          <article class="panel chart-panel">
            <div class="chart-panel-head">
              <div class="chart-title">及时处理</div>
              <div class="chart-summary">
                <div class="chart-summary-value">
                  <span>{{ chartSummaries.timely.value }}</span>
                  <small>条</small>
                </div>
                <div class="chart-summary-sub">加急 <span>{{ chartSummaries.timely.urgent }}</span> 条</div>
              </div>
            </div>
            <div ref="riskChartRef" class="chart-box"></div>
          </article>
          <article class="panel chart-panel">
            <div class="chart-panel-head">
              <div class="chart-title">发货任务</div>
              <div class="chart-summary">
                <div class="chart-summary-value">
                  <span>{{ chartSummaries.delivery.value }}</span>
                  <small>条</small>
                </div>
                <div class="chart-summary-sub">加急 <span>{{ chartSummaries.delivery.urgent }}</span> 条</div>
              </div>
            </div>
            <div ref="deliveryChartRef" class="chart-box"></div>
          </article>
        </section>

        <section class="detail-grid">
          <article v-for="table in detailTables" :key="table.key" class="panel table-panel">
            <div class="panel-caption">{{ table.title }}</div>
            <div class="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th v-for="column in table.columns" :key="column.key" :style="{ width: column.width }">
                      {{ column.label }}
                    </th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-if="table.rows.length === 0" class="empty-row">
                    <td :colspan="table.columns.length">暂无数据</td>
                  </tr>
                  <tr v-for="row in table.rows" :key="`${table.key}-${row._idx}`" :class="{ warning: row.urgentValue > 0 }">
                    <td v-for="column in table.columns" :key="column.key">
                      {{ row[column.key] }}
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          </article>
        </section>
      </main>
    </div>
  </div>
</template>

<script setup>
import { computed, inject, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
import * as echarts from 'echarts'

defineOptions({ name: 'WarehouseDashboard' })

const CreateData = inject('CreateData')
const ExecDatabase = inject('ExecDatabase')

const clientLogoUrl = './public/ClientLogo.png'
const now = ref(new Date())
const lastRefreshTime = ref('')
const style = reactive({
  width: 1920,
  height: 1080,
  transform: 'scaleY(1) scaleX(1) translate(-50%, -50%)'
})

let clockTimer = null
let refreshTimer = null
let resizeHandler = null
let scrollTimers = []
let inboundChart = null
let pickingChart = null
let riskChart = null
let deliveryChart = null

const inboundChartRef = ref(null)
const pickingChartRef = ref(null)
const riskChartRef = ref(null)
const deliveryChartRef = ref(null)

const summaryRows = ref([])
const inboundOverdueRows = ref([])
const outboundOverdueRows = ref([])
const urgentPickingRows = ref([])
const todayDeliveryRows = ref([])
const inboundOffset = ref(0)
const outboundOffset = ref(0)
const urgentPickingOffset = ref(0)
const deliveryOffset = ref(0)

const VISIBLE_ROWS = {
  inbound: 7,
  outbound: 7,
  urgentPicking: 7,
  delivery: 7
}

const inboundCategories = ['原料', '零件', '机加', '装配']
const pickingCategories = ['机加', '装配']
const riskCategories = ['上架', '入库', '汇报']

const currentTime = computed(() => formatDateTime(now.value))
const refreshTimeText = computed(() => lastRefreshTime.value || '--:--:--')
const chartSummaries = computed(() => ({
  inbound: formatChartSummary(getSectionTotal('入库')),
  picking: formatChartSummary(getPickingSectionTotal()),
  timely: formatChartSummary(getSectionTotal('及时处理')),
  delivery: formatChartSummary(getDeliverySectionTotal())
}))

const inboundDisplayRows = computed(() => makeDisplayRows(inboundOverdueRows.value, inboundOffset.value, VISIBLE_ROWS.inbound))
const outboundDisplayRows = computed(() => makeDisplayRows(outboundOverdueRows.value, outboundOffset.value, VISIBLE_ROWS.outbound))
const urgentPickingDisplayRows = computed(() => makeDisplayRows(urgentPickingRows.value, urgentPickingOffset.value, VISIBLE_ROWS.urgentPicking))
const deliveryDisplayRows = computed(() => makeDisplayRows(todayDeliveryRows.value, deliveryOffset.value, VISIBLE_ROWS.delivery))

const detailTables = computed(() => [
  {
    key: 'inbound',
    title: '加急入库列表',
    columns: urgentInboundColumns,
    rows: inboundDisplayRows.value
  },
  {
    key: 'outbound',
    title: '拣配任务列表',
    columns: pickingColumns,
    rows: outboundDisplayRows.value
  },
  {
    key: 'urgentPicking',
    title: '加急拣配列表',
    columns: urgentPickingColumns,
    rows: urgentPickingDisplayRows.value
  },
  {
    key: 'delivery',
    title: '发货任务列表',
    columns: deliveryColumns,
    rows: deliveryDisplayRows.value
  }
])

onMounted(() => {
  startClock()
  setScale()
  resizeHandler = () => {
    setScale()
    resizeCharts()
  }
  window.addEventListener('resize', resizeHandler)
  nextTick(() => {
    initCharts()
    searchDashboardData()
  })
  startAllScroll()
  refreshTimer = window.setInterval(searchDashboardData, 300000)
})

onUnmounted(() => {
  if (clockTimer) {
    window.clearInterval(clockTimer)
  }
  if (refreshTimer) {
    window.clearInterval(refreshTimer)
  }
  if (resizeHandler) {
    window.removeEventListener('resize', resizeHandler)
  }
  stopAllScroll()
  disposeCharts()
})

const startClock = () => {
  clockTimer = window.setInterval(() => {
    now.value = new Date()
  }, 1000)
}

const setScale = () => {
  const scale = getScale()
  style.transform = `scaleY(${scale.y}) scaleX(${scale.x}) translate(-50%, -50%)`
}

const getScale = () => ({
  x: window.innerWidth / style.width,
  y: window.innerHeight / style.height
})

const initCharts = () => {
  if (inboundChartRef.value && !inboundChart) {
    inboundChart = echarts.init(inboundChartRef.value)
  }
  if (pickingChartRef.value && !pickingChart) {
    pickingChart = echarts.init(pickingChartRef.value)
  }
  if (riskChartRef.value && !riskChart) {
    riskChart = echarts.init(riskChartRef.value)
  }
  if (deliveryChartRef.value && !deliveryChart) {
    deliveryChart = echarts.init(deliveryChartRef.value)
  }
  renderCharts()
}

const renderCharts = () => {
  if (!inboundChart || !pickingChart || !riskChart || !deliveryChart) {
    return
  }

  inboundChart.setOption(createInboundChartOption(), true)
  pickingChart.setOption(createPickingChartOption(), true)
  riskChart.setOption(createRiskChartOption(), true)
  deliveryChart.setOption(createDeliveryChartOption(), true)
  resizeCharts()
}

const resizeCharts = () => {
  ;[inboundChart, pickingChart, riskChart, deliveryChart].forEach(chart => {
    if (chart) {
      chart.resize()
    }
  })
}

const disposeCharts = () => {
  ;[inboundChart, pickingChart, riskChart, deliveryChart].forEach(chart => {
    if (chart) {
      chart.dispose()
    }
  })
  inboundChart = null
  pickingChart = null
  riskChart = null
  deliveryChart = null
}

const searchDashboardData = () => {
  const tasks = [
    queryDashboardData('仓库大屏_汇总查询', applySummaryData),
    queryDashboardData('仓库大屏_加急入库列表', applyInboundOverdueData),
    queryDashboardData('仓库大屏_拣配任务列表', applyOutboundOverdueData),
    queryDashboardData('仓库大屏_加急拣配列表', applyUrgentPickingData),
    queryDashboardData('装配中心任务看板_发货状态查询', applyTodayDeliveryData)
  ]

  Promise.all(tasks).finally(() => {
    lastRefreshTime.value = formatTime(new Date())
    nextTick(renderCharts)
  })
}

const queryDashboardData = (procedureName, applyData) => {
  if (!CreateData || !ExecDatabase) {
    applyData([])
    return Promise.resolve([])
  }

  const data = CreateData('11', procedureName, [])
  return ExecDatabase(data)
    .then(response => {
      const rows = getResponseRows(response)
      applyData(rows)
      return rows
    })
    .catch(error => {
      console.error(`${procedureName} 查询失败:`, error)
      applyData([])
      return []
    })
}

const getResponseRows = response => {
  if (response && Array.isArray(response.data)) {
    return response.data
  }
  if (response && response.data && Array.isArray(response.data.rows)) {
    return response.data.rows
  }
  if (response && response.data && Array.isArray(response.data.result)) {
    return response.data.result
  }
  return []
}

const applySummaryData = rows => {
  if (!Array.isArray(rows) || rows.length === 0) {
    return
  }

  summaryRows.value = rows.map(row => ({
    section: normalizeText(row.环节),
    category: normalizeText(row.分类),
    taskCount: toNumber(row.任务数),
    quantity: toNumber(row.数量),
    urgentQty: toNumber(row.加急数量),
    sort: toNumber(row.排序)
  }))
}

const applyInboundOverdueData = rows => {
  inboundOffset.value = 0
  inboundOverdueRows.value = rows.map((row, index) => ({
    _idx: index + 1,
    category: normalizeText(row.类别),
    orderNo: normalizeText(row.单号),
    itemName: normalizeText(row.物料名称),
    urgentQty: formatAmount(row.加急数量, 2),
    urgentValue: toNumber(row.加急数量)
  }))
}

const applyOutboundOverdueData = rows => {
  outboundOffset.value = 0
  outboundOverdueRows.value = rows.map((row, index) => ({
    _idx: index + 1,
    salesOrder: normalizeText(row.合同号),
    productionOrder: normalizeText(row.生产订单),
    itemName: normalizeText(row.物料名称),
    completeSet: normalizeText(row.齐套),
    status: normalizeText(row.状态),
    urgentValue: 0
  }))
}

const applyUrgentPickingData = rows => {
  urgentPickingOffset.value = 0
  urgentPickingRows.value = rows.map((row, index) => ({
    _idx: index + 1,
    category: normalizeText(row.类别),
    orderNo: normalizeText(row.单号),
    itemName: normalizeText(row.物料名称),
    urgentStatus: normalizeText(row.加急状态),
    urgentValue: 1
  }))
}

const applyTodayDeliveryData = rows => {
  deliveryOffset.value = 0
  todayDeliveryRows.value = rows.map((row, index) => ({
    _idx: index + 1,
    salesOrder: normalizeText(row.合同号),
    itemName: normalizeText(row.物料描述 || row.物料名称),
    deliveryQty: formatAmount(row.交货数量 || row.计划数量, 2),
    deliveryDate: formatDateValue(row.要求发货日期 || row.发货日期),
    testQty: formatAmount(row.检验数量, 2),
    urgentValue: toNumber(row.加急总数 || row.加急数量)
  }))
}

const startAllScroll = () => {
  startScrollWhenOverflow(inboundOverdueRows, inboundOffset, VISIBLE_ROWS.inbound)
  startScrollWhenOverflow(outboundOverdueRows, outboundOffset, VISIBLE_ROWS.outbound)
  startScrollWhenOverflow(urgentPickingRows, urgentPickingOffset, VISIBLE_ROWS.urgentPicking)
  startScrollWhenOverflow(todayDeliveryRows, deliveryOffset, VISIBLE_ROWS.delivery)
}

const startScrollWhenOverflow = (rowsRef, offsetRef, visibleCount) => {
  const timerId = window.setInterval(() => {
    if (rowsRef.value.length <= visibleCount) {
      offsetRef.value = 0
      return
    }

    const maxOffset = rowsRef.value.length - visibleCount
    offsetRef.value = offsetRef.value >= maxOffset ? 0 : offsetRef.value + 1
  }, 2600)
  scrollTimers.push(timerId)
}

const stopAllScroll = () => {
  scrollTimers.forEach(timerId => window.clearInterval(timerId))
  scrollTimers = []
}

const makeDisplayRows = (rows, offset, visibleCount) => {
  if (!Array.isArray(rows) || rows.length === 0) {
    return []
  }

  const maxOffset = Math.max(rows.length - visibleCount, 0)
  const safeOffset = Math.min(Math.max(offset, 0), maxOffset)
  return rows.slice(safeOffset, safeOffset + visibleCount).map((row, index) => ({
    ...row,
    _idx: safeOffset + index + 1
  }))
}

const createInboundChartOption = () => createBarOption({
  categories: inboundCategories,
  totalName: '任务',
  urgentName: '加急',
  totalData: inboundCategories.map(category => getSummaryRow('入库', category).taskCount),
  urgentData: inboundCategories.map(category => getSummaryRow('入库', category).urgentQty)
})

const createPickingChartOption = () => createBarOption({
  categories: [...pickingCategories, '异常出库'],
  totalName: '任务',
  urgentName: '加急',
  totalData: [
    ...pickingCategories.map(category => getSummaryRow('拣配', category).taskCount),
    getSummaryRow('发货', '异常出库').taskCount
  ],
  urgentData: [
    ...pickingCategories.map(category => getSummaryRow('拣配', category).urgentQty),
    getSummaryRow('发货', '异常出库').urgentQty
  ]
})

const createBarOption = ({ categories, totalName, urgentName, totalData, urgentData }) => ({
  color: ['#35c5ff', '#ff3345'],
  tooltip: {
    trigger: 'axis',
    axisPointer: { type: 'shadow' },
    backgroundColor: 'rgba(3, 16, 48, 0.94)',
    borderColor: 'rgba(43, 216, 255, 0.55)',
    textStyle: { color: '#f3f9ff', fontSize: 19 },
    valueFormatter: value => formatAmount(value, 2)
  },
  legend: {
    top: 0,
    right: 18,
    itemWidth: 18,
    itemHeight: 12,
    textStyle: { color: '#bde9ff', fontSize: 19 }
  },
  grid: {
    left: 18,
    right: 18,
    top: 46,
    bottom: 36,
    containLabel: true
  },
  xAxis: {
    type: 'category',
    data: categories,
    axisLine: { lineStyle: { color: 'rgba(141, 211, 255, 0.6)' } },
    axisTick: { show: false },
    axisLabel: { color: '#d8f3ff', fontSize: 21, fontWeight: 700 }
  },
  yAxis: {
    type: 'value',
    axisLine: { show: false },
    axisTick: { show: false },
    axisLabel: { show: false },
    splitLine: { show: false }
  },
  series: [
    {
      name: totalName,
      type: 'bar',
      barWidth: 32,
      data: totalData,
      itemStyle: {
        borderRadius: [3, 3, 0, 0]
      },
      label: {
        show: true,
        position: 'top',
        color: '#f3f9ff',
        fontSize: 19,
        fontWeight: 700,
        formatter: params => formatCompactNumber(params.value)
      }
    },
    {
      name: urgentName,
      type: 'bar',
      barWidth: 32,
      data: urgentData,
      itemStyle: {
        borderRadius: [3, 3, 0, 0]
      },
      label: {
        show: true,
        position: 'top',
        color: '#ff3345',
        fontSize: 19,
        fontWeight: 800,
        formatter: params => formatCompactNumber(params.value)
      }
    }
  ]
})

const createRiskChartOption = () => createBarOption({
  categories: riskCategories,
  totalName: '任务',
  urgentName: '加急',
  totalData: riskCategories.map(category => getSummaryRow('及时处理', category).taskCount),
  urgentData: riskCategories.map(category => getSummaryRow('及时处理', category).urgentQty)
})

const createDeliveryChartOption = () => {
  const categories = ['发货任务', '小于今日']
  return createBarOption({
    categories,
    totalName: '任务',
    urgentName: '加急',
    totalData: categories.map(category => getSummaryRow('发货', category).taskCount),
    urgentData: categories.map(category => getSummaryRow('发货', category).urgentQty)
  })
}

const getSummaryRow = (section, category) => {
  return summaryRows.value.find(row => row.section === section && row.category === category) || {
    section,
    category,
    taskCount: 0,
    quantity: 0,
    urgentQty: 0,
    sort: 0
  }
}

const sumRows = (section, key) => {
  return summaryRows.value
    .filter(row => row.section === section)
    .reduce((total, row) => total + toNumber(row[key]), 0)
}

const getSectionTotal = section => ({
  taskCount: sumRows(section, 'taskCount'),
  quantity: sumRows(section, 'quantity'),
  urgentQty: sumRows(section, 'urgentQty')
})

const getPickingSectionTotal = () => {
  const pickingTotal = getSectionTotal('拣配')
  const abnormalDelivery = getSummaryRow('发货', '异常出库')
  return {
    taskCount: pickingTotal.taskCount + abnormalDelivery.taskCount,
    quantity: pickingTotal.quantity + abnormalDelivery.quantity,
    urgentQty: pickingTotal.urgentQty + abnormalDelivery.urgentQty
  }
}

const getDeliverySectionTotal = () => {
  const deliveryTask = getSummaryRow('发货', '发货任务')
  const todayDelivery = getSummaryRow('发货', '小于今日')
  return {
    taskCount: deliveryTask.taskCount ,
    quantity: deliveryTask.quantity,
    urgentQty: deliveryTask.urgentQty 
  }
}

const formatChartSummary = total => ({
  value: formatAmount(total.taskCount),
  urgent: formatAmount(total.urgentQty)
})

const pad = value => String(value).padStart(2, '0')

const formatDateTime = value => {
  const date = value instanceof Date ? value : new Date(value)
  if (Number.isNaN(date.getTime())) {
    return ''
  }
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${formatTime(date)}`
}

const formatTime = value => {
  const date = value instanceof Date ? value : new Date(value)
  if (Number.isNaN(date.getTime())) {
    return ''
  }
  return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}

const formatDateValue = value => {
  if (!value) {
    return ''
  }
  if (value instanceof Date) {
    return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`
  }
  return String(value).split('T')[0].split(' ')[0]
}

const formatAmount = (value, maximumFractionDigits = 0) => {
  const number = toNumber(value)
  return new Intl.NumberFormat('zh-CN', {
    maximumFractionDigits
  }).format(number)
}

const formatCompactNumber = value => {
  const number = toNumber(value)
  const absolute = Math.abs(number)

  if (absolute >= 100000000) {
    return `${trimZero((number / 100000000).toFixed(2))}亿`
  }
  if (absolute >= 10000) {
    return `${trimZero((number / 10000).toFixed(2))}万`
  }
  return formatAmount(number, Number.isInteger(number) ? 0 : 2)
}

const formatPercent = (part, total) => {
  const totalNumber = toNumber(total)
  if (totalNumber <= 0) {
    return '0%'
  }
  return `${trimZero(((toNumber(part) * 100) / totalNumber).toFixed(1))}%`
}

const trimZero = value => String(value).replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1')

const toNumber = value => {
  if (value === null || value === undefined || value === '') {
    return 0
  }
  const number = Number(String(value).replace(/,/g, ''))
  return Number.isNaN(number) ? 0 : number
}

const normalizeText = value => {
  if (value === null || value === undefined) {
    return ''
  }
  return String(value).trim()
}

const urgentInboundColumns = [
  { label: '类别', key: 'category', width: '13%' },
  { label: '单号', key: 'orderNo', width: '20%' },
  { label: '物料名称', key: 'itemName', width: '52%' },
  { label: '加急', key: 'urgentQty', width: '15%' }
]

const pickingColumns = [
  { label: '合同号', key: 'salesOrder', width: '20%' },
  { label: '生产订单', key: 'productionOrder', width: '18%' },
  { label: '物料名称', key: 'itemName', width: '47%' },
  { label: '齐套', key: 'completeSet', width: '15%' }
]

const urgentPickingColumns = [
  { label: '类别', key: 'category', width: '13%' },
  { label: '单号', key: 'orderNo', width: '20%' },
  { label: '物料名称', key: 'itemName', width: '52%' },
  { label: '状态', key: 'urgentStatus', width: '15%' }
]

const deliveryColumns = [
  { label: '合同号', key: 'salesOrder', width: '24%' },
  { label: '物料名称', key: 'itemName', width: '30%' },
  { label: '数量', key: 'deliveryQty', width: '12%' },
  { label: '发货日期', key: 'deliveryDate', width: '25%' },
  { label: '测试', key: 'testQty', width: '10%' }
]
</script>

<style scoped lang="scss">
* {
  box-sizing: border-box;
}

.warehouse-dashboard {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 1920px;
  height: 1080px;
  overflow: hidden;
  color: #f3f9ff;
  font-family: 'Microsoft YaHei', Arial, sans-serif;
  background:
    radial-gradient(circle at 18% 16%, rgba(13, 87, 122, 0.34), transparent 28%),
    radial-gradient(circle at 78% 72%, rgba(86, 30, 55, 0.22), transparent 30%),
    linear-gradient(180deg, #07001f 0%, #07132d 54%, #071628 100%);
  transform-origin: 0 0;
  transition: 0.3s;
}

.dashboard-shell {
  width: 100%;
  height: 100%;
  padding: 0 15px 15px;
}

.dashboard-header {
  display: grid;
  grid-template-columns: 336px 1fr 442px;
  align-items: center;
  height: 95px;
  border-bottom: 1px solid rgba(21, 162, 240, 0.7);
}

.brand {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  width: 300px;
  height: 72px;
  overflow: visible;
}

.brand-logo {
  width: 224px;
  height: 58px;
  padding: 5px 10px;
  object-fit: contain;
  object-position: left center;
  background: #ffffff;
  border-radius: 6px;
  filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.28));
}

.dashboard-header h1 {
  margin: 0;
  color: #ffffff;
  font-size: 55px;
  font-weight: 900;
  letter-spacing: 0;
  text-align: center;
}

.time-block {
  display: grid;
  gap: 6px;
  padding-right: 40px;
  text-align: right;
}

.current-time {
  color: #eef7ff;
  font-size: 27px;
}

.refresh-time {
  color: #89d4ff;
  font-size: 17px;
}

.dashboard-content {
  display: grid;
  grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
  gap: 15px;
  height: calc(100% - 95px);
  padding-top: 10px;
}

.chart-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 15px;
  min-height: 0;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 15px;
  min-height: 0;
}

.panel {
  position: relative;
  min-width: 0;
  min-height: 0;
  border: 1px solid rgba(29, 153, 229, 0.78);
  background: rgba(3, 16, 48, 0.48);
  box-shadow:
    inset 0 0 18px rgba(27, 130, 214, 0.24),
    0 0 10px rgba(1, 132, 220, 0.18);
}

.panel::before {
  position: absolute;
  inset: -1px;
  content: '';
  pointer-events: none;
  background:
    linear-gradient(90deg, #2bd8ff 0 14px, transparent 14px) left top / 14px 2px no-repeat,
    linear-gradient(180deg, #2bd8ff 0 14px, transparent 14px) left top / 2px 14px no-repeat,
    linear-gradient(270deg, #2bd8ff 0 14px, transparent 14px) right top / 14px 2px no-repeat,
    linear-gradient(180deg, #2bd8ff 0 14px, transparent 14px) right top / 2px 14px no-repeat,
    linear-gradient(90deg, #2bd8ff 0 14px, transparent 14px) left bottom / 14px 2px no-repeat,
    linear-gradient(0deg, #2bd8ff 0 14px, transparent 14px) left bottom / 2px 14px no-repeat,
    linear-gradient(270deg, #2bd8ff 0 14px, transparent 14px) right bottom / 14px 2px no-repeat,
    linear-gradient(0deg, #2bd8ff 0 14px, transparent 14px) right bottom / 2px 14px no-repeat;
}

.panel::after {
  position: absolute;
  inset: 0;
  content: '';
  pointer-events: none;
  box-shadow: inset 0 0 12px rgba(43, 216, 255, 0.12);
}


.chart-panel,
.table-panel {
  display: flex;
  flex-direction: column;
}

.chart-panel-head {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 104px;
  padding: 12px 22px 4px;
  gap: 14px;
}

.chart-title {
  flex: 1;
  min-width: 0;
  color: #8cd3ff;
  font-size: 36px;
  font-weight: 800;
  line-height: 1.15;
}

.chart-summary {
  flex: 0 0 auto;
  min-width: 210px;
  color: #f3f9ff;
  text-align: right;
}

.chart-summary-value {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  color: #36c8ff;
  font-weight: 900;
  line-height: 1;
  white-space: nowrap;
}

.chart-summary-value span {
  font-size: 64px;
}

.chart-summary-value small {
  margin-left: 8px;
  color: #ffffff;
  font-size: 28px;
  font-weight: 800;
}

.chart-summary-sub {
  margin-top: 6px;
  color: #c8eaff;
  font-size: 21px;
  font-weight: 700;
  line-height: 1.25;
  white-space: nowrap;
}

.chart-summary-sub span {
  color: #ff3345;
  font-weight: 900;
}

.panel-caption {
  height: 44px;
  color: #8cd3ff;
  font-size: 34px;
  font-weight: 700;
  line-height: 44px;
  text-align: center;
}

.chart-box {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
}

.table-wrap {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 0 6px 8px;
}

table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

th,
td {
  border: 1px solid rgba(53, 149, 217, 0.54);
  color: #f1f8ff;
  line-height: 1.18;
  text-align: center;
  vertical-align: middle;
  word-break: break-all;
  background: rgba(4, 24, 57, 0.5);
}

th {
  height: 44px;
  color: #bde9ff;
  font-size: 18px;
  font-weight: 600;
  background: rgba(12, 68, 119, 0.34);
}

td {
  height: 44px;
  padding: 0 4px;
  overflow: hidden;
  font-size: 17px;
  text-overflow: ellipsis;
}

.warning td {
  color: #ff4949;
  font-weight: 700;
}

.empty-row td {
  height: 228px;
  color: #89d4ff;
  font-size: 22px;
}
</style>
