You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
14 KiB

<template>
<div class="my-resources-container">
<div class="page-header">
<h1 class="page-title">我的资源</h1>
<el-button type="primary" @click="handleUpload">
<el-icon><Upload /></el-icon>
</el-button>
</div>
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
<el-tab-pane label="我上传的资源" name="uploaded">
<el-table
v-loading="loading"
:data="resources"
style="width: 100%"
empty-text="暂无资源"
>
<el-table-column prop="title" label="资源标题" min-width="200">
<template #default="scope">
<div class="resource-title-cell">
<el-icon v-if="getFileIcon(scope.row.fileType)" :size="20">
<component :is="getFileIcon(scope.row.fileType)" />
</el-icon>
<router-link :to="`/resource/${scope.row.id}`" class="resource-link">
{{ scope.row.title }}
</router-link>
</div>
</template>
</el-table-column>
<el-table-column prop="categoryName" label="分类" width="120" />
<el-table-column prop="fileSize" label="大小" width="120">
<template #default="scope">
{{ formatFileSize(scope.row.fileSize) }}
</template>
</el-table-column>
<el-table-column prop="downloadCount" label="下载次数" width="100" />
<el-table-column prop="likeCount" label="点赞数" width="100" />
<el-table-column prop="createdAt" label="上传时间" width="180">
<template #default="scope">
{{ formatDate(scope.row.createdAt) }}
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" @click="handleDownload(scope.row.id)">下载</el-button>
<el-button size="small" type="primary" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 50]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-tab-pane>
</el-tabs>
<!-- 上传资源对话框 -->
<el-dialog
v-model="uploadDialogVisible"
title="上传资源"
width="500px"
>
<el-form :model="uploadForm" label-width="80px" :rules="uploadRules" ref="uploadFormRef">
<el-form-item label="标题" prop="title">
<el-input v-model="uploadForm.title" placeholder="请输入资源标题"></el-input>
</el-form-item>
<el-form-item label="分类" prop="categoryId">
<el-select v-model="uploadForm.categoryId" placeholder="请选择分类">
<el-option
v-for="category in categories"
:key="category.id"
:label="category.name"
:value="category.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input
v-model="uploadForm.description"
type="textarea"
:rows="3"
placeholder="请输入资源描述"
></el-input>
</el-form-item>
<el-form-item label="文件" prop="file">
<el-upload
class="resource-upload"
:auto-upload="false"
:limit="1"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
>
<el-button type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
文件大小不超过50MB
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="uploadDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitUpload" :loading="uploading">
上传
</el-button>
</span>
</template>
</el-dialog>
<!-- 编辑资源对话框 -->
<el-dialog
v-model="editDialogVisible"
title="编辑资源信息"
width="500px"
>
<el-form :model="editForm" label-width="80px" :rules="editRules" ref="editFormRef">
<el-form-item label="标题" prop="title">
<el-input v-model="editForm.title" placeholder="请输入资源标题"></el-input>
</el-form-item>
<el-form-item label="分类" prop="categoryId">
<el-select v-model="editForm.categoryId" placeholder="请选择分类">
<el-option
v-for="category in categories"
:key="category.id"
:label="category.name"
:value="category.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input
v-model="editForm.description"
type="textarea"
:rows="3"
placeholder="请输入资源描述"
></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitEdit" :loading="submitting">
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox, type FormInstance } from 'element-plus';
import { resourceApi } from '@/api';
import { Upload, Document, Picture, Files, Folder, Grid, Reading, Promotion } from '@element-plus/icons-vue';
const router = useRouter();
// 资源列表数据
const resources = ref<any[]>([]);
const categories = ref<any[]>([]);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const loading = ref(false);
const activeTab = ref('uploaded');
// 上传资源相关
const uploadDialogVisible = ref(false);
const uploadFormRef = ref<FormInstance>();
const uploading = ref(false);
const uploadForm = reactive({
title: '',
description: '',
categoryId: undefined as number | undefined,
file: null as File | null
});
const uploadRules = {
title: [{ required: true, message: '请输入资源标题', trigger: 'blur' }],
categoryId: [{ required: true, message: '请选择分类', trigger: 'change' }],
file: [{ required: true, message: '请上传文件', trigger: 'change' }]
};
// 编辑资源相关
const editDialogVisible = ref(false);
const editFormRef = ref<FormInstance>();
const submitting = ref(false);
const currentEditId = ref<number | null>(null);
const editForm = reactive({
title: '',
description: '',
categoryId: undefined as number | undefined
});
const editRules = {
title: [{ required: true, message: '请输入资源标题', trigger: 'blur' }],
categoryId: [{ required: true, message: '请选择分类', trigger: 'change' }]
};
// 初始化
onMounted(async () => {
await Promise.all([
fetchMyResources(),
fetchCategories()
]);
});
// 获取我的资源列表
const fetchMyResources = async () => {
loading.value = true;
try {
const params = {
page: currentPage.value,
size: pageSize.value
};
const res = await resourceApi.getMyResources(params);
if (res.code === 200) {
resources.value = res.data.list;
total.value = res.data.total;
}
} catch (error) {
console.error('获取我的资源列表失败:', error);
ElMessage.error('获取我的资源列表失败');
} finally {
loading.value = false;
}
};
// 获取分类列表
const fetchCategories = async () => {
try {
const res = await resourceApi.getResourceCategories();
if (res.code === 200) {
categories.value = res.data.list;
}
} catch (error) {
console.error('获取分类列表失败:', error);
}
};
// 处理标签页切换
const handleTabChange = () => {
fetchMyResources();
};
// 处理分页大小变化
const handleSizeChange = (val: number) => {
pageSize.value = val;
fetchMyResources();
};
// 处理页码变化
const handleCurrentChange = (val: number) => {
currentPage.value = val;
fetchMyResources();
};
// 处理上传资源
const handleUpload = () => {
uploadDialogVisible.value = true;
};
// 处理文件变化
const handleFileChange = (file: any) => {
uploadForm.file = file.raw;
};
// 处理文件移除
const handleFileRemove = () => {
uploadForm.file = null;
};
// 提交上传
const submitUpload = async () => {
if (!uploadFormRef.value) return;
await uploadFormRef.value.validate(async (valid) => {
if (valid && uploadForm.file) {
uploading.value = true;
try {
const formData = new FormData();
formData.append('file', uploadForm.file);
formData.append('title', uploadForm.title);
formData.append('categoryId', String(uploadForm.categoryId));
formData.append('description', uploadForm.description || '');
const res = await resourceApi.uploadResource(formData);
if (res.code === 200) {
ElMessage.success('资源上传成功');
uploadDialogVisible.value = false;
resetUploadForm();
fetchMyResources();
}
} catch (error) {
console.error('上传资源失败:', error);
ElMessage.error('上传资源失败');
} finally {
uploading.value = false;
}
}
});
};
// 重置上传表单
const resetUploadForm = () => {
uploadForm.title = '';
uploadForm.description = '';
uploadForm.categoryId = undefined;
uploadForm.file = null;
if (uploadFormRef.value) {
uploadFormRef.value.resetFields();
}
};
// 处理编辑
const handleEdit = (resource: any) => {
currentEditId.value = resource.id;
editForm.title = resource.title;
editForm.description = resource.description || '';
editForm.categoryId = resource.categoryId;
editDialogVisible.value = true;
};
// 提交编辑
const submitEdit = async () => {
if (!editFormRef.value || !currentEditId.value) return;
await editFormRef.value.validate(async (valid) => {
if (valid) {
submitting.value = true;
try { const res = await resourceApi.updateResource(currentEditId.value!, editForm); if (res.code === 200) {
ElMessage.success('资源信息更新成功');
editDialogVisible.value = false;
fetchMyResources();
}
} catch (error) {
console.error('更新资源信息失败:', error);
ElMessage.error('更新资源信息失败');
} finally {
submitting.value = false;
}
}
});
};
// 处理下载
const handleDownload = async (id: number) => {
try {
const res = await resourceApi.downloadResource(id);
if (res.code === 200) {
// 创建下载链接
const link = document.createElement('a');
link.href = res.data.fileUrl;
link.download = res.data.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 刷新资源列表,更新下载次数
fetchMyResources();
}
} catch (error) {
console.error('下载资源失败:', error);
ElMessage.error('下载资源失败');
}
};
// 处理删除
const handleDelete = (id: number) => {
ElMessageBox.confirm(
'确定要删除该资源吗?此操作不可恢复',
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
const res = await resourceApi.deleteResource(id);
if (res.code === 200) {
ElMessage.success('资源删除成功');
fetchMyResources();
}
} catch (error) {
console.error('删除资源失败:', error);
ElMessage.error('删除资源失败');
}
}).catch(() => {
// 用户取消删除
});
};
// 获取文件图标
const getFileIcon = (fileType: string) => {
if (fileType.includes('pdf')) {
return Document;
} else if (fileType.includes('image')) {
return Picture;
} else if (fileType.includes('word')) {
return Reading;
} else if (fileType.includes('excel')) {
return Grid;
} else if (fileType.includes('powerpoint')) {
return Promotion;
} else if (fileType.includes('zip') || fileType.includes('rar')) {
return Folder;
} else {
return Files;
}
};
// 格式化日期
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
};
// 格式化文件大小
const formatFileSize = (size: number) => {
if (size < 1024) {
return size + ' B';
} else if (size < 1024 * 1024) {
return (size / 1024).toFixed(2) + ' KB';
} else if (size < 1024 * 1024 * 1024) {
return (size / (1024 * 1024)).toFixed(2) + ' MB';
} else {
return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
}
};
</script>
<style scoped>
.my-resources-container {
padding: 20px;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.page-title {
font-size: 24px;
margin: 0;
}
.resource-title-cell {
display: flex;
align-items: center;
gap: 8px;
}
.resource-link {
color: var(--el-color-primary);
text-decoration: none;
}
.resource-link:hover {
text-decoration: underline;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: center;
}
.resource-upload {
width: 100%;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
</style>