<template>
  <div class="file-manager">
    <!-- 顶部分类导航 -->
    <div class="top-categories">
      <div class="category-tabs">
        <!-- 全部文件标签 -->
        <div
          class="category-tab"
          :class="{ active: !currentTopCategory }"
          @click="switchTopCategory(null)"
        >
          <el-icon>
            <Folder />
          </el-icon>
          <span>全部文件</span>
        </div>
        <!-- 具体分类标签 -->
        <div
          v-for="topCategory in topCategories"
          :key="topCategory.id"
          class="category-tab"
          :class="{ active: currentTopCategory?.id === topCategory.id }"
          @click="switchTopCategory(topCategory)"
        >
          <el-icon v-if="topCategory.icon">
            <component :is="topCategory.icon" />
          </el-icon>
          <el-icon v-else>
            <Folder />
          </el-icon>
          <span>{{ topCategory.name }}</span>
        </div>
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div class="main-container">
      <!-- 工具栏 -->
      <div class="toolbar">
        <div class="toolbar-left">
          <el-button type="primary" @click="openUploadDialog">
            <el-icon><Plus /></el-icon>
            {{ getUploadButtonText() }}
          </el-button>
          <el-button @click="handleBatchDelete" :disabled="selectedFiles.length === 0">
            删除{{ getFileTypeText() }}
          </el-button>
          <el-dropdown @command="handleMoveToCategory" :disabled="selectedFiles.length === 0">
            <el-button>
              {{ getFileTypeText() }}移至<el-icon class="el-icon--right"><ArrowDown /></el-icon>
            </el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item
                  v-for="category in categoryList"
                  :key="category.id"
                  :command="category.id"
                >
                  {{ category.name }}
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </div>
        <div class="toolbar-right">
          <el-input
            v-model="searchKeyword"
            :placeholder="`请输入${getFileTypeText()}名`"
            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>添加分类</h3>
            <el-button link icon="Plus" @click="handleAddCategory">+</el-button>
          </div>
          <div class="category-list">
            <!-- 全部文件 -->
            <div
              class="category-item all-files"
              :class="{ active: currentCategory?.id === null }"
              @click="handleShowAllFiles"
            >
              <el-icon class="category-icon"><Folder /></el-icon>
              <span>全部{{ getFileTypeText() }}</span>
            </div>

            <!-- 树形控件 -->
            <el-tree
              ref="categoryTreeRef"
              :data="filteredCategoryTree"
              :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>
                  <el-dropdown
                    @command="handleCategoryAction"
                    trigger="click"
                    @click.stop
                    class="node-actions"
                  >
                    <el-icon class="more-icon"><MoreFilled /></el-icon>
                    <template #dropdown>
                      <el-dropdown-menu>
                        <el-dropdown-item :command="{ action: 'addChild', data: data }">添加子分类</el-dropdown-item>
                        <el-dropdown-item :command="{ action: 'edit', data: data }">编辑</el-dropdown-item>
                        <el-dropdown-item :command="{ action: 'delete', data: data }">删除</el-dropdown-item>
                      </el-dropdown-menu>
                    </template>
                  </el-dropdown>
                </div>
              </template>
            </el-tree>
          </div>
        </div>

        <!-- 右侧文件展示区 -->
        <div class="content-area">
          <!-- 网格视图 -->
          <div v-if="viewMode === 'grid'" class="file-grid">
            <div
              v-for="file in fileList"
              :key="file.id"
              class="file-item"
              :class="{ selected: selectedFiles.includes(file.id) }"
              @click="toggleFileSelection(file.id)"
            >
              <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"
                  ></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="selectedFiles.includes(file.id)"
                    @change="(val) => toggleFileSelection(file.id, val)"
                    @click.stop
                  />
                </div>
              </div>
              <div class="file-info">
                <div class="file-name">{{ file.name || file.originalName }}</div>
                <div class="file-actions">
                  <el-button link size="small" @click="handlePreview(file)">预览</el-button>
                  <el-button link size="small" @click="handleRename(file)">重命名</el-button>
                  <el-button
                    link
                    size="small"
                    class="delete-btn"
                    @click="handleDelete(file)"
                  >
                    删除
                  </el-button>
                </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="list-image-error">
                        <el-icon size="20" color="#c0c4cc">
                          <Picture />
                        </el-icon>
                      </div>
                    </template>
                    <template #placeholder>
                      <div class="list-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"
                      class="video-thumbnail"
                    ></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="类型" prop="type" width="120" />
              <el-table-column label="上传时间" width="180">
                <template #default="{ row }">
                  {{ formatTime(row.createTime) }}
                </template>
              </el-table-column>
              <el-table-column label="操作" width="200" fixed="right">
                <template #default="{ row }">
                  <el-button link @click="handlePreview(row)">预览</el-button>
                  <el-button link @click="handleRename(row)">重命名</el-button>
                  <el-button
                    link
                    class="delete-btn"
                    @click="handleDelete(row)"
                  >
                    删除
                  </el-button>
                </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="getList"
              @current-change="getList"
            />
          </div>
        </div>
      </div>
    </div>

    <!-- 上传对话框 -->
    <el-dialog v-model="showUploadDialog" :title="`上传${getFileTypeText()}`" width="600px">
      <el-form ref="uploadFormRef" :model="uploadForm" label-width="100px">
        <!-- 文件分类选择 -->
        <el-form-item label="文件分类" prop="categoryId">
          <el-tree-select
            v-model="uploadForm.categoryId"
            :data="uploadCategoryTree"
            :props="{ value: 'id', label: 'name', children: 'children' }"
            placeholder="请选择文件分类（可选）"
            style="width: 100%"
            clearable
            check-strictly
            @change="onCategoryChange"
          />
          <div class="form-tip" v-if="selectedCategoryType">
            当前分类只能上传：{{ getFileTypeByCategory(selectedCategoryType) }}
          </div>
        </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
            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">
                <span v-if="uploadForm.categoryId">
                  支持 {{ getUploadFileTypeText() }} 格式，单个文件不超过 50MB
                </span>
                <span v-else>
                  支持多文件上传，单个文件不超过 50MB
                </span>
              </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="showUploadDialog = false">取消</el-button>
        <el-button type="primary" @click="submitUpload" :loading="uploadLoading">确定</el-button>
      </template>
    </el-dialog>

    <!-- 分类管理对话框 -->
    <el-dialog v-model="categoryDialogVisible" :title="categoryDialogTitle" width="500px">
      <el-form ref="categoryFormRef" :model="categoryForm" :rules="categoryRules" label-width="100px">
        <!-- 分类名称 -->
        <el-form-item label="分类名称" prop="name" required>
          <el-input v-model="categoryForm.name" placeholder="请输入分类名称" />
        </el-form-item>

        <!-- 分类编码 -->
        <el-form-item label="分类编码" prop="code" required>
          <el-input v-model="categoryForm.code" placeholder="请输入分类编码（英文大写）" />
        </el-form-item>

        <!-- 父级分类 -->
        <el-form-item label="父级分类" prop="parentId">
          <el-tree-select
            v-model="categoryForm.parentId"
            :data="categoryTree"
            :props="{ value: 'id', label: 'name', children: 'children' }"
            placeholder="请选择父级分类（可选，不选则为顶级分类）"
            clearable
            check-strictly
            :disabled="(categoryForm.id && isEditing) || isAddingChildCategory"
          />
          <div class="form-tip">
            <span v-if="categoryForm.id && isEditing">编辑模式下不能修改父级分类</span>
            <span v-else-if="isAddingChildCategory">正在为选定的分类添加子分类</span>
            <span v-else>选择父级分类可以创建子分类，不选则创建顶级分类</span>
          </div>
        </el-form-item>

        <!-- 分类类型 -->
        <el-form-item label="分类类型" prop="type" required>
          <el-select v-model="categoryForm.type" placeholder="请选择分类类型" style="width: 100%">
            <el-option label="图片文件" :value="1" />
            <el-option label="视频文件" :value="2" />
            <el-option label="音频文件" :value="3" />
            <el-option label="文档文件" :value="4" />
            <el-option label="其他文件" :value="5" />
          </el-select>
        </el-form-item>

        <!-- 排序 -->
        <el-form-item label="排序" prop="sort">
          <el-input-number v-model="categoryForm.sort" :min="0" :max="999" placeholder="排序值" />
        </el-form-item>

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

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="categoryDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitCategory" :loading="categoryLoading">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 重命名对话框 -->
    <el-dialog v-model="renameDialogVisible" title="重命名文件" width="400px">
      <el-form ref="renameFormRef" :model="renameForm" label-width="80px">
        <el-form-item label="原文件名">
          <el-input v-model="renameForm.originalName" readonly />
        </el-form-item>
        <el-form-item
          label="新文件名"
          prop="name"
          :rules="[
            { required: true, message: '请输入新文件名', trigger: 'blur' },
            { min: 1, max: 100, message: '文件名长度在 1 到 100 个字符', trigger: 'blur' }
          ]"
        >
          <el-input
            v-model="renameForm.name"
            placeholder="请输入新文件名"
            @keyup.enter="submitRename"
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="renameDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitRename">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 图片裁剪组件 -->
    <ImageCropper
      v-model="cropDialogVisible"
      :file="currentCropFile"
      :image-url="cropImageUrl"
      @confirm="handleCropConfirm"
      @cancel="handleCropCancel"
    />
  </div>
</template>

<script setup name="FileInfo" lang="ts">
import { ref, onMounted, getCurrentInstance, watch, h, computed, nextTick } from 'vue';
import { listFileInfo, delFileInfo, addFileInfo, updateDownloadCount, updateFileInfo } from '@/api/file/info';
import { listFileCategoryTree, addFileCategory, updateFileCategory, delFileCategory } from '@/api/file/category';
import {
  Plus, Search, UploadFilled, Document, VideoPlay,
  Microphone, Picture, FolderOpened, Edit, MoreFilled, Back,
  ArrowDown, Grid, List, Folder, Loading
} from '@element-plus/icons-vue';
import ImageCropper from '@/components/ImageCropper/index.vue';
import { globalHeaders } from '@/utils/request';
import { getToken } from '@/utils/auth';
import { ElMessage, ElMessageBox } from 'element-plus';
import type { FormRules } from 'element-plus';

const { proxy } = getCurrentInstance();

// 响应式数据
const loading = ref(false);
const fileList = ref([]);
const total = ref(0);
const searchKeyword = ref('');
const selectedFiles = ref([]);
const showUploadDialog = ref(false);
const uploadFileList = ref([]);
const uploadLoading = ref(false);
const currentTopCategory = ref(null);
const viewMode = ref('grid');

// 分类相关数据
const categoryTree = ref([]);
const categoryList = ref([]);
const topCategories = ref([]);
const currentCategory = ref(null);
const expandedKeys = ref([]);
const categoryTreeRef = ref();

// 分类管理对话框
const categoryDialogVisible = ref(false);
const categoryDialogTitle = ref('添加分类');
const categoryLoading = ref(false);
const categoryFormRef = ref();
const isEditing = ref(false);
const isAddingChildCategory = ref(false);

// 上传表单
const uploadFormRef = ref();
const selectedCategoryType = ref(null);

// 重命名相关数据
const renameDialogVisible = ref(false);
const renameForm = ref({
  id: null,
  name: '',
  originalName: '',
  currentFile: null
});
const renameFormRef = ref();

// 图片裁剪相关数据
const cropDialogVisible = ref(false);
const currentCropFile = ref(null);
const cropImageUrl = ref('');

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

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

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

// 分类表单数据
const categoryForm = ref({
  id: null,
  name: '',
  code: '',
  parentId: null,
  type: 1,
  sort: 0,
  description: '',
  status: 0
});

// 分类表单验证规则
const categoryRules = ref<FormRules>({
  name: [
    { required: true, message: '请输入分类名称', trigger: 'blur' },
    { min: 2, max: 50, message: '分类名称长度在 2 到 50 个字符', trigger: 'blur' }
  ],
  code: [
    { required: true, message: '请输入分类编码', trigger: 'blur' },
    { pattern: /^[A-Z_]+$/, message: '分类编码只能包含大写字母和下划线', trigger: 'blur' }
  ],
  type: [
    { required: true, message: '请选择分类类型', trigger: 'change' }
  ]
});

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

// 获取文件列表
const getList = async () => {
  try {
    loading.value = true;
    const response = await listFileInfo(queryParams.value) as any;
    const data = response?.data ?? response;
    if (data && data.rows) {
      fileList.value = data.rows as any[];
      total.value = data.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 handleSearch = () => {
  queryParams.value.name = searchKeyword.value || null;
  queryParams.value.pageNum = 1;
  getList();
};

// 多选处理
const handleSelectionChange = (selection) => {
  selectedFiles.value = selection.map(item => item.id);
};

// 获取分类树
const getCategoryTree = async () => {
  try {
    const response = await listFileCategoryTree();
    categoryTree.value = response.data || [];
    categoryList.value = flattenCategories(categoryTree.value);

    console.log('getCategoryTree - response.data:', response.data);
    console.log('getCategoryTree - categoryTree.value:', categoryTree.value);

    // 获取顶级分类（parent_id为0的分类）
    topCategories.value = categoryTree.value.filter(category => category.parentId === 0 || category.parentId === null);
    console.log('getCategoryTree - topCategories.value:', topCategories.value);

    // 默认不选择任何顶级分类，显示所有文件
    if (!currentTopCategory.value) {
      currentTopCategory.value = null;
      queryParams.value.categoryType = null;
      console.log('getCategoryTree - set currentTopCategory to null (show all files)');
    }

    return response;
  } catch (error) {
    console.error('获取分类树失败:', error);
    ElMessage.error('获取分类树失败');
    throw error;
  }
};

// 扁平化分类列表
const flattenCategories = (categories, result = []) => {
  categories.forEach(category => {
    result.push(category);
    if (category.children && category.children.length > 0) {
      flattenCategories(category.children, result);
    }
  });
  return result;
};

// 分类点击事件
const handleCategoryClick = (data) => {
  currentCategory.value = data;
  queryParams.value.categoryId = data.id;
  queryParams.value.pageNum = 1;
  getList();
};

// 树节点点击事件
const handleTreeNodeClick = (data, node, treeComponent) => {
  handleCategoryClick(data);
};

// 显示全部文件
const handleShowAllFiles = () => {
  currentCategory.value = null;
  queryParams.value.categoryId = null;
  queryParams.value.pageNum = 1;
  getList();
};

// 切换分类展开状态
const toggleExpand = (categoryId) => {
  const index = expandedKeys.value.indexOf(categoryId);
  if (index > -1) {
    // 如果已展开，则收起
    expandedKeys.value.splice(index, 1);
  } else {
    // 如果未展开，则展开
    expandedKeys.value.push(categoryId);
  }
  console.log('toggleExpand - categoryId:', categoryId, 'expandedKeys:', expandedKeys.value);
};

// 文件类型判断
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;
};

// 获取图片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 handlePreview = (file) => {
  if (file.type?.includes('image')) {
    // 使用弹窗预览图片
    handlePreviewImage(file);
  } else if (file.type?.includes('video')) {
    handlePlayVideo(file);
  } else if (file.type?.includes('audio')) {
    handlePlayAudio(file);
  } else if (file.type?.includes('pdf')) {
    handlePreviewPdf(file);
  } else if (file.type?.includes('text')) {
    handlePreviewText(file);
  } else {
    // 其他文件类型使用弹窗预览
    handlePreviewOther(file);
  }
};

// 下载文件
const handleDownload = async (file) => {
  console.log('下载文件:', file);

  if (!file.url && !file.path) {
    ElMessage.error('文件URL不存在');
    return;
  }

  // 获取文件URL
  let fileUrl = file.url || file.path;
  let fileName = file.name || file.originalName || 'download';

  // 确保URL是完整的
  if (fileUrl && !fileUrl.startsWith('http')) {
    // 如果是相对路径，添加基础URL
    fileUrl = import.meta.env.VITE_APP_BASE_API + fileUrl;
  }

  // 确保文件名有正确的扩展名
  const extension = file.extension || fileName.split('.').pop()?.toLowerCase();
  if (extension && !fileName.toLowerCase().endsWith('.' + extension)) {
    fileName = fileName + '.' + extension;
  }

  console.log('文件URL:', fileUrl);
  console.log('文件名:', fileName);
  console.log('文件类型:', file.type);
  console.log('文件扩展名:', extension);

  try {
    // 如果URL是OSS ID（纯数字），需要先获取文件信息
    if (/^\d+$/.test(fileUrl)) {
      console.log('检测到OSS ID，获取文件信息');
      try {
        const { listByIds } = await import('@/api/system/oss');
        const res = await listByIds(fileUrl);
        if (res.data && res.data.length > 0) {
          fileUrl = res.data[0].url;
          fileName = res.data[0].originalName || fileName;
          console.log('获取到OSS文件信息:', fileUrl, fileName);
        } else {
          ElMessage.error('未找到对应的文件信息');
          return;
        }
      } catch (error) {
        console.error('获取OSS文件信息失败:', error);
        ElMessage.error('获取文件信息失败');
        return;
      }
    }

    // 使用fetch下载文件
    const response = await fetch(fileUrl, {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer ' + getToken()
      }
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const blob = await response.blob();

    // 根据文件类型设置正确的MIME类型
    let mimeType = file.type || 'application/octet-stream';

    // 如果文件类型不正确，根据扩展名推断
    if (!mimeType || mimeType === 'application/octet-stream') {
      switch (extension) {
        case 'jpg':
        case 'jpeg':
          mimeType = 'image/jpeg';
          break;
        case 'png':
          mimeType = 'image/png';
          break;
        case 'gif':
          mimeType = 'image/gif';
          break;
        case 'bmp':
          mimeType = 'image/bmp';
          break;
        case 'webp':
          mimeType = 'image/webp';
          break;
        case 'mp4':
          mimeType = 'video/mp4';
          break;
        case 'avi':
          mimeType = 'video/x-msvideo';
          break;
        case 'mov':
          mimeType = 'video/quicktime';
          break;
        case 'wmv':
          mimeType = 'video/x-ms-wmv';
          break;
        case 'flv':
          mimeType = 'video/x-flv';
          break;
        case 'mkv':
          mimeType = 'video/x-matroska';
          break;
        case 'mp3':
          mimeType = 'audio/mpeg';
          break;
        case 'wav':
          mimeType = 'audio/wav';
          break;
        case 'flac':
          mimeType = 'audio/flac';
          break;
        case 'aac':
          mimeType = 'audio/aac';
          break;
        case 'ogg':
          mimeType = 'audio/ogg';
          break;
        case 'pdf':
          mimeType = 'application/pdf';
          break;
        case 'doc':
          mimeType = 'application/msword';
          break;
        case 'docx':
          mimeType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
          break;
        case 'xls':
          mimeType = 'application/vnd.ms-excel';
          break;
        case 'xlsx':
          mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
          break;
        case 'ppt':
          mimeType = 'application/vnd.ms-powerpoint';
          break;
        case 'pptx':
          mimeType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
          break;
        case 'txt':
          mimeType = 'text/plain';
          break;
        case 'zip':
          mimeType = 'application/zip';
          break;
        case 'rar':
          mimeType = 'application/vnd.rar';
          break;
        case '7z':
          mimeType = 'application/x-7z-compressed';
          break;
        default:
          mimeType = 'application/octet-stream';
      }
    }

    console.log('使用的MIME类型:', mimeType);
    console.log('最终文件名:', fileName);

    // 创建带有正确MIME类型的blob
    const correctBlob = new Blob([blob], { type: mimeType });

    // 创建下载链接
    const url = window.URL.createObjectURL(correctBlob);
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    link.style.display = 'none';

    // 添加到DOM并触发下载
    document.body.appendChild(link);
    link.click();

    // 清理
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);

    ElMessage.success('文件下载已开始');

    // 更新下载次数
    updateDownloadCount(file.id).then(() => {
      console.log('下载次数已更新');
    }).catch((error) => {
      console.error('更新下载次数失败:', error);
    });

  } catch (error) {
    console.error('下载文件失败:', error);
    const msg = error instanceof Error ? error.message : String(error);
    ElMessage.error('下载文件失败: ' + msg);
  }
};

// 重命名文件
const handleRename = (file) => {
  console.log('重命名文件:', file);
  renameForm.value = {
    id: file.id,
    name: file.name || file.originalName || '',
    originalName: file.name || file.originalName || '',
    currentFile: file // 保存完整的文件信息
  };
  renameDialogVisible.value = true;
};

// 提交重命名
const submitRename = async () => {
  try {
    await renameFormRef.value?.validate();

    if (!renameForm.value.name.trim()) {
      ElMessage.error('请输入新文件名');
      return;
    }

    if (renameForm.value.name === renameForm.value.originalName) {
      ElMessage.warning('新文件名与原文件名相同');
      return;
    }

    // 调用重命名API
    const file = renameForm.value.currentFile;
    await updateFileInfo({
      id: renameForm.value.id,
      name: renameForm.value.name.trim(),
      originalName: file.originalName,
      path: file.path,
      url: file.url,
      size: file.size,
      type: file.type,
      extension: file.extension,
      categoryId: file.categoryId,
      description: file.description
    });

    ElMessage.success('重命名成功');
    renameDialogVisible.value = false;

    // 刷新文件列表
    getList();

    console.log('重命名文件:', {
      id: renameForm.value.id,
      oldName: renameForm.value.originalName,
      newName: renameForm.value.name.trim()
    });

  } catch (error) {
    console.error('重命名失败:', error);
    ElMessage.error('重命名失败');
  }
};

// 删除文件
const handleDelete = async (file) => {
  try {
    await ElMessageBox.confirm(`确定要删除文件"${file.name || file.originalName}"吗？`, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });

    await delFileInfo(file.id);
    ElMessage.success('删除成功');
    getList();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除失败:', error);
      ElMessage.error('删除失败');
    }
  }
};

// 批量删除
const handleBatchDelete = async () => {
  if (selectedFiles.value.length === 0) {
    ElMessage.warning('请选择要删除的文件');
    return;
  }

  try {
    await ElMessageBox.confirm(`确定要删除选中的 ${selectedFiles.value.length} 个文件吗？`, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });

    const promises = selectedFiles.value.map(id => delFileInfo(id));
    await Promise.all(promises);
    ElMessage.success('批量删除成功');
    selectedFiles.value = [];
    getList();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('批量删除失败:', error);
      ElMessage.error('批量删除失败');
    }
  }
};

// 移动到分类
const handleMoveToCategory = async (categoryId) => {
  if (selectedFiles.value.length === 0) {
    ElMessage.warning('请选择要移动的文件');
    return;
  }

  try {
    await ElMessageBox.confirm(`确定要将选中的 ${selectedFiles.value.length} 个文件移动到分类"${categoryList.value.find(cat => cat.id === categoryId)?.name}"吗？`, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });

    const promises = selectedFiles.value.map(id => updateFileInfoCategory(id, categoryId));
    await Promise.all(promises);
    ElMessage.success('批量移动成功');
    selectedFiles.value = [];
    getList();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('批量移动失败:', error);
      ElMessage.error('批量移动失败');
    }
  }
};

// 更新文件分类
const updateFileInfoCategory = async (fileId, categoryId) => {
  const fileInfo = {
    id: fileId,
    categoryId: categoryId
  };
  // 这里需要调用更新文件信息的API，暂时注释掉
  // await updateFileInfo(fileInfo);
  console.log('更新文件分类:', fileId, categoryId);
};

// 添加分类
const handleAddCategory = () => {
  categoryDialogVisible.value = true;
  categoryDialogTitle.value = '添加分类';
  categoryForm.value = {
    id: null,
    name: '',
    code: '',
    parentId: null,
    type: 1,
    sort: 0,
    description: '',
    status: 0
  };
  isEditing.value = false;
  isAddingChildCategory.value = false;
};

// 添加子分类
const handleAddChildCategory = (parentCategory) => {
  console.log('添加子分类，父分类:', parentCategory);
  categoryDialogVisible.value = true;
  categoryDialogTitle.value = `添加子分类 - ${parentCategory.name}`;
  categoryForm.value = {
    id: null,
    name: '',
    code: '',
    parentId: parentCategory.id, // 设置父分类ID
    type: parentCategory.type,   // 继承父分类的类型
    sort: 0,
    description: '',
    status: 0
  };
  isEditing.value = false;
  isAddingChildCategory.value = true;
};

// 打开上传对话框
const openUploadDialog = () => {
  showUploadDialog.value = true;
  // 自动填充当前主分类的类型和名称
  const defaultCategoryType = currentTopCategory.value ? currentTopCategory.value.type : null;
  const defaultCategoryName = currentTopCategory.value ? currentTopCategory.value.name : null;

  uploadForm.value = {
    categoryId: null,
    categoryType: defaultCategoryType,
    categoryName: defaultCategoryName,
    description: ''
  };
  uploadFileList.value = [];
  selectedCategoryType.value = defaultCategoryType;
};

// 编辑分类
const handleEditCategory = (data) => {
  categoryDialogVisible.value = true;
  categoryDialogTitle.value = '编辑分类';
  categoryForm.value = { ...data };
  isEditing.value = true;
  isAddingChildCategory.value = false;
};

// 删除分类
const handleDeleteCategory = async (data) => {
  try {
    await ElMessageBox.confirm(`确定要删除分类"${data.name}"吗？`, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });

    await delFileCategory(data.id);
    ElMessage.success('删除成功');
    getCategoryTree();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除分类失败:', error);
      ElMessage.error('删除分类失败');
    }
  }
};

// 分类操作处理
const handleCategoryAction = (command) => {
  if (command.action === 'addChild') {
    handleAddChildCategory(command.data);
  } else if (command.action === 'edit') {
    handleEditCategory(command.data);
  } else if (command.action === 'delete') {
    // 检查是否有子分类
    if (command.data.children && command.data.children.length > 0) {
      ElMessage.warning('该分类下有子分类，请先删除子分类');
      return;
    }
    handleDeleteCategory(command.data);
  }
};

// 提交分类
const submitCategory = async () => {
  try {
    await categoryFormRef.value?.validate();
    categoryLoading.value = true;

    const categoryData = {
      ...categoryForm.value,
      tenantId: '000000'
    };

    if (categoryForm.value.id) {
      await updateFileCategory(categoryData);
    } else {
      await addFileCategory(categoryData);
    }

    ElMessage.success(categoryForm.value.id ? '更新成功' : '添加成功');
    categoryDialogVisible.value = false;
    getCategoryTree();
  } catch (error) {
    console.error('保存分类失败:', error);
    ElMessage.error('保存分类失败');
  } finally {
    categoryLoading.value = false;
  }
};

// 上传前检查
const beforeUpload = (file) => {
  console.log('开始上传文件:', file.name, '原始MIME类型:', file.type);

  // 获取准确的MIME类型
  const actualMimeType = getFileMimeType(file);
  const fileName = file.name || '';
  const extension = fileName.split('.').pop()?.toLowerCase();

  console.log('检测到的MIME类型:', actualMimeType, '文件扩展名:', extension);

  // 如果是图片文件，且当前分类是图片分类，则打开裁剪对话框
  const currentCategoryType = uploadForm.value.categoryType || getCategoryType(uploadForm.value.categoryId);
  const isImageFile = actualMimeType.startsWith('image/') || ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension);
  
  if (isImageFile && (currentCategoryType === 1 || !currentCategoryType)) {
    // 延迟打开裁剪对话框，让上传组件先完成初始化
    setTimeout(() => {
      openCropDialog(file);
    }, 100);
    
    // 返回false阻止自动上传，等待裁剪完成后手动上传
    return false;
  }

  // 如果选择了分类或有分类类型，检查文件类型
  const selectedCategoryType = uploadForm.value.categoryType || getCategoryType(uploadForm.value.categoryId);

  if (selectedCategoryType) {
    let isValidType = false;
    let fileTypeText = '';

    if (selectedCategoryType === 1) { // 图片分类
      isValidType = actualMimeType.startsWith('image/') ||
        ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(extension);
      fileTypeText = '图片';
    } else if (selectedCategoryType === 2) { // 视频分类
      isValidType = actualMimeType.startsWith('video/') ||
        ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'].includes(extension);
      fileTypeText = '视频';
    } else if (selectedCategoryType === 3) { // 音频分类
      isValidType = actualMimeType.startsWith('audio/') ||
        ['mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a'].includes(extension);
      fileTypeText = '音频';
    } else if (selectedCategoryType === 4) { // 文档分类
      isValidType = actualMimeType.includes('pdf') ||
        actualMimeType.includes('document') ||
        actualMimeType.includes('word') ||
        actualMimeType.includes('excel') ||
        actualMimeType.includes('powerpoint') ||
        actualMimeType.includes('text') ||
        actualMimeType === 'application/msword' ||
        actualMimeType === 'application/vnd.ms-excel' ||
        actualMimeType === 'application/vnd.ms-powerpoint' ||
        ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'].includes(extension);
      fileTypeText = '文档';
    } else {
      isValidType = true;
      fileTypeText = '文件';
    }

    if (!isValidType) {
      ElMessage.error(`当前分类只能上传${fileTypeText}文件! 检测到的文件类型: ${actualMimeType}`);
      return false;
    }

    console.log('文件类型验证通过:', fileTypeText, '类型');
  }

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

  console.log('文件大小验证通过:', (file.size / 1024 / 1024).toFixed(2), 'MB');
  
  // 非图片文件或非图片分类，直接上传
  return true;
};

// 获取文件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',

    // 视频类型
    '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',

    // 压缩文件
    'zip': 'application/zip',
    'rar': 'application/vnd.rar',
    '7z': 'application/x-7z-compressed',
    'tar': 'application/x-tar',
    'gz': 'application/gzip',

    // 其他常见类型
    'json': 'application/json',
    'xml': 'application/xml',
    'csv': 'text/csv',
    'html': 'text/html',
    'css': 'text/css',
    'js': 'application/javascript'
  };

  return mimeTypeMap[extension] || 'application/octet-stream';
};

// 上传成功
const onUploadSuccess = (response, file) => {
  if (response.code === 200) {
    ElMessage.success('文件上传成功');

    // 获取文件MIME类型和扩展名
    const mimeType = getFileMimeType(file);
    const fileName = file.name || '';
    const extension = fileName.split('.').pop()?.toLowerCase() || '';

    uploadFileList.value.push({
      name: file.name,
      url: response.data?.url || '',
      size: file.size,
      type: mimeType,
      extension: extension,
      originalName: file.name,
      ossId: response.data?.ossId || ''
    });

    console.log('文件上传成功，MIME类型:', mimeType, '扩展名:', extension);
  } else {
    ElMessage.error('上传失败：' + response.msg);
  }
};

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

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

  // 验证分类信息，如果没有分类信息，提示用户选择分类
  if (!uploadForm.value.categoryType && !uploadForm.value.categoryId) {
    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,
        extension: file.extension,
        categoryId: uploadForm.value.categoryId,
        categoryType: uploadForm.value.categoryType,
        description: uploadForm.value.description || '',
        uploadStatus: 1,
        isPublic: 1,
        status: 0,
        downloadCount: 0,
        viewCount: 0
      };

      console.log('保存文件信息到后端:', {
        文件名: fileInfo.name,
        原始文件名: fileInfo.originalName,
        MIME类型: fileInfo.type,
        文件扩展名: fileInfo.extension,
        文件大小: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
        文件主分类: fileInfo.categoryType,
        分类ID: fileInfo.categoryId,
        文件URL: fileInfo.url
      });

      return addFileInfo(fileInfo);
    });

    await Promise.all(promises);

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

// 获取分类类型
const getCategoryType = (categoryId) => {
  const category = categoryList.value.find(cat => cat.id === categoryId);
  return category ? category.type : null;
};

// 获取分类文件类型文本
const getFileTypeByCategory = (categoryType) => {
  if (categoryType === 1) return 'jpg/png/gif/bmp/webp';
  if (categoryType === 2) return 'mp4/avi/mov/wmv/flv/mkv';
  if (categoryType === 3) return 'mp3/wav/flac/aac/ogg';
  if (categoryType === 4) return 'pdf/doc/docx/xls/xlsx/ppt/pptx/txt';
  if (categoryType === 5) return '所有文件';
  return '所有文件';
};

// 获取上传文件接受类型
const getUploadFileAccept = () => {
  if (uploadForm.value.categoryId) {
    const categoryType = getCategoryType(uploadForm.value.categoryId);
    if (categoryType === 1) return '.jpg,.jpeg,.png,.gif,.bmp,.webp';
    if (categoryType === 2) return '.mp4,.avi,.mov,.wmv,.flv,.mkv';
    if (categoryType === 3) return '.mp3,.wav,.flac,.aac,.ogg';
    if (categoryType === 4) return '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt';
    if (categoryType === 5) return ''; // 其他文件类型允许所有文件格式
  }
  return '';
};

// 获取上传文件类型文本
const getUploadFileTypeText = () => {
  if (uploadForm.value.categoryId) {
    const categoryType = getCategoryType(uploadForm.value.categoryId);
    return getFileTypeByCategory(categoryType);
  }
  return '所有文件';
};

// 类别变化时更新上传表单
const onCategoryChange = () => {
  selectedCategoryType.value = getCategoryType(uploadForm.value.categoryId);
};

// 打开裁剪对话框
const openCropDialog = (file) => {
  console.log('准备打开裁剪对话框，文件:', file.name, '大小:', (file.size / 1024 / 1024).toFixed(2), 'MB');
  currentCropFile.value = file;
  
  // 清除可能的表单验证状态
  nextTick(() => {
    // 清除上传表单的验证状态
    uploadFormRef.value?.clearValidate();
    // 清除分类表单的验证状态
    categoryFormRef.value?.clearValidate();
    // 清除重命名表单的验证状态
    renameFormRef.value?.clearValidate();
  });
  
  // 读取文件为base64
  const reader = new FileReader();
  reader.onload = (e) => {
    const result = e.target?.result as string;
    if (result) {
      console.log('图片已转换为base64，长度:', result.length);
      cropImageUrl.value = result;
      
      // 延迟打开对话框，确保图片已加载
      setTimeout(() => {
        cropDialogVisible.value = true;
      }, 100);
    }
  };
  
  reader.onerror = () => {
    ElMessage.error('读取图片文件失败');
  };
  
  reader.readAsDataURL(file);
};

// 处理裁剪确认
const handleCropConfirm = async (croppedFile) => {
  try {
    console.log('裁剪完成，新文件大小:', (croppedFile.size / 1024 / 1024).toFixed(2), 'MB');
    
    // 上传裁剪后的文件
    await uploadCroppedFile(croppedFile);
    
  } catch (error) {
    console.error('处理裁剪文件失败:', error);
    const errorMessage = error instanceof Error ? error.message : String(error);
    ElMessage.error('处理失败: ' + errorMessage);
  }
};

// 处理裁剪取消
const handleCropCancel = () => {
  currentCropFile.value = null;
  cropImageUrl.value = '';
  
  // 关闭对话框后清除表单验证状态
  nextTick(() => {
    uploadFormRef.value?.clearValidate();
    categoryFormRef.value?.clearValidate();
    renameFormRef.value?.clearValidate();
  });
};

// 上传裁剪后的文件
const uploadCroppedFile = async (file) => {
  try {
    // 创建FormData
    const formData = new FormData();
    formData.append('file', file);
    
    // 上传文件
    const response = await fetch(uploadUrl.value, {
      method: 'POST',
      headers: uploadHeaders.value,
      body: formData
    });
    
    const result = await response.json();
    
    if (result.code === 200) {
      ElMessage.success('裁剪并上传成功');
      
      // 添加到上传文件列表
      const mimeType = getFileMimeType(file);
      const fileName = file.name || '';
      const extension = fileName.split('.').pop()?.toLowerCase() || '';
      
      uploadFileList.value.push({
        name: file.name,
        url: result.data?.url || '',
        size: file.size,
        type: mimeType,
        extension: extension,
        originalName: file.name,
        ossId: result.data?.ossId || ''
      });
      
      // 清理裁剪状态
      handleCropCancel();
      
    } else {
      throw new Error(result.msg || '上传失败');
    }
    
  } catch (error) {
    console.error('上传裁剪文件失败:', error);
    const errorMessage = error instanceof Error ? error.message : String(error);
    ElMessage.error('上传失败: ' + errorMessage);
  }
};

// 格式化文件大小
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 handlePreviewImage = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('图片文件地址不存在');
    return;
  }

  // 使用ElMessageBox创建图片预览对话框
  const imageUrl = file.url || file.path;
  ElMessageBox({
    title: `预览图片 - ${file.name || file.originalName}`,
    message: h('div', { style: 'text-align: center;' }, [
      h('img', {
        src: imageUrl,
        style: 'max-width: 100%; max-height: 500px; height: auto; border-radius: 4px;',
        onError: () => {
          ElMessage.error('图片加载失败');
        }
      })
    ]),
    showCancelButton: false,
    confirmButtonText: '关闭',
    customClass: 'image-preview-dialog'
  });
};

// 播放视频
const handlePlayVideo = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('视频文件地址不存在');
    return;
  }

  // 创建视频播放对话框
  const videoUrl = file.url || file.path;
  ElMessageBox({
    title: `播放视频 - ${file.name || file.originalName}`,
    message: h('div', { style: 'text-align: center;' }, [
      h('video', {
        src: videoUrl,
        controls: true,
        autoplay: true,
        style: 'width: 100%; max-width: 800px; height: auto;'
      })
    ]),
    showCancelButton: false,
    confirmButtonText: '关闭',
    customClass: 'video-player-dialog'
  });
};

// 播放音频
const handlePlayAudio = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('音频文件地址不存在');
    return;
  }

  console.log('开始播放音频文件:', file);

  // 获取完整的音频URL
  let audioUrl = file.url || file.path;

  // 处理URL，确保是完整路径
  if (audioUrl) {
    // 如果是OSS ID（纯数字），需要特殊处理
    if (/^\d+$/.test(audioUrl)) {
      // 直接打开新窗口播放
      window.open(import.meta.env.VITE_APP_BASE_API + '/resource/oss/download/' + audioUrl, '_blank');
      return;
    }

    // 处理相对路径
    if (!audioUrl.startsWith('http')) {
      // 如果是相对路径，添加基础URL
      audioUrl = import.meta.env.VITE_APP_BASE_API + (audioUrl.startsWith('/') ? audioUrl : '/' + audioUrl);
    }
  }

  console.log('处理后的音频URL:', audioUrl);

  // 创建一个临时的audio元素测试URL是否可访问
  const testAudio = new Audio();
  testAudio.src = audioUrl;
  testAudio.oncanplay = () => {
    console.log('音频可以播放，URL有效');
    // URL有效，创建音频播放对话框
    showAudioDialog(file, audioUrl);
  };

  testAudio.onerror = (e) => {
    console.error('音频URL测试失败:', e);
    // 尝试直接在新窗口打开
    const confirmed = window.confirm(`音频预览加载失败，是否在新窗口打开？`);
    if (confirmed) {
      window.open(audioUrl, '_blank');
    }
  };
};

// 显示音频播放对话框
const showAudioDialog = (file, audioUrl) => {
  // 创建音频播放对话框
  ElMessageBox({
    title: `播放音频 - ${file.name || file.originalName}`,
    message: h('div', { style: 'text-align: center;' }, [
      h('div', { class: 'audio-container' }, [
        h('audio', {
          src: audioUrl,
          controls: true,
          autoplay: false,
          preload: 'auto',
          style: 'width: 100%; max-width: 500px;',
          ref: 'audioPlayer',
          id: `audio-player-${file.id || Date.now()}`,
          onError: (e) => {
            console.error('音频加载失败:', e);
            ElMessage.error('音频加载失败，请检查文件格式或网络连接');
          }
        }),
        h('div', { class: 'audio-info' }, [
          h('p', { style: 'margin-top: 15px; color: #606266;' }, `文件名: ${file.name || file.originalName}`),
          h('p', { style: 'color: #909399; font-size: 12px;' }, `格式: ${file.type || '音频文件'}`),
          h('p', { style: 'color: #909399; font-size: 12px;' }, `大小: ${formatFileSize(file.size)}`)
        ])
      ])
    ]),
    showCancelButton: true,
    confirmButtonText: '在新窗口打开',
    cancelButtonText: '关闭',
    customClass: 'audio-player-dialog',
    beforeClose: (action, instance, done) => {
      // 关闭对话框前停止音频播放
      try {
        const audioId = document.getElementById(`audio-player-${file.id || Date.now()}`);
        if (audioId && audioId instanceof HTMLAudioElement) {
          audioId.pause();
        }

        const audioElements = document.querySelectorAll('.audio-player-dialog audio');
        if (audioElements && audioElements.length > 0) {
          audioElements.forEach(audio => {
            if (audio instanceof HTMLAudioElement) {
              audio.pause();
            }
          });
        }
      } catch (err) {
        console.warn('停止音频播放失败:', err);
      }
      done();
    }
  }).then(() => {
    // 用户点击"在新窗口打开"按钮
    window.open(audioUrl, '_blank');
  }).catch(() => {
    // 用户点击"关闭"按钮，不做任何操作
  });
};

// 预览PDF
const handlePreviewPdf = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('PDF文件地址不存在');
    return;
  }

  const pdfUrl = file.url || file.path;
  // 使用弹窗预览PDF
  ElMessageBox({
    title: `预览PDF - ${file.name || file.originalName}`,
    message: h('div', { style: 'text-align: center;' }, [
      h('iframe', {
        src: pdfUrl,
        style: 'width: 100%; height: 600px; border: none; border-radius: 4px;',
        onError: () => {
          ElMessage.error('PDF加载失败');
        }
      })
    ]),
    showCancelButton: false,
    confirmButtonText: '关闭',
    customClass: 'pdf-preview-dialog'
  });
};

// 预览其他文件类型
const handlePreviewOther = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('文件地址不存在');
    return;
  }

  const fileUrl = file.url || file.path;
  const fileExtension = file.extension?.toLowerCase() || '';

  // 判断文件类型并使用相应的预览方式
  if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(fileExtension)) {
    // Office文档使用iframe预览
    ElMessageBox({
      title: `预览文档 - ${file.name || file.originalName}`,
      message: h('div', { style: 'text-align: center;' }, [
        h('iframe', {
          src: `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fileUrl)}`,
          style: 'width: 100%; height: 600px; border: none; border-radius: 4px;',
          onError: () => {
            ElMessage.error('文档预览失败，请尝试下载查看');
          }
        })
      ]),
      showCancelButton: false,
      confirmButtonText: '关闭',
      customClass: 'document-preview-dialog'
    });
  } else {
    // 其他文件类型显示文件信息和下载提示
    ElMessageBox({
      title: `文件信息 - ${file.name || file.originalName}`,
      message: h('div', { style: 'text-align: center; padding: 20px;' }, [
        h('div', { style: 'margin-bottom: 15px;' }, [
          h('i', { class: 'el-icon-document', style: 'font-size: 48px; color: #909399;' })
        ]),
        h('p', { style: 'margin: 10px 0; font-size: 16px; font-weight: 500;' }, file.name || file.originalName),
        h('p', { style: 'margin: 5px 0; color: #666;' }, `文件类型: ${file.type || '未知'}`),
        h('p', { style: 'margin: 5px 0; color: #666;' }, `文件大小: ${formatFileSize(file.size)}`),
        h('p', { style: 'margin: 15px 0; color: #999;' }, '此文件类型无法直接预览，您可以下载后查看')
      ]),
      showCancelButton: true,
      confirmButtonText: '下载文件',
      cancelButtonText: '关闭',
      customClass: 'file-info-dialog'
    }).then(() => {
      // 点击下载按钮时执行下载
      handleDownload(file);
    }).catch(() => {
      // 用户取消，不做任何操作
    });
  }
};

// 预览文本文件
const handlePreviewText = (file) => {
  if (!file.url && !file.path) {
    ElMessage.error('文本文件地址不存在');
    return;
  }

  // 下载并读取文本内容
  fetch(file.url || file.path)
    .then(response => response.text())
    .then(text => {
      ElMessageBox({
        title: `预览文本 - ${file.name || file.originalName}`,
        message: h('div', { style: 'max-height: 400px; overflow-y: auto;' }, [
          h('pre', { style: 'white-space: pre-wrap; word-wrap: break-word;' }, text)
        ]),
        showCancelButton: false,
        confirmButtonText: '关闭',
        customClass: 'text-preview-dialog'
      });
    })
    .catch(error => {
      console.error('读取文本文件失败:', error);
      ElMessage.error('读取文本文件失败');
    });
};

// 切换顶级分类
const switchTopCategory = (topCategory) => {
  console.log('switchTopCategory - switching to:', topCategory);
  currentTopCategory.value = topCategory;
  currentCategory.value = null;
  selectedFiles.value = [];
  queryParams.value.pageNum = 1;
  queryParams.value.categoryId = null;

  // 设置categoryType为顶部分类的ID值
  if (topCategory && topCategory.type) {
    // 按类型过滤（1=图片,2=视频,3=音频,4=文档）
    queryParams.value.categoryType = topCategory.type;
    console.log('switchTopCategory - set categoryType to type:', topCategory.type);
  } else {
    queryParams.value.categoryType = null;
    console.log('switchTopCategory - cleared categoryType (show all files)');
  }

  getList();
};

// 获取上传按钮文本
const getUploadButtonText = () => {
  if (!currentTopCategory.value) return '上传文件';

  switch (currentTopCategory.value.type) {
    case 1:
      return '上传图片';
    case 2:
      return '上传视频';
    case 3:
      return '上传音频';
    case 4:
      return '上传文档';
    default:
      return '上传文件';
  }
};

// 获取文件类型文本
const getFileTypeText = () => {
  if (!currentTopCategory.value) return '文件';

  switch (currentTopCategory.value.type) {
    case 1:
      return '图片';
    case 2:
      return '视频';
    case 3:
      return '音频';
    case 4:
      return '文档';
    default:
      return '文件';
  }
};

// 切换文件选择状态
const toggleFileSelection = (id, checked = null) => {
  if (checked !== null) {
    // 如果传入了checked参数，使用它
    if (checked) {
      selectedFiles.value.push(id);
    } else {
      selectedFiles.value = selectedFiles.value.filter(fileId => fileId !== id);
    }
  } else {
    // 如果没有传入checked参数，切换状态
    const index = selectedFiles.value.indexOf(id);
    if (index > -1) {
      selectedFiles.value.splice(index, 1);
    } else {
      selectedFiles.value.push(id);
    }
  }
};

// 根据当前顶级分类过滤子分类
const filteredCategoryTree = computed(() => {
  console.log('filteredCategoryTree computed - currentTopCategory:', currentTopCategory.value);
  console.log('filteredCategoryTree computed - categoryTree:', categoryTree.value);

  if (!currentTopCategory.value || !categoryTree.value || categoryTree.value.length === 0) {
    console.log('filteredCategoryTree computed - returning empty array');
    return [];
  }

  // 从树形结构中获取当前顶级分类的子分类
  const getSubCategories = (parentId) => {
    // 在顶级分类中查找对应的分类
    const parentCategory = categoryTree.value.find(category => category.id === parentId);
    if (parentCategory && parentCategory.children) {
      console.log('getSubCategories - parentId:', parentId, 'subCategories:', parentCategory.children);
      return parentCategory.children;
    }
    console.log('getSubCategories - parentId:', parentId, 'subCategories: not found');
    return [];
  };

  const result = getSubCategories(currentTopCategory.value.id);
  console.log('filteredCategoryTree computed - result:', result);
  return result;
});

// 上传对话框中的分类选项
const uploadCategoryOptions = computed(() => {
  if (!currentTopCategory.value || !categoryTree.value || categoryTree.value.length === 0) {
    return [];
  }

  // 获取当前顶级分类的子分类
  const parentCategory = categoryTree.value.find(category => category.id === currentTopCategory.value.id);
  if (parentCategory && parentCategory.children) {
    return parentCategory.children;
  }

  return [];
});

// 上传对话框中的树形分类数据（仅允许选择叶子节点：非叶子设置为 disabled）
const uploadCategoryTree = computed(() => {
  if (!currentTopCategory.value || !categoryTree.value || categoryTree.value.length === 0) {
    return [];
  }
  const mapWithDisabled = (nodes) => {
    if (!Array.isArray(nodes)) return [];
    return nodes.map(node => {
      const hasChildren = Array.isArray(node.children) && node.children.length > 0;
      const mappedChildren = hasChildren ? mapWithDisabled(node.children) : undefined;
      return {
        ...node,
        children: mappedChildren,
        disabled: hasChildren
      };
    });
  };
  const parentCategory = categoryTree.value.find(category => category.id === currentTopCategory.value.id);
  const children = parentCategory && Array.isArray(parentCategory.children) ? parentCategory.children : [];
  return mapWithDisabled(children);
});

// 监听分类变化
watch(currentCategory, () => {
  queryParams.value.pageNum = 1;
  selectedFiles.value = [];
  getList();
});

// 页面初始化
onMounted(async () => {
  await getCategoryTree();
  getList();
});
</script>

<style scoped>
.file-manager {
  padding: 20px;
  background: #f5f7fa;
  min-height: calc(100vh - 120px);
}

/* 顶部分类导航 */
.top-categories {
  background: white;
  border-radius: 8px 8px 0 0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-bottom: 0;
  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;
}

.category-tab .el-icon {
  font-size: 18px;
}

/* 主容器 */
.main-container {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 0 0 8px 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-left: 0px !important;
}

.content-wrapper {
  display: flex;
  gap: 20px;
  margin-top: 20px;
  height: 100%;

}

.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);
}

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

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

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

.toolbar-left h2 {
  margin: 0;
  color: #303133;
  font-size: 18px;
  font-weight: 600;
}

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

.main-content {
  display: flex;
  gap: 20px;
  height: calc(100vh - 280px);
}

.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;
  height: 100%;
}

.sidebar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #ebeef5;
  background: #fafafa;
}

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

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

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

.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.active:hover {
  background: #66b1ff;
}

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

.category-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.expand-icon {
  font-size: 16px;
  color: #909399;
  cursor: pointer;
  transition: transform 0.3s;
  margin-right: 5px;
}

.expand-icon:hover {
  color: #409eff;
}

.expand-icon.expanded {
  transform: rotate(90deg);
}

.indent {
  width: 20px;
  flex-shrink: 0;
}

.child-category {
  margin-left: 0;
}

.grandchild-category {
  margin-left: 0;
}

.more-icon {
  font-size: 16px;
  color: #909399;
  cursor: pointer;
  transition: color 0.3s;
}

.more-icon:hover {
  color: #409eff;
}

/* 树形控件样式 */
.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;
}

.category-tree :deep(.el-tree-node.is-current > .el-tree-node__content:hover) {
  background: #66b1ff;
}

.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;
}

.tree-node-content .node-actions {
  margin-left: auto;
}

.tree-node-content .more-icon {
  font-size: 16px;
  color: #909399;
  cursor: pointer;
  transition: color 0.3s;
  padding: 2px 5px;
  border-radius: 2px;
}

.tree-node-content .more-icon:hover {
  color: #409eff;
  background: rgba(64, 158, 255, 0.1);
}

.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

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

.breadcrumb .clickable {
  cursor: pointer;
  color: #409eff;
}

.breadcrumb .clickable:hover {
  text-decoration: underline;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.file-count {
  color: #909399;
  font-size: 14px;
}

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

.pagination {
  display: flex;
  justify-content: center;
  padding: 20px;
  background: white;
  flex-shrink: 0;
}

.form-tip {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

.el-table {
  border: none;
}

.el-table th {
  background: #fafafa;
  color: #606266;
  font-weight: 500;
}

.el-table td {
  border-bottom: 1px solid #ebeef5;
}

.el-table tr:hover td {
  background: #f5f7fa;
}

.el-upload-dragger {
  width: 100%;
  height: 180px;
  background: #fafafa;
  border: 2px dashed #d9d9d9;
  border-radius: 6px;
  box-sizing: border-box;
  text-align: center;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.el-upload-dragger:hover {
  border-color: #409eff;
}

.el-icon--upload {
  font-size: 67px;
  color: #c0c4cc;
  margin: 40px 0 16px;
  line-height: 50px;
}

.el-upload__text {
  color: #606266;
  font-size: 14px;
  text-align: center;
}

.el-upload__text em {
  color: #409eff;
  font-style: normal;
}

.el-upload__tip {
  font-size: 12px;
  color: #606266;
  margin-top: 7px;
}

.file-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 15px;
  padding: 15px;
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

.file-item {
  position: relative;
  cursor: pointer;
  border: 1px solid #ebeef5;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

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

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

.file-wrapper {
  position: relative;
  width: 100%;
  height: 150px; /* Fixed height for grid view */
  overflow: hidden;
}

.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: 48px;
}

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

.file-checkbox :deep(.el-checkbox__inner) {
  border: 2px solid #fff;
  background: transparent;
  border-radius: 0;
}

.file-checkbox :deep(.el-checkbox.is-checked .el-checkbox__inner) {
  background: #409eff;
  border-color: #409eff;
}

.file-info {
  padding: 10px;
  background: #f5f7fa;
  border-top: 1px solid #ebeef5;
  border-radius: 0 0 8px 8px;
}

.file-name {
  font-size: 14px;
  color: #303133;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 5px;
}

.file-actions {
  display: flex;
  justify-content: space-around;
  gap: 8px;
}

.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;
}

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

.list-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;
}

.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;
}

.file-list {
  padding: 15px;
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

/* 删除按钮样式 - 浅灰色 */
.delete-btn {
  color: #909399 !important;
}

.delete-btn:hover {
  color: #606266 !important;
}

/* 图片预览对话框样式 */
.image-preview-dialog {
  max-width: 80vw;
}

.image-preview-dialog .el-message-box__content {
  padding: 20px !important;
}

.image-preview-dialog .el-message-box__message {
  margin: 0 !important;
}

/* 音频播放器对话框样式 */
.audio-player-dialog {
  max-width: 600px;
  min-width: 400px;
}

.audio-player-dialog .el-message-box__content {
  padding: 30px 20px !important;
}

.audio-player-dialog .el-message-box__message {
  margin: 0 !important;
}

.audio-player-dialog .audio-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 15px;
  background: #f8f9fa;
  border-radius: 10px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.audio-player-dialog audio {
  width: 100%;
  border-radius: 8px;
  background: #f0f9ff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  padding: 10px;
  margin-bottom: 10px;
}

.audio-player-dialog .audio-info {
  width: 100%;
  text-align: left;
  margin-top: 10px;
  padding: 10px;
  background: white;
  border-radius: 8px;
  border: 1px solid #ebeef5;
}

.audio-player-dialog .el-message-box__btns {
  padding: 15px 20px !important;
}

/* 选中指示器 */
.select-indicator {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 50%;
  padding: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

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

/* 防止对话框影响主页面元素样式 */
.file-selector :deep(.el-input.is-error),
.file-selector :deep(.el-input.is-invalid) {
  border-color: #dcdfe6 !important;
}

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

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

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

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

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

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

