UNPKG

linkmore-design

Version:

🌈 🚀lm组件库。🚀

420 lines (396 loc) 12.3 kB
"use strict"; 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;