<template>
  <div class="file-selector">
    <!-- 文件选择对话框 -->
    <el-dialog 
      v-model="dialogVisible" 
      :title="dialogTitle" 
      width="80%" 
      :before-close="handleClose"
      class="file-selector-dialog"
      :modal-class="'file-selector-modal'"
      :z-index="3000"
    >
      <div class="selector-container">
        <!-- 顶部分类导航 - 仅在允许多种类型时显示 -->
        <div class="top-categories" v-if="allowedTypes.length > 1">
          <div class="category-tabs">
            <div
              v-for="category in filteredTopCategories"
              :key="category.type"
              class="category-tab"
              :class="{ active: currentCategoryType === category.type }"
              @click="switchCategoryType(category.type)"
            >
              <el-icon>
                <component :is="category.icon" />
              </el-icon>
              <span>{{ category.name }}</span>
            </div>
          </div>
        </div>

        <!-- 主要内容区域 -->
        <div class="main-container">
          <!-- 工具栏 -->
          <div class="toolbar">
            <div class="toolbar-left">
              <el-button type="primary" @click="openUploadForm" v-if="allowUpload">
                <el-icon><Plus /></el-icon>
                上传{{ multiple ? '' : '单个' }}{{ getCurrentTypeText() }}
              </el-button>
              <span class="selected-info" v-if="selectedFiles.length > 0">
                已选择 {{ selectedFiles.length }} {{ multiple ? '个文件' : '个文件（单选模式）' }}
              </span>
            </div>
            <div class="toolbar-right">
              <el-input
                v-model="searchKeyword"
                :placeholder="`搜索${getCurrentTypeText()}`"
                style="width: 200px"
                clearable
                @input="handleSearch"
              >
                <template #prefix>
                  <el-icon><Search /></el-icon>
                </template>
              </el-input>
              <div class="view-toggle">
                <el-button 
                  :type="viewMode === 'grid' ? 'primary' : 'default'"
                  size="small"
                  @click="viewMode = 'grid'"
                >
                  <el-icon><Grid /></el-icon>
                </el-button>
                <el-button 
                  :type="viewMode === 'list' ? 'primary' : 'default'"
                  size="small"
                  @click="viewMode = 'list'"
                >
                  <el-icon><List /></el-icon>
                </el-button>
              </div>
            </div>
          </div>

          <!-- 内容区域 -->
          <div class="content-wrapper">
            <!-- 左侧分类树 -->
            <div class="sidebar">
              <div class="sidebar-header">
                <h3>{{ getCurrentTypeText() }}分类</h3>
              </div>
              <div class="category-list">
                <!-- 全部文件 -->
                <div 
                  class="category-item"
                  :class="{ active: currentSubCategory === null }"
                  @click="handleShowAllFiles"
                >
                  <el-icon class="category-icon"><Folder /></el-icon>
                  <span>全部{{ getCurrentTypeText() }}</span>
                </div>
                
                <!-- 子分类树 -->
                <el-tree
                  ref="categoryTreeRef"
                  :data="subCategoryTree"
                  :props="treeProps"
                  :expand-on-click-node="false"
                  :highlight-current="true"
                  node-key="id"
                  @node-click="handleTreeNodeClick"
                  class="category-tree"
                >
                  <template #default="{ node, data }">
                    <div class="tree-node-content">
                      <el-icon class="category-icon"><Folder /></el-icon>
                      <span class="node-label">{{ data.name }}</span>
                    </div>
                  </template>
                </el-tree>
              </div>
            </div>

            <!-- 右侧文件展示区 -->
            <div class="content-area">
              <!-- 网格视图 -->
              <div v-if="viewMode === 'grid'" class="file-grid" v-loading="loading">
                <!-- 调试信息 -->
                <div v-if="fileList.length === 0 && !loading" class="empty-state">
                  <p>暂无文件数据</p>
                </div>
                <div 
                  v-for="file in fileList" 
                  :key="file.id"
                  class="file-item"
                  :class="{ selected: isFileSelected(file.id) }"
                  @click="toggleFileSelection(file)"
                >
                  <div class="file-wrapper">
                    <el-image
                      v-if="isImage(file)"
                      :src="getImageUrl(file)"
                      fit="cover"
                      class="file-thumbnail"
                      :preview-disabled="true"
                      lazy
                    >
                      <template #error>
                        <div class="file-error">
                          <el-icon size="24" color="#c0c4cc">
                            <Picture />
                          </el-icon>
                        </div>
                      </template>
                      <template #placeholder>
                        <div class="file-loading">
                          <el-icon size="24" color="#409eff">
                            <Loading />
                          </el-icon>
                        </div>
                      </template>
                    </el-image>
                    <div v-else-if="isVideo(file)" class="video-thumbnail-wrapper full">
                                             <video
                         :src="getVideoUrl(file)"
                         class="file-thumbnail video-thumbnail"
                         muted
                         preload="metadata"
                         @loadedmetadata="onVideoLoadedMetadata"
                         @error="onVideoError"
                         @contextmenu.prevent
                         :controls="false"
                         :controlslist="'nodownload nofullscreen noremoteplayback'"
                         :disablepictureinpicture="true"
                         :disableremoteplayback="true"
                       ></video>
                      <div class="video-play-overlay">
                        <el-icon size="32" color="#fff">
                          <VideoPlay />
                        </el-icon>
                      </div>
                    </div>
                    <div v-else class="file-icon-wrapper">
                      <el-icon class="file-icon" :color="getFileIconColor(file)">
                        <component :is="getFileIcon(file)" />
                      </el-icon>
                    </div>
                    <div class="file-checkbox">
                      <el-checkbox 
                        :model-value="isFileSelected(file.id)"
                        @click.stop
                      />
                    </div>
                  </div>
                  <div class="file-info">
                    <div class="file-name">{{ file.name || file.originalName }}</div>
                    <div class="file-size">{{ formatFileSize(file.size) }}</div>
                  </div>
                </div>
              </div>

              <!-- 列表视图 -->
              <div v-else class="file-list">
                <el-table
                  v-loading="loading"
                  :data="fileList"
                  style="width: 100%"
                  @selection-change="handleSelectionChange"
                >
                  <el-table-column type="selection" width="55" />
                  <el-table-column label="预览" width="80">
                    <template #default="{ row }">
                      <el-image
                        v-if="isImage(row)"
                        :src="getImageUrl(row)"
                        style="width: 50px; height: 50px; border-radius: 4px;"
                        fit="cover"
                        :preview-disabled="true"
                        lazy
                      >
                        <template #error>
                          <div class="image-error">
                            <el-icon size="20" color="#c0c4cc">
                              <Picture />
                            </el-icon>
                          </div>
                        </template>
                        <template #placeholder>
                          <div class="image-loading">
                            <el-icon size="20" color="#409eff">
                              <Loading />
                            </el-icon>
                          </div>
                        </template>
                      </el-image>
                      <div v-else-if="isVideo(row)" class="video-thumbnail-wrapper">
                        <video
                          :src="getVideoUrl(row)"
                          style="width: 50px; height: 50px; border-radius: 4px; object-fit: cover;"
                          muted
                          preload="metadata"
                          @loadedmetadata="onVideoLoadedMetadata"
                          @error="onVideoError"
                          @contextmenu.prevent
                          class="video-thumbnail"
                          :controls="false"
                          :controlslist="'nodownload nofullscreen noremoteplayback'"
                          :disablepictureinpicture="true"
                          :disableremoteplayback="true"
                        ></video>
                        <div class="video-play-overlay">
                          <el-icon size="16" color="#fff">
                            <VideoPlay />
                          </el-icon>
                        </div>
                      </div>
                      <el-icon v-else size="30" :color="getFileIconColor(row)">
                        <component :is="getFileIcon(row)" />
                      </el-icon>
                    </template>
                  </el-table-column>
                  <el-table-column label="文件名" prop="name" min-width="200">
                    <template #default="{ row }">
                      {{ row.name || row.originalName }}
                    </template>
                  </el-table-column>
                  <el-table-column label="大小" width="100">
                    <template #default="{ row }">
                      {{ formatFileSize(row.size) }}
                    </template>
                  </el-table-column>
                  <el-table-column label="上传时间" width="180">
                    <template #default="{ row }">
                      {{ formatTime(row.createTime) }}
                    </template>
                  </el-table-column>
                </el-table>
              </div>

              <!-- 分页 -->
              <div class="pagination">
                <el-pagination
                  v-model:current-page="queryParams.pageNum"
                  v-model:page-size="queryParams.pageSize"
                  :total="total"
                  :page-sizes="[12, 24, 48, 96]"
                  layout="total, sizes, prev, pager, next, jumper"
                  @size-change="getFileList"
                  @current-change="getFileList"
                />
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 上传表单 -->
      <el-dialog v-model="showUploadForm" title="上传文件" width="600px" append-to-body :z-index="3100">
        <el-form ref="uploadFormRef" :model="uploadForm" label-width="100px">
          <!-- 文件分类选择 -->
          <el-form-item label="文件分类" prop="categoryId">
            <el-select
              v-model="uploadForm.categoryId"
              placeholder="请选择具体分类（可选）"
              style="width: 100%"
              clearable
            >
              <el-option
                v-for="category in subCategoryTree"
                :key="category.id"
                :label="category.name"
                :value="category.id"
              />
            </el-select>
          </el-form-item>

          <!-- 文件上传 -->
          <el-form-item label="文件上传" required>
            <el-upload
              ref="uploadRef"
              :action="uploadUrl"
              :headers="uploadHeaders"
              :before-upload="beforeUpload"
              :on-success="onUploadSuccess"
              :on-error="onUploadError"
              :file-list="uploadFileList"
              :multiple="multiple"
              :limit="multiple ? undefined : 1"
              drag
              :accept="getUploadFileAccept()"
            >
              <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
              <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
              <template #tip>
                <div class="el-upload__tip">
                  {{ multiple ? '支持多个文件上传，' : '仅支持上传单个文件，' }}支持 {{ getUploadFileTypeText() }} 格式，单个文件不超过 50MB
                </div>
              </template>
            </el-upload>
          </el-form-item>

          <!-- 文件描述 -->
          <el-form-item label="文件描述" prop="description">
            <el-input
              v-model="uploadForm.description"
              type="textarea"
              :rows="3"
              placeholder="请输入文件描述（可选）"
            />
          </el-form-item>
        </el-form>

        <template #footer>
          <el-button @click="showUploadForm = false">取消</el-button>
          <el-button type="primary" @click="submitUpload" :loading="uploadLoading">确定</el-button>
        </template>
      </el-dialog>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleClose">取消</el-button>
          <el-button type="primary" @click="handleConfirm" :disabled="selectedFiles.length === 0">
            确定选择 ({{ selectedFiles.length }})
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, h } from 'vue';
import { listFileInfo, addFileInfo } from '@/api/file/info';
import { listFileCategoryTree } from '@/api/file/category';
import {
  Plus, Search, UploadFilled, Document, VideoPlay,
  Microphone, Picture, FolderOpened, Edit, Grid, List, Folder, Loading
} from '@element-plus/icons-vue';
import { globalHeaders } from '@/utils/request';
import { ElMessage, ElMessageBox } from 'element-plus';

// Props
interface Props {
  // 是否显示对话框
  modelValue: boolean;
  // 允许的文件类型 [1: 图片, 2: 视频, 3: 音频, 4: 文档, 5: 其他]
  // 例如：[1] 仅显示图片类型，[1,2] 显示图片和视频类型
  allowedTypes?: number[];
  // 是否允许多选（单选/多选文件）
  multiple?: boolean;
  // 是否允许上传新文件
  allowUpload?: boolean;
  // 对话框标题
  title?: string;
}

const props = withDefaults(defineProps<Props>(), {
  allowedTypes: () => [1], // 默认只允许图片
  multiple: false,
  allowUpload: true,
  title: '选择文件'
});

// Emits
const emit = defineEmits<{
  'update:modelValue': [value: boolean];
  'confirm': [files: any[]];
}>();

// 响应式数据
const dialogVisible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
});

const dialogTitle = computed(() => props.title);
const loading = ref(false);
const fileList = ref([]);
const total = ref(0);
const searchKeyword = ref('');
const selectedFiles = ref([]);
const viewMode = ref('grid');
const currentCategoryType = ref(props.allowedTypes[0]);
const currentSubCategory = ref(null);

// 分类相关
const categoryTree = ref([]);
const categoryTreeRef = ref();

// 上传相关
const showUploadForm = ref(false);
const uploadFileList = ref([]);
const uploadLoading = ref(false);
const uploadFormRef = ref();

// 查询参数
const queryParams = ref({
  pageNum: 1,
  pageSize: 20,
  name: null,
  categoryId: null,
  categoryType: null
});

// 上传表单
const uploadForm = ref({
  categoryId: null,
  categoryType: null,
  description: ''
});

// 上传配置
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload');
const uploadHeaders = ref(globalHeaders());

// 树形控件配置
const treeProps = {
  label: 'name',
  children: 'children'
};

// 文件类型配置
const fileTypeConfig = {
  1: { name: '图片文件', icon: Picture, extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'] },
  2: { name: '视频文件', icon: VideoPlay, extensions: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'] },
  3: { name: '音频文件', icon: Microphone, extensions: ['mp3', 'wav', 'flac', 'aac', 'ogg'] },
  4: { name: '文档文件', icon: Document, extensions: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'] },
  5: { name: '其他文件', icon: Document, extensions: [] } // 其他文件类型允许所有文件格式
};

// 计算属性
const filteredTopCategories = computed(() => {
  return props.allowedTypes.map(type => ({
    type,
    ...fileTypeConfig[type]
  }));
});

const subCategoryTree = computed(() => {
  if (!categoryTree.value || !currentCategoryType.value) return [];
  
  // 找到当前类型对应的分类树
  const typeCategory = categoryTree.value.find(cat => cat.type === currentCategoryType.value);
  return typeCategory?.children || [];
});

// 方法
const getCurrentTypeText = () => {
  return fileTypeConfig[currentCategoryType.value]?.name.replace('文件', '') || '文件';
};

const getFileList = async () => {
  try {
    loading.value = true;
    const response = await listFileInfo(queryParams.value);
    if (response && response.rows) {
      fileList.value = (response.rows as unknown) as any[];
      total.value = response.total || 0;
    } else {
      fileList.value = [];
      total.value = 0;
    }
  } catch (error) {
    console.error('获取文件列表失败:', error);
    ElMessage.error('获取文件列表失败');
    fileList.value = [];
    total.value = 0;
  } finally {
    loading.value = false;
  }
};

const getCategoryTree = async () => {
  try {
    const response = await listFileCategoryTree();
    categoryTree.value = response.data || [];
  } catch (error) {
    console.error('获取分类树失败:', error);
    ElMessage.error('获取分类树失败');
  }
};

const switchCategoryType = (type) => {
  currentCategoryType.value = type;
  currentSubCategory.value = null;
  queryParams.value.categoryType = type;
  queryParams.value.categoryId = null;
  queryParams.value.pageNum = 1;
  selectedFiles.value = [];
  getFileList();
};

const handleShowAllFiles = () => {
  currentSubCategory.value = null;
  queryParams.value.categoryId = null;
  queryParams.value.pageNum = 1;
  getFileList();
};

const handleTreeNodeClick = (data) => {
  currentSubCategory.value = data;
  queryParams.value.categoryId = data.id;
  queryParams.value.pageNum = 1;
  getFileList();
};

const handleSearch = () => {
  queryParams.value.name = searchKeyword.value || null;
  queryParams.value.pageNum = 1;
  getFileList();
};

const isFileSelected = (fileId) => {
  return selectedFiles.value.some(file => file.id === fileId);
};

const toggleFileSelection = (file) => {
  const index = selectedFiles.value.findIndex(f => f.id === file.id);
  if (index > -1) {
    selectedFiles.value.splice(index, 1);
  } else {
    if (!props.multiple) {
      selectedFiles.value = [file];
    } else {
      selectedFiles.value.push(file);
    }
  }
};

const handleSelectionChange = (selection) => {
  selectedFiles.value = selection;
};

// 文件类型判断
const isImage = (file) => {
  // 首先检查MIME类型
  if (file.type?.includes('image')) {
    return true;
  }
  
  // 检查文件扩展名
  const extension = file.extension?.toLowerCase();
  if (extension && ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'].includes(extension)) {
    return true;
  }
  
  // 从文件名中提取扩展名作为备选方案
  const fileName = file.name || file.originalName || '';
  const fileExt = fileName.split('.').pop()?.toLowerCase();
  if (fileExt && ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'].includes(fileExt)) {
    return true;
  }
  
  return false;
};

// 视频文件类型判断
const isVideo = (file) => {
  // 首先检查MIME类型
  if (file.type?.includes('video')) {
    return true;
  }
  
  // 检查文件扩展名
  const extension = file.extension?.toLowerCase();
  if (extension && ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'm4v', '3gp'].includes(extension)) {
    return true;
  }
  
  // 从文件名中提取扩展名作为备选方案
  const fileName = file.name || file.originalName || '';
  const fileExt = fileName.split('.').pop()?.toLowerCase();
  if (fileExt && ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'm4v', '3gp'].includes(fileExt)) {
    return true;
  }
  
  return false;
};

// 音频文件类型判断
const isAudio = (file) => {
  // 首先检查MIME类型
  if (file.type?.includes('audio')) {
    return true;
  }
  
  // 检查文件扩展名
  const extension = file.extension?.toLowerCase();
  if (extension && ['mp3', 'wav', 'flac', 'aac', 'ogg', 'wma', 'm4a'].includes(extension)) {
    return true;
  }
  
  // 从文件名中提取扩展名作为备选方案
  const fileName = file.name || file.originalName || '';
  const fileExt = fileName.split('.').pop()?.toLowerCase();
  if (fileExt && ['mp3', 'wav', 'flac', 'aac', 'ogg', 'wma', 'm4a'].includes(fileExt)) {
    return true;
  }
  
  return false;
};

// 获取图片URL
const getImageUrl = (file) => {
  // 优先使用url字段
  if (file.url) {
    // 如果是完整的URL，直接返回
    if (file.url.startsWith('http://') || file.url.startsWith('https://')) {
      return file.url;
    }
    // 如果是相对路径，添加基础URL
    if (file.url.startsWith('/')) {
      return import.meta.env.VITE_APP_BASE_API + file.url;
    }
    return file.url;
  }
  
  // 备选方案：使用path字段
  if (file.path) {
    if (file.path.startsWith('http://') || file.path.startsWith('https://')) {
      return file.path;
    }
    if (file.path.startsWith('/')) {
      return import.meta.env.VITE_APP_BASE_API + file.path;
    }
    return file.path;
  }
  
  // 如果都没有，返回空字符串，触发错误处理
  return '';
};

// 获取视频URL
const getVideoUrl = (file) => {
  // 优先使用url字段
  if (file.url) {
    // 如果是完整的URL，直接返回
    if (file.url.startsWith('http://') || file.url.startsWith('https://')) {
      return file.url;
    }
    // 如果是相对路径，添加基础URL
    if (file.url.startsWith('/')) {
      return import.meta.env.VITE_APP_BASE_API + file.url;
    }
    return file.url;
  }
  
  // 备选方案：使用path字段
  if (file.path) {
    if (file.path.startsWith('http://') || file.path.startsWith('https://')) {
      return file.path;
    }
    if (file.path.startsWith('/')) {
      return import.meta.env.VITE_APP_BASE_API + file.path;
    }
    return file.path;
  }
  
  // 如果都没有，返回空字符串，触发错误处理
  return '';
};

const getFileIcon = (file) => {
  if (file.type?.includes('video')) return VideoPlay;
  if (file.type?.includes('audio')) return Microphone;
  if (file.type?.includes('pdf')) return Document;
  if (file.type?.includes('word') || file.extension === 'doc' || file.extension === 'docx') return Edit;
  if (file.type?.includes('zip') || file.extension === 'zip') return FolderOpened;
  return Document;
};

const getFileIconColor = (file) => {
  if (file.type?.includes('video')) return '#409eff';
  if (file.type?.includes('audio')) return '#67c23a';
  if (file.type?.includes('pdf')) return '#f56c6c';
  return '#909399';
};

// 视频缩略图相关事件处理
const onVideoLoadedMetadata = (event) => {
  const video = event.target;
  // 跳转到视频的第一秒或10%位置来获取有意义的缩略图
  video.currentTime = Math.min(1, video.duration * 0.1);
};

const onVideoError = (event) => {
  console.warn('视频加载失败:', event.target.src);
  // 可以在这里添加错误处理逻辑，比如显示默认图标
};

const formatFileSize = (size) => {
  if (!size) return '0 B';
  const units = ['B', 'KB', 'MB', 'GB'];
  let index = 0;
  let fileSize = size;
  while (fileSize >= 1024 && index < units.length - 1) {
    fileSize /= 1024;
    index++;
  }
  return fileSize.toFixed(2) + ' ' + units[index];
};

const formatTime = (time) => {
  if (!time) return '';
  return new Date(time).toLocaleString();
};

// 上传相关方法
const openUploadForm = () => {
  showUploadForm.value = true;
  uploadForm.value = {
    categoryId: null,
    categoryType: currentCategoryType.value,
    description: ''
  };
  uploadFileList.value = [];
};

const getUploadFileAccept = () => {
  const extensions = fileTypeConfig[currentCategoryType.value]?.extensions || [];
  // 如果是其他文件类型（type=5）或没有扩展名限制，则允许所有文件
  if (currentCategoryType.value === 5 || extensions.length === 0) {
    return '';
  }
  return extensions.map(ext => `.${ext}`).join(',');
};

const getUploadFileTypeText = () => {
  const extensions = fileTypeConfig[currentCategoryType.value]?.extensions || [];
  // 如果是其他文件类型（type=5）或没有扩展名限制，则显示"所有文件"
  if (currentCategoryType.value === 5 || extensions.length === 0) {
    return '所有文件';
  }
  return extensions.join('/');
};

const beforeUpload = (file) => {
  const extensions = fileTypeConfig[currentCategoryType.value]?.extensions || [];
  const fileName = file.name || '';
  const extension = fileName.split('.').pop()?.toLowerCase();
  
  // 如果是其他文件类型（type=5）或没有扩展名限制，则跳过文件类型检查
  if (currentCategoryType.value !== 5 && extensions.length > 0 && !extensions.includes(extension)) {
    ElMessage.error(`只能上传 ${getUploadFileTypeText()} 格式的文件!`);
    return false;
  }

  const isLtSize = file.size / 1024 / 1024 < 50;
  if (!isLtSize) {
    ElMessage.error('上传文件大小不能超过 50MB!');
    return false;
  }
  return true;
};

const onUploadSuccess = (response, file) => {
  if (response.code === 200) {
    ElMessage.success('文件上传成功');
    
    // 获取文件扩展名
    const fileName = file.name || '';
    const extension = fileName.split('.').pop()?.toLowerCase() || '';
    
    // 构建完整的文件信息，确保预览所需的所有字段都存在
    const fileInfo = {
      id: response.data?.id || Date.now(), // 临时ID用于预览
      name: file.name,
      originalName: file.name,
      url: response.data?.url || '',
      path: response.data?.url || '', // 确保path字段存在
      size: file.size,
      type: file.type || getFileMimeType(file),
      extension: extension,
      categoryId: uploadForm.value.categoryId,
      categoryType: uploadForm.value.categoryType,
      description: uploadForm.value.description || '',
      uploadStatus: 1,
      isPublic: 1,
      status: 0,
      downloadCount: 0,
      viewCount: 0,
      createTime: new Date().toISOString(),
      ossId: response.data?.ossId || ''
    };
    
    uploadFileList.value.push(fileInfo);
    
    console.log('文件上传成功，完整信息:', {
      文件名: fileInfo.name,
      URL: fileInfo.url,
      类型: fileInfo.type,
      扩展名: fileInfo.extension,
      是否为图片: isImage(fileInfo)
    });
  } else {
    ElMessage.error('上传失败：' + response.msg);
  }
};

// 获取文件MIME类型
const getFileMimeType = (file) => {
  // 优先使用浏览器检测的MIME类型
  if (file.type) {
    return file.type;
  }
  
  // 如果浏览器无法检测，根据文件扩展名推断
  const fileName = file.name || '';
  const extension = fileName.split('.').pop()?.toLowerCase();
  
  const mimeTypeMap = {
    // 图片类型
    'jpg': 'image/jpeg',
    'jpeg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'bmp': 'image/bmp',
    'webp': 'image/webp',
    'svg': 'image/svg+xml',
    'ico': 'image/x-icon',
    
    // 视频类型
    'mp4': 'video/mp4',
    'avi': 'video/x-msvideo',
    'mov': 'video/quicktime',
    'wmv': 'video/x-ms-wmv',
    'flv': 'video/x-flv',
    'mkv': 'video/x-matroska',
    'webm': 'video/webm',
    
    // 音频类型
    'mp3': 'audio/mpeg',
    'wav': 'audio/wav',
    'flac': 'audio/flac',
    'aac': 'audio/aac',
    'ogg': 'audio/ogg',
    'm4a': 'audio/mp4',
    
    // 文档类型
    'pdf': 'application/pdf',
    'doc': 'application/msword',
    'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'xls': 'application/vnd.ms-excel',
    'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'ppt': 'application/vnd.ms-powerpoint',
    'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'txt': 'text/plain'
  };
  
  return mimeTypeMap[extension] || 'application/octet-stream';
};

const onUploadError = (error) => {
  console.error('上传失败:', error);
  ElMessage.error('上传失败');
};

const submitUpload = async () => {
  if (uploadFileList.value.length === 0) {
    ElMessage.error('请先上传文件');
    return;
  }

  try {
    uploadLoading.value = true;

    const promises = uploadFileList.value.map(file => {
      const fileInfo = {
        name: file.name,
        originalName: file.originalName,
        path: file.url,
        url: file.url,
        size: file.size,
        type: file.type,
        categoryId: uploadForm.value.categoryId,
        categoryType: uploadForm.value.categoryType,
        description: uploadForm.value.description || '',
        uploadStatus: 1,
        isPublic: 1,
        status: 0,
        downloadCount: 0,
        viewCount: 0
      };
      return addFileInfo(fileInfo);
    });

    await Promise.all(promises);

    ElMessage.success('文件上传成功');
    showUploadForm.value = false;
    uploadFileList.value = [];
    uploadForm.value = {
      categoryId: null,
      categoryType: currentCategoryType.value,
      description: ''
    };
    getFileList();
  } catch (error) {
    console.error('保存文件信息失败:', error);
    ElMessage.error('保存文件信息失败');
  } finally {
    uploadLoading.value = false;
  }
};

const handleClose = () => {
  selectedFiles.value = [];
  emit('update:modelValue', false);
};

const handleConfirm = () => {
  emit('confirm', selectedFiles.value);
  emit('update:modelValue', false);
};

// 监听对话框显示状态
watch(dialogVisible, (visible) => {
  if (visible) {
    // 重置状态
    selectedFiles.value = [];
    currentCategoryType.value = props.allowedTypes[0];
    queryParams.value.categoryType = currentCategoryType.value;
    queryParams.value.categoryId = null;
    queryParams.value.pageNum = 1;
    
    // 获取数据
    getCategoryTree();
    getFileList();
  }
});
</script>

<style scoped>
/* FileSelector组件根容器 */

.file-selector-dialog {
  max-height: 90vh;
}

/* 确保在所有缩放级别下正确显示 */
.file-selector .file-selector-dialog :deep(.el-dialog) {
  display: flex;
  flex-direction: column;
  max-height: 90vh;
  height: 80vh;
}

.file-selector .file-selector-dialog :deep(.el-dialog__header) {
  flex-shrink: 0;
}

.file-selector .file-selector-dialog :deep(.el-dialog__body) {
  padding: 0;
  flex: 1;
  overflow: hidden;
  min-height: 0;
}

.file-selector .file-selector-dialog :deep(.el-dialog__footer) {
  border-top: 1px solid #ebeef5;
  padding: 15px 20px;
  flex-shrink: 0;
}

.selector-container {
  display: flex;
  flex-direction: column;
  height: 70vh;
  min-height: 500px;
}

/* 顶部分类导航 */
.top-categories {
  background: white;
  border-bottom: 1px solid #ebeef5;
  padding: 0 20px;
}

.category-tabs {
  display: flex;
  gap: 0;
}

.category-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px 24px;
  cursor: pointer;
  border-bottom: 3px solid transparent;
  transition: all 0.3s ease;
  color: #606266;
  font-size: 14px;
  font-weight: 500;
}

.category-tab:hover {
  color: #409eff;
  background: #f5f7fa;
}

.category-tab.active {
  color: #409eff;
  border-bottom-color: #409eff;
  background: #f0f9ff;
}

/* 主容器 */
.main-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 20px;
  overflow: hidden;
  min-height: 450px;
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 16px 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  flex-shrink: 0;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.view-toggle {
  display: flex;
  gap: 0;
}

.selected-info {
  color: #409eff;
  font-size: 14px;
  font-weight: 500;
}

.content-wrapper {
  display: flex;
  gap: 20px;
  flex: 1;
  overflow: hidden;
  min-height: 350px;
}

.sidebar {
  width: 280px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.sidebar-header {
  padding: 16px 20px;
  border-bottom: 1px solid #ebeef5;
  background: #fafafa;
}

.sidebar-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.category-list {
  padding: 10px;
  overflow-y: auto;
  flex: 1;
}

.category-item {
  display: flex;
  align-items: center;
  padding: 10px 15px;
  border-radius: 6px;
  cursor: pointer;
  margin-bottom: 8px;
  background: #f5f7fa;
  transition: background-color 0.3s;
}

.category-item:hover {
  background: #ebeef5;
}

.category-item.active {
  background: #409eff;
  color: white;
}

.category-item .category-icon {
  margin-right: 10px;
  font-size: 18px;
}

.category-tree {
  margin-top: 10px;
  background: transparent;
}

.category-tree :deep(.el-tree-node__content) {
  height: 40px;
  border-radius: 6px;
  margin-bottom: 4px;
  background: #f5f7fa;
  transition: background-color 0.3s;
}

.category-tree :deep(.el-tree-node__content:hover) {
  background: #ebeef5;
}

.category-tree :deep(.el-tree-node.is-current > .el-tree-node__content) {
  background: #409eff;
  color: white;
}

.tree-node-content {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0 5px;
}

.tree-node-content .category-icon {
  margin-right: 8px;
  font-size: 16px;
}

.tree-node-content .node-label {
  flex: 1;
  font-size: 14px;
}

.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 400px;
}

.file-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 20px;
  padding: 20px;
  flex: 1;
  overflow-y: auto;
  min-height: 300px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  align-content: start;
}

/* 响应式网格布局 */
@media (max-width: 768px) {
  .file-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 16px;
    padding: 16px;
  }
  
  .file-item {
    min-height: 200px;
    margin-bottom: 8px;
  }
  
  .file-wrapper {
    min-height: 120px;
  }
  
  .file-info {
    min-height: 55px;
  }
}

@media (min-width: 1200px) {
  .file-grid {
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 24px;
    padding: 24px;
  }
  
  .file-item {
    min-height: 260px;
    margin-bottom: 12px;
  }
  
  .file-wrapper {
    min-height: 160px;
  }
  
  .file-info {
    min-height: 70px;
  }
}

@media (min-width: 1600px) {
  .file-grid {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 28px;
    padding: 28px;
  }
  
  .file-item {
    min-height: 280px;
    margin-bottom: 15px;
  }
  
  .file-info {
    min-height: 75px;
  }
}

/* 高DPI缩放兼容性 */
@media (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
  .file-grid {
    contain: layout style;
  }
  
  .file-item {
    contain: layout style;
  }
  
  .file-wrapper {
    contain: layout;
  }
}

.file-item {
  position: relative;
  cursor: pointer;
  border: 1px solid #ebeef5;
  border-radius: 8px;
  overflow: visible;
  transition: all 0.3s;
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  aspect-ratio: 1 / 1.3;
  min-height: 270px;
  margin-bottom: 10px;
}

.file-item:hover {
  transform: translateY(-5px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  z-index: 10;
}

.file-item.selected {
  border: 2px solid #409eff;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}

.file-wrapper {
  position: relative;
  width: 100%;
  flex: 1;
  overflow: hidden;
  min-height: 140px;
  border-radius: 8px 8px 0 0;
}

.file-thumbnail {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.file-icon-wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f5f7fa;
}

.file-icon {
  font-size: 40px;
}

.file-checkbox {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
}

.file-info {
  padding: 10px;
  background: #f5f7fa;
  border-top: 1px solid #ebeef5;
  border-radius: 0 0 8px 8px;
  flex-shrink: 0;
  min-height: 60px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  z-index: 1;
}

.file-name {
  font-size: 13px;
  color: #303133;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 3px;
  line-height: 1.2;
}

.file-size {
  font-size: 11px;
  color: #909399;
  line-height: 1;
}

.file-error {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background: #f5f7fa;
  color: #c0c4cc;
}

.file-loading {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background: #f0f9ff;
  color: #409eff;
}

.file-list {
  padding: 15px;
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-top: 10px;
  flex-shrink: 0;
}

/* 图片预览样式 */
.image-error {
  width: 50px;
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f5f7fa;
  border-radius: 4px;
  border: 1px solid #ebeef5;
}

.image-loading {
  width: 50px;
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f0f9ff;
  border-radius: 4px;
  border: 1px solid #b3d8ff;
}

/* 视频缩略图样式 */
.video-thumbnail-wrapper {
  position: relative;
  display: inline-block;
  overflow: hidden;
  border-radius: 4px;
}

.video-thumbnail-wrapper.full {
  width: 100%;
  height: 100%;
}

.video-thumbnail {
  display: block;
  object-fit: cover;
  background: #000;
  pointer-events: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.video-thumbnail::-webkit-media-controls {
  display: none !important;
}

.video-thumbnail::-webkit-media-controls-panel {
  display: none !important;
}

.video-thumbnail::-webkit-media-controls-play-button {
  display: none !important;
}

.video-thumbnail::-webkit-media-controls-start-playback-button {
  display: none !important;
}

.video-play-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;
  transition: all 0.3s ease;
}

.video-thumbnail-wrapper:hover .video-play-overlay {
  background: rgba(0, 0, 0, 0.8);
  transform: translate(-50%, -50%) scale(1.1);
}

/* 列表视图中的视频缩略图样式 */
.video-thumbnail-wrapper:not(.full) {
  width: 50px;
  height: 50px;
}

.video-thumbnail-wrapper:not(.full) .video-play-overlay {
  width: 30px;
  height: 30px;
}

.dialog-footer {
  text-align: right;
}

/* 空状态样式 */
.empty-state {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 200px;
  color: #909399;
  font-size: 14px;
}

/* 防止样式冲突 - 只针对FileSelector对话框内的元素 */
.file-selector-dialog :deep(.el-input) {
  /* 重置可能被父页面影响的样式 */
  border-color: #dcdfe6 !important;
}

.file-selector-dialog :deep(.el-input:hover) {
  border-color: #c0c4cc !important;
}

.file-selector-dialog :deep(.el-input:focus) {
  border-color: #409eff !important;
}

.file-selector-dialog :deep(.el-input.is-focus) {
  border-color: #409eff !important;
}

/* 确保分页组件样式正常 */
.file-selector-dialog :deep(.el-pagination) {
  border: none !important;
}

.file-selector-dialog :deep(.el-pagination .el-input) {
  border-color: #dcdfe6 !important;
}

.file-selector-dialog :deep(.el-pagination .el-input:hover) {
  border-color: #c0c4cc !important;
}

.file-selector-dialog :deep(.el-pagination .el-input:focus) {
  border-color: #409eff !important;
}

/* 确保选择器组件样式正常 */
.file-selector-dialog :deep(.el-select .el-input) {
  border-color: #dcdfe6 !important;
}

.file-selector-dialog :deep(.el-select .el-input:hover) {
  border-color: #c0c4cc !important;
}

.file-selector-dialog :deep(.el-select .el-input.is-focus) {
  border-color: #409eff !important;
}

/* 确保日期选择器样式正常 */
.file-selector-dialog :deep(.el-date-editor) {
  border-color: #dcdfe6 !important;
}

.file-selector-dialog :deep(.el-date-editor:hover) {
  border-color: #c0c4cc !important;
}

.file-selector-dialog :deep(.el-date-editor.is-active) {
  border-color: #409eff !important;
}

/* FileSelector对话框层级控制 - 简化版本 */
.file-selector-dialog {
  z-index: 3000 !important;
}

/* 上传表单对话框需要在FileSelector之上 */
.file-selector :deep(.el-dialog__wrapper:last-of-type) {
  z-index: 3100 !important;
}
</style>
