<template>
  <div class="config-container">
    <div class="page-header">
      <h2>首页功能配置</h2>
      <p>选择要在首页快捷功能区域显示的功能</p>
    </div>

    <div class="config-content">
      <el-card class="config-card">
        <template #header>
          <div class="card-header">
            <span>功能选择</span>
            <el-button class="button" type="primary" @click="saveConfig">保存配置</el-button>
          </div>
        </template>
        
        <div class="config-layout">
          <div class="menu-tree-section">
            <el-input
              v-model="filterText"
              placeholder="输入关键字进行过滤"
              size="default"
              style="margin-bottom: 16px;"
            />
            <el-card v-loading="loading" class="tree-card">
              <el-tree
                ref="treeRef"
                :data="menuTree"
                :props="treeProps"
                show-checkbox
                node-key="menuId"
                :default-expanded-keys="expandedKeys"
                :default-checked-keys="checkedKeys"
                :filter-node-method="filterNode"
                :expand-on-click-node="false"
                @check="handleCheckChange"
              >
                <template #default="{ node, data }">
                  <span class="custom-tree-node">
                    <div class="tree-node-info">
                      <div class="node-main">
                        <svg-icon :icon-class="data.icon" :style="{ color: getIconColor(data) }" />
                        <span class="menu-label" style="margin-left: 8px;">{{ node.label }}</span>
                        <el-tag v-if="data.fullPath" type="info" size="small" effect="plain" class="path-tag-inline">
                          {{ data.fullPath }}
                        </el-tag>
                        <el-tag v-else-if="data.path" type="info" size="small" effect="plain" class="path-tag-inline">
                          {{ data.path }}
                        </el-tag>
                      </div>
                    </div>
                    <span>
                      <el-tag
                        v-if="data.menuType === 'M'"
                        type="info"
                        size="small"
                        style="margin-right: 8px;">
                        目录
                      </el-tag>
                      <el-tag
                        v-if="data.menuType === 'C'"
                        type="success"
                        size="small"
                        style="margin-right: 8px;">
                        菜单
                      </el-tag>
                      <el-tag
                        v-if="data.menuType === 'F'"
                        type="warning"
                        size="small">
                        按钮
                      </el-tag>
                    </span>
                  </span>
                </template>
              </el-tree>
            </el-card>
          </div>

          <div class="selected-functions-section">
            <div class="selected-functions-header">
              <h4>已选择的功能</h4>
              <el-tag type="info" size="small">{{ selectedFunctions.length }}/8</el-tag>
            </div>
            <div
              class="selected-functions-list"
              @dragover.prevent
              @drop="handleDrop"
            >
              <div
                v-for="(item, index) in selectedFunctions"
                :key="item.menuId"
                class="selected-function-item"
                draggable
                @dragstart="handleDragStart($event, index)"
                @dragover="handleDragOver"
                @dragenter="handleDragEnter"
                @dragleave="handleDragLeave"
                @drop="handleDrop"
                @dragend="handleDragEnd"
              >
                <div class="drag-handle">
                  <el-icon><Rank /></el-icon>
                </div>
                <div class="function-info">
                  <svg-icon :icon-class="item.icon" :style="{ color: getIconColor(item) }" />
                  <div class="function-details">
                    <span class="function-name">{{ item.menuName }}</span>
                    <el-tag v-if="item.fullPath" type="info" size="small" class="function-path-below">
                      {{ item.fullPath }}
                    </el-tag>
                    <el-tag v-else-if="item.path" type="info" size="small" class="function-path-below">
                      {{ item.path }}
                    </el-tag>
                  </div>
                </div>
                <el-button
                  type="danger"
                  size="small"
                  icon="Delete"
                  circle
                  @click="removeSelected(item.menuId)"
                />
              </div>
              <div v-if="selectedFunctions.length === 0" class="no-selected">
                暂无选择功能
              </div>
            </div>
          </div>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import Sortable from 'sortablejs'
import useUserStore from '@/store/modules/user'
import { listMenu } from '@/api/system/menu'
import { getMenuFullPath } from '@/api/system/menu'
import { saveCurrentUserConfig, getCurrentUserConfig } from '@/api/system/userConfig'
import {
  Menu,
  Grid,
  Folder,
  Tickets,
  Document,
  Setting,
  User,
  Goods,
  ChatDotSquare,
  Histogram,
  Wallet,
  OfficeBuilding,
  Postcard,
  Collection,
  VideoPlay,
  Camera,
  Headset,
  Phone,
  Message,
  ChatLineSquare,
  ChatRound,
  Guide,
  Help,
  InfoFilled,
  CircleCheck,
  CircleClose,
  Warning,
  QuestionFilled,
  Star,
  Link,
  Position,
  Picture,
  Upload,
  Download,
  CaretLeft,
  CaretRight,
  More,
  Close,
  Check,
  ArrowUp,
  ArrowDown,
  ArrowLeft,
  ArrowRight,
  Plus,
  Minus,
  ZoomIn,
  ZoomOut,
  Refresh,
  Search,
  Edit,
  Delete,
  Share,
  View,
  SwitchButton,
  Hide,
  Finished,
  CirclePlus,
  Remove,
  CircleCheckFilled,
  CircleCloseFilled,
  WarningFilled,
  InfoFilled as InfoFilledIcon,
  SuccessFilled,
  QuestionFilled as QuestionFilledIcon,
  Rank
} from '@element-plus/icons-vue'
import SvgIcon from '@/components/SvgIcon'

// 添加 loading 状态
const loading = ref(false)

const treeRef = ref()
const menuTree = ref([])
const expandedKeys = ref([])
const checkedKeys = ref([])
const selectedFunctions = ref([]) // 已选择的功能
const filterText = ref('') // 过滤文本
const userStore = useUserStore()
const treeProps = {
  children: 'children',
  label: 'menuName'
}

// Sortable实例
let sortable = null

// 监听过滤文本变化
watch(filterText, (val) => {
  treeRef.value?.filter(val)
})

// 监听selectedFunctions的变化，重新初始化Sortable
watch(selectedFunctions, () => {
  nextTick(() => {
    if (sortable) {
      sortable.destroy();
    }
    initSortable();
  });
}, { deep: true })


// 获取图标颜色
const getIconColor = (data) => {
  if (data.menuType === 'M') return '#409EFF' // 目录蓝色
  if (data.menuType === 'C') return '#67C23A' // 菜单绿色
  if (data.menuType === 'F') return '#E6A23C' // 按钮橙色
  return '#909399' // 默认灰色
}

// 加载菜单数据
const loadMenuData = async () => {
  loading.value = true
  try {
    // 尝试从本地缓存获取菜单数据
    const cachedMenuData = localStorage.getItem('menuTreeCache');
    const cacheTimestamp = localStorage.getItem('menuTreeCacheTimestamp');

    // 检查缓存是否有效（24小时内）
    if (cachedMenuData && cacheTimestamp) {
      const cacheAge = Date.now() - parseInt(cacheTimestamp);
      if (cacheAge < 24 * 60 * 60 * 1000) { // 24小时
        menuTree.value = JSON.parse(cachedMenuData);
        // 展开所有节点
        expandedKeys.value = getAllNodeIds(menuTree.value);
        // 获取已保存的配置
        await loadSavedConfig();
        loading.value = false;
        return;
      }
    }

    const response = await listMenu({})
    if (response.code === 200) {
      // 过滤掉隐藏的菜单项、目录和按钮类型的菜单，只保留当前角色可访问的菜单项
      const filteredMenus = filterVisibleMenus(response.data)
      menuTree.value = filteredMenus

      // 展开所有节点
      expandedKeys.value = getAllNodeIds(filteredMenus)

      // 将菜单数据缓存到本地存储
      localStorage.setItem('menuTreeCache', JSON.stringify(filteredMenus));
      localStorage.setItem('menuTreeCacheTimestamp', Date.now().toString());

      // 获取已保存的配置
      await loadSavedConfig()
    } else {
      ElMessage.error('获取菜单数据失败: ' + response.msg)
    }
  } catch (error) {
    console.error('加载菜单数据失败:', error)
    ElMessage.error('加载菜单数据失败')
  } finally {
    loading.value = false
  }
}

// 过滤可见的菜单项（非隐藏且非按钮类型，仅显示当前角色可访问的菜单）
const filterVisibleMenus = (menus) => {
  return menus.filter(menu => {
    // 过滤掉隐藏的菜单项和按钮类型的菜单，保留目录（M类型）和菜单（C类型）
    // visible为'0'表示可见，'1'表示隐藏
    return menu.visible !== '1' && menu.menuType !== 'F'
  }).map(menu => {
    // 保留完整路径信息
    if (menu.fullPath) {
      menu.fullPath = menu.fullPath;
    }
    // 递归处理子菜单
    if (menu.children && menu.children.length > 0) {
      menu.children = filterVisibleMenus(menu.children)
    }
    return menu
  })
}

// 获取所有节点ID
const getAllNodeIds = (nodes) => {
  const ids = []
  nodes.forEach(node => {
    ids.push(node.menuId)
    if (node.children) {
      ids.push(...getAllNodeIds(node.children))
    }
  })
  return ids
}


// 保存配置
const saveConfig = async () => {
  loading.value = true
  try {
    // 获取所有选中的节点，包括半选状态的节点
    const checkedNodes = treeRef.value.getCheckedNodes()
    // 只保留菜单类型（C类型）的节点
    const validMenuNodes = checkedNodes.filter(node => node.menuType === 'C')

    // 创建包含菜单ID和完整路径的对象数组
    const menuPromises = validMenuNodes.map(async (node) => {
      try {
        console.log(`开始获取菜单 ${node.menuName} (ID: ${node.menuId}) 的完整路径`);
        console.log(`节点对象:`, node);
        console.log(`节点的 path 属性:`, node.path);

        // 获取菜单的完整路径
        const fullPathResponse = await getMenuFullPath(node.menuId);
        console.log(`菜单 ${node.menuName} 的完整路径响应:`, fullPathResponse);

        let fullPath = fullPathResponse.code === 200 ? (fullPathResponse.data || fullPathResponse.msg) : node.path;
        // 确保路径格式正确，去除多余的斜杠
        if (fullPath && typeof fullPath === 'string') {
          // 将多个连续的斜杠替换为单个斜杠，但保留协议部分的双斜杠（如 http://）
          fullPath = fullPath.replace(/([^:])\/{2,}/g, '$1/');
        }
        console.log(`菜单 ${node.menuName} 的完整路径:`, fullPath);

        const menuItem = {
          menuId: node.menuId,
          fullPath: fullPath,
          menuName: node.menuName,
          path: node.path,
          icon: node.icon,        // 保存数据库中的图标类名
          menuType: node.menuType // 保存菜单类型信息
        };

        console.log(`构造的菜单项对象:`, menuItem);
        return menuItem;
      } catch (error) {
        console.error(`获取菜单 ${node.menuName} 的完整路径失败:`, error);
        console.error(`错误堆栈:`, error.stack);

        // 如果获取完整路径失败，使用现有路径作为备选
        console.log(`在错误处理中，节点的 path 属性:`, node.path);
        const menuItem = {
          menuId: node.menuId,
          fullPath: node.path,
          menuName: node.menuName,
          path: node.path,
          icon: node.icon,        // 保存数据库中的图标类名
          menuType: node.menuType // 保存菜单类型信息
        };
        console.log(`构造的菜单项对象（错误处理）:`, menuItem);
        return menuItem;
      }
    });

    // 等待所有完整路径获取完成
    const menuDataWithPaths = await Promise.all(menuPromises);

    // 添加调试信息
    console.log('准备保存的菜单数据:', menuDataWithPaths);

    // 检查每个对象是否包含 fullPath 属性
    menuDataWithPaths.forEach((item, index) => {
      console.log(`菜单项 ${index} 包含 fullPath:`, item.hasOwnProperty('fullPath'), '值为:', item.fullPath);
    });

    // 对配置值进行URL编码以避免特殊字符问题
    const encodedConfigValue = encodeURIComponent(JSON.stringify(menuDataWithPaths))
    console.log('编码后的配置值:', encodedConfigValue);

    // 保存到数据库
    const saveResult = await saveCurrentUserConfig('homeFeaturesConfig', encodedConfigValue)

    if (saveResult.code === 200) {
      // 只有在数据库保存成功后，才保存到本地存储
      localStorage.setItem('homeFeaturesConfig', JSON.stringify(menuDataWithPaths))
      // 同时更新缓存配置
      localStorage.setItem('homeFeaturesConfigCache', JSON.stringify(menuDataWithPaths));
      localStorage.setItem('homeFeaturesConfigCacheTimestamp', Date.now().toString());
      // 清除菜单树缓存，以便下次加载最新数据
      localStorage.removeItem('menuTreeCache');
      localStorage.removeItem('menuTreeCacheTimestamp');
      ElMessage.success('配置保存成功')
      // 触发全局事件，通知首页更新快捷功能
      window.dispatchEvent(new CustomEvent('homeFeaturesConfigUpdated', {
        detail: { config: menuDataWithPaths } // 传递最新配置数据
      }));
    } else {
      console.error('保存到数据库失败:', saveResult);
      ElMessage.error('保存到数据库失败')
    }
  } catch (error) {
    console.error('保存配置失败:', error)
    ElMessage.error('保存配置失败')
  } finally {
    loading.value = false
  }
}

// 处理复选框变化
const handleCheckChange = () => {
  // 获取当前选中的节点
  const checkedNodes = treeRef.value.getCheckedNodes()
  // 只保留菜单类型（C）的节点，排除目录（M）和按钮（F）
  selectedFunctions.value = checkedNodes.filter(node => node.menuType === 'C')
}

// 移除已选择的功能
const removeSelected = (menuId) => {
  // 从树中取消勾选该节点
  treeRef.value.setChecked(menuId, false, false)
  // 更新已选择的功能列表
  selectedFunctions.value = selectedFunctions.value.filter(item => item.menuId !== menuId)
}

// 获取默认选择项（前几个菜单项）
const getDefaultSelections = (nodes, count = 8) => {
  const selections = []
  const traverse = (items) => {
    for (const item of items) {
      if (selections.length >= count) break
      if (item.menuType === 'C') { // 只选择菜单类型（C），不选择目录（M）或按钮（F）
        selections.push(item.menuId)
      }
      if (item.children && item.children.length > 0) {
        traverse(item.children)
      }
    }
  }
  traverse(nodes)
  return selections.slice(0, count)
}

// 过滤节点方法
const filterNode = (value, data) => {
  if (!value) return true
  return data.menuName.indexOf(value) !== -1
}

// 加载已保存的配置
const loadSavedConfig = async () => {
  try {
    // 尝试从本地缓存获取配置
    const cachedConfig = localStorage.getItem('homeFeaturesConfigCache');
    const cacheTimestamp = localStorage.getItem('homeFeaturesConfigCacheTimestamp');

    // 检查缓存是否有效（1小时内）
    if (cachedConfig && cacheTimestamp) {
      const cacheAge = Date.now() - parseInt(cacheTimestamp);
      if (cacheAge < 60 * 60 * 1000) { // 1小时
        const parsedConfig = JSON.parse(cachedConfig);
        // 检查数据格式，如果是包含对象的数组（新格式），提取菜单ID
        if (parsedConfig && Array.isArray(parsedConfig)) {
          if (parsedConfig.length > 0 && typeof parsedConfig[0] === 'object' && parsedConfig[0].hasOwnProperty('menuId')) {
            // 新格式：[{menuId: 1, fullPath: "...", ...}, ...]
            checkedKeys.value = parsedConfig.map(item => item.menuId);
          } else {
            // 旧格式：[1, 2, 3, ...]
            checkedKeys.value = parsedConfig;
          }

          // 根据保存的配置初始化已选择的功能
          const allNodes = getAllNodes(menuTree.value)
          const checkedNodes = allNodes.filter(node =>
            checkedKeys.value.includes(node.menuId) && node.menuType === 'C'
          )
          selectedFunctions.value = checkedNodes
        }
        return; // 使用缓存数据，直接返回
      }
    }

    // 优先从数据库获取已保存的配置
    const response = await getCurrentUserConfig('homeFeaturesConfig')
    let savedConfig = null;

    if (response.code === 200) {
      savedConfig = response.data; // 从数据库获取的配置
    }

    // 如果数据库中没有配置，尝试从本地存储获取
    if (!savedConfig) {
      savedConfig = localStorage.getItem('homeFeaturesConfig')
    }

    if (savedConfig) {
      // 尝试解码配置值（如果是URL编码的）
      let parsedConfig;
      try {
        // 先尝试解码
        const decodedConfig = decodeURIComponent(savedConfig);
        parsedConfig = JSON.parse(decodedConfig);
      } catch (e) {
        // 如果解码失败，尝试直接解析（兼容旧数据）
        try {
          parsedConfig = JSON.parse(savedConfig);
        } catch (e2) {
          console.error('解析配置失败:', e2);
          parsedConfig = null;
        }
      }

      if (parsedConfig && Array.isArray(parsedConfig)) {
        // 检查数据格式，如果是包含对象的数组（新格式），提取菜单ID
        if (parsedConfig.length > 0 && typeof parsedConfig[0] === 'object' && parsedConfig[0].hasOwnProperty('menuId')) {
          // 新格式：[{menuId: 1, fullPath: "...", ...}, ...]
          checkedKeys.value = parsedConfig.map(item => item.menuId);
        } else {
          // 旧格式：[1, 2, 3, ...]
          checkedKeys.value = parsedConfig;
        }

        // 根据保存的配置初始化已选择的功能
        const allNodes = getAllNodes(menuTree.value)
        const checkedNodes = allNodes.filter(node =>
          checkedKeys.value.includes(node.menuId) && node.menuType === 'C'
        )
        selectedFunctions.value = checkedNodes

        // 将配置缓存到本地存储
        localStorage.setItem('homeFeaturesConfigCache', JSON.stringify(parsedConfig));
        localStorage.setItem('homeFeaturesConfigCacheTimestamp', Date.now().toString());
      } else {
        // 如果解析失败，使用默认配置
        const defaultSelections = getDefaultSelections(menuTree.value)
        checkedKeys.value = defaultSelections
        // 初始化已选择的功能
        const allNodes = getAllNodes(menuTree.value)
        const checkedNodes = allNodes.filter(node =>
          defaultSelections.includes(node.menuId) && node.menuType === 'C'
        )
        selectedFunctions.value = checkedNodes
      }
    } else {
      // 如果没有配置，使用默认配置
      const defaultSelections = getDefaultSelections(menuTree.value)
      checkedKeys.value = defaultSelections
      // 初始化已选择的功能
      const allNodes = getAllNodes(menuTree.value)
      const checkedNodes = allNodes.filter(node =>
        defaultSelections.includes(node.menuId) && node.menuType === 'C'
      )
      selectedFunctions.value = checkedNodes
    }
  } catch (error) {
    console.error('加载配置失败:', error)
    // 如果加载失败，使用默认配置
    const defaultSelections = getDefaultSelections(menuTree.value)
    checkedKeys.value = defaultSelections
    // 初始化已选择的功能
    const allNodes = getAllNodes(menuTree.value)
    const checkedNodes = allNodes.filter(node =>
      defaultSelections.includes(node.menuId)
    )
    selectedFunctions.value = checkedNodes
  } finally {
    // 确保在数据加载完成后初始化Sortable
    // 使用 nextTick 确保DOM已更新
    nextTick(() => {
      if (sortable) {
        sortable.destroy();
      }
      initSortable();
    });
  }
}

// 获取所有节点（递归）
const getAllNodes = (nodes) => {
  if (!nodes || !Array.isArray(nodes)) {
    return []
  }

  let result = []
  nodes.forEach(node => {
    result.push(node)
    if (node.children && Array.isArray(node.children)) {
      result = result.concat(getAllNodes(node.children))
    }
  })
  return result
}

// 初始化Sortable
const initSortable = () => {
  const container = document.querySelector('.selected-functions-list')
  if (container && selectedFunctions.value.length > 0) {
    sortable = Sortable.create(container, {
      animation: 150, // 动画时长
      ghostClass: 'sortable-ghost', // 拖拽时的样式
      chosenClass: 'sortable-chosen', // 选中时的样式
      dragClass: 'sortable-drag', // 拖拽过程中的样式
      onEnd: function(evt) {
        // 拖拽结束时更新数组顺序
        const oldIndex = evt.oldIndex
        const newIndex = evt.newIndex

        if (oldIndex !== newIndex) {
          // 移动数组元素
          const movedItem = selectedFunctions.value.splice(oldIndex, 1)[0]
          selectedFunctions.value.splice(newIndex, 0, movedItem)

          // 更新树形控件的选中状态
          updateTreeCheckState()
        }
      }
    })
  }
}

// 更新树形控件的选中状态
const updateTreeCheckState = () => {
  // 获取当前所有选中的菜单ID
  const checkedIds = selectedFunctions.value.map(item => item.menuId)

  // 更新 checkedKeys 和树形控件的选中状态
  checkedKeys.value = checkedIds

  // 如果 treeRef 存在，手动设置选中状态
  if (treeRef.value) {
    // 清除当前选中状态
    treeRef.value.setCheckedKeys([])
    // 设置新的选中状态
    checkedIds.forEach(id => {
      treeRef.value.setChecked(id, true, false)
    })
  }
}

onMounted(() => {
  loadMenuData()
})

// 在组件卸载时销毁Sortable实例
onUnmounted(() => {
  if (sortable) {
    sortable.destroy()
    sortable = null
  }
})
</script>

<style scoped lang="scss">
.config-container {
  padding: 20px;
  background: #f5f7fa;
  min-height: calc(100vh - 120px);

  .page-header {
    margin-bottom: 20px;
    text-align: center;

    h2 {
      font-size: 24px;
      color: #303133;
      margin-bottom: 8px;
    }

    p {
      font-size: 14px;
      color: #909399;
    }
  }

  .config-content {
    .config-card {
      .card-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .menu-tree {
        margin-top: 20px;
      }

      :deep(.el-card__body) {
        padding: 20px 0;
      }
    }

    .custom-tree-node {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 14px;
      padding-right: 8px;
    }

    .tree-node-info {
      display: flex;
      align-items: center;
      flex: 1;
      min-width: 0; /* 允许flex项目收缩到其内容的固有尺寸以下 */
    }

    .node-main {
      display: flex;
      align-items: center;
      flex: 1;
      min-width: 0; /* 允许收缩 */
    }

    .menu-label {
      margin: 0 8px;
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .path-tag-inline {
      font-size: 12px;
      margin-left: 8px;
      flex-shrink: 0; /* 防止路径标签被压缩 */
    }
  }
}

.config-layout {
  display: flex;
  gap: 20px;
}

.menu-tree-section {
  flex: 1;
}

.tree-card {
  min-height: 400px;
}

.selected-functions-section {
  width: 400px; /* 增加宽度 */
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 16px;
  background-color: #fafafa;
}

.selected-functions-list {
  max-height: 500px;
  overflow-y: auto;
  margin-top: 10px;
}

.selected-function-item {
  display: flex;
  align-items: center;
  padding: 8px;
  margin-bottom: 8px;
  background: white;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  cursor: move; /* 添加拖拽光标 */
  transition: all 0.2s ease;
}

.selected-function-item.drag-over {
  border: 2px dashed #409eff;
  background-color: #ecf5ff;
}

.drag-handle {
  cursor: move;
  padding: 0 8px;
  color: #909399;
  display: flex;
  align-items: center;
  justify-content: center;
}

.function-info {
  display: flex;
  align-items: flex-start; /* 改为flex-start以适应多行内容 */
  flex: 1;
}

.function-details {
  display: flex;
  flex-direction: column;
  margin: 0 8px;
  flex: 1;
}

.function-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.function-path-below {
  margin-top: 4px;
  font-size: 12px;
  align-self: flex-start; /* 让路径标签左对齐 */
}

.no-selected {
  text-align: center;
  color: #999;
  font-style: italic;
  padding: 20px 0;
}

.selected-functions-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

/* Sortable相关样式 */
.sortable-ghost {
  opacity: 0.4;
}

.sortable-chosen {
  background-color: #ecf5ff;
  border: 1px solid #409eff;
  box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}

.sortable-drag {
  user-select: none;
}
</style>