<script lang="ts" setup generic="T">
import type { TableInstance, TableProps } from 'element-plus'
import {
  Comment,
  Fragment,
  Text,
  cloneVNode,
  computed,
  nextTick,
  provide,
  ref,
  useAttrs,
  useSlots,
  watch
} from 'vue'
import { useRoute } from 'vue-router'
import { TableContextKey } from './token'
import type { ColumnAlign, ColumnFixed, ColumnSettingItem } from './token'
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
import type { VNode } from 'vue'

interface ColumnMeta {
  key: string
  label: string
  visible?: boolean
  action: boolean
  configurable: boolean
  fixed: ColumnFixed
  children: ColumnMeta[]
}

interface Props
  extends /* @vue-ignore */ Partial<
    Omit<TableProps<T extends DefaultRow ? T : DefaultRow>, 'data'>
  > {
  data: T[]
  loading: boolean
  customClass?: boolean
  showBorder?: boolean
  hoverHighlight?: boolean
  align?: ColumnAlign
  columnMaxWidth?: number
  settingsCache?: boolean
  settingsCacheKey?: string
}

const props = defineProps<Props>()
const attrs = useAttrs()
const slots = useSlots()
const route = useRoute()
const tableRef = ref<TableInstance>()
const columnSettings = ref<ColumnSettingItem[]>([])
const columnDefaultSettings = ref<ColumnSettingItem[]>([])
const slotColumnSignature = ref('')
const columnSettingsStorageKey = ref('')
const isSyncingColumnSettings = ref(false)
const columnSettingsStoragePrefix = 'zm-table:column-settings:'

const defaultOptions: Partial<Props> = {
  size: 'default',
  stripe: true,
  border: true,
  highlightCurrentRow: true,
  showOverflowTooltip: true,
  scrollbarAlwaysOn: true,
  showBorder: false,
  hoverHighlight: true,
  customClass: false,
  tooltipOptions: {
    popperClass: 'max-w-120'
  }
}

const bindProps = computed(() => {
  const {
    data,
    customClass: _customClass,
    showBorder: _showBorder,
    hoverHighlight: _hoverHighlight,
    align: _align,
    columnMaxWidth,
    settingsCache: _settingsCache,
    settingsCacheKey: _settingsCacheKey,
    ...otherProps
  } = props

  return {
    ...defaultOptions,
    ...attrs,
    ...otherProps,
    data: data || []
  }
})

const safeData = computed(() => props.data || [])
const safeLoading = computed(() => props.loading)
const safeColumnAlign = computed<ColumnAlign>(() => {
  return props.align === 'left' || props.align === 'right' || props.align === 'center'
    ? props.align
    : 'center'
})
const safeColumnMaxWidth = computed(() => {
  const maxWidth = Number(props.columnMaxWidth)
  return Number.isFinite(maxWidth) && maxWidth > 0 ? maxWidth : 360
})
const isColumnSettingsCacheEnabled = computed(() => props.settingsCache !== false)

const forwardedSlots = computed(() => {
  const { default: _default, ...restSlots } = slots
  return restSlots
})

const getPropValue = (props: Record<string, any> | null | undefined, ...keys: string[]) => {
  if (!props) return undefined
  for (const key of keys) {
    if (props[key] !== undefined) return props[key]
  }
  return undefined
}

const toBoolean = (value: unknown) => value === true || value === ''

const normalizeFixed = (fixed: unknown): ColumnFixed => {
  if (fixed === true || fixed === 'left') return 'left'
  if (fixed === 'right') return 'right'
  return false
}

const isColumnNode = (node: VNode) => {
  if (!node.type && typeof node.type !== 'object') return false
  const nodeType = node.type as { __name?: string }
  return nodeType.__name === 'ZmTableColumn'
}

const canResolveColumnChildren = (node: VNode) => {
  const nodeProps = node.props
  return toBoolean(getPropValue(nodeProps, 'isParent', 'is-parent'))
}

const getColumnKey = (node: VNode, index: number, parentKey?: string) => {
  const nodeProps = node.props
  const key = getPropValue(nodeProps, 'columnKey', 'column-key')
  const prop = getPropValue(nodeProps, 'prop')
  const type = getPropValue(nodeProps, 'type')
  const label = getPropValue(nodeProps, 'label')
  const fallbackKey = parentKey ? `${parentKey}.column-${index}` : `column-${index}`
  return String(key ?? prop ?? type ?? label ?? fallbackKey)
}

const getColumnLabel = (node: VNode, index: number, parentKey?: string) => {
  const label = getPropValue(node.props, 'label')
  return String(label ?? getColumnKey(node, index, parentKey))
}

const getColumnChildren = (node: VNode) => {
  if (!canResolveColumnChildren(node)) return []
  const children = node.children
  if (children && typeof children === 'object' && 'default' in children) {
    const defaultSlot = (children as { default?: unknown }).default
    if (typeof defaultSlot !== 'function') return []
    try {
      const slotNodes = defaultSlot()
      const normalizedNodes = Array.isArray(slotNodes) ? slotNodes : slotNodes ? [slotNodes] : []
      return flattenSlotNodes(normalizedNodes as VNode[]).filter(isColumnNode)
    } catch {
      return []
    }
  }
  return []
}

const getColumnMeta = (node: VNode, index: number, parentKey?: string): ColumnMeta => {
  const key = getColumnKey(node, index, parentKey)
  const action = toBoolean(getPropValue(node.props, 'action'))
  const hideInColumnSettings = toBoolean(
    getPropValue(node.props, 'hideInColumnSettings', 'hide-in-column-settings')
  )
  return {
    key,
    label: getColumnLabel(node, index, parentKey),
    visible: getPropValue(node.props, 'visible'),
    action,
    configurable: !hideInColumnSettings,
    fixed: normalizeFixed(getPropValue(node.props, 'fixed')),
    children: getColumnChildren(node)
      .map((child, childIndex) => getColumnMeta(child, childIndex, key))
      .filter((item) => item.configurable)
  }
}

const flattenSlotNodes = (nodes: Array<VNode | null | undefined>): VNode[] => {
  return nodes.flatMap((node) => {
    if (!node) return []
    if (node.type === Fragment && Array.isArray(node.children)) {
      return flattenSlotNodes(node.children as VNode[])
    }
    if (node.type === Comment || node.type === Text) return []
    return [node]
  })
}

const syncColumnSettings = (nodes: VNode[]) => {
  const metas = nodes
    .map((node, index) => getColumnMeta(node, index))
    .filter((item) => item.configurable)
  const signature = JSON.stringify(metas)
  if (signature === slotColumnSignature.value) return
  slotColumnSignature.value = signature
  nextTick(() => {
    const defaults = metas.map(createDefaultColumnSetting)
    const storageKey = resolveColumnSettingsStorageKey(defaults)
    const cachedSettings = loadColumnSettings(storageKey)
    columnDefaultSettings.value = defaults
    columnSettingsStorageKey.value = storageKey
    setColumnSettings(mergeColumnSettings(defaults, cachedSettings || columnSettings.value))
  })
}

const createDefaultColumnSetting = (meta: ColumnMeta): ColumnSettingItem => ({
  key: meta.key,
  label: meta.label,
  visible: true,
  fixed: meta.fixed,
  children: meta.children.length ? meta.children.map(createDefaultColumnSetting) : undefined
})

const mergeColumnSettings = (
  defaults: ColumnSettingItem[],
  current: ColumnSettingItem[]
): ColumnSettingItem[] => {
  const defaultMap = new Map(defaults.map((item) => [item.key, item]))
  const currentMap = new Map(current.map((item) => [item.key, item]))
  const existingItems = current
    .filter((item) => defaultMap.has(item.key))
    .map((item) => {
      const defaultItem = defaultMap.get(item.key)!
      return {
        ...defaultItem,
        visible: item.visible,
        fixed: item.fixed,
        children: defaultItem.children
          ? mergeColumnSettings(defaultItem.children, item.children || [])
          : undefined
      }
    })
  const addedItems = defaults.filter((item) => !currentMap.has(item.key))
  return [...existingItems, ...addedItems]
}

const mapColumnSettings = (
  items: ColumnSettingItem[],
  mapper: (item: ColumnSettingItem) => ColumnSettingItem
): ColumnSettingItem[] => {
  return items.map((item) => {
    const mappedItem = mapper(item)
    return {
      ...mappedItem,
      children: mappedItem.children ? mapColumnSettings(mappedItem.children, mapper) : undefined
    }
  })
}

const updateColumnVisible = (key: string, visible: boolean) => {
  columnSettings.value = mapColumnSettings(columnSettings.value, (item) =>
    item.key === key ? { ...item, visible } : item
  )
}

const updateColumnFixed = (key: string, fixed: ColumnFixed) => {
  columnSettings.value = mapColumnSettings(columnSettings.value, (item) =>
    item.key === key ? { ...item, fixed } : item
  )
}

const sortSettingsByKeys = (items: ColumnSettingItem[], keys: string[]) => {
  const orderMap = new Map(keys.map((key, index) => [key, index]))
  return [...items].sort((a, b) => {
    const orderA = orderMap.get(a.key) ?? Number.MAX_SAFE_INTEGER
    const orderB = orderMap.get(b.key) ?? Number.MAX_SAFE_INTEGER
    return orderA - orderB
  })
}

const updateColumnOrder = (keys: string[], parentKey?: string) => {
  if (!parentKey) {
    columnSettings.value = sortSettingsByKeys(columnSettings.value, keys)
    return
  }

  columnSettings.value = mapColumnSettings(columnSettings.value, (item) => {
    if (item.key !== parentKey) return item

    return {
      ...item,
      children: item.children ? sortSettingsByKeys(item.children, keys) : item.children
    }
  })
}

const cloneColumnSettings = (items: ColumnSettingItem[]): ColumnSettingItem[] => {
  return items.map((item) => ({
    ...item,
    children: item.children ? cloneColumnSettings(item.children) : undefined
  }))
}

const resetColumnSettings = () => {
  setColumnSettings(cloneColumnSettings(columnDefaultSettings.value))
}

const flattenColumnSettingKeys = (items: ColumnSettingItem[]): string[] => {
  return items.flatMap((item) => [
    item.key,
    ...(item.children ? flattenColumnSettingKeys(item.children) : [])
  ])
}

const encodeStorageKeyPart = (value: string) => {
  try {
    return encodeURIComponent(value)
  } catch {
    return value
  }
}

const resolveColumnSettingsStorageKey = (defaults: ColumnSettingItem[]) => {
  if (!isColumnSettingsCacheEnabled.value) return ''

  const userKey = props.settingsCacheKey?.trim()
  if (userKey) return `${columnSettingsStoragePrefix}${encodeStorageKeyPart(userKey)}`

  const routeKey = String(route.name || route.path || 'global')
  const columnKey = flattenColumnSettingKeys(defaults).sort().join('|')
  return `${columnSettingsStoragePrefix}${encodeStorageKeyPart(`${routeKey}:${columnKey}`)}`
}

const isColumnSettingItem = (item: unknown): item is ColumnSettingItem => {
  if (!item || typeof item !== 'object') return false
  const setting = item as ColumnSettingItem
  const validFixed =
    setting.fixed === false || setting.fixed === 'left' || setting.fixed === 'right'
  return typeof setting.key === 'string' && typeof setting.visible === 'boolean' && validFixed
}

const normalizeCachedColumnSettings = (items: unknown): ColumnSettingItem[] => {
  if (!Array.isArray(items)) return []

  return items.filter(isColumnSettingItem).map((item) => ({
    key: item.key,
    label: typeof item.label === 'string' ? item.label : item.key,
    visible: item.visible,
    fixed: item.fixed,
    children: item.children ? normalizeCachedColumnSettings(item.children) : undefined
  }))
}

const loadColumnSettings = (storageKey: string) => {
  if (!storageKey || typeof window === 'undefined') return null

  try {
    const rawValue = window.localStorage.getItem(storageKey)
    if (!rawValue) return null

    const cachedValue = JSON.parse(rawValue)
    const settings = normalizeCachedColumnSettings(cachedValue?.settings)
    return settings.length ? settings : null
  } catch {
    return null
  }
}

const saveColumnSettings = (storageKey: string, settings: ColumnSettingItem[]) => {
  if (!storageKey || typeof window === 'undefined') return

  try {
    window.localStorage.setItem(
      storageKey,
      JSON.stringify({
        version: 1,
        settings
      })
    )
  } catch {
    // localStorage 可能被浏览器策略禁用，失败时不影响表格正常使用。
  }
}

const setColumnSettings = (settings: ColumnSettingItem[]) => {
  isSyncingColumnSettings.value = true
  columnSettings.value = settings
  nextTick(() => {
    isSyncingColumnSettings.value = false
    saveColumnSettings(columnSettingsStorageKey.value, columnSettings.value)
  })
}

watch(
  columnSettings,
  (settings) => {
    if (isSyncingColumnSettings.value) return
    saveColumnSettings(columnSettingsStorageKey.value, settings)
  },
  { deep: true }
)

watch(
  [() => props.settingsCache, () => props.settingsCacheKey, () => route.name, () => route.path],
  () => {
    slotColumnSignature.value = ''
  }
)

const applyColumnSetting = (node: VNode, setting: ColumnSettingItem) => {
  const clonedNode = cloneVNode(
    node,
    {
      columnKey: setting.key,
      fixed: setting.fixed || undefined,
      key: `${setting.key}-${setting.visible}-${setting.fixed || 'none'}`
    },
    true
  )

  const childNodes = getColumnChildren(node)
  if (!childNodes.length || !setting.children?.length) return clonedNode

  const originalChildren =
    clonedNode.children && typeof clonedNode.children === 'object' ? clonedNode.children : {}

  return {
    ...clonedNode,
    children: {
      ...(originalChildren as Record<string, unknown>),
      default: () => renderColumnNodes(childNodes, setting.children || [], setting.key)
    }
  } as VNode
}

const getSettingVisible = (meta: ColumnMeta, setting?: ColumnSettingItem) => {
  return meta.visible ?? setting?.visible ?? true
}

const isColumnVisible = (meta: ColumnMeta, setting?: ColumnSettingItem) => {
  if (!getSettingVisible(meta, setting)) return false
  if (!meta.children.length) return true

  const childrenSettings = setting?.children || []
  const childSettingMap = new Map(childrenSettings.map((item) => [item.key, item]))
  return meta.children.some((child) => isColumnVisible(child, childSettingMap.get(child.key)))
}

const renderColumnNodes = (nodes: VNode[], settings: ColumnSettingItem[], parentKey?: string) => {
  const settingMap = new Map(settings.map((item) => [item.key, item]))
  const orderMap = new Map(settings.map((item, index) => [item.key, index]))
  const sortedConfigurableNodes = nodes
    .map((node, index) => ({ node, meta: getColumnMeta(node, index, parentKey) }))
    .filter(({ meta }) => {
      const setting = settingMap.get(meta.key)
      return meta.configurable && setting && isColumnVisible(meta, setting)
    })
    .sort((a, b) => {
      const orderA = orderMap.get(a.meta.key) ?? Number.MAX_SAFE_INTEGER
      const orderB = orderMap.get(b.meta.key) ?? Number.MAX_SAFE_INTEGER
      return orderA - orderB
    })

  return nodes.flatMap((node, index) => {
    const meta = getColumnMeta(node, index, parentKey)

    const setting = settingMap.get(meta.key)

    if (!isColumnVisible(meta, setting)) return []

    if (!meta.configurable) return [node]

    const nextColumn = sortedConfigurableNodes.shift()
    if (!nextColumn) return []

    const nextColumnSetting = settingMap.get(nextColumn.meta.key)
    return nextColumnSetting
      ? [applyColumnSetting(nextColumn.node, nextColumnSetting)]
      : [nextColumn.node]
  })
}

const renderDefaultSlot = () => {
  const nodes = flattenSlotNodes(slots.default?.() || [])
  syncColumnSettings(nodes)
  return renderColumnNodes(nodes, columnSettings.value)
}

const TableDefaultSlot = () => renderDefaultSlot()

provide(TableContextKey, {
  data: safeData,
  loading: safeLoading,
  columnAlign: safeColumnAlign,
  columnMaxWidth: safeColumnMaxWidth,
  columnSettings,
  updateColumnVisible,
  updateColumnFixed,
  updateColumnOrder,
  resetColumnSettings
})

defineExpose({
  elTableRef: tableRef
})
</script>

<template>
  <el-table
    ref="tableRef"
    v-loading="loading"
    :class="{
      'zm-table': !customClass,
      'show-border': showBorder,
      'is-hover-highlight-disabled': hoverHighlight === false
    }"
    v-bind="bindProps"
    :data="data">
    <template v-for="(_, name) in forwardedSlots" #[name]="slotData">
      <slot :name="name" v-bind="slotData || {}"></slot>
    </template>
    <TableDefaultSlot />
  </el-table>
</template>

<style lang="scss">
.zm-table {
  --zm-table-font-family: inherit;
  --zm-table-font-size: 12px;
  --zm-table-text-color: #40546d;
  --zm-table-strong-text-color: #24364d;
  --zm-table-row-font-weight: 500;
  --zm-table-bg: var(--el-bg-color);
  --zm-table-border-color: #e7edf4;
  --zm-table-radius: 10px;
  --zm-table-header-bg: var(--el-fill-color-extra-light, #f7f9fc);
  --zm-table-header-text-color: var(--el-text-color-secondary, #6b7f99);
  --zm-table-header-border-color: var(--zm-table-border-color);
  --zm-table-header-cell-height: 36px;
  --zm-table-header-group-cell-height: 42px;
  --zm-table-header-font-size: var(--zm-table-font-size);
  --zm-table-header-font-weight: 600;
  --zm-table-header-line-height: 16px;
  --zm-table-header-icon-btn-size: 18px;
  --zm-table-header-icon-btn-color: #8aa0b8;
  --zm-table-header-icon-btn-radius: 4px;
  --zm-table-header-icon-btn-hover-color: var(--el-color-primary);
  --zm-table-header-icon-btn-hover-bg: var(--el-color-primary-light-9);
  --zm-table-header-icon-btn-active-color: var(--zm-table-header-icon-btn-hover-color);
  --zm-table-header-icon-btn-active-bg: var(--zm-table-header-icon-btn-hover-bg);
  --zm-table-header-icon-size: 16px;
  --zm-table-row-border-color: #edf2f7;
  --zm-table-stripe-bg: #fcfdff;
  --zm-table-hover-bg: #f5f9ff;
  --zm-table-current-bg: #eef6ff;
  --zm-table-summary-bg: #f7f9fc;
  --zm-table-summary-text-color: var(--zm-table-strong-text-color);
  --zm-table-summary-font-weight: 600;
  --zm-table-summary-border-color: var(--zm-table-border-color);
  --zm-table-cell-height: 38px;
  --zm-table-cell-padding-x: 8px;
  --zm-table-cell-first-padding-left: 0px;
  --zm-table-cell-last-padding-right: 0px;
  --zm-table-cell-line-height: 18px;
  --zm-table-empty-min-height: 148px;
  --zm-table-empty-bg: var(--zm-table-bg);
  --zm-table-empty-text-font-size: var(--zm-table-font-size);
  --zm-table-empty-text-color: var(--el-text-color-secondary);
  --zm-table-scrollbar-size: 7px;
  --zm-table-scrollbar-thumb-bg: #b8c5d6;

  width: 100%;
  overflow: hidden;
  font-family: var(--zm-table-font-family);
  font-size: var(--zm-table-font-size);
  color: var(--zm-table-text-color);
  background: var(--zm-table-bg);
  border: 1px solid var(--zm-table-border-color);
  border-radius: var(--zm-table-radius);
  box-shadow: none;

  &::before,
  &::after {
    display: none;
  }

  .el-table__inner-wrapper {
    &::before,
    &::after {
      display: none;
    }
  }

  .el-table__border-left-patch {
    display: none;
  }

  .el-table__inner-wrapper,
  .el-table__header-wrapper,
  .el-table__body-wrapper,
  .el-scrollbar__wrap {
    background: transparent;
  }

  .el-table__inner-wrapper {
    border-radius: var(--zm-table-radius);
  }

  .el-table__cell {
    height: var(--zm-table-cell-height);
    padding: 0;
    color: var(--zm-table-text-color);
    background: var(--zm-table-bg);
    border-right: 1px solid var(--zm-table-row-border-color) !important;
    border-bottom: 1px solid var(--zm-table-row-border-color) !important;
    transition:
      background-color 0.16s ease,
      color 0.16s ease;

    &:last-child {
      border-right: none !important;
    }
  }

  .cell {
    padding-right: var(--zm-table-cell-padding-x);
    padding-left: var(--zm-table-cell-padding-x);
    line-height: var(--zm-table-cell-line-height);
  }

  .el-table__header {
    color: var(--zm-table-header-text-color);

    .el-table__cell {
      height: var(--zm-table-header-cell-height);
      font-size: var(--zm-table-header-font-size);
      font-weight: var(--zm-table-header-font-weight);
      color: var(--zm-table-header-text-color);
      background: var(--zm-table-header-bg) !important;
      border-right: 1px solid var(--zm-table-header-border-color) !important;
      border-bottom: 1px solid var(--zm-table-header-border-color) !important;

      .cell {
        display: flex;
        min-height: 100%;
        align-items: center;
        justify-content: center;
        padding-top: 0;
        padding-bottom: 0;
      }

      &:last-child {
        .cell {
          border-right: none;
        }
      }
    }

    tr:first-child {
      .el-table__cell {
        &:first-child {
          border-top-left-radius: var(--zm-table-radius);
        }

        &:last-child {
          border-top-right-radius: var(--zm-table-radius);
        }
      }
    }

    tr:not(:last-child) {
      .el-table__cell {
        height: var(--zm-table-header-group-cell-height);
        border-bottom-color: var(--zm-table-header-border-color) !important;
      }
    }
  }

  .el-table__body {
    tr.el-table__row--striped {
      .el-table__cell {
        background: var(--zm-table-stripe-bg);
      }
    }

    tr.current-row {
      .el-table__cell {
        // color: var(--el-color-primary);
        background: var(--zm-table-current-bg) !important;
      }
    }
  }

  &:not(.is-hover-highlight-disabled) {
    .el-table__body {
      tr:hover,
      tr.hover-row {
        .el-table__cell {
          background: var(--zm-table-hover-bg) !important;
        }
      }
    }
  }

  .el-table__row {
    .el-table__cell {
      font-weight: var(--zm-table-row-font-weight);
      color: var(--zm-table-strong-text-color);

      &:first-child {
        // .cell {
        //   padding-left: var(--zm-table-cell-first-padding-left);
        // }
      }

      &:last-child {
        // .cell {
        //   padding-right: var(--zm-table-cell-last-padding-right);
        // }
      }
    }
  }

  .el-table__empty-block {
    width: 100% !important;
    min-width: 100%;
    min-height: var(--zm-table-empty-min-height);
    background: var(--zm-table-empty-bg);
  }

  .el-table__empty-text {
    font-size: var(--zm-table-empty-text-font-size);
    color: var(--zm-table-empty-text-color);
  }

  .el-table__footer-wrapper {
    background: var(--zm-table-summary-bg);
    border-top: 1px solid var(--zm-table-summary-border-color);
  }

  .el-table__footer {
    color: var(--zm-table-summary-text-color);

    .el-table__cell {
      height: var(--zm-table-cell-height);
      font-weight: var(--zm-table-summary-font-weight);
      color: var(--zm-table-summary-text-color);
      background: var(--zm-table-summary-bg) !important;
      border-right: 1px solid var(--zm-table-row-border-color) !important;
      border-bottom: none !important;

      .cell {
        display: flex;
        min-height: 100%;
        align-items: center;
        justify-content: center;
      }

      &:last-child {
        border-right: none !important;
      }
    }

    tr:last-child {
      .el-table__cell {
        &:first-child {
          border-bottom-left-radius: var(--zm-table-radius);
        }

        &:last-child {
          border-bottom-right-radius: var(--zm-table-radius);
        }
      }
    }

    .el-table__cell.el-table-fixed-column--left.is-last-column,
    .el-table__cell.el-table-fixed-column--right.is-first-column {
      box-shadow: none;
    }
  }

  .el-table__cell.el-table-fixed-column--left,
  .el-table__cell.el-table-fixed-column--right {
    background: inherit;
  }

  .el-table__cell.el-table-fixed-column--left.is-last-column {
    box-shadow: 6px 0 12px -10px rgb(15 23 42 / 22%);
  }

  .el-table__cell.el-table-fixed-column--right.is-first-column {
    box-shadow: -6px 0 12px -10px rgb(15 23 42 / 22%);
  }

  .el-table__fixed-right-patch {
    background: var(--zm-table-header-bg);
    border-bottom: 1px solid var(--zm-table-header-border-color);
  }

  .el-scrollbar__bar {
    &.is-horizontal {
      height: var(--zm-table-scrollbar-size);
    }

    &.is-vertical {
      width: var(--zm-table-scrollbar-size);
    }
  }

  .el-scrollbar__thumb {
    background: var(--zm-table-scrollbar-thumb-bg);
    border-radius: 999px;
    opacity: 0.55;

    &:hover {
      opacity: 0.85;
    }
  }
}

.zm-table:not(.show-border) {
  .el-table__header {
    .el-table__cell {
      border-right-color: var(--zm-table-header-border-color) !important;

      .cell {
        border-right: none;
      }

      &:last-child {
        .cell {
          border-right: none;
        }
      }
    }
  }
}
</style>
