feat: upload组件支持计算md5(通过组件参数开启)

This commit is contained in:
Pan Qiancheng 2025-12-03 18:42:42 +08:00
parent d8d78edde1
commit f57dacfe5d
6 changed files with 126 additions and 7 deletions

View File

@ -33,6 +33,7 @@
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-touch-backend": "^16.0.1",
"sha1": "^1.1.1",
"spark-md5": "^3.0.2",
"tslib": "^2.4.0",
"uuid": "^8.3.2",
"weixin-js-sdk": "^1.6.3",
@ -66,8 +67,9 @@
"@types/react-dom": "^18.2.14",
"@types/react-native": "^0.72.8",
"@types/sha1": "^1.1.3",
"@types/spark-md5": "^3.0.5",
"@types/uuid": "^9.0.6",
"@types/wechat-miniprogram": "^3.4.5",
"@types/wechat-miniprogram": "^3.4.9",
"antd": "5.13.3",
"antd-mobile": "5.33.0",
"antd-mobile-icons": "0.3.0",

View File

@ -4,6 +4,7 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
import { generateNewId } from 'oak-domain/lib/utils/uuid';
import { assert } from 'oak-domain/lib/utils/assert';
import { calculateFileMd5 } from '../../../utils/files/md5';
type ExtraFile = EntityDict['extraFile']['OpSchema'];
export interface EnhancedExtraFile extends ExtraFile {
@ -90,6 +91,7 @@ export default OakComponent({
size: 3, // 每行可显示的个数 小程序独有
showUploadList: true, //web独有
showUploadProgress: false, // web独有
calcMd5: false, // 是否计算文件md5值
accept: 'image/*', // web独有
disablePreview: false, // 图片是否可预览
disableDelete: false, // 图片是否可删除
@ -180,6 +182,7 @@ export default OakComponent({
fileType: string;
size: number;
sort: number;
md5: string;
},
file: File | string
) {
@ -193,7 +196,7 @@ export default OakComponent({
bucket,
autoUpload,
} = this.props;
const { name, fileType, size, sort } = options;
const { name, fileType, size, sort, md5 } = options;
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
const { files } = this.state;
@ -210,6 +213,7 @@ export default OakComponent({
entity,
filename,
size,
md5,
extension,
fileType,
entityId,
@ -228,13 +232,26 @@ export default OakComponent({
this.features.extraFile.addLocalFile(id, file);
}
},
addFileByWeb(file: File) {
async addFileByWeb(file: File) {
const { size, type, name } = file;
this.addExtraFileInner(
let md5 = null;
if (this.props.calcMd5) {
try {
// 计算文件md5值
md5 = await calculateFileMd5(file)
} catch (error) {
this.triggerEvent('onError', {
level: 'error',
msg: '计算文件MD5失败',
});
}
}
await this.addExtraFileInner(
{
name,
fileType: type,
size,
md5,
sort: this.getSort(),
},
file
@ -256,7 +273,7 @@ export default OakComponent({
msg: errMsg,
});
} else {
tempFiles.map((tempExtraFile, index) => {
await Promise.all(tempFiles.map(async (tempExtraFile, index) => {
const {
tempFilePath,
thumbTempFilePath,
@ -266,16 +283,28 @@ export default OakComponent({
const filePath = tempFilePath || thumbTempFilePath;
const fileFullName =
filePath.match(/[^/]+(?!.*\/)/g)![0];
this.addExtraFileInner(
let md5 = null;
if (this.props.calcMd5) {
try {
md5 = await calculateFileMd5(filePath);
} catch (error) {
this.triggerEvent('onError', {
level: 'error',
msg: '计算文件MD5失败',
});
}
}
await this.addExtraFileInner(
{
name: fileFullName,
fileType,
size,
md5,
sort: this.getSort(index),
},
filePath
);
});
}));
}
} catch (err: any) {
if (err.errMsg !== 'chooseMedia:fail cancel') {
@ -520,6 +549,8 @@ export default OakComponent({
size: number;
showUploadList: boolean;
showUploadProgress: boolean;
// 是否计算文件md5值
calcMd5: boolean;
accept: string;
// 图片是否可预览
disablePreview: boolean;

17
src/utils/files/md5.mp.ts Normal file
View File

@ -0,0 +1,17 @@
export async function calculateFileMd5(
filePath: string
): Promise<string> {
return new Promise((resolve, reject) => {
const fs = wx.getFileSystemManager();
(fs as any).getFileInfo({
filePath: filePath,
digestAlgorithm: 'md5',
success(res: any) {
resolve(res.digest as string);
},
fail(err: any) {
reject(err);
}
});
});
}

View File

@ -0,0 +1,31 @@
import SparkMd5 from 'spark-md5';
export function calculateFileMd5(
file: File
): Promise<string> {
return new Promise((resolve, reject) => {
const chunkSize = 2097152;
const chunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
const spark = new SparkMd5.ArrayBuffer();
const fileReader = new FileReader();
fileReader.onload = function (e) {
spark.append(e.target?.result as ArrayBuffer);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
resolve(spark.end());
}
};
fileReader.onerror = function () {
reject(new Error('Failed to read file'));
};
function loadNext() {
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
fileReader.readAsArrayBuffer(file.slice(start, end));
}
loadNext();
});
}

7
src/utils/files/md5.ts Normal file
View File

@ -0,0 +1,7 @@
export function calculateFileMd5(
file: File | string
): Promise<string> {
return new Promise((revlove) => {
revlove('dummy-md5-hash-for-index');
})
}

View File

@ -0,0 +1,31 @@
import SparkMd5 from 'spark-md5';
export function calculateFileMd5(
file: File
): Promise<string> {
return new Promise((resolve, reject) => {
const chunkSize = 2097152;
const chunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
const spark = new SparkMd5.ArrayBuffer();
const fileReader = new FileReader();
fileReader.onload = function (e) {
spark.append(e.target?.result as ArrayBuffer);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
resolve(spark.end());
}
};
fileReader.onerror = function () {
reject(new Error('Failed to read file'));
};
function loadNext() {
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
fileReader.readAsArrayBuffer(file.slice(start, end));
}
loadNext();
});
}