请求拦截Code
Yann authored at 2025-07-01 14:00:58 Yann committed at 2025-07-01 15:20:51
8.82 KiB
cube-front
<template>
  <div>
    <div class="page-header">
      <h1>文件管理</h1>
      <p>文件上传、下载、压缩解压等管理操作</p>
    </div>

    <el-card>
      <template #header>
        <div class="card-header">
          <span>文件操作</span>
          <div>
            <el-button type="primary" @click="showUploadDialog = true">
              <el-icon><Plus /></el-icon>
              上传文件
            </el-button>
            <el-button @click="refreshFileList">
              <el-icon><Refresh /></el-icon>
              刷新
            </el-button>
          </div>
        </div>
      </template>

      <div class="file-operations">
        <el-form :model="queryForm" inline>
          <el-form-item label="路径">
            <el-input
              v-model="queryForm.r"
              placeholder="请输入文件路径"
              style="width: 300px"
            />
          </el-form-item>
          <el-form-item label="排序">
            <el-select v-model="queryForm.sort" placeholder="选择排序方式" style="width: 120px">
              <el-option label="名称" value="name" />
              <el-option label="大小" value="size" />
              <el-option label="时间" value="time" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="getFileList">查询</el-button>
          </el-form-item>
        </el-form>
      </div>

      <div class="file-list" v-loading="loading.list">
        <el-table :data="fileList" style="width: 100%">
          <el-table-column prop="name" label="文件名" />
          <el-table-column prop="size" label="大小" />
          <el-table-column prop="modified" label="修改时间" />
          <el-table-column prop="type" label="类型" />
          <el-table-column label="操作" width="300">
            <template #default="{ row }">
              <el-button size="small" @click="handleDownload(row)">
                下载
              </el-button>
              <el-button size="small" @click="handleCompress(row)">
                压缩
              </el-button>
              <el-button size="small" @click="handleDecompress(row)">
                解压
              </el-button>
              <el-button size="small" @click="handleCopy(row)">
                复制
              </el-button>
              <el-button size="small" type="danger" @click="handleDelete(row)">
                删除
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-card>

    <!-- 上传对话框 -->
    <el-dialog v-model="showUploadDialog" title="上传文件" width="500px">
      <el-form :model="uploadForm" label-width="80px">
        <el-form-item label="上传路径">
          <el-input v-model="uploadForm.r" placeholder="请输入上传路径" />
        </el-form-item>
        <el-form-item label="选择文件">
          <el-upload
            ref="uploadRef"
            :action="uploadAction"
            :data="uploadForm"
            :auto-upload="false"
            :show-file-list="true"
            :limit="1"
          >
            <el-button type="primary">选择文件</el-button>
          </el-upload>
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="showUploadDialog = false">取消</el-button>
        <el-button type="primary" :loading="loading.upload" @click="handleUpload">
          上传
        </el-button>
      </template>
    </el-dialog>

    <!-- 头像上传对话框 -->
    <el-dialog v-model="showAvatarDialog" title="上传头像" width="400px">
      <el-upload
        ref="avatarUploadRef"
        action="/Admin/File/UploadAvatar"
        :auto-upload="false"
        :show-file-list="true"
        :limit="1"
        accept="image/*"
      >
        <el-button type="primary">选择头像</el-button>
        <template #tip>
          <div class="el-upload__tip">
            只能上传jpg/png文件,且不超过2MB
          </div>
        </template>
      </el-upload>

      <template #footer>
        <el-button @click="showAvatarDialog = false">取消</el-button>
        <el-button type="primary" :loading="loading.avatar" @click="handleAvatarUpload">
          上传
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessageBox } from 'element-plus'
import { Plus, Refresh } from '@element-plus/icons-vue'
import { request } from '@core/utils/request'

// 文件信息接口
interface FileInfo {
  name: string
  size: string
  modified: string
  type: string
  path: string
}

// 对话框状态
const showUploadDialog = ref(false)
const showAvatarDialog = ref(false)

// 表单数据
const queryForm = reactive({
  r: '',
  sort: 'name',
  message: ''
})

const uploadForm = reactive({
  r: ''
})

// 数据
const fileList = ref<FileInfo[]>([])

// 加载状态
const loading = reactive({
  list: false,
  upload: false,
  avatar: false
})

// 上传组件引用
const uploadRef = ref()
const avatarUploadRef = ref()

// 上传地址
const uploadAction = '/Admin/File/Upload'

// 获取文件列表
const getFileList = async () => {
  try {
    loading.list = true

    const data = await request.get('/Admin/File', {
      params: {
        r: queryForm.r || undefined,
        sort: queryForm.sort || undefined,
        message: queryForm.message || undefined
      }
    })

    // 处理不同的响应格式
    if (data && typeof data === 'object' && 'data' in data) {
      fileList.value = Array.isArray(data.data) ? data.data : []
    } else if (Array.isArray(data)) {
      fileList.value = data
    } else {
      fileList.value = []
    }
  } catch {
    fileList.value = []
  } finally {
    loading.list = false
  }
}

// 刷新文件列表
const refreshFileList = () => {
  getFileList()
}

// 上传文件
const handleUpload = async () => {
  try {
    loading.upload = true

    // 触发上传
    await uploadRef.value.submit()

    showUploadDialog.value = false
    uploadForm.r = ''
    refreshFileList()
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  } finally {
    loading.upload = false
  }
}

// 上传头像
const handleAvatarUpload = async () => {
  try {
    loading.avatar = true

    // 触发上传
    await avatarUploadRef.value.submit()

    showAvatarDialog.value = false
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  } finally {
    loading.avatar = false
  }
}

// 下载文件
const handleDownload = async (row: FileInfo) => {
  try {
    // 使用 request 发送下载请求,获取二进制数据
    const blob = await request.post('/Admin/File/Download',
      { r: row.path },
      {
        responseType: 'blob'
      }
    )

    // 创建下载链接
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = row.name
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  }
}

// 压缩文件
const handleCompress = async (row: FileInfo) => {
  try {
    await request.post('/Admin/File/Compress', { r: row.path })
    refreshFileList()
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  }
}

// 解压文件
const handleDecompress = async (row: FileInfo) => {
  try {
    await request.post('/Admin/File/Decompress', { r: row.path })
    refreshFileList()
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  }
}

// 复制文件
const handleCopy = async (row: FileInfo) => {
  try {
    await request.post('/Admin/File/Copy', { r: row.path, f: row.name })
    // 复制操作成功会通过request拦截器自动提示
  } catch {
    // 错误提示已经在 request 拦截器中自动处理
  }
}

// 删除文件
const handleDelete = async (row: FileInfo) => {
  try {
    await ElMessageBox.confirm(
      `确定要删除文件 "${row.name}" 吗?`,
      '确认删除',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
    )

    await request.post('/Admin/File/Delete', { r: row.path })
    refreshFileList()
  } catch (error) {
    if (error !== 'cancel') {
      // 错误提示已经在 request 拦截器中自动处理
    }
  }
}

// 组件挂载时获取文件列表
onMounted(() => {
  getFileList()
})
</script>

<style scoped>
.page-header {
  margin-bottom: 20px;
}

.page-header h1 {
  margin: 0 0 8px 0;
  font-size: 24px;
  font-weight: 500;
}

.page-header p {
  margin: 0;
  color: #666;
  font-size: 14px;
}

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

.file-operations {
  margin-bottom: 20px;
}

.file-list {
  margin-top: 20px;
}
</style>