<template>
  <div class="dashboard-page">
    <!-- 主要内容区域 -->
    <main class="dashboard-main">
      <!-- 问题输入界面 -->
      <section v-if="showQuestionInput" class="question-input-section">
        <div class="question-container">
          <!-- <h1 class="question-title">今天有什么问题？</h1> -->
          <div class="chat-input-container">
            <!-- 左侧头像/图标 -->
            <div class="chat-avatar">
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
                <circle cx="12" cy="7" r="4"/>
              </svg>
            </div>
            
            <!-- 中间输入框区域 -->
            <div class="input-wrapper">
              <textarea 
                v-model="questionText"
                class="chat-input"
                placeholder="发消息或输入..."
                @keyup.enter="handleQuestionSubmit"
                rows="1"
              ></textarea>
            </div>
            
            <!-- 右侧按钮组 -->
            <div class="input-actions">
              <button class="action-btn voice-btn" title="语音输入">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
                  <path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
                  <line x1="12" y1="19" x2="12" y2="23"/>
                  <line x1="8" y1="23" x2="16" y2="23"/>
                </svg>
              </button>
              <button class="action-btn send-btn" title="发送" @click="handleQuestionSubmit">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M22 2L11 13"/>
                  <path d="M22 2L15 22L11 13L2 9L22 2Z"/>
                </svg>
              </button>
            </div>
          </div>
        </div>
      </section>

      <!-- 思考过程界面 -->
      <section v-if="isThinking" class="thinking-section">
        <div class="thinking-container">
          <div class="thinking-spinner">
            <div class="spinner-ring"></div>
            <div class="spinner-ring"></div>
            <div class="spinner-ring"></div>
          </div>
          <h2 class="thinking-text">{{ thinkingText }}</h2>
          <div class="thinking-dots">
            <span class="dot"></span>
            <span class="dot"></span>
            <span class="dot"></span>
          </div>
        </div>
      </section>

      <!-- 结果卡片界面 -->
      <section v-if="showResults" class="modules-section animate-fade-in animate-delay-400">
        <div class="modules-container" ref="modulesContainer">
          <ModuleCard
            v-for="(config, index) in moduleConfigs"
            :key="config.id"
            :config="config"
            :stats="getModuleStats(config.id)"
            :is-active="selectedModule === config.id"
            :is-draggable="isDragEnabled"
            :initial-position="moduleLayouts[config.id]?.position || { x: 0, y: 0 }"
            :initial-size="moduleLayouts[config.id]?.size || { width: 280, height: 200 }"
            :initial-question="config.id === 'inputCard' ? submittedQuestion : ''"
            :task-list="config.id === 'inputCard' ? taskList : []"
            :train-data="getTrainData(config.id)"
            :mechanic-data="getMechanicData(config.id)"
            :diagnostic-codes="getDiagnosticCodes(config.id)"
            :treatment-methods="getTreatmentMethods(config.id)"
            :file-list="getFileList(config.id)"
            :rule-list="getRuleList(config.id)"
            :precaution-list="getPrecautionList(config.id)"
            :route-data="getRouteData(config.id)"
            :fault-causes="getFaultCauses(config.id)"
            :typical-cases="getTypicalCases(config.id)"
            :class="[
              `animate-slide-in-up animate-delay-${(index + 1) * 100}`,
              'draggable-module-card'
            ]"
            :style="getModuleStyle(config.id)"
            @click="handleModuleClick"
            @dblclick="handleModuleDoubleClick"
            @position-change="handlePositionChange"
            @size-change="handleSizeChange"
            @open-rule-pdf="handleOpenRulePdf"
            @open-case-pdf="handleOpenCasePdf"
          />
        </div>
      </section>
    </main>

    <!-- 加载状态 -->
    <div v-if="isLoading" class="loading-overlay">
      <div class="spinner"></div>
      <p>正在加载数据...</p>
    </div>

    <!-- 通知提示 -->
    <div 
      v-if="notification.show" 
      class="notification animate-slide-in-down"
      :class="`notification--${notification.type}`"
    >
      <span>{{ notification.message }}</span>
    </div>

    <!-- 详情弹窗 -->
    <DetailModal
      v-model="showDetailModal"
      :module-type="selectedModuleForDetail"
      :data="selectedModuleForDetail ? dashboardStore.getModuleData(selectedModuleForDetail) : []"
      @refresh="handleDetailRefresh"
    />

    <!-- 规章制度 PDF 预览弹窗（页面级） -->
    <el-dialog
      v-model="rulePdfDialogVisible"
      title="PDF预览"
      width="85%"
      class="rule-pdf-dialog"
      :close-on-click-modal="false"
      :append-to-body="true"
      center
    >
      <div v-loading="rulePdfLoading" class="preview-content">
        <VueOfficePdf
          v-if="currentRulePdfUrl"
          :src="currentRulePdfUrl"
          @rendered="() => { rulePdfLoading = false }"
          @error="() => { rulePdfLoading = false; ElMessage.error('PDF预览失败') }"
          class="pdf-preview"
        />
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, reactive, watch } from 'vue';
import { useDashboardStore } from '@/store/modules/dashboard';
import { useAclStore } from '@/store/modules/acl';
import { MODULE_CONFIGS } from '@/constants/modules';
import ModuleCard from '@/components/dashboard/ModuleCard.vue';
import DetailModal from '@/components/dashboard/DetailModal.vue';
import type { ModuleConfig, ModuleType, SearchResult, StatusStats, Position, Size, RuleRegulation, TypicalCase } from '@/types/dashboard';
import { webSocketService } from '@/utils/websocket';
import { baseURL } from '@/config';
import { v4 as uuidv4 } from 'uuid';
import { getEmuTreatment } from '@/api/dashboard';
import { ElDialog, ElMessage } from 'element-plus';
import VueOfficePdf from '@vue-office/pdf';
import { sendChatMessage } from '@/api/chat';

// 使用store
const dashboardStore = useDashboardStore();
const aclStore = useAclStore();

// 响应式数据
const showDetailModal = ref(false);
const selectedModuleForDetail = ref<ModuleType | null>(null);
const isDragEnabled = ref(true); // 拖拽控制开关
const modulesContainer = ref<HTMLElement>();

// 问答界面状态管理
const showQuestionInput = ref(true); // 控制问题输入框显示
const isThinking = ref(false); // 控制思考过程显示
const showResults = ref(false); // 控制结果卡片显示
const questionText = ref(''); // 用户输入的问题
const thinkingText = ref('正在思考...'); // 思考过程文字
const submittedQuestion = ref(''); // 保存已提交的问题，用于传递给AI对话卡片

// WebSocket 相关
const sysMessageId = ref(''); // 系统消息ID

// 任务列表相关 - 用于在AI助手卡片中显示加载进度
interface TaskItem {
  id: string;
  title: string;
  status: 'pending' | 'loading' | 'completed' | 'error';
  dataKey: string; // 对应的数据字段名
}

const taskList = ref<TaskItem[]>([]);

// 通知相关
const notification = ref({
  show: false,
  message: '',
  type: 'success' as 'success' | 'error' | 'info'
});
let notificationTimer: ReturnType<typeof setTimeout> | null = null;



// 模块布局状态
interface ModuleLayout {
  position: Position;
  size: Size;
}

// 模块配置
const moduleConfigs = MODULE_CONFIGS;

// 默认布局配置
const getDefaultLayout = (): Record<string, ModuleLayout> => {
  const defaultLayouts: Record<string, ModuleLayout> = {};
  const cardWidth = 280;
  const cardHeight = 200;
  const gap = 24;
  const cols = 4;
  
  moduleConfigs.forEach((config, index) => {
    const row = Math.floor(index / cols);
    const col = index % cols;
    
    // 应急处置建议模块占两个位置
    const width = config.id === 'emergencyDisposal' ? cardWidth * 2 + gap : cardWidth;
    
    defaultLayouts[config.id] = {
      position: {
        x: col * (cardWidth + gap),
        y: row * (cardHeight + gap)
      },
      size: {
        width,
        height: cardHeight
      }
    };
  });
  
  return defaultLayouts;
};

// 模块布局状态
const initializeModuleLayouts = () => {
  const savedLayouts = localStorage.getItem('moduleLayouts');
  
  let layouts;
  if (savedLayouts) {
    layouts = JSON.parse(savedLayouts);
    
    // 获取默认布局以补充缺失的模块
    const defaultLayouts = getDefaultLayout();
    
    // 检查并补充缺失的模块
    let hasUpdates = false;
    moduleConfigs.forEach(config => {
      if (!layouts[config.id]) {
        layouts[config.id] = defaultLayouts[config.id];
        hasUpdates = true;
      }
    });
    
    // 如果有更新，保存到localStorage
    if (hasUpdates) {
      localStorage.setItem('moduleLayouts', JSON.stringify(layouts));
    }
  } else {
    layouts = getDefaultLayout();
  }
  
  return layouts;
};

const moduleLayouts = reactive<Record<string, ModuleLayout>>(initializeModuleLayouts());

// 计算属性
const searchQuery = computed({
  get: () => dashboardStore.searchQuery,
  set: (value: string) => dashboardStore.updateSearchQuery(value)
});

const searchResults = computed(() => dashboardStore.searchResults);
const selectedModule = computed(() => dashboardStore.selectedModule);
const isLoading = computed(() => dashboardStore.isLoading);
const totalTrains = computed(() => dashboardStore.totalTrains);
const runningTrains = computed(() => dashboardStore.runningTrains);
const maintenanceTrains = computed(() => dashboardStore.maintenanceTrains);
const activeMechanics = computed(() => dashboardStore.activeMechanics);

/**
 * 获取模块样式
 * 使用 transform: translate3d() 启用 GPU 加速，避免 layout 重计算
 */
const getModuleStyle = (moduleId: string) => {
  const layout = moduleLayouts[moduleId];
  if (!layout) return {};
  
  return {
    position: 'absolute',
    transform: `translate3d(${layout.position.x}px, ${layout.position.y}px, 0)`,
    width: `${layout.size.width}px`,
    height: `${layout.size.height}px`,
    // 移除 transition 以避免拖拽时的冲突
    // 在 ModuleCard 组件中会根据拖拽状态动态控制过渡效果
  };
};

/**
 * 保存布局到本地存储
 */
const saveLayout = () => {
  localStorage.setItem('moduleLayouts', JSON.stringify(moduleLayouts));
};

// 节流保存布局，避免频繁写入localStorage
let saveLayoutTimer: ReturnType<typeof setTimeout> | null = null;
const throttledSaveLayout = () => {
  if (saveLayoutTimer) {
    clearTimeout(saveLayoutTimer);
  }
  saveLayoutTimer = setTimeout(() => {
    saveLayout();
  }, 100); // 100ms节流
};

/**
 * 处理位置变化
 * 优化：减少不必要的对象创建和响应式更新
 */
const handlePositionChange = (moduleId: string, position: Position) => {
  const layout = moduleLayouts[moduleId];
  if (!layout) return;
  
  // 检查位置是否真的改变了
  if (layout.position.x === position.x && layout.position.y === position.y) {
    return;
  }
  
  // 直接修改现有对象，避免创建新对象
  layout.position.x = position.x;
  layout.position.y = position.y;
  
  // 节流保存
  throttledSaveLayout();
};

/**
 * 处理大小变化
 * 优化：减少不必要的对象创建和响应式更新
 */
const handleSizeChange = (moduleId: string, size: Size) => {
  const layout = moduleLayouts[moduleId];
  if (!layout) return;
  
  // 检查大小是否真的改变了
  if (layout.size.width === size.width && layout.size.height === size.height) {
    return;
  }
  
  // 直接修改现有对象，避免创建新对象
  layout.size.width = size.width;
  layout.size.height = size.height;
  
  // 节流保存
  throttledSaveLayout();
};




/**
 * 获取模块统计数据
 */
const getModuleStats = (moduleType: ModuleType): StatusStats => {
  const data = dashboardStore.getModuleData(moduleType);
  
  // 根据不同模块类型计算统计数据
  switch (moduleType) {
    case 'trainInfo':
      return {
        total: data.length,
        active: data.filter((item: any) => item.status === 'running').length,
        inactive: data.filter((item: any) => item.status === 'standby').length,
        warning: data.filter((item: any) => item.status === 'maintenance').length
      };
    case 'mechanicInfo':
      return {
        total: data.length,
        active: data.filter((item: any) => item.status === 'working').length,
        inactive: data.filter((item: any) => item.status === 'break').length,
        warning: data.filter((item: any) => item.status === 'available').length
      };
    case 'faultInfo':
      return {
        total: data.length,
        active: data.filter((item: any) => item.severity === 'low').length,
        inactive: data.filter((item: any) => item.severity === 'medium').length,
        warning: data.filter((item: any) => item.severity === 'high').length
      };
    default:
      return {
        total: data.length,
        active: Math.floor(data.length * 0.8),
        inactive: Math.floor(data.length * 0.1),
        warning: Math.floor(data.length * 0.1)
      };
  }
};

/**
 * 获取模块标题
 */
const getModuleTitle = (moduleType: ModuleType): string => {
  const config = moduleConfigs.find(c => c.id === moduleType);
  return config?.title || '未知模块';
};

/**
 * 获取车组数据 - 只返回第一条数据给卡片显示
 */
const getTrainData = (moduleType: ModuleType) => {
  if (moduleType === 'trainInfo') {
    const trainData = dashboardStore.trainInfo;
    return trainData.length > 0 ? trainData[0] : undefined;
  }
  return undefined;
};

/**
 * 获取机械师数据 - 只返回第一条数据给卡片显示
 */
const getMechanicData = (moduleType: ModuleType) => {
  if (moduleType === 'mechanicInfo' || moduleType === 'personnelInfo') {
    const mechanicData = dashboardStore.mechanicInfo;
    return mechanicData.length > 0 ? mechanicData[0] : undefined;
  }
  return undefined;
};

/**
 * 获取诊断代码数据
 */
const getDiagnosticCodes = (moduleType: ModuleType) => {
  if (moduleType === 'faultInfo') {
    return dashboardStore.diagnosticCodes;
  }
  return [];
};

/**
 * 获取处置方法数据
 */
const getTreatmentMethods = (moduleType: ModuleType) => {
  if (moduleType === 'emergencyDisposal') {
    return dashboardStore.treatmentMethods;
  }
  return [];
};

/**
 * 获取文件列表数据
 */
const getFileList = (moduleType: ModuleType) => {
  if (moduleType === 'typicalCase') {
    return dashboardStore.standardFiles;
  }
  return [];
};

/**
 * 获取规章制度数据
 */
const getRuleList = (moduleType: ModuleType) => {
  if (moduleType === 'ruleRegulation') {
    return dashboardStore.ruleRegulations;
  }
  return [];
};

/**
 * 获取注意事项数据
 */
const getPrecautionList = (moduleType: ModuleType) => {
  if (moduleType === 'precautions') {
    return dashboardStore.precautions;
  }
  return [];
};

/**
 * 获取交路信息数据 - 只返回第一条数据给卡片显示
 */
const getRouteData = (moduleType: ModuleType) => {
  if (moduleType === 'routeInfo') {
    const routeData = dashboardStore.routeInfo;
    return routeData.length > 0 ? routeData[0] : undefined;
  }
  return undefined;
};

/**
 * 获取故障原因数据
 */
const getFaultCauses = (moduleType: ModuleType) => {
  if (moduleType === 'emergencyDisposal') {
    return dashboardStore.getFaultCauses();
  }
  return [];
};

/**
 * 获取典型案例数据
 */
const getTypicalCases = (moduleType: ModuleType) => {
  if (moduleType === 'typicalCase') {
    return dashboardStore.typicalCases;
  }
  return [];
};

/**
 * 处理搜索输入
 */
const handleSearch = (value: string) => {
  dashboardStore.updateSearchQuery(value);
};

/**
 * 处理搜索结果点击
 */
const handleSearchResultClick = (result: SearchResult) => {
  dashboardStore.selectModule(result.type);
  dashboardStore.updateSearchQuery('');
};

/**
 * 处理模块卡片点击
 */
const handleModuleClick = (config: ModuleConfig) => {
  // 单击只负责选中模块
  dashboardStore.selectModule(config.id);
};

/**
 * 处理模块卡片双击
 */
const handleModuleDoubleClick = (config: ModuleConfig) => {
  // 双击直接打开详情弹窗
  selectedModuleForDetail.value = config.id;
  showDetailModal.value = true;
};

/**
 * 处理详情弹窗刷新
 */
const handleDetailRefresh = (moduleType: ModuleType) => {
  dashboardStore.refreshModuleData(moduleType);
};

/**
 * 生成随机的系统消息ID
 */
const generateSysMessageId = (): string => {
  const fullUUID = uuidv4().replace(/-/g, ''); // 生成UUID并去除连字符
  return fullUUID.substring(0, 12); // 截取前12位
};

/**
 * 建立 WebSocket 连接
 */
const connectWebSocket = () => {
  try {
    const urlList = baseURL.split(':');
    const wsUrl = `ws:${urlList[1]}:16750/api/webSocketServer/${sysMessageId.value}`;
    
    console.log('正在建立 WebSocket 连接:', wsUrl);
    webSocketService.connect(wsUrl);
    
    // 监听 WebSocket 消息
    webSocketService.on('message', handleWebSocketMessage);
    webSocketService.on('connect', () => {
      console.log('HomePage WebSocket 已连接, sysMessageId:', sysMessageId.value);
      showNotification('WebSocket 连接成功', 'success');
    });
    webSocketService.on('error', (error: any) => {
      console.error('HomePage WebSocket 错误:', error);
      showNotification('WebSocket 连接失败', 'error');
    });
  } catch (error) {
    console.error('建立 WebSocket 连接失败:', error);
    showNotification('建立 WebSocket 连接失败', 'error');
  }
};

/**
 * 处理 WebSocket 消息
 * 支持接收所有卡片模块的数据
 */
const handleWebSocketMessage = (data: string) => {
  try {
    console.log('收到 WebSocket 消息:', data);
    const messageData = JSON.parse(data);
    
    let hasUpdates = false;
    const updatedModules: string[] = [];
    
    // 处理车组信息
    if (messageData.trainInfo && Array.isArray(messageData.trainInfo)) {
      dashboardStore.updateTrainInfo(messageData.trainInfo);
      updateTaskStatus('trainInfo', 'completed');
      hasUpdates = true;
      updatedModules.push('车组信息');
    }
    
    // 处理机械师/人员信息
    if (messageData.mechanicInfo && Array.isArray(messageData.mechanicInfo)) {
      dashboardStore.updateMechanicInfo(messageData.mechanicInfo);
      updateTaskStatus('mechanicInfo', 'completed');
      hasUpdates = true;
      updatedModules.push('人员信息');
    }
    
    // 处理诊断代码/故障信息
    if (messageData.diagnosticCodes && Array.isArray(messageData.diagnosticCodes)) {
      dashboardStore.updateDiagnosticCodes(messageData.diagnosticCodes);
      updateTaskStatus('diagnosticCodes', 'completed');
      hasUpdates = true;
      updatedModules.push('故障信息');
    }
    
    // 处理处置方法（应急处置建议）
    if (messageData.treatmentMethod && Array.isArray(messageData.treatmentMethod)) {
      dashboardStore.updateTreatmentMethods(messageData.treatmentMethod);
      updateTaskStatus('treatmentMethod', 'completed');
      hasUpdates = true;
      updatedModules.push('应急处置建议');
    }
    
    // 处理故障原因
    if (messageData.faultCause && Array.isArray(messageData.faultCause)) {
      dashboardStore.updateFaultCauses(messageData.faultCause);
      hasUpdates = true;
      updatedModules.push('故障原因');
    }
    
    // 处理典型案例
    if (messageData.typicalCases && Array.isArray(messageData.typicalCases)) {
      dashboardStore.updateTypicalCases(messageData.typicalCases);
      hasUpdates = true;
      updatedModules.push('典型案例');
    }
    
    // 处理标准文件
    if (messageData.standardFiles && Array.isArray(messageData.standardFiles)) {
      dashboardStore.updateStandardFiles(messageData.standardFiles);
      updateTaskStatus('standardFiles', 'completed');
      hasUpdates = true;
      updatedModules.push('标准文件');
    }
    
    // 处理规章制度
    if (messageData.ruleRegulations && Array.isArray(messageData.ruleRegulations)) {
      dashboardStore.updateRuleRegulations(messageData.ruleRegulations);
      updateTaskStatus('ruleRegulations', 'completed');
      hasUpdates = true;
      updatedModules.push('规章制度');
    }
    
    // 处理注意事项
    if (messageData.precautions && Array.isArray(messageData.precautions)) {
      dashboardStore.updatePrecautions(messageData.precautions);
      updateTaskStatus('precautions', 'completed');
      hasUpdates = true;
      updatedModules.push('注意事项');
    }
    
    // 处理交路信息
    if (messageData.routeInfo && Array.isArray(messageData.routeInfo)) {
      dashboardStore.updateRouteInfo(messageData.routeInfo);
      updateTaskStatus('routeInfo', 'completed');
      hasUpdates = true;
      updatedModules.push('交路信息');
    }
    
    // 如果有数据更新
    if (hasUpdates) {
      const updateMessage = `${updatedModules.join('、')} 数据已更新`;
      showNotification(updateMessage, 'success');
      console.log('已更新的模块:', updatedModules);
      
      // 如果还在思考状态，立即显示结果
      if (isThinking.value) {
        isThinking.value = false;
        showResults.value = true;
        triggerCardAnimations();
      }
    } else {
      console.warn('WebSocket 消息中没有可识别的数据字段');
    }
  } catch (error) {
    console.error('处理 WebSocket 消息失败:', error);
    showNotification('数据处理失败', 'error');
  }
};

/**
 * 初始化任务列表
 */
const initializeTaskList = () => {
  taskList.value = [
    {
      id: 'emergencyDisposal',
      title: '应急处置建议',
      status: 'loading',
      dataKey: 'treatmentMethod'
    },
    {
      id: 'faultInfo',
      title: '故障信息',
      status: 'loading',
      dataKey: 'diagnosticCodes'
    },
    {
      id: 'routeInfo',
      title: '交路信息',
      status: 'loading',
      dataKey: 'routeInfo'
    },
    {
      id: 'trainInfo',
      title: '车组信息',
      status: 'loading',
      dataKey: 'trainInfo'
    },
    {
      id: 'personnelInfo',
      title: '人员信息',
      status: 'loading',
      dataKey: 'mechanicInfo'
    },
    {
      id: 'ruleRegulation',
      title: '规章制度',
      status: 'loading',
      dataKey: 'ruleRegulations'
    },
    {
      id: 'typicalCase',
      title: '典型案例',
      status: 'loading',
      dataKey: 'standardFiles'
    },
    {
      id: 'precautions',
      title: '注意事项',
      status: 'loading',
      dataKey: 'precautions'
    }
  ];
};

/**
 * 更新任务状态
 */
const updateTaskStatus = (dataKey: string, status: 'completed' | 'error') => {
  const task = taskList.value.find(t => t.dataKey === dataKey);
  if (task) {
    task.status = status;
  }
};

/**
 * 处理问题提交
 * 实现问答交互流程：输入问题 → 思考过程 → 显示结果
 */
const handleQuestionSubmit = async () => {
  if (!questionText.value.trim()) return;
  
  // 生成随机的系统消息ID
  sysMessageId.value = generateSysMessageId();
  console.log('生成的 sysMessageId:', sysMessageId.value);
  
  // 初始化任务列表
  initializeTaskList();
  
  // 建立 WebSocket 连接
  connectWebSocket();
  
  // 保存用户提交的问题
  submittedQuestion.value = questionText.value.trim();
  
  // 第一步：隐藏输入框，显示思考过程
  showQuestionInput.value = false;
  isThinking.value = true;
  
  // 模拟思考过程的文字变化
  const thinkingMessages = [
    '正在分析您的问题...',
    '正在搜索相关信息...',
    '正在整理数据...',
    '正在生成结果...'
  ];
  
  let messageIndex = 0;
  const thinkingInterval = setInterval(() => {
    if (messageIndex < thinkingMessages.length) {
      thinkingText.value = thinkingMessages[messageIndex];
      messageIndex++;
    }
  }, 500);
  
  try {
    // 调用 sendChatMessage 方法发送聊天消息
    const userId = aclStore.getUserId;
    if (!userId) {
      throw new Error('未获取到用户ID');
    }
    
    await sendChatMessage({
      content: submittedQuestion.value,
      userId: userId,
      chatType: '4',
      sysMessageId: sysMessageId.value
    });
    
    console.log('已向后端发送请求，等待 WebSocket 推送数据...');
  } catch (error) {
    console.error('调用后端接口失败:', error);
    clearInterval(thinkingInterval);
    isThinking.value = false;
    showNotification('获取数据失败，请重试', 'error');
    showQuestionInput.value = true;
    return;
  }
  
  // 第二步：2秒后隐藏思考过程，显示结果卡片（如果WebSocket还没有推送数据）
  setTimeout(() => {
    clearInterval(thinkingInterval);
    if (isThinking.value) {
      isThinking.value = false;
      showResults.value = true;
      
      // 触发卡片逐个弹出动画
      triggerCardAnimations();
    }
  }, 2000);
};

/**
 * 触发卡片逐个弹出动画 - 增强版
 * 使用多种动画变体和更丰富的视觉效果
 */
const triggerCardAnimations = () => {
  // 重置所有卡片的动画状态
  const cards = document.querySelectorAll('.draggable-module-card');
  
  // 动画变体数组
  const animationVariants = [
    'animate-card-pop-enhanced',
    'animate-card-pop-top-left', 
    'animate-card-pop-bottom-right',
    'animate-card-pop-spiral'
  ];
  
  cards.forEach((card, index) => {
    const element = card as HTMLElement;
    
    // 清除之前的动画类
    element.classList.remove(...animationVariants);
    element.classList.remove('card-particles', 'card-glow-effect');
    
    // 初始状态：优化的隐藏状态
    element.style.opacity = '0';
    element.style.visibility = 'hidden';
    element.style.transform = 'translateY(60px) translateX(-20px) scale(0.7) rotateX(15deg) rotateY(-10deg)';
    element.style.filter = 'blur(6px) brightness(0.6)';
    element.style.boxShadow = '0 0 0 rgba(0, 212, 255, 0)';
    
    // 优化延迟计算：更平滑的节奏
    const baseDelay = 100; // 减少基础延迟
    const staggerDelay = index * 80; // 减少间隔，让节奏更紧凑
    const randomOffset = Math.random() * 40; // 减少随机性，保持节奏感
    const totalDelay = baseDelay + staggerDelay + randomOffset;
    
    // 智能选择动画变体
    let animationClass;
    if (index === 0) {
      // 第一个卡片使用增强版动画
      animationClass = 'animate-card-pop-enhanced';
    } else if (index % 4 === 1) {
      // 每4个卡片中的第2个使用左上角动画
      animationClass = 'animate-card-pop-top-left';
    } else if (index % 4 === 2) {
      // 每4个卡片中的第3个使用右下角动画
      animationClass = 'animate-card-pop-bottom-right';
    } else if (index % 4 === 3) {
      // 每4个卡片中的第4个使用螺旋动画
      animationClass = 'animate-card-pop-spiral';
    } else {
      // 其他使用增强版动画
      animationClass = 'animate-card-pop-enhanced';
    }
    
    setTimeout(() => {
      // 恢复可见性
      element.style.visibility = 'visible';
      
      // 添加动画类
      element.classList.add(animationClass);
      
      // 为特定卡片添加特效（更有规律）
      if (index === 0 || index % 3 === 0) {
        element.classList.add('card-particles');
      }
      
      if (index === 1 || index % 5 === 0) {
        element.classList.add('card-glow-effect');
      }
      
      // 添加精细的延迟类
      const delayClass = `animate-delay-${Math.min(Math.floor(index * 30 + 50), 500)}`;
      element.classList.add(delayClass);
      
      // 动画完成后的回调处理
      const animationDuration = animationClass === 'animate-card-pop-enhanced' ? 1000 : 
                               animationClass === 'animate-card-pop-spiral' ? 900 : 700;
      
      setTimeout(() => {
        // 清除内联样式，恢复CSS控制
        element.style.opacity = '';
        element.style.visibility = '';
        element.style.transform = '';
        element.style.filter = '';
        element.style.boxShadow = '';
        
        // 移除动画类，但保留效果类
        element.classList.remove(animationClass, delayClass);
        
        // 添加悬停效果
        element.classList.add('hover-glow');
        
        // 触发完成回调
        if (index === cards.length - 1) {
          onAllAnimationsComplete();
        }
      }, animationDuration);
      
    }, totalDelay);
  });
};

/**
 * 所有动画完成后的回调函数
 */
const onAllAnimationsComplete = () => {
  // 可以在这里添加额外的效果，比如显示提示信息
  console.log('所有卡片动画已完成');
  
  // 可选：显示一个完成提示
  setTimeout(() => {
    showNotification('智能分析完成，可以开始操作了！', 'success');
  }, 500);
};

/**
 * 切换拖拽功能开关
 */
const toggleDragMode = () => {
  isDragEnabled.value = !isDragEnabled.value;
};

/**
 * 保存当前布局
 */
const saveCurrentLayout = () => {
  try {
    localStorage.setItem('savedLayout', JSON.stringify(moduleLayouts));
    showNotification('布局已保存', 'success');
  } catch (error) {
    console.error('保存布局失败:', error);
    showNotification('保存布局失败', 'error');
  }
};

/**
 * 还原到保存的布局
 */
const restoreLayout = () => {
  try {
    const savedLayout = localStorage.getItem('savedLayout');
    
    if (savedLayout) {
      const parsedLayout = JSON.parse(savedLayout);
      
      // 更新当前布局
      Object.keys(parsedLayout).forEach(moduleId => {
        if (moduleLayouts[moduleId]) {
          moduleLayouts[moduleId].position = parsedLayout[moduleId].position;
          moduleLayouts[moduleId].size = parsedLayout[moduleId].size;
        }
      });
      
      saveLayout();
      showNotification('布局已还原', 'success');
    } else {
      // 如果没有保存的布局，还原到默认布局
      resetToDefaultLayout();
    }
  } catch (error) {
    console.error('还原布局失败:', error);
    showNotification('还原布局失败', 'error');
  }
};

/**
 * 重置到默认布局
 */
const resetToDefaultLayout = () => {
  try {
    const defaultLayout = getDefaultLayout();
    
    Object.keys(defaultLayout).forEach(moduleId => {
      if (moduleLayouts[moduleId]) {
        moduleLayouts[moduleId].position = defaultLayout[moduleId].position;
        moduleLayouts[moduleId].size = defaultLayout[moduleId].size;
      }
    });
    
    saveLayout();
    showNotification('已重置为默认布局', 'success');
  } catch (error) {
    console.error('重置布局失败:', error);
    showNotification('重置布局失败', 'error');
  }
};

/**
 * 显示通知
 */
const showNotification = (message: string, type: 'success' | 'error' | 'info' = 'success') => {
  // 清除之前的定时器
  if (notificationTimer) {
    clearTimeout(notificationTimer);
  }
  
  // 设置通知内容
  notification.value = {
    show: true,
    message,
    type
  };
  
  // 3秒后自动隐藏
  notificationTimer = setTimeout(() => {
    notification.value.show = false;
  }, 3000);
};




// 生命周期钩子
onMounted(async () => {
  // 设置全局标识，表明当前在 homePage
  (window as any).__isHomePage__ = true;
  
  // 触发 VabTopBar 更新检测
  window.dispatchEvent(new CustomEvent('homepage-mounted'));
  
  // 加载数据
  await dashboardStore.loadAllData();
  
  // 监听来自 VabTopBar 的事件
  window.addEventListener('toggle-drag-mode', ((e: CustomEvent) => {
    isDragEnabled.value = e.detail.enabled;
  }) as EventListener);
  
  window.addEventListener('save-layout', (() => {
    saveCurrentLayout();
  }) as EventListener);
  
  window.addEventListener('restore-layout', (() => {
    restoreLayout();
  }) as EventListener);
});

onUnmounted(() => {
  // 清除全局标识
  (window as any).__isHomePage__ = false;
  
  // 触发 VabTopBar 更新检测
  window.dispatchEvent(new CustomEvent('homepage-unmounted'));
  
  // 清理事件监听器
  window.removeEventListener('toggle-drag-mode', (() => {}) as EventListener);
  window.removeEventListener('save-layout', (() => {}) as EventListener);
  window.removeEventListener('restore-layout', (() => {}) as EventListener);
  
  // 断开 WebSocket 连接并清理监听器
  webSocketService.off('message', handleWebSocketMessage);
  webSocketService.off('connect');
  webSocketService.off('error');
  // 注意：不要在这里调用 disconnect，因为 App.vue 可能还在使用
});

// 规章制度 PDF 预览状态与方法（页面级）
const rulePdfDialogVisible = ref(false);
const currentRulePdfUrl = ref('');
const rulePdfLoading = ref(false);

const handleOpenRulePdf = (rule: RuleRegulation) => {
  if (!rule.fileUrl) {
    ElMessage.warning('该条目未配置预览文件');
    return;
  }
  
  // 重置加载状态和PDF URL
  rulePdfLoading.value = true;
  currentRulePdfUrl.value = '';
  
  // 显示弹窗
  rulePdfDialogVisible.value = true;
  
  // 延迟设置PDF URL，确保组件重新渲染
  setTimeout(() => {
    currentRulePdfUrl.value = rule.fileUrl;
  }, 100);
};

const handleOpenCasePdf = (caseItem: TypicalCase) => {
  if (!caseItem.fileUrl) {
    ElMessage.warning('该案例未配置预览文件');
    return;
  }
  
  // 重置加载状态和PDF URL
  rulePdfLoading.value = true;
  currentRulePdfUrl.value = '';
  
  // 显示弹窗
  rulePdfDialogVisible.value = true;
  
  // 延迟设置PDF URL，确保组件重新渲染
  setTimeout(() => {
    currentRulePdfUrl.value = caseItem.fileUrl;
  }, 100);
};

// 监听弹窗关闭，重置状态
watch(rulePdfDialogVisible, (newValue) => {
  if (!newValue) {
    // 弹窗关闭时重置状态
    setTimeout(() => {
      currentRulePdfUrl.value = '';
      rulePdfLoading.value = false;
    }, 300); // 延迟重置，避免关闭动画期间的闪烁
  }
});
</script>

<style scoped lang="scss">
.dashboard-page {
  min-height: 100vh;
  background: url('@/assets/background.png');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: #ffffff;
  overflow: hidden; // 隐藏滚动条（保持，避免出现滚动条）
  position: relative;
  
  &::before {
    content: '';
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: 
      radial-gradient(circle at 20% 50%, rgba(0, 162, 255, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 80% 20%, rgba(0, 255, 255, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 40% 80%, rgba(0, 162, 255, 0.1) 0%, transparent 50%);
    pointer-events: none;
    z-index: 0;
  }
  
  > * {
    position: relative;
    z-index: 1;
  }
}


.dashboard-main {
  padding: 20px;
  max-width: 5500px;
  margin: 0 auto;
  overflow: visible; // 允许卡片超出显示
}



.modules-section {
  margin-bottom: 40px;
  overflow: visible; // 允许卡片超出显示
}

// 问题输入界面样式 - 简洁聊天风格
.question-input-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  padding: 40px 80px;
  
  .question-container {
    width: 60%;
    max-width: 1400px;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  
  .question-title {
    font-size: 2rem;
    font-weight: 500;
    background: linear-gradient(135deg, #00D4FF 0%, #1890FF 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    text-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
    margin-bottom: 40px;
    text-align: center;
  }
  
  .chat-input-container {
    display: flex;
    align-items: flex-start;
    width: 100%;
    background: rgba(15, 23, 42, 0.8);
    border: 1px solid rgba(0, 212, 255, 0.3);
    border-radius: 24px;
    padding: 20px 24px;
    box-shadow: 0 2px 8px rgba(0, 212, 255, 0.1);
    transition: all 0.3s ease;
    backdrop-filter: blur(10px);
    
    &:hover {
      border-color: rgba(0, 212, 255, 0.5);
      box-shadow: 0 4px 12px rgba(0, 212, 255, 0.2);
    }
    
    &:focus-within {
      border-color: #00D4FF;
      box-shadow: 0 0 0 2px rgba(0, 212, 255, 0.3);
    }
    
    .chat-avatar {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 44px;
      height: 44px;
      background: rgba(0, 212, 255, 0.15);
      border: 1px solid rgba(0, 212, 255, 0.3);
      border-radius: 50%;
      margin-right: 16px;
      margin-top: 4px;
      flex-shrink: 0;
      
      svg {
        width: 22px;
        height: 22px;
        color: #00D4FF;
      }
    }
    
    .input-wrapper {
      flex: 1;
      margin-right: 16px;
      
      .chat-input {
        width: 100%;
        border: none;
        outline: none;
        background: transparent;
        font-size: 16px;
        color: #ffffff;
        padding: 12px 0;
        min-height: 40px;
        max-height: 200px;
        resize: none;
        overflow-y: auto;
        line-height: 1.5;
        font-family: inherit;
        
        &::placeholder {
          color: #94A3B8;
        }
        
        &::-webkit-scrollbar {
          width: 4px;
        }
        
        &::-webkit-scrollbar-track {
          background: rgba(0, 212, 255, 0.1);
          border-radius: 2px;
        }
        
        &::-webkit-scrollbar-thumb {
          background: rgba(0, 212, 255, 0.3);
          border-radius: 2px;
          
          &:hover {
            background: rgba(0, 212, 255, 0.5);
          }
        }
      }
    }
    
    .input-actions {
      display: flex;
      gap: 10px;
      align-items: flex-start;
      margin-top: 4px;
      
      .action-btn {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        background: rgba(0, 212, 255, 0.1);
        border: 1px solid rgba(0, 212, 255, 0.3);
        color: #94A3B8;
        cursor: pointer;
        transition: all 0.2s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        
        svg {
          width: 20px;
          height: 20px;
        }
        
        &:hover {
          background: rgba(0, 212, 255, 0.2);
          color: #00D4FF;
          border-color: rgba(0, 212, 255, 0.5);
        }
        
        &.voice-btn:hover {
          background: rgba(255, 77, 79, 0.15);
          color: #ff4d4f;
          border-color: rgba(255, 77, 79, 0.3);
        }
        
        &.send-btn {
          background: #00D4FF;
          color: white;
          border-color: #00D4FF;
          
          &:hover {
            background: #1890FF;
            border-color: #1890FF;
          }
          
          &:active {
            background: #0066CC;
            border-color: #0066CC;
          }
        }
      }
    }
  }
}

// 思考过程样式
.thinking-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  padding: 40px;
  
  .thinking-spinner {
    width: 60px;
    height: 60px;
    border: 3px solid rgba(0, 212, 255, 0.2);
    border-top: 3px solid #00d4ff;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-bottom: 30px;
    box-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
  }
  
  .thinking-text {
    font-size: 1.5rem;
    color: #ffffff;
    margin-bottom: 10px;
    background: linear-gradient(135deg, #00d4ff 0%, #1890ff 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }
  
  .thinking-dots {
    font-size: 1.5rem;
    color: #00d4ff;
    
    .dot {
      animation: thinkingDots 1.5s ease-in-out infinite;
      
      &:nth-child(1) { animation-delay: 0s; }
      &:nth-child(2) { animation-delay: 0.3s; }
      &:nth-child(3) { animation-delay: 0.6s; }
    }
  }
}

.modules-container {
  position: relative;
  width: 100%;
  min-height: calc(100vh - 70px); // 减去顶部导航栏高度
  max-width: 1200px;
  margin: 0 auto;
  overflow: visible; // 允许卡片超出容器显示
}

/* 可拖拽模块卡片样式 */
.draggable-module-card {
  cursor: move;
  user-select: none;
  transition: all 0.3s ease;
}

.draggable-module-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}



/* 移动端响应式设计 */
@media (max-width: 768px) {
  .modules-container {
    min-height: 100vh;
  }
}

/* 平板端响应式设计 */
@media (min-width: 769px) and (max-width: 1024px) {
  .modules-container {
    min-height: 100vh;
  }
}

.overview-section {
  margin-top: 40px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
  max-width: 800px;
  margin: 0 auto;
  
  .chart-title {
    color: #00a2ff;
    font-size: 18px;
    font-weight: 600;
    margin: 20px 0 10px 0;
    text-align: center;
    grid-column: 1 / -1;
    
    &:first-of-type {
      margin-top: 40px;
    }
  }
}



.overview-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  background: linear-gradient(135deg, rgba(15, 23, 42, 0.8) 0%, rgba(30, 41, 59, 0.6) 100%);
  border: 1px solid rgba(0, 212, 255, 0.3);
  border-radius: 12px;
  padding: 20px;
  backdrop-filter: blur(10px);
  transition: all 0.3s ease;
  text-align: center;
  
  &:hover {
    border-color: rgba(0, 212, 255, 0.6);
    transform: translateY(-2px);
  }
  
  h3 {
    font-size: 28px;
    font-weight: 700;
    margin: 0;
    color: #FFFFFF;
  }
  
  p {
    font-size: 14px;
    color: #94A3B8;
    margin: 0;
  }
}

.overview-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  background: linear-gradient(135deg, rgba(0, 212, 255, 0.2) 0%, rgba(24, 144, 255, 0.2) 100%);
  border-radius: 12px;
  color: #00D4FF;
  
  &--success {
    background: linear-gradient(135deg, rgba(82, 196, 26, 0.2) 0%, rgba(82, 196, 26, 0.2) 100%);
    color: #52C41A;
  }
  
  &--warning {
    background: linear-gradient(135deg, rgba(250, 173, 20, 0.2) 0%, rgba(250, 173, 20, 0.2) 100%);
    color: #FAAD14;
  }
  
  &--info {
    background: linear-gradient(135deg, rgba(19, 194, 194, 0.2) 0%, rgba(19, 194, 194, 0.2) 100%);
    color: #13C2C2;
  }
}



.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(10, 22, 40, 0.8);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  z-index: 9999;
  backdrop-filter: blur(5px);
  
  .spinner {
    width: 40px;
    height: 40px;
    border: 3px solid rgba(0, 212, 255, 0.3);
    border-top: 3px solid #00D4FF;
    border-radius: 50%;
    animation: spin 1s linear infinite;
  }
  
  p {
    color: #94A3B8;
    font-size: 16px;
    margin: 0;
  }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

@keyframes thinkingDots {
  0%, 20% { opacity: 0.3; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.2); }
  80%, 100% { opacity: 0.3; transform: scale(1); }
}

@keyframes particleFloat {
  0%, 100% { transform: translateY(0px) rotate(0deg); }
  33% { transform: translateY(-10px) rotate(120deg); }
  66% { transform: translateY(5px) rotate(240deg); }
}

@keyframes borderGlow {
  0%, 100% { 
    background-size: 200% 200%;
    background-position: 0% 50%;
  }
  50% { 
    background-size: 200% 200%;
    background-position: 100% 50%;
  }
}

@keyframes iconPulse {
  0%, 100% { 
    opacity: 0.7; 
    transform: translateY(-50%) scale(1);
  }
  50% { 
    opacity: 1; 
    transform: translateY(-50%) scale(1.1);
  }
}

@keyframes buttonGlow {
  0%, 100% { opacity: 0; }
  50% { opacity: 0.8; }
}

@keyframes cardPopIn {
  0% {
    box-shadow: 0 0 0 rgba(0, 212, 255, 0);
  }
  30% {
    box-shadow: 
      0 0 30px rgba(0, 212, 255, 0.4),
      0 0 60px rgba(0, 255, 255, 0.2),
      0 8px 32px rgba(0, 212, 255, 0.15);
  }
  60% {
    box-shadow: 
      0 0 20px rgba(0, 212, 255, 0.3),
      0 0 40px rgba(0, 255, 255, 0.15),
      0 8px 32px rgba(0, 212, 255, 0.15);
  }
  100% {
    box-shadow: 0 8px 32px rgba(0, 212, 255, 0.15);
  }
}

// 大屏适配 (4K及以上)
@media (min-width: 2560px) {
  .dashboard-main {
    padding: 20px;
    max-width: 2400px;
  }
  
  .modules-container {
    max-width: none;
    min-height: 800px;
  }
  
  .question-input-section {
    padding: 40px 120px;
    
    .question-container {
      max-width: 1800px;
    }
  }
  
  .overview-section {
    grid-template-columns: repeat(4, 1fr);
    gap: 32px;
    max-width: none;
    
    .chart-title {
      font-size: 20px;
    }
  }
}

// 超宽屏适配 (1920px-2560px)
@media (min-width: 1920px) and (max-width: 2559px) {
  .dashboard-main {
    padding: 20px;
    max-width: 1800px;
  }
  
  .modules-container {
    max-width: none;
    min-height: 800px;
  }
  
  .question-input-section {
    padding: 40px 100px;
    
    .question-container {
      max-width: 1600px;
    }
  }
  
  .overview-section {
    grid-template-columns: repeat(4, 1fr);
    gap: 28px;
    max-width: none;
  }
}

// 标准大屏适配 (1440px-1920px)
@media (min-width: 1440px) and (max-width: 1919px) {
  .dashboard-main {
    padding: 20px;
    max-width: 1600px;
  }
  
  .modules-container {
    max-width: none;
    min-height: 800px;
  }
}

// 中等屏幕适配 (1025px-1439px)
@media (min-width: 1025px) and (max-width: 1439px) {
  .modules-container {
    max-width: 1200px;
    min-height: 800px;
  }
}

@media (max-width: 1024px) {
  .dashboard-main {
    padding: 20px;
  }
  
  .overview-section {
    max-width: 800px;
  }
  
  // 中等屏幕聊天输入框调整
  .question-input-section {
    padding: 40px 40px;
    
    .question-container {
      max-width: 1200px;
    }
  }
  
  .chat-input-container {
    .chat-avatar {
      width: 34px;
      height: 34px;
      
      svg {
        width: 19px;
        height: 19px;
      }
    }
    
    .input-actions {
      .action-btn {
        width: 34px;
        height: 34px;
        
        svg {
          width: 17px;
          height: 17px;
        }
      }
    }
  }
}

@media (max-width: 768px) {
  .overview-section {
    grid-template-columns: repeat(2, 1fr);
  }
  
  // 聊天输入框响应式设计
  .question-input-section {
    padding: 30px 20px;
    
    .question-container {
      max-width: 100%;
    }
  }
  
  .chat-input-container {
    padding: 10px 12px;
    
    .chat-avatar {
      width: 32px;
      height: 32px;
      margin-right: 10px;
      
      svg {
        width: 18px;
        height: 18px;
      }
    }
    
    .input-wrapper {
      margin-right: 10px;
      
      .chat-input {
        font-size: 15px;
        padding: 6px 0;
        min-height: 60px;
      }
    }
    
    .input-actions {
      gap: 6px;
      
      .action-btn {
        width: 32px;
        height: 32px;
        
        svg {
          width: 16px;
          height: 16px;
        }
      }
    }
  }
}

@media (max-width: 480px) {
  .dashboard-main {
    padding: 12px;
  }
  
  // 小屏幕聊天输入框优化
  .question-input-section {
    padding: 20px 16px;
    
    .question-title {
      font-size: 1.5rem;
    }
  }
  
  .chat-input-container {
    padding: 8px 10px;
    border-radius: 20px;
    
    .chat-avatar {
      width: 28px;
      height: 28px;
      margin-right: 8px;
      
      svg {
        width: 16px;
        height: 16px;
      }
    }
    
    .input-wrapper {
      margin-right: 8px;
      
      .chat-input {
        font-size: 14px;
        padding: 4px 0;
        min-height: 48px;
      }
    }
    
    .input-actions {
      gap: 4px;
      
      .action-btn {
        width: 28px;
        height: 28px;
        
        svg {
          width: 14px;
          height: 14px;
        }
      }
    }
  }
   
  .overview-section {
    grid-template-columns: 1fr;
    gap: 12px;
    
    .chart-title {
      font-size: 14px;
    }
  }
}



@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.8;
  }
}

// 通知组件样式
.notification {
  position: fixed;
  top: 80px;
  right: 20px;
  z-index: 9999;
  padding: 12px 20px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(10px);
  border: 1px solid;
  transition: all 0.3s ease;
  
  &--success {
    background: rgba(82, 196, 26, 0.1);
    border-color: rgba(82, 196, 26, 0.3);
    color: #52C41A;
  }
  
  &--error {
    background: rgba(255, 77, 79, 0.1);
    border-color: rgba(255, 77, 79, 0.3);
    color: #FF4D4F;
  }
  
  &--info {
    background: rgba(0, 162, 255, 0.1);
    border-color: rgba(0, 162, 255, 0.3);
    color: #00A2FF;
  }
}

/* 规章制度 PDF 预览弹窗样式（页面级） */
.rule-pdf-dialog {
  :deep(.el-dialog__header) {
    background: linear-gradient(135deg, #13c2c2 0%, #08979c 100%);
    color: #fff;
    border-radius: 12px 12px 0 0;
  }
  :deep(.el-dialog__title) {
    color: #fff;
    font-weight: 600;
  }
}

.preview-content {
  min-height: 750px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0b1424;
  border-radius: 0 0 12px 12px;
}

.pdf-preview {
  width: 100%;
  height: 750px;
  border-radius: 8px;
  overflow: hidden;
  background: #ffffff;
}
</style>
