@pbkj/msm-upload-client
v1.1.2
Published
Browser SDK and Vue 3 components for msm-base-upload multipart file uploads.
Maintainers
Readme
@pbkj/msm-upload-client
面向 msm-base-upload 的 Vue 3 上传组件库,用于在业务系统中打开上传弹窗并调用后端上传接口,默认请求 POST /sys-admin/api/base-file/upload。
该包对外推荐只使用 Vue 3 组件入口:
import { MsmUploadButton, MsmUploadDialog } from "@pbkj/msm-upload-client/vue";底层上传 SDK 仍保留为组件内部实现和历史兼容能力,但不作为业务系统的推荐接入方式。
安装
npm install @pbkj/msm-upload-client业务项目需要使用 Vue 3:
npm install vue@3快速使用
<script setup lang="ts">
import { MsmUploadButton } from "@pbkj/msm-upload-client/vue";
import type { MsmUploadResult } from "@pbkj/msm-upload-client";
function handleConfirm(results: MsmUploadResult[]) {
console.log("用户确认的上传结果", results);
}
</script>
<template>
<MsmUploadButton
token="your-token-value"
bucket="article"
button-text="选择文件"
@confirm="handleConfirm"
/>
</template>base-url 默认是 /sys-admin,upload-path 默认是 /api/base-file/upload,因此不传 base-url 时会直接请求 /sys-admin/api/base-file/upload。base-url 是接口前缀,upload-path 是上传接口路径,两个参数互不修正斜杠,最终请求地址始终是 ${baseUrl}${uploadPath}。例如 base-url="https://example.com" 时最终请求 https://example.com/api/base-file/upload;如果传入 base-url="https://example.com/",则会请求 https://example.com//api/base-file/upload。
认证默认使用后端约定的 x-u-token 请求头。推荐通过 token prop 传入;如果没有传入 token,且 headers 中也没有 x-u-token,组件会尝试读取浏览器 localStorage["mzk-token"] 并自动写入 x-u-token 请求头。
组件行为
点击 MsmUploadButton 后会打开上传弹窗。默认只显示“上传文件”页签;传入 show-media-library 后才会显示“媒资库”页签。
上传文件:选择文件后立即上传,显示文件名、大小、进度、成功或失败状态媒资库:调用媒资列表接口,按fileType自动筛选图片或视频,支持关键词搜索、分页、进入文件夹和选择已有媒资文件
上传成功后,结果只保存在弹窗内部。调用方只有在用户点击右下角 确定 后,才会通过 confirm(results) 事件收到上传结果;点击 取消 或右上角关闭按钮不会触发 confirm。
其他行为:
- 存在上传中的文件时,
确定按钮禁用 - 存在失败文件时,
确定只返回成功上传的结果 - 已上传成功的文件可以从列表中删除,删除只影响本次弹窗结果,不调用后端删除接口
- 图片上传成功后会显示缩略图,点击缩略图可预览图片并查看上传成功后的
url - 点击弹窗外层 mask 不会关闭弹窗
- 媒资库中选择的文件会在点击
确定后和上传成功结果一起返回
常用配置
bucket
<MsmUploadButton
bucket="video"
@confirm="(results) => console.log(results)"
/>bucket 会作为上传参数提交给后端,用于区分保存目录或业务分类。
多文件上传
<MsmUploadButton
bucket="article"
multiple
@confirm="(results) => console.log(results)"
/>未传 multiple 时为单文件模式。单文件模式下即使浏览器或调用方传入多个文件,组件也只取第一个文件上传,并替换当前弹窗列表。
文件类型限制
<MsmUploadButton
file-type="picture"
@upload-error="(item) => console.log(item.error)"
/>fileType 只支持三类:
all:默认值,不限制上传文件类型,媒资库不传typepicture:只允许图片;文件选择框只展示图片类型,媒资库请求type=1video:只允许视频;文件选择框只展示视频类型,媒资库请求type=3
组件会在上传前校验文件类型。不匹配的文件不会发起上传,会在弹窗列表中显示失败状态,错误信息为 不支持的文件类型,并触发 upload-error(item)。前端限制只用于交互体验,不能替代后端白名单校验。
自动分片上传
<MsmUploadButton
bucket="video"
:chunk-size="5 * 1024 * 1024"
@confirm="(results) => console.log(results)"
/>组件内部始终按自动分片逻辑执行:文件大小大于 chunk-size 时自动分片,否则普通上传。chunk-size 默认值为 5MB。例如上传 60MB 文件且分片大小为 5MB 时,会发起多次 /sys-admin/api/base-file/upload 请求。分片上传进度只会在每个分片接口返回后推进,最后一个分片接口返回前不会显示 100%。
自定义请求头
<script setup lang="ts">
import { MsmUploadButton } from "@pbkj/msm-upload-client/vue";
const headers = {
"x-u-token": "your-token-value"
};
</script>
<template>
<MsmUploadButton
:headers="headers"
@confirm="(results) => console.log(results)"
/>
</template>不要手动设置 Content-Type,组件会交给浏览器自动生成 multipart/form-data boundary。
媒资库选择
<MsmUploadButton
token="your-token-value"
show-media-library
:media-office-int-id="1001"
file-type="picture"
media-search-text="会议"
:media-page-size="12"
@confirm="(results) => console.log(results)"
/>媒资库默认调用:
/aiMediaApi/appapi/mediaResources/recommend/list请求方式为 POST JSON。组件会按当前 UI 状态提交:
officeIntId:来自media-office-int-id,使用媒资库时必传,类型为整数机构 IDtype:由fileType自动映射,picture提交1,video提交3,all不传parentId:进入文件夹时提交文件夹 ID;有搜索关键词时提交0searchText:关键词搜索page、pageSize:分页参数
媒资请求复用上传组件的 token/headers 认证配置,token 会写入 x-u-token。媒资列表接口的 Content-Type 固定为 application/json。
媒资列表响应格式:
{
"code": 0,
"msg": "success",
"data": {
"total": 1,
"rows": []
}
}组件从 data.rows 读取列表,从 data.total 读取总数。
媒资库中的 type=9 为文件夹,只能点击进入子列表,不会被选中。非文件夹媒资可选择;multiple=false 时只保留一个媒资选择,multiple=true 时可跨分页或文件夹选择多个媒资文件。
受控弹窗
如果业务系统需要自己控制弹窗显隐,可以直接使用 MsmUploadDialog:
<script setup lang="ts">
import { ref } from "vue";
import { MsmUploadDialog } from "@pbkj/msm-upload-client/vue";
import type { MsmUploadResult } from "@pbkj/msm-upload-client";
const visible = ref(false);
function handleConfirm(results: MsmUploadResult[]) {
console.log(results);
}
</script>
<template>
<button type="button" @click="visible = true">打开上传弹窗</button>
<MsmUploadDialog
v-model="visible"
bucket="article"
multiple
file-type="picture"
show-media-library
:media-office-int-id="1001"
@confirm="handleConfirm"
/>
</template>Props
MsmUploadButton
| Prop | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| baseUrl | string | /sys-admin | 后端接口前缀 |
| uploadPath | string | /api/base-file/upload | 上传接口路径 |
| token | string \| null | - | 写入 x-u-token 请求头的 token |
| headers | object \| () => object \| Promise<object> | - | 自定义请求头 |
| bucket | string \| null | - | 上传 bucket 参数 |
| multiple | boolean | false | 是否允许多文件上传 |
| fileType | "all" \| "picture" \| "video" | "all" | 文件类型限制,同时控制媒资库类型筛选 |
| chunkSize | number | 5 * 1024 * 1024 | 分片大小 |
| timeout | number | - | 请求超时时间,单位毫秒 |
| disabled | boolean | false | 是否禁用触发按钮 |
| buttonText | string | 选择文件 | 触发按钮文案 |
| client | MsmUploadClient | - | 兼容/高级用法:传入已创建的底层上传客户端 |
| showMediaLibrary | boolean | false | 是否显示媒资库页签 |
| mediaApiUrl | string | 媒资推荐列表接口 | 媒资库列表接口地址 |
| mediaOfficeIntId | number | - | 媒资库查询机构整数 ID |
| mediaSearchText | string | - | 媒资库初始搜索关键词 |
| mediaPageSize | number | 10 | 媒资库每页数量 |
MsmUploadDialog
MsmUploadDialog 支持 MsmUploadButton 的上传配置 props,并额外支持:
| Prop | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| modelValue | boolean | - | 控制弹窗显隐,支持 v-model |
| title | string | 上传文件 | 弹窗标题 |
| confirmText | string | 确定 | 确认按钮文案 |
| cancelText | string | 取消 | 取消按钮文案 |
Events
| 事件 | 参数 | 说明 |
|------|------|------|
| select | files: File[] | 用户选择文件后触发 |
| upload-start | item | 单个文件开始上传 |
| upload-progress | item | 单个文件上传进度变化 |
| upload-success | item | 单个文件上传成功 |
| upload-error | item | 单个文件上传失败或类型不匹配 |
| remove | item | 用户删除已上传成功文件 |
| media-load | { items, pagination, parentId } | 媒资列表加载成功 |
| media-error | error | 媒资列表加载失败 |
| media-select | items | 媒资库选择变化 |
| confirm | results: MsmUploadResult[] | 用户点击 确定 后返回成功结果 |
| cancel | - | 用户点击 取消 或关闭弹窗 |
| update:modelValue | visible: boolean | 仅 MsmUploadDialog,用于 v-model |
上传过程事件中的 item.actualUploadMode 表示当前文件实际使用的上传方式,取值为 file 或 chunks。
返回结果
confirm(results) 返回仍保留在弹窗列表中的成功上传结果,以及用户在媒资库选择的已有文件结果。上传结果排在前面,媒资库选择结果排在后面。
interface MsmUploadResult {
status: "success" | "uploading" | string;
url: string | null;
path: string | null;
bucket: string | null;
complete: boolean;
uuid: string | null;
chunk: number | null;
chunks: number | null;
originalFilename: string | null;
size: number;
source?: "upload" | "media";
mediaId?: number | null;
mediaFileId?: number | null;
mediaTitle?: string | null;
thumbnailUrl?: string | null;
coverUrl?: string | null;
mediaSourceType?: string | null;
}字段说明:
url:文件访问地址,适合前端展示或下载path:基于后端msm.upload.base-path的本地相对路径,以/开头complete:是否已完成上传;分片上传只有最后一个分片合并成功后才为trueuuid/chunk/chunks:分片上传相关字段,普通上传可能为nullsource:媒资库选择结果为media;上传结果可能为空或由后端返回mediaFileId/mediaId/mediaTitle:媒资库选择结果的媒资文件 ID、媒资 ID 和标题thumbnailUrl/coverUrl/mediaSourceType:媒资库选择结果的缩略图、封面和来源类型
媒资库选择结果按接口字段转换:
url取mediaResources.mediaResourcesFile.fileUrlpath取filePath || localPath || nulloriginalFilename取fileName || mediaResources.titlesize取fileSize || 0bucket/uuid/chunk/chunks固定为null
后端统一响应字段以 msm-base-upload 源码为准:code、msg、data。
错误处理
组件不会把失败文件返回到 confirm(results) 中。业务系统可以监听 upload-error(item) 获取失败原因:
<MsmUploadButton
file-type="picture"
@upload-error="(item) => console.error(item.name, item.error)"
@confirm="(results) => console.log(results)"
/>常见失败场景:
- 文件类型不匹配
fileType - HTTP 状态码不是
2xx - 响应不是合法 JSON
- 后端统一响应
code !== 0 - 后端成功响应中
data为空 - 请求超时、网络错误或上传被取消
Demo 测试
仓库内提供 Vue 3 + Vite 示例项目用于人工验证上传:
cd frontend-libs/msm-upload-client
npm.cmd install
npm.cmd run build
cd ../msm-upload-client-demo
npm.cmd install
npm.cmd run dev浏览器打开 Vite 输出地址后,可以在页面中配置 baseUrl、bucket、是否多选、fileType、分片大小、媒资接口地址、媒资机构整数 ID 和默认搜索关键词,并查看事件日志与 confirm(results) 返回值。
Demo 不包含 mock 后端,需要使用已经启动的真实 msm-base-upload 服务和可访问的媒资接口。如果上传或媒资列表加载失败,请优先检查页面配置的完整接口地址、浏览器 Network 和 Console。
