feat: 添加download路由用于展示文档信息
All checks were successful
deploy to server / build-and-deploy (push) Successful in 5m4s

- 添加/download/documentID路由用于文档下载
- server端添加文档元数据获取与下载API
- 将app中的types移至shared,与server共享
This commit is contained in:
2025-10-27 17:16:51 +08:00
parent 5ab72111ca
commit 4e7131b291
18 changed files with 276 additions and 0 deletions

133
app/pages/download/[id].vue Normal file
View File

@ -0,0 +1,133 @@
<template>
<div class="page-container">
<div class="page-header">
<h1 class="page-title">文件下载</h1>
<el-breadcrumb class="breadcrumb">
<el-breadcrumb-item class="text-md opacity-50">
<NuxtLink :to="$localePath('/')">{{
$t('navigation.home')
}}</NuxtLink>
</el-breadcrumb-item>
<el-breadcrumb-item class="text-md opacity-50">
<NuxtLink :to="$localePath('/products')">{{
$t('navigation.downloads')
}}</NuxtLink>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div v-if="!pending" class="page-content">
<el-card shadow="hover" class="p-4">
<template #header>
<div class="header-content">
<el-icon class="header-icon"><ElIconDocument /></el-icon>
<span class="truncate font-medium">{{
file.filename_download
}}</span>
</div>
</template>
<dl class="text-gray-600 space-y-1 mb-6">
<div>
<dt class="font-semibold inline">类型</dt>
<dd class="inline">{{ file.type }}</dd>
</div>
<div>
<dt class="font-semibold inline">大小</dt>
<dd class="inline">{{ formatFileSize(file.filesize) }}</dd>
</div>
<div>
<dt class="font-semibold inline">上传时间</dt>
<dd class="inline">
{{ new Date(file.uploaded_on).toLocaleDateString() }}
</dd>
</div>
</dl>
<template #footer>
<div class="button-group">
<el-button type="primary" @click="handleDownload">下载</el-button>
<el-button v-if="file.previewable" @click="handlePreview"
>预览</el-button
>
</div>
</template>
</el-card>
</div>
<div v-else>
<el-skeleton :rows="6" animated />
</div>
</div>
</template>
<script setup lang="ts">
const route = useRoute();
const router = useRouter();
// 获取路由参数
const id = computed(() => route.params.id as string);
const {
data: file,
pending,
error,
} = await useFetch<FileMeta>(`/api/file/${id.value}`);
if (error.value || !file.value) {
throw createError({
statusCode: 404,
statusMessage: '文件未找到',
});
}
function handleDownload() {
const link = document.createElement('a');
link.href = `/api/download/${id.value}`;
link.download = file.value?.filename_download ?? 'download';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function handlePreview() {
router.push(`/preview/${id.value}`);
}
</script>
<style scoped>
.page-container {
padding: 2rem;
margin: 0 auto;
max-width: 1200px;
}
.page-header {
display: flex;
}
.page-title {
font-size: 2rem;
font-weight: bold;
color: var(--el-color-primary);
margin-bottom: 1rem;
}
.breadcrumb {
margin-left: auto;
}
.header-content {
display: flex;
align-items: center;
gap: 3px;
margin-bottom: 4px;
}
.header-icon {
font-size: 1.5rem;
margin-right: 0.5rem;
}
.button-group {
display: flex;
justify-content: flex-end;
align-items: baseline;
gap: 1rem;
}
</style>