reactor:【INFRA】文件上传 api,增加 directory 参数,去除 path 参数,并支持按照日期分目录、文件名不再使用 sha256 而是时间戳
parent
368f7c753f
commit
91d70b41cb
|
@ -259,6 +259,7 @@ setupVbenVxeTable({
|
||||||
|
|
||||||
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
|
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
|
||||||
// vxeUI.formats.add
|
// vxeUI.formats.add
|
||||||
|
// add by 星语:数量格式化,例如说:金额
|
||||||
vxeUI.formats.add('formatAmount', {
|
vxeUI.formats.add('formatAmount', {
|
||||||
cellFormatMethod({ cellValue }, digits = 2) {
|
cellFormatMethod({ cellValue }, digits = 2) {
|
||||||
if (cellValue === null || cellValue === undefined) {
|
if (cellValue === null || cellValue === undefined) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ export namespace BpmCategoryApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 模型分类信息 */
|
/** 模型分类信息 */
|
||||||
|
// TODO @jason:这个应该非 api 的,可以考虑抽到页面里哈。
|
||||||
export interface ModelCategoryInfo {
|
export interface ModelCategoryInfo {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace BpmModelApi {
|
export namespace BpmModelApi {
|
||||||
/** 用户信息 TODO 这个是不是可以抽取出来定义在公共模块 */
|
/** 用户信息 TODO 这个是不是可以抽取出来定义在公共模块 */
|
||||||
|
// TODO @芋艿:一起看看。
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
id: number;
|
id: number;
|
||||||
nickname: string;
|
nickname: string;
|
||||||
|
@ -9,6 +10,7 @@ export namespace BpmModelApi {
|
||||||
deptId?: number;
|
deptId?: number;
|
||||||
deptName?: string;
|
deptName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 流程定义 VO */
|
/** 流程定义 VO */
|
||||||
export interface ProcessDefinitionVO {
|
export interface ProcessDefinitionVO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -23,12 +23,13 @@ export namespace InfraFileApi {
|
||||||
configId: number; // 文件配置编号
|
configId: number; // 文件配置编号
|
||||||
uploadUrl: string; // 文件上传 URL
|
uploadUrl: string; // 文件上传 URL
|
||||||
url: string; // 文件 URL
|
url: string; // 文件 URL
|
||||||
|
path: string; // 文件路径
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 上传文件 */
|
/** 上传文件 */
|
||||||
export interface FileUploadReqVO {
|
export interface FileUploadReqVO {
|
||||||
file: globalThis.File;
|
file: globalThis.File;
|
||||||
path?: string;
|
directory?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +46,11 @@ export function deleteFile(id: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取文件预签名地址 */
|
/** 获取文件预签名地址 */
|
||||||
export function getFilePresignedUrl(path: string) {
|
export function getFilePresignedUrl(name: string, directory?: string) {
|
||||||
return requestClient.get<InfraFileApi.FilePresignedUrlRespVO>(
|
return requestClient.get<InfraFileApi.FilePresignedUrlRespVO>(
|
||||||
'/infra/file/presigned-url',
|
'/infra/file/presigned-url',
|
||||||
{
|
{
|
||||||
params: { path },
|
params: { name, directory },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -64,5 +65,9 @@ export function uploadFile(
|
||||||
data: InfraFileApi.FileUploadReqVO,
|
data: InfraFileApi.FileUploadReqVO,
|
||||||
onUploadProgress?: AxiosProgressEvent,
|
onUploadProgress?: AxiosProgressEvent,
|
||||||
) {
|
) {
|
||||||
|
// 特殊:由于 upload 内部封装,即使 directory 为 undefined,也会传递给后端
|
||||||
|
if (!data.directory) {
|
||||||
|
delete data.directory;
|
||||||
|
}
|
||||||
return requestClient.upload('/infra/file/upload', data, { onUploadProgress });
|
return requestClient.upload('/infra/file/upload', data, { onUploadProgress });
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ const props = withDefaults(
|
||||||
file: File,
|
file: File,
|
||||||
onUploadProgress?: AxiosProgressEvent,
|
onUploadProgress?: AxiosProgressEvent,
|
||||||
) => Promise<AxiosResponse<any>>;
|
) => Promise<AxiosResponse<any>>;
|
||||||
|
// 上传的目录
|
||||||
|
directory?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
// 最大数量的文件,Infinity不限制
|
// 最大数量的文件,Infinity不限制
|
||||||
|
@ -44,13 +46,14 @@ const props = withDefaults(
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
value: () => [],
|
value: () => [],
|
||||||
|
directory: undefined,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
helpText: '',
|
helpText: '',
|
||||||
maxSize: 2,
|
maxSize: 2,
|
||||||
maxNumber: 1,
|
maxNumber: 1,
|
||||||
accept: () => [],
|
accept: () => [],
|
||||||
multiple: false,
|
multiple: false,
|
||||||
api: useUpload().httpRequest,
|
api: undefined,
|
||||||
resultField: '',
|
resultField: '',
|
||||||
showDescription: false,
|
showDescription: false,
|
||||||
},
|
},
|
||||||
|
@ -141,10 +144,9 @@ const beforeUpload = async (file: File) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function customRequest(info: UploadRequestOption<any>) {
|
async function customRequest(info: UploadRequestOption<any>) {
|
||||||
const { api } = props;
|
let { api } = props;
|
||||||
if (!api || !isFunction(api)) {
|
if (!api || !isFunction(api)) {
|
||||||
console.warn('upload api must exist and be a function');
|
api = useUpload(props.directory).httpRequest;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// 上传文件
|
// 上传文件
|
||||||
|
|
|
@ -30,6 +30,8 @@ const props = withDefaults(
|
||||||
file: File,
|
file: File,
|
||||||
onUploadProgress?: AxiosProgressEvent,
|
onUploadProgress?: AxiosProgressEvent,
|
||||||
) => Promise<AxiosResponse<any>>;
|
) => Promise<AxiosResponse<any>>;
|
||||||
|
// 上传的目录
|
||||||
|
directory?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
listType?: UploadListType;
|
listType?: UploadListType;
|
||||||
|
@ -47,6 +49,7 @@ const props = withDefaults(
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
value: () => [],
|
value: () => [],
|
||||||
|
directory: undefined,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
listType: 'picture-card',
|
listType: 'picture-card',
|
||||||
helpText: '',
|
helpText: '',
|
||||||
|
@ -54,7 +57,7 @@ const props = withDefaults(
|
||||||
maxNumber: 1,
|
maxNumber: 1,
|
||||||
accept: () => defaultImageAccepts,
|
accept: () => defaultImageAccepts,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
api: useUpload().httpRequest,
|
api: undefined,
|
||||||
resultField: '',
|
resultField: '',
|
||||||
showDescription: true,
|
showDescription: true,
|
||||||
},
|
},
|
||||||
|
@ -177,10 +180,9 @@ const beforeUpload = async (file: File) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function customRequest(info: UploadRequestOption<any>) {
|
async function customRequest(info: UploadRequestOption<any>) {
|
||||||
const { api } = props;
|
let { api } = props;
|
||||||
if (!api || !isFunction(api)) {
|
if (!api || !isFunction(api)) {
|
||||||
console.warn('upload api must exist and be a function');
|
api = useUpload(props.directory).httpRequest;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// 上传文件
|
// 上传文件
|
||||||
|
|
|
@ -7,8 +7,7 @@ import { computed, unref } from 'vue';
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
import CryptoJS from 'crypto-js';
|
// import CryptoJS from 'crypto-js';
|
||||||
|
|
||||||
import { createFile, getFilePresignedUrl, uploadFile } from '#/api/infra/file';
|
import { createFile, getFilePresignedUrl, uploadFile } from '#/api/infra/file';
|
||||||
import { baseRequestClient } from '#/api/request';
|
import { baseRequestClient } from '#/api/request';
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ export function useUploadType({
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @芋艿:目前保持和 admin-vue3 一致,后续可能重构
|
// TODO @芋艿:目前保持和 admin-vue3 一致,后续可能重构
|
||||||
export const useUpload = () => {
|
export const useUpload = (directory?: string) => {
|
||||||
// 后端上传地址
|
// 后端上传地址
|
||||||
const uploadUrl = getUploadUrl();
|
const uploadUrl = getUploadUrl();
|
||||||
// 是否使用前端直连上传
|
// 是否使用前端直连上传
|
||||||
|
@ -97,7 +96,7 @@ export const useUpload = () => {
|
||||||
// 1.1 生成文件名称
|
// 1.1 生成文件名称
|
||||||
const fileName = await generateFileName(file);
|
const fileName = await generateFileName(file);
|
||||||
// 1.2 获取文件预签名地址
|
// 1.2 获取文件预签名地址
|
||||||
const presignedInfo = await getFilePresignedUrl(fileName);
|
const presignedInfo = await getFilePresignedUrl(fileName, directory);
|
||||||
// 1.3 上传文件
|
// 1.3 上传文件
|
||||||
return baseRequestClient
|
return baseRequestClient
|
||||||
.put(presignedInfo.uploadUrl, file, {
|
.put(presignedInfo.uploadUrl, file, {
|
||||||
|
@ -107,13 +106,13 @@ export const useUpload = () => {
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 1.4. 记录文件信息到后端(异步)
|
// 1.4. 记录文件信息到后端(异步)
|
||||||
createFile0(presignedInfo, fileName, file);
|
createFile0(presignedInfo, file);
|
||||||
// 通知成功,数据格式保持与后端上传的返回结果一致
|
// 通知成功,数据格式保持与后端上传的返回结果一致
|
||||||
return { data: presignedInfo.url };
|
return { data: presignedInfo.url };
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 模式二:后端上传
|
// 模式二:后端上传
|
||||||
return uploadFile({ file }, onUploadProgress);
|
return uploadFile({ file, directory }, onUploadProgress);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,18 +133,13 @@ export const getUploadUrl = (): string => {
|
||||||
* 创建文件信息
|
* 创建文件信息
|
||||||
*
|
*
|
||||||
* @param vo 文件预签名信息
|
* @param vo 文件预签名信息
|
||||||
* @param name 文件名称
|
|
||||||
* @param file 文件
|
* @param file 文件
|
||||||
*/
|
*/
|
||||||
function createFile0(
|
function createFile0(vo: InfraFileApi.FilePresignedUrlRespVO, file: File) {
|
||||||
vo: InfraFileApi.FilePresignedUrlRespVO,
|
|
||||||
name: string,
|
|
||||||
file: File,
|
|
||||||
) {
|
|
||||||
const fileVO = {
|
const fileVO = {
|
||||||
configId: vo.configId,
|
configId: vo.configId,
|
||||||
url: vo.url,
|
url: vo.url,
|
||||||
path: name,
|
path: vo.path,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
type: file.type,
|
type: file.type,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
|
@ -160,12 +154,13 @@ function createFile0(
|
||||||
* @param file 要上传的文件
|
* @param file 要上传的文件
|
||||||
*/
|
*/
|
||||||
async function generateFileName(file: File) {
|
async function generateFileName(file: File) {
|
||||||
// 读取文件内容
|
// // 读取文件内容
|
||||||
const data = await file.arrayBuffer();
|
// const data = await file.arrayBuffer();
|
||||||
const wordArray = CryptoJS.lib.WordArray.create(data);
|
// const wordArray = CryptoJS.lib.WordArray.create(data);
|
||||||
// 计算SHA256
|
// // 计算SHA256
|
||||||
const sha256 = CryptoJS.SHA256(wordArray).toString();
|
// const sha256 = CryptoJS.SHA256(wordArray).toString();
|
||||||
// 拼接后缀
|
// // 拼接后缀
|
||||||
const ext = file.name.slice(Math.max(0, file.name.lastIndexOf('.')));
|
// const ext = file.name.slice(Math.max(0, file.name.lastIndexOf('.')));
|
||||||
return `${sha256}${ext}`;
|
// return `${sha256}${ext}`;
|
||||||
|
return file.name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,10 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
},
|
},
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
// TODO @芋艿:图片上传
|
|
||||||
{
|
{
|
||||||
fieldName: 'logo',
|
fieldName: 'logo',
|
||||||
label: '应用图标',
|
label: '应用图标',
|
||||||
component: 'UploadImage',
|
component: 'ImageUpload',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue