<template>
  <div class="file-management p-1 bg-gray-50 h-screen flex flex-col">
    <div class="flex-1 flex gap-2 overflow-hidden">
      <!-- 左侧文件分类 -->
      <div class="w-48 bg-white rounded-lg shadow-sm border border-gray-100 flex flex-col overflow-hidden">
        <div class="px-4 py-3 border-b border-gray-100">
          <h3 class="text-sm font-medium text-gray-900">
            文件分类
          </h3>
        </div>
        <div class="flex-1 overflow-y-auto">
          <div class="p-2 space-y-1">
            <div
              v-for="category in fileCategories"
              :key="category.value"
              class="flex items-center px-3 py-2 rounded-md cursor-pointer transition-colors category-item"
              :class="selectedCategory === category.value ? 'category-selected' : 'category-unselected'"
              @click="handleCategoryChange(category.value)"
            >
              <component :is="category.icon" class="w-4 h-4 mr-2" />
              <span class="text-sm flex-1">{{ category.label }}</span>
              <NTag
                v-if="selectedCategory === category.value"
                type="primary"
                size="small"
                class="ml-auto"
              >
                ✓
              </NTag>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧文件列表 -->
      <div class="flex-1 bg-white rounded-lg shadow-sm border border-gray-100 flex flex-col overflow-hidden">
        <!-- 搜索表单 -->
        <div class="px-4 py-2 border-b border-gray-100">
          <n-form
            ref="searchFormRef"
            :model="searchForm"
            label-placement="left"
            label-width="auto"
            class="search-form"
          >
            <n-grid :cols="5" :x-gap="8" :y-gap="4">
              <n-grid-item>
                <n-form-item label="文件名称" path="fileName">
                  <n-input
                    v-model:value="searchForm.fileName"
                    placeholder="请输入文件名称"
                    clearable
                    @keydown.enter="handleSearch"
                  />
                </n-form-item>
              </n-grid-item>

              <n-grid-item>
                <n-form-item label="文件后缀" path="fileSuffix">
                  <n-input
                    v-model:value="searchForm.fileSuffix"
                    placeholder="请输入文件后缀"
                    clearable
                    @keydown.enter="handleSearch"
                  />
                </n-form-item>
              </n-grid-item>

              <n-grid-item>
                <n-form-item label="存储类型" path="fileService">
                  <n-select
                    v-model:value="searchForm.fileService"
                    placeholder="请选择存储类型"
                    clearable
                    :options="FILE_SERVICE_DB_OPTIONS"
                  />
                </n-form-item>
              </n-grid-item>

              <n-grid-item>
                <n-form-item label="" path="">
                  <NSpace>
                    <NButton type="primary" @click="handleSearch">
                      <template #icon>
                        <NIcon><icon-park-outline:search /></NIcon>
                      </template>
                      搜索
                    </NButton>
                    <NButton @click="handleReset">
                      <template #icon>
                        <NIcon><icon-park-outline:refresh /></NIcon>
                      </template>
                      重置
                    </NButton>
                  </NSpace>
                </n-form-item>
              </n-grid-item>
            </n-grid>
          </n-form>
        </div>

        <!-- 表格头部操作栏 -->
        <div class="flex items-center justify-between px-4 py-2 border-b border-gray-100">
          <div class="flex items-center gap-4">
            <NButton
              v-permission="PERMISSIONS.FILE.UPLOAD"
              type="primary"
              class="px-3 flex items-center"
              @click="handleUpload"
            >
              <template #icon>
                <NIcon class="mr-1" style="transform: translateY(-1px)">
                  <icon-park-outline:upload />
                </NIcon>
              </template>
              上传文件
            </NButton>

            <NButton
              v-permission="PERMISSIONS.FILE.DELETE"
              type="error"
              :disabled="selectedRows.length === 0"
              class="px-3 flex items-center"
              @click="handleBatchDelete"
            >
              <template #icon>
                <NIcon class="mr-1" style="transform: translateY(-1px)">
                  <icon-park-outline:delete />
                </NIcon>
              </template>
              批量删除
            </NButton>
          </div>

          <div class="flex items-center gap-4 text-sm text-gray-500">
            <span>共 {{ pagination.itemCount }} 条</span>
            <NButton text @click="handleRefresh">
              <template #icon>
                <NIcon><icon-park-outline:refresh /></NIcon>
              </template>
            </NButton>
          </div>
        </div>

        <!-- 表格内容 -->
        <div class="table-wrapper flex-1 overflow-auto pt-4">
          <!-- 数据表格 -->
          <NDataTable
            v-if="tableData.length > 0 || loading"
            ref="tableRef"
            :columns="columns"
            :data="tableData"
            :loading="loading"
            :row-key="(row: SysFileVo) => row.fileId"
            :checked-row-keys="selectedRowKeys"
            :on-update:checked-row-keys="handleRowKeysUpdate"
            :bordered="false"
            :single-line="false"
            :scroll-x="1600"
            size="small"
            class="custom-table"
          />

          <!-- 空状态 -->
          <CoiEmpty
            v-else
            type="empty"
            title="暂无文件数据"
            description="当前没有找到任何文件记录"
            size="medium"
          />
        </div>

        <!-- 分页器 -->
        <div v-if="tableData.length > 0" class="flex items-center px-4 py-2 border-t border-gray-100">
          <div class="text-sm text-gray-500 mr-4">
            共 {{ pagination.itemCount }} 条
          </div>
          <n-pagination
            v-model:page="pagination.page"
            v-model:page-size="pagination.pageSize"
            :item-count="pagination.itemCount"
            :show-size-picker="true"
            :page-sizes="[10, 20, 50, 100]"
            show-quick-jumper
            @update:page="handlePageChange"
            @update:page-size="handlePageSizeChange"
          />
        </div>
      </div>
    </div>

    <!-- 文件上传弹框 -->
    <CoiDialog
      ref="uploadDialogRef"
      title="上传操作 ☀️"
      :width="600"
      height="auto"
      confirm-text="确定"
      cancel-text="取消"
      @coi-confirm="handleUploadConfirm"
      @coi-cancel="handleUploadCancel"
    >
      <template #content>
        <div class="px-3 py-2">
          <n-form
            ref="uploadFormRef"
            :model="uploadForm"
            :rules="uploadRules"
            label-placement="left"
            label-width="100px"
            require-mark-placement="right-hanging"
          >
            <!-- 文件服务选择 -->
            <n-form-item label="文件服务" path="fileService">
              <n-select
                v-model:value="uploadForm.fileService"
                placeholder="请选择文件服务"
                :options="[
                  { label: 'LOCAL', value: 'LOCAL' },
                  { label: 'MINIO', value: 'MINIO' },
                  { label: 'OSS', value: 'OSS' },
                ]"
              />
            </n-form-item>

            <!-- 文件回显路径 -->
            <n-form-item label="文件回显路径" path="filePath">
              <n-input
                v-model:value="uploadForm.filePath"
                placeholder="系统自动生成"
                readonly
                disabled
              />
            </n-form-item>

            <!-- 文件上传区域 -->
            <n-form-item label="上传文件" path="files">
              <div class="w-full">
                <NUpload
                  ref="uploadRef"
                  v-model:file-list="uploadFileList"
                  :max="5"
                  multiple
                  directory-dnd
                  :before-upload="beforeUpload"
                  :custom-request="customUpload"
                  :on-remove="handleRemoveFile"
                  :on-error="handleUploadError"
                  @change="handleFileChange"
                >
                  <NUploadDragger>
                    <div class="text-center">
                      <div class="mb-3">
                        <NIcon size="48" class="text-blue-500">
                          <icon-park-outline:upload />
                        </NIcon>
                      </div>
                      <NText class="text-base">
                        点击或者拖动文件到该区域来上传
                      </NText>
                      <NP depth="3" class="mt-2">
                        支持图片[jpg, jpeg, png, gif, bmp, webp, svg] 文档[doc/docx/pdf/txt/xls/xlsx/ppt/pptx/md/zip/rar/7z]；
                      </NP>
                      <NP depth="3">
                        文件大小不能超过2MB；最多上传5个；
                      </NP>
                    </div>
                  </NUploadDragger>
                </NUpload>
              </div>
            </n-form-item>
          </n-form>
        </div>
      </template>
    </CoiDialog>

    <!-- 图片预览弹框 -->
    <n-modal
      v-model:show="imagePreviewVisible"
      preset="card"
      title="图片预览"
      :style="{ width: '80%', maxWidth: '800px' }"
      :mask-closable="true"
    >
      <div class="text-center">
        <img
          v-if="previewImageUrl"
          :src="previewImageUrl"
          :alt="previewImageName"
          class="max-w-full max-h-96 mx-auto"
        >
        <div class="mt-2 text-sm text-gray-500">
          {{ previewImageName }}
        </div>
      </div>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { h, onMounted, ref } from 'vue'
import { NButton, NIcon, NImage, NP, NPopconfirm, NSpace, NTag, NText, NUpload, NUploadDragger } from 'naive-ui'
import type { DataTableColumns, DataTableInst, FormInst, UploadFileInfo, UploadInst } from 'naive-ui'
import CoiEmpty from '@/components/common/CoiEmpty.vue'
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
import { usePermission } from '@/hooks/usePermission'
import { PERMISSIONS } from '@/constants/permissions'
import {
  batchDeleteSysFiles,
  deleteSysFile,
  getSysFileList,
  uploadFile,
} from '@/service/api/system/file'
import type { SysFileQueryBo, SysFileSearchForm, SysFileVo } from '@/service/api/system/file'
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
import IconParkOutlinePreviewOpen from '~icons/icon-park-outline/preview-open'

// 文件分类图标组件
const StarIcon = () => h('span', { class: 'text-yellow-500' }, '✨')
const _ImageIcon = () => h('span', { class: 'text-pink-500' }, '🎨')
const DocumentIcon = () => h('span', { class: 'text-blue-500' }, '📄')
const AudioIcon = () => h('span', { class: 'text-purple-500' }, '🎵')
const VideoIcon = () => h('span', { class: 'text-red-500' }, '📹')
const ArchiveIcon = () => h('span', { class: 'text-orange-500' }, '🗂️')
const AppIcon = () => h('span', { class: 'text-green-500' }, '🦄')
const OtherIcon = () => h('span', { class: 'text-gray-500' }, '🎃')

// 文件分类选项
const fileCategories = [
  { label: '全部', value: '0', icon: StarIcon },
  { label: '图片', value: '1', icon: StarIcon },
  { label: '文档', value: '2', icon: DocumentIcon },
  { label: '音频', value: '3', icon: AudioIcon },
  { label: '视频', value: '4', icon: VideoIcon },
  { label: '压缩包', value: '5', icon: ArchiveIcon },
  { label: '应用程序', value: '6', icon: AppIcon },
  { label: '其他', value: '9', icon: OtherIcon },
]

// 权限验证
const { hasPermission } = usePermission()

// 响应式数据
const searchFormRef = ref<FormInst>()
const tableRef = ref<DataTableInst>()
const uploadFormRef = ref<FormInst>()
const uploadRef = ref<UploadInst>()
const uploadDialogRef = ref()
const loading = ref(false)
const tableData = ref<SysFileVo[]>([])
const selectedCategory = ref<string>('0') // 默认选中全部
const selectedRows = ref<SysFileVo[]>([])
const selectedRowKeys = ref<number[]>([])

// 搜索表单
const searchForm = ref<SysFileSearchForm>({
  fileName: '',
  fileSuffix: '',
  fileService: '',
  fileType: '0', // 默认全部
})

// 图片预览相关
const imagePreviewVisible = ref(false)
const previewImageUrl = ref('')
const previewImageName = ref('')

// 文件上传相关
const uploadFileList = ref<UploadFileInfo[]>([])
const uploading = ref(false)

// 上传表单数据
const uploadForm = ref({
  fileService: 'LOCAL',
  filePath: '',
})

// 上传表单验证规则
const uploadRules = {
  fileService: [
    { required: true, message: '请选择文件服务', trigger: 'change' },
  ],
}

// 分页设置
const pagination = ref({
  page: 1,
  pageSize: 20,
  itemCount: 0,
})

// 表格列定义
const columns: DataTableColumns<SysFileVo> = [
  {
    type: 'selection',
    width: 50,
    disabled: (_row: SysFileVo) => !hasPermission(PERMISSIONS.FILE.DELETE),
  },
  {
    title: '序号',
    key: 'index',
    width: 80,
    render: (_, index) => {
      return (pagination.value.page - 1) * pagination.value.pageSize + index + 1
    },
  },
  {
    title: '文件原始名称',
    key: 'fileName',
    width: 200,
    ellipsis: {
      tooltip: true,
    },
  },
  {
    title: '文件新名称',
    key: 'newName',
    width: 200,
    ellipsis: {
      tooltip: true,
    },
  },
  {
    title: '文件后缀',
    key: 'fileSuffix',
    width: 100,
    render: (row) => {
      return h(NTag, {
        type: 'primary',
        size: 'small',
      }, { default: () => row.fileSuffix?.toUpperCase() })
    },
  },
  {
    title: '文件上传路径',
    key: 'fileUpload',
    width: 250,
    ellipsis: {
      tooltip: true,
    },
  },
  {
    title: '文件回显路径',
    key: 'filePath',
    width: 200,
    ellipsis: {
      tooltip: true,
    },
    render: (row) => {
      const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(
        row.fileSuffix?.toLowerCase() || '',
      )

      if (isImage && row.filePath) {
        return h(NImage, {
          src: row.filePath,
          width: 45,
          height: 30,
          objectFit: 'cover',
          previewDisabled: true,
          onClick: () => handleImagePreview(row.filePath!, row.fileName),
          class: 'cursor-pointer rounded border',
        })
      }

      // 对于非图片文件，返回文本让 ellipsis 配置生效
      return row.filePath || '--'
    },
  },
  {
    title: '文件服务类型',
    key: 'fileService',
    width: 120,
    render: (row) => {
      const serviceMap: Record<string, { type: 'success' | 'info' | 'warning', text: string }> = {
        1: { type: 'success', text: '本地存储' },
        2: { type: 'info', text: 'MinIO' },
        3: { type: 'warning', text: '阿里云OSS' },
      }
      const config = serviceMap[row.fileService] || { type: 'info', text: '未知' }
      return h(NTag, {
        type: config.type,
        size: 'small',
      }, { default: () => config.text })
    },
  },
  {
    title: '创建时间',
    key: 'createTime',
    width: 160,
    render: (row) => {
      return row.createTime ? new Date(row.createTime).toLocaleString() : '--'
    },
  },
  {
    title: '操作',
    key: 'actions',
    width: 160,
    align: 'center',
    fixed: 'right',
    render: (row) => {
      const buttons = []

      // 预览按钮
      buttons.push(h(NButton, {
        type: 'primary',
        size: 'small',
        onClick: () => handlePreview(row),
      }, {
        icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, {
          default: () => h(IconParkOutlinePreviewOpen),
        }),
        default: () => '预览',
      }))

      // 删除按钮
      if (hasPermission(PERMISSIONS.FILE.DELETE)) {
        buttons.push(h(NPopconfirm, {
          onPositiveClick: () => handleDelete(row.fileId!),
          negativeText: '取消',
          positiveText: '确定',
        }, {
          default: () => '确定删除此文件吗？',
          trigger: () => h(NButton, {
            type: 'error',
            size: 'small',
          }, {
            icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, {
              default: () => h(IconParkOutlineDelete),
            }),
            default: () => '删除',
          }),
        }))
      }

      return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
    },
  },
]

// 查询文件列表
async function fetchData() {
  loading.value = true
  try {
    const params: SysFileQueryBo = {
      pageNo: pagination.value.page,
      pageSize: pagination.value.pageSize,
      fileName: searchForm.value.fileName || undefined,
      fileSuffix: searchForm.value.fileSuffix || undefined,
      fileService: searchForm.value.fileService || undefined,
      fileType: selectedCategory.value === '0' ? undefined : selectedCategory.value,
    }

    const { data } = await getSysFileList(params)
    if (data) {
      tableData.value = data.records
      pagination.value.itemCount = data.total
    }
  }
  catch {
    coiMsgError('获取文件列表失败')
  }
  finally {
    loading.value = false
  }
}

// 搜索
function handleSearch() {
  pagination.value.page = 1
  fetchData()
}

// 重置搜索
function handleReset() {
  searchForm.value = {
    fileName: '',
    fileSuffix: '',
    fileService: '',
    fileType: '0',
  }
  selectedCategory.value = '0'
  handleSearch()
}

// 刷新
function handleRefresh() {
  fetchData()
}

// 分页变化处理
function handlePageChange(page: number) {
  pagination.value.page = page
  fetchData()
}

function handlePageSizeChange(pageSize: number) {
  pagination.value.pageSize = pageSize
  pagination.value.page = 1
  fetchData()
}

// 分类切换
function handleCategoryChange(category: string) {
  selectedCategory.value = category
  searchForm.value.fileType = category
  handleSearch()
}

// 表格行选择
function handleRowKeysUpdate(keys: number[]) {
  selectedRowKeys.value = keys
  selectedRows.value = tableData.value.filter(row => keys.includes(row.fileId!))
}

// 删除文件
async function handleDelete(id: number) {
  try {
    await deleteSysFile(id)
    coiMsgSuccess('删除成功')
    fetchData()
  }
  catch {
    coiMsgError('删除失败')
  }
}

// 批量删除
async function handleBatchDelete() {
  if (selectedRowKeys.value.length === 0) {
    coiMsgWarning('请选择要删除的文件')
    return
  }

  try {
    await coiMsgBox(`确定要删除选中的 ${selectedRowKeys.value.length} 个文件吗？`, '批量删除确认')
    await batchDeleteSysFiles(selectedRowKeys.value)
    coiMsgSuccess('批量删除成功')
    selectedRowKeys.value = []
    selectedRows.value = []
    fetchData()
  }
  catch (error) {
    if (error !== 'cancel') {
      coiMsgError('批量删除失败')
    }
  }
}

// 预览文件
function handlePreview(row: SysFileVo) {
  if (row.filePath) {
    handleImagePreview(row.filePath, row.fileName)
  }
}

// 图片预览
function handleImagePreview(url: string, name: string) {
  previewImageUrl.value = url
  previewImageName.value = name
  imagePreviewVisible.value = true
}

// 文件上传相关函数

// 打开上传弹框
function handleUpload() {
  uploadForm.value = {
    fileService: 'LOCAL',
    filePath: '',
  }
  uploadFileList.value = []
  uploading.value = false
  uploadDialogRef.value?.coiOpen()
}

// 通用文件验证函数
function validateFile(file: File, fileName: string, showError: boolean = true) {
  // 文件空检查
  if (!file || file.size === 0) {
    if (showError)
      coiMsgError('请选择有效的文件')
    return false
  }

  // 文件名检查
  if (!fileName) {
    if (showError)
      coiMsgError('无法获取文件名信息')
    return false
  }

  // 提取文件扩展名
  const fileExtension = fileName.split('.').pop()?.toLowerCase()
  if (!fileExtension) {
    if (showError)
      coiMsgError('文件必须有扩展名')
    return false
  }

  // 文件大小验证 (2MB)
  const fileSize = file.size / 1024 / 1024
  if (fileSize > 2) {
    if (showError) {
      coiMsgError(`文件大小超出限制！当前文件：${fileSize.toFixed(2)}MB，最大允许：2MB`)
    }
    return false
  }

  // 文件格式验证 - 与后端完全一致
  const allowedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
  const allowedDocumentExtensions = ['doc', 'docx', 'pdf', 'txt', 'xls', 'xlsx', 'ppt', 'pptx', 'md', 'zip', 'rar', '7z']
  const allAllowedExtensions = [...allowedImageExtensions, ...allowedDocumentExtensions]

  if (!allAllowedExtensions.includes(fileExtension)) {
    if (showError) {
      coiMsgError(`不支持的文件格式"${fileExtension}"，仅支持：${allAllowedExtensions.join(', ')}`)
    }
    return false
  }

  return true
}

// 文件上传前验证
function beforeUpload(data: { file: UploadFileInfo }) {
  try {
    const file = data.file.file as File
    const fileName = data.file.name || file?.name || ''

    // 显示错误提示的主要验证点
    return validateFile(file, fileName, true)
  }
  catch {
    coiMsgError('文件验证失败，请重新选择文件')
    return false
  }
}

// 自定义上传逻辑
async function customUpload({ file, onProgress, onFinish, onError }: any) {
  try {
    const fileObj = file.file as File
    const fileName = file.name || fileObj.name

    // 在 customUpload 中再次验证 - 双重保险
    if (!validateFile(fileObj, fileName, false)) {
      onError()
      return
    }

    // 判断文件夹名称：图片文件夹为 pictures，其他为 files
    const fileExtension = fileName.split('.').pop()?.toLowerCase()
    const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(fileExtension || '')
    const folderName = isImage ? 'pictures' : 'files'

    // 设置进度
    onProgress({ percent: 10 })

    // 调用上传API
    await uploadFile(fileObj, folderName, 2, '-1')

    // 设置完成进度
    onProgress({ percent: 100 })

    // 完成上传
    onFinish()

    coiMsgSuccess(`文件 ${fileObj.name} 上传成功`)
  }
  catch (error: any) {
    onError()

    // 解析后端错误信息
    let errorMessage = `文件 ${file.file.name} 上传失败`

    // 检查是否是服务返回的结构化错误
    if (error?.isSuccess === false) {
      if (error.message) {
        errorMessage = error.message
      }
      else if (error.msg) {
        errorMessage = error.msg
      }
    }
    else if (error?.response?.data?.msg) {
      errorMessage = error.response.data.msg
    }
    else if (error?.message) {
      if (error.message.includes('413')) {
        errorMessage = '文件大小超出限制，请选择较小的文件'
      }
      else if (error.message.includes('400')) {
        errorMessage = '文件格式不支持或文件无效'
      }
      else {
        errorMessage = error.message
      }
    }

    coiMsgError(errorMessage)
  }
}

// 文件列表变化处理
function handleFileChange(data: { fileList: UploadFileInfo[] }) {
  uploadFileList.value = data.fileList
}

// 移除文件
function handleRemoveFile(data: { file: UploadFileInfo }) {
  const index = uploadFileList.value.findIndex(item => item.id === data.file.id)
  if (index !== -1) {
    uploadFileList.value.splice(index, 1)
  }
}

// 上传错误处理 - 静默处理，避免重复错误提示
function handleUploadError(_data: { file: UploadFileInfo, event?: ProgressEvent }) {
  // 静默处理，主要错误信息已在 customUpload 中处理
}

// 确认上传
async function handleUploadConfirm() {
  if (!uploadFormRef.value)
    return

  try {
    // 表单验证
    await uploadFormRef.value.validate()
  }
  catch {
    coiMsgWarning('请检查表单填写')
    return
  }

  // 检查是否有待上传的文件
  const pendingFiles = uploadFileList.value.filter(file => file.status === 'pending')
  if (pendingFiles.length > 0) {
    coiMsgWarning('还有文件未完成上传，请等待上传完成')
    return
  }

  // 检查是否有上传失败的文件
  const errorFiles = uploadFileList.value.filter(file => file.status === 'error')
  if (errorFiles.length > 0) {
    coiMsgWarning('有文件上传失败，请重新上传')
    return
  }

  // 如果有上传成功的文件，刷新列表
  const finishedFiles = uploadFileList.value.filter(file => file.status === 'finished')
  if (finishedFiles.length > 0) {
    coiMsgSuccess('所有文件上传完成')
    uploadDialogRef.value?.coiClose()
    await fetchData() // 刷新文件列表
  }
  else {
    coiMsgWarning('请先选择要上传的文件')
  }
}

// 取消上传
function handleUploadCancel() {
  uploadDialogRef.value?.coiClose()
  uploadFileList.value = []
  uploading.value = false
}

// 页面加载时获取数据
onMounted(() => {
  fetchData()
})
</script>

<style scoped>
.search-form :deep(.n-form-item-label) {
  font-size: 12px;
  color: #666;
}

.search-form :deep(.n-form-item) {
  margin-bottom: 0;
}

.file-management {
  min-height: 0;
}

.file-management .n-data-table {
  --n-th-font-weight: normal;
}

/* 表格字体和间距优化 */
.custom-table :deep(.n-data-table-td) {
  font-size: 13px;
  padding: 8px 12px;
}

.custom-table :deep(.n-data-table-th) {
  font-size: 13px;
  padding: 10px 12px;
  font-weight: 500;
}

/* 操作按钮尺寸优化 */
.custom-table :deep(.n-button--small-type) {
  font-size: 12px;
  padding: 4px 8px;
}

/* 标签尺寸优化 */
.custom-table :deep(.n-tag--small-type) {
  font-size: 11px;
  padding: 2px 6px;
}

/* 分类选择器样式 */
.category-item {
  transition: all 0.2s ease;
}

.category-selected {
  background-color: #f8faff;
  font-weight: 500;
}

.category-unselected {
  color: #666;
}

.category-unselected:hover {
  background-color: #f5f5f5;
  color: #333;
}
</style>
