linkmore-design
Version:
🌈 🚀lm组件库。🚀
420 lines (396 loc) • 12.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _ahooks = require("ahooks");
var _aliOss = _interopRequireDefault(require("ali-oss"));
var _react = require("react");
var _message = _interopRequireDefault(require("../../message"));
const useCoreOptions = ({
state,
dispatch,
props
}) => {
const {
uid,
onChange,
type,
fileSize,
fileSizeType,
fileAreaSize,
enabledOss,
enableCrop,
ossConfig,
multiple,
locale
} = props;
const fileUploadLen = (0, _react.useRef)(null); // 上传的文件数量
const doneFileUploadLen = (0, _react.useRef)([]); // 已完成上传的文件
/* 获取两个对象是否存在指定值相等
* 取用户定义的列字段,如果读取不到则取'fileName'对比
*/
const getHasEqual = (0, _react.useCallback)((obj1, obj2) => {
const extend = [uid, 'fileName'];
let flag = false;
extend.forEach(v => {
if (!flag && obj1[v] && obj2[v]) {
flag = obj1[v] === obj2[v];
}
});
return flag;
}, [uid]);
// 从对象中读取存在的指定属性
const getFileHasValue = (0, _react.useCallback)(obj => {
if (!obj) return '';
const extend = [uid, 'fileName'];
let val = '';
extend.forEach(v => {
if (!val && obj[v]) val = obj[v];
});
return val;
}, [uid]);
// 获取当前的文件列表
const getFileList = (0, _react.useCallback)(() => {
return props.fileList || state.fileList;
}, [props.fileList, state.fileList]);
// 获取上传状态
const getUploadStatus = (0, _react.useCallback)(() => {
const uploading = typeof state.percent === 'number';
return {
uploading
};
}, [state.percent]);
// 获取文件字段值
const getFileFields = (0, _react.useCallback)(fileParams => {
const {
fileNames
} = props;
const obj = {};
Object.entries(fileNames).forEach(v => {
const itemKey = v[0];
const itemValue = v[1];
if (fileParams[itemKey]) {
obj[itemKey] = fileParams[itemValue];
}
});
return obj;
}, [props]);
// 获取是否达到最大上传数量
const getIsMaxCount = (0, _react.useCallback)(() => {
const {
maxCount,
limit
} = props;
let flag = false;
const num = maxCount || limit;
if (num && typeof num === 'number') {
flag = !(getFileList().length < num);
}
return flag;
}, [getFileList, props]);
// 上传成功事件: File, fileParams
const uploadSuccess = (0, _react.useCallback)(async (file, params, ossCallBack) => {
const fileList = Array.isArray(params) ? [...getFileList(), ...params] : [...getFileList(), params];
dispatch({
type: 'changeFileList',
fileList
});
dispatch({
type: 'changePercent',
percent: null
});
// 上传事件:抛出 file: 文件 filelist: 文件列表 event: 上传进度信息
props.onSuccess?.({
file,
fileList
});
onChange?.({
file,
fileList
});
doneFileUploadLen.current = [];
const res = await ossCallBack?.(Array.isArray(params) ? params : [params]);
props.onCallBack?.(res, {
file,
fileList
});
}, [getFileList, props.onSuccess, props.onCallBack, onChange, dispatch, doneFileUploadLen.current]);
// 上传进度事件
const uploadProgress = (0, _react.useCallback)((file, {
progress,
checkPoint,
result
}) => {
const params = {
file,
fileList: getFileList(),
event: {
progress,
checkPoint,
result,
status: typeof progress !== 'number' ? 'done' : 'uploading'
}
};
props.onProgress?.(params);
onChange?.(params);
dispatch({
type: 'changePercent',
percent: Number((progress * 100).toFixed(2))
});
}, [getFileList, props.onProgress, onChange, dispatch]);
// 上传失败事件
const uploadError = (0, _react.useCallback)(({
error,
file
}) => {
props.onError ? props.onError({
error,
file,
fileList: getFileList()
}) : _message.default.warning(locale.fileUploadError, 1.5);
onChange?.({
file,
fileList: getFileList(),
event: {
status: 'error'
}
});
doneFileUploadLen.current = [];
}, [props.onError, getFileList, onChange, doneFileUploadLen.current, locale]);
// 上传至ali-oss
const uploadOss = (0, _react.useCallback)(async file => {
try {
const {
dir: filePath = '/BizFile/4595/Supplier/',
shortlink,
region = 'oss-cn-hangzhou',
accessKeyId,
accessKeySecret,
stsToken,
bucket = 'linkmore-scm-test',
ossCallBack
} = ossConfig();
const client = new _aliOss.default({
region,
accessKeyId,
accessKeySecret,
stsToken,
bucket
});
const timestamp = Date.now();
const pattern = /[!@#$%^&*()_+{}:“<>?,;'[\]\\|`~]+/g;
// 删除特殊字符
const tripFileName = file.name.replace(pattern, '');
const suffixIndex = tripFileName.lastIndexOf('.');
const realFileName = tripFileName.slice(0, Math.min(100, suffixIndex)) + tripFileName.slice(suffixIndex);
const fileName = `${timestamp}-${realFileName}`;
const pathName = filePath.slice(-1) === '/' ? `${filePath}${fileName}` : `${filePath}/${fileName}`;
const url = `${shortlink}${pathName}` || '';
await client.multipartUpload(pathName, file, {
// 获取分片上传进度、断点和返回值。
progress: (progress, checkPoint, result) => !multiple && uploadProgress(file, {
progress,
checkPoint,
result
}),
parallel: 4,
// 并发上传分片数量
partSize: 1024 * 1024 // 分片大小
// 会导致部分图片无法上传
// headers: { 'Content-Disposition': `attachment; filename=${realFileName}` },
});
const params = props.fileConfig({
file,
timestamp,
fileName,
filePath,
shortlink,
url,
realFileName
});
if (!multiple) {
uploadSuccess(file, params, ossCallBack);
}
if (multiple) {
doneFileUploadLen.current = [...doneFileUploadLen.current, params];
if (fileUploadLen.current === doneFileUploadLen.current.length) {
uploadSuccess(null, doneFileUploadLen.current, ossCallBack);
}
}
} catch (error) {
uploadError({
error,
file
});
}
}, [multiple, ossConfig, uploadProgress, props.fileConfig, uploadSuccess, uploadError, fileUploadLen.current, doneFileUploadLen.current]);
// 自定义使用外部上传
const customUpload = (0, _react.useCallback)(file => {
props.fileUpload?.({
file,
value: getFileList(),
onChange: uploadSuccess
});
}, [props.fileUpload, getFileList, uploadSuccess]);
// 调用上传方法: 执行 uploadOss && customUpload事件
const uploadFile = (0, _react.useCallback)(file => {
enabledOss && uploadOss(file);
customUpload(file);
}, [enabledOss, uploadOss, customUpload]);
// 检测完成, 执行外部 `beforeUpload` 事件
const checkOver = (0, _react.useCallback)(async file => {
// 默认
if (!props?.beforeUpload) {
uploadFile(file);
return;
}
const res = props.beforeUpload(file, getFileList());
// Promise
if (res?.then) {
try {
const newFile = await res;
uploadFile(newFile);
} catch (error) {
console.log('上传失败!');
}
return;
}
// () => false
if (!res) return;
// () => true
uploadFile(file);
}, [props.beforeUpload, getFileList, uploadFile]);
// 单个文件异步校验
const fileCheckAsync = (0, _react.useCallback)(file => {
return new Promise((resolve, reject) => {
// 文件类型校验是否通过 | 存在通配符或符合规定类型
const isCheckType = type.includes('*') || type.includes(file.name.replace(/.*\./, '').toLowerCase());
// 大小校验是否通过
const isCheckSize = file.size / 1024 / (fileSizeType.toLowerCase().includes('m') ? 1024 : 1) <= fileSize;
if (!isCheckType) {
const content = type.join('、');
reject(new Error(`${locale.fileTypeMessageBefore}${content}${locale.fileTypeMessageAfter}`));
}
if (!isCheckSize) {
reject(new Error(`${locale.fileSizeMessage}${fileSize}${fileSizeType}!`));
}
// 是否需要校验图片宽高
if (fileAreaSize) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = evt => {
const res = evt.target.result;
const imageObj = new Image();
imageObj.src = res;
imageObj.onload = () => {
const {
maxWidth,
maxHeight
} = fileAreaSize;
const isCheckAreaSizeMaxWidth = !maxWidth || imageObj.width <= maxWidth;
const isCheckAreaSizeMaxHeight = !maxHeight || imageObj.height <= maxHeight;
if (!isCheckAreaSizeMaxWidth || !isCheckAreaSizeMaxHeight) {
reject(new Error(locale.fileSizeLimitMessage));
} else {
resolve(file);
}
};
};
} else {
resolve(file);
}
});
}, [type, fileSize, fileSizeType, fileAreaSize, locale]);
// 文件循环校验,返回校验后的文件数组
const filesLoopCheck = (0, _react.useCallback)(files => Promise.all(files?.map(fileCheckAsync)), [fileCheckAsync]);
/*
* 上传前: 先校验 => 全部校验通过后开始上传
* 事件执行顺序:
* beforeUpload => filesLoopCheck => checkOver
* => uploadFile => uploadOss && customUpload
* => uploadProgress => uploadSuccess || uploadError
* => Props.onChange && (Props.onSuccess || Props.onError)
*/
const beforeUpload = (0, _react.useCallback)(async e => {
const files = Array.from(e.target ? e.target.files : e);
try {
const res = await filesLoopCheck(files);
fileUploadLen.current = res.length;
// 仅单文件上传时可剪裁
if (enableCrop) {
dispatch({
type: 'changeCropFile',
cropFile: res[0]
});
} else {
// 校验完成开始执行上传
res.forEach(checkOver);
}
} catch (error) {
console.log('文件校验未通过!', error.message);
_message.default.warning(error.message, 1.5);
}
}, [filesLoopCheck, enableCrop, checkOver, fileUploadLen.current]);
// 删除事件
const remove = (0, _react.useCallback)(async file => {
const res = await props.onRemove?.(file);
if (res) {
const fileList = getFileList()?.filter(v => !getHasEqual(v, file));
dispatch({
type: 'changeFileList',
fileList
});
onChange?.({
file,
fileList
});
}
}, [props.onRemove, getFileList, onChange, dispatch, getHasEqual]);
// 点击文件链接或预览图标时的回调
const preview = (0, _ahooks.useMemoizedFn)(file => {
props.onPreview?.(file, getFileList());
});
// 点击下载文件时的回调
const download = (0, _react.useCallback)(file => {
props.onDownload?.(file);
}, [props.onDownload]);
// 拖拽移动事件
const move = (0, _react.useCallback)((active, over, fileList) => {
props.onMove?.(active, over, fileList);
onChange?.({
file: active,
fileList
});
dispatch({
type: 'changeFileList',
fileList
});
}, [props.onMove, onChange, dispatch]);
const CoreMethods = {
getIsMaxCount,
// 获取是否达到最大上传数量
getFileHasValue,
getFileFields,
beforeUpload,
checkOver,
getUploadStatus,
remove,
preview,
download,
move
};
const RefMethods = {
getState: () => state,
getFileList,
// 获取文件列表
uploadFile
};
return {
CoreMethods,
RefMethods
};
};
var _default = useCoreOptions;
exports.default = _default;