Repository navigation
upload components
面向在 SandAdmin / Sand Core 管理端开发插件表单的 Vue 3 开发者。组件由前端自动注册,在已配置上传存储、已登录且具有相应权限的宿主环境中使用。普通附件用 sa-file-upload;需要分片进度和手动开始上传时用 sa-chunk-upload。以下是源码对应的接入参考,不代表本次已运行真实 HTTP 上传。
一个支持大文件分片上传的 Vue 3 组件,基于 Element Plus 的 el-upload 封装。
- ✅ 分片上传: 自动将大文件切分成小块上传,支持自定义分片大小
- ✅ MD5 标识: 自动计算文件 MD5,随分片请求发送作为文件标识
- ✅ 进度跟踪: 实时显示上传进度、当前分片、上传速度
- ✅ 失败重试: 上传失败后可重试,当前重试从首个分片重新开始,不承诺断点续传或刷新续传
- ✅ 取消上传: 可随时取消正在进行的上传任务
- ✅ 拖拽上传: 支持拖拽文件到指定区域上传
- ✅ 文件验证: 支持文件类型和大小验证
- ✅ 并发控制: 串行上传多个文件,避免服务器压力过大
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| modelValue | v-model 绑定值,文件 URL | string | string[] |
[] |
| multiple | 是否支持多选文件 | boolean |
false |
| limit | 最大上传文件数量 | number |
1 |
| maxSize | 单个文件最大大小(MB) | number |
1024 |
| chunkSize | 分片大小(MB) | number |
5 |
| accept | 接受的文件类型 | string |
'*' |
| acceptHint | 文件类型提示文本 | string |
'' |
| disabled | 是否禁用 | boolean |
false |
| drag | 是否启用拖拽上传 | boolean |
true |
| buttonText | 按钮文本 | string |
'选择文件' |
| autoUpload | 是否自动上传 | boolean |
false |
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 文件 URL 更新 | (value: string | string[]) |
| success | 上传成功 | (response: any) |
| error | 上传失败 | (error: any) |
| progress | 上传进度更新 | (progress: number) |
<template>
<sa-chunk-upload v-model="fileUrl" />
</template>
<script setup>
import { ref } from 'vue'
const fileUrl = ref('')
</script><template>
<sa-chunk-upload
v-model="videoUrl"
accept="video/*"
accept-hint="MP4、AVI、MOV"
:max-size="2048"
:chunk-size="10"
:drag="true"
@success="handleSuccess"
@progress="handleProgress"
/>
</template>
<script setup>
import { ref } from 'vue'
const videoUrl = ref('')
const handleSuccess = (response) => {
console.log('上传成功:', response)
}
const handleProgress = (progress) => {
console.log('上传进度:', progress + '%')
}
</script><template>
<sa-chunk-upload
v-model="fileUrls"
:multiple="true"
:limit="5"
:chunk-size="5"
/>
</template>
<script setup>
import { ref } from 'vue'
const fileUrls = ref([])
</script><template>
<!-- 只允许上传压缩文件 -->
<sa-chunk-upload
v-model="zipUrl"
accept=".zip,.rar,.7z"
accept-hint="ZIP、RAR、7Z"
:max-size="500"
/>
<!-- 只允许上传 PDF -->
<sa-chunk-upload
v-model="pdfUrl"
accept=".pdf"
accept-hint="PDF"
/>
</template><template>
<sa-chunk-upload
v-model="fileUrl"
:auto-upload="true"
/>
</template><template>
<sa-chunk-upload
v-model="fileUrl"
:auto-upload="false"
/>
<!-- 组件会自动显示"开始上传"按钮 -->
</template>组件会调用 chunkUpload API,每个分片上传时会发送以下参数:
{
file: Blob, // 当前分片
ext: string, // 文件扩展名
size: string, // 整个文件字节数
type: string, // MIME 类型
hash: string, // 整个文件的 MD5
index: string, // 当前分片索引,从 0 开始
total: string, // 分片总数
name: string // 原文件名
}当前 API 是 /core/system/chunkUpload,以 FormData 发送以上字段;数字字段通过 toString() 发送。宿主已有 ChunkUploadService 负责接收、合并和记录附件,插件接入者无需重复实现服务。组件从 API 解包后的结果读取 url;最终成功后更新 v-model,并触发 success({ url, hash })。
-
接收分片: 根据
hash和index保存分片 -
合并文件: 当接收到所有分片后(
index === total - 1),合并所有分片 - 返回 URL: 合并完成后返回文件访问 URL
- 失败重试: 当前组件从首个分片重新开始;已有后端分片检查能力不代表当前组件实现了断点续传
{
"code": 200,
"data": {
"url": "/uploads/abc123def456/example.mp4",
"hash": "abc123def456"
},
"message": "上传成功"
}- 文件选择: 用户选择文件后,组件计算文件需要分成多少片
- MD5 计算: 计算整个文件的 MD5 哈希值,作为分片文件标识
- 分片上传: 按顺序上传每个分片,实时更新进度
- 进度显示: 显示当前分片、总分片数、上传速度
- 完成处理: 所有分片上传完成后,更新 v-model 值
-
分片大小:
- 网络较好: 可设置 10-20MB
- 网络一般: 建议 5-10MB
- 网络较差: 建议 2-5MB
-
文件大小限制: 根据实际需求设置合理的
maxSize -
并发控制: 组件默认串行上传文件,避免同时上传多个大文件
- 当前前端清单已有
spark-md5和@types/spark-md5;按宿主安装流程安装依赖即可。 - 服务端上传配置须允许目标扩展名,上传目录须可写;使用已登录且有上传权限的宿主环境。
- MD5 用于标识文件;本说明不承诺后端会重新校验分片内容。
- 大文件上传时注意服务器及代理的请求体和超时限制。
- 成功应看到文件地址写入
v-model;若收到格式拒绝,核对服务端允许的扩展名;若返回“上传完成但未返回文件地址”,应查看上传 API 响应和宿主日志,再重试。
pnpm add spark-md5
pnpm add -D @types/spark-md5使用 /core/system/uploadFile。默认单选、最多一个文件、大小上限 10 MB,不启用拖拽;选中文件后立即上传。多选需要同时设置 multiple 和 limit。accept 是客户端筛选,服务端允许的扩展名仍由宿主配置决定。
以下示例保留单文件、多文件、拖拽、PDF/Word、压缩文件五种使用方式。成功后 v-model 获得地址(多文件为地址数组);上传失败时组件显示错误,确认格式、大小和权限后重新选择上传。
<!--
sa-file-upload 组件使用示例
基本用法:
<sa-file-upload v-model="fileUrl" />
多文件上传:
<sa-file-upload v-model="fileUrls" :multiple="true" :limit="5" />
拖拽上传:
<sa-file-upload v-model="fileUrl" :drag="true" />
限制文件类型:
<sa-file-upload
v-model="fileUrl"
accept=".pdf,.doc,.docx"
accept-hint="PDF、Word"
/>
-->
<template>
<div class="demo-container">
<h2>文件上传组件示例</h2>
<!-- 示例1: 基本用法 -->
<el-card header="基本用法" class="demo-card">
<sa-file-upload v-model="singleFile" />
<div class="result">当前文件: {{ singleFile }}</div>
</el-card>
<!-- 示例2: 多文件上传 -->
<el-card header="多文件上传" class="demo-card">
<sa-file-upload
v-model="multipleFiles"
:multiple="true"
:limit="5"
/>
<div class="result">当前文件: {{ multipleFiles }}</div>
</el-card>
<!-- 示例3: 拖拽上传 -->
<el-card header="拖拽上传" class="demo-card">
<sa-file-upload
v-model="dragFile"
:drag="true"
button-text="点击或拖拽上传"
/>
<div class="result">当前文件: {{ dragFile }}</div>
</el-card>
<!-- 示例4: 限制文件类型 - PDF/Word -->
<el-card header="限制文件类型 (PDF、Word)" class="demo-card">
<sa-file-upload
v-model="docFile"
accept=".pdf,.doc,.docx"
accept-hint="PDF、Word"
:max-size="20"
/>
<div class="result">当前文件: {{ docFile }}</div>
</el-card>
<!-- 示例5: 限制文件类型 - Excel -->
<el-card header="限制文件类型 (Excel)" class="demo-card">
<sa-file-upload
v-model="excelFile"
accept=".xls,.xlsx"
accept-hint="Excel"
/>
<div class="result">当前文件: {{ excelFile }}</div>
</el-card>
<!-- 示例6: 压缩文件 -->
<el-card header="压缩文件上传" class="demo-card">
<sa-file-upload
v-model="zipFile"
accept=".zip,.rar,.7z"
accept-hint="ZIP、RAR、7Z"
:max-size="50"
:drag="true"
/>
<div class="result">当前文件: {{ zipFile }}</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const singleFile = ref('')
const multipleFiles = ref<string[]>([])
const dragFile = ref('')
const docFile = ref('')
const excelFile = ref('')
const zipFile = ref('')
</script>
<style scoped lang="scss">
.demo-container {
padding: 20px;
h2 {
margin-bottom: 20px;
}
.demo-card {
margin-bottom: 20px;
.result {
margin-top: 15px;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
font-size: 12px;
color: #606266;
word-break: break-all;
}
}
}
</style>
返回插件开发与发布。
开始使用
基础包参考
开发插件
版本更新
版本和维护