diff --git a/packages/yike-design/package.json b/packages/yike-design/package.json index 5dc85aa1..1ce1a794 100644 --- a/packages/yike-design/package.json +++ b/packages/yike-design/package.json @@ -24,7 +24,9 @@ "react-dom": ">=16.8.0" }, "dependencies": { - "@babel/runtime": "^7.22.6" + "@babel/runtime": "^7.22.6", + "axios": "^1.4.0", + "clsx": "^2.0.0" }, "devDependencies": { "clean-package": "^2.2.0" diff --git a/packages/yike-design/src/components/Upload/components/Upload.tsx b/packages/yike-design/src/components/Upload/components/Upload.tsx new file mode 100644 index 00000000..a7016935 --- /dev/null +++ b/packages/yike-design/src/components/Upload/components/Upload.tsx @@ -0,0 +1,174 @@ +import clsx from 'clsx'; +import type React from 'react'; +import { useRef, useState } from 'react'; +import axios, { type AxiosProgressEvent } from 'axios'; + +import { uploadClsPrefix } from '../constants'; +import type { UploadFile, UploadProps } from '../types/types'; + +const Upload: React.FC> = props => { + const { + action, + defaultFileList, + header, + name, + data, + withCredentials, + accept, + multiple, + // drag, + onProgress, + onSuccess, + onError, + beforeUpload, + // onRemove, + onChange, + + children, + } = props; + + const uploadInputRef = useRef(null); + const [fileList, setFileList] = useState(defaultFileList || []); + + const updateFileList = (updateFile: UploadFile, updateObj: Partial) => { + setFileList(prevList => { + return prevList.map(file => { + if (file.uid === updateFile.uid) { + return { ...file, ...updateObj }; + } else { + return file; + } + }); + }); + }; + + const handleClick = () => { + if (uploadInputRef.current) { + uploadInputRef.current.click(); + } + }; + + const handleFileChange = (e: React.ChangeEvent) => { + const files = e.target.files; + if (!files) { + return; + } + uploadFile(files); + if (uploadInputRef.current) { + uploadInputRef.current.value = ''; + } + }; + + const uploadFile = (file: FileList) => { + const files = Array.from(file); + files.forEach(file => { + if (!beforeUpload) { + postFile(file); + } else { + const result = beforeUpload(file); + if (result && result instanceof Promise) { + result.then(processedFile => { + postFile(processedFile); + }); + } else if (result != false) { + postFile(file); + } + } + }); + }; + + const postFile = (file: File) => { + const _file: UploadFile = { + uid: Date.now() + 'upload', + size: file.size, + name: file.name, + status: 'ready', + percent: 0, + raw: file, + }; + setFileList(prev => { + return [_file, ...prev]; + }); + const formData = new FormData(); + formData.append(name || 'file', file); + if (data) { + Object.keys(data).forEach(key => { + formData.append(key, data[key]); + }); + } + axios + .post(action, formData, { + headers: { + ...header, + 'Content-Type': 'multipart/form-data', + }, + withCredentials, + onUploadProgress: (e: AxiosProgressEvent) => { + if (e.total) { + const percent = Math.round((e.loaded * 100) / e.total) || 0; + if (percent < 100) { + updateFileList(_file, { percent: percent, status: 'uploading' }); + if (onProgress) { + onProgress(percent, file); + } + } + } + }, + }) + .then(response => { + updateFileList(_file, { percent: 100, status: 'success', response: response.data }); + if (onSuccess) { + onSuccess(response, file); + } + if (onChange) { + onChange(file); + } + }) + .catch(err => { + updateFileList(_file, { status: 'error', error: err }); + if (onError) { + onError(err, file); + } + if (onChange) { + onChange(file); + } + }); + }; + + // const handleRemove = (file: UploadFile) => { + // setFileList(prevList => { + // return prevList.filter(item => item.uid !== file.uid); + // }); + // if (onRemove) { + // onRemove(file); + // } + // }; + + return ( +
+
+ + {children} +
+
+ {fileList.map((item, index) => { + return
{item.name}
; + })} +
+
+ ); +}; + +export default Upload; diff --git a/packages/yike-design/src/components/Upload/constants/index.ts b/packages/yike-design/src/components/Upload/constants/index.ts new file mode 100644 index 00000000..ad5300c7 --- /dev/null +++ b/packages/yike-design/src/components/Upload/constants/index.ts @@ -0,0 +1,3 @@ +export const uiClsPrefix = 'yike'; + +export const uploadClsPrefix = `${uiClsPrefix}-upload`; diff --git a/packages/yike-design/src/components/Upload/index.tsx b/packages/yike-design/src/components/Upload/index.tsx new file mode 100644 index 00000000..c3d04682 --- /dev/null +++ b/packages/yike-design/src/components/Upload/index.tsx @@ -0,0 +1,3 @@ +import Upload from './components/Upload'; + +export { Upload }; diff --git a/packages/yike-design/src/components/Upload/style/Upload.scss b/packages/yike-design/src/components/Upload/style/Upload.scss new file mode 100644 index 00000000..8c0da8e3 --- /dev/null +++ b/packages/yike-design/src/components/Upload/style/Upload.scss @@ -0,0 +1,3 @@ +/* stylelint-disable-next-line block-no-empty */ +.yike-upload { +} diff --git a/packages/yike-design/src/components/Upload/style/index.scss b/packages/yike-design/src/components/Upload/style/index.scss new file mode 100644 index 00000000..8c0da8e3 --- /dev/null +++ b/packages/yike-design/src/components/Upload/style/index.scss @@ -0,0 +1,3 @@ +/* stylelint-disable-next-line block-no-empty */ +.yike-upload { +} diff --git a/packages/yike-design/src/components/Upload/style/index.ts b/packages/yike-design/src/components/Upload/style/index.ts new file mode 100644 index 00000000..67aac616 --- /dev/null +++ b/packages/yike-design/src/components/Upload/style/index.ts @@ -0,0 +1 @@ +import './index.scss'; diff --git a/packages/yike-design/src/components/Upload/types/types.ts b/packages/yike-design/src/components/Upload/types/types.ts new file mode 100644 index 00000000..a42e4d7a --- /dev/null +++ b/packages/yike-design/src/components/Upload/types/types.ts @@ -0,0 +1,33 @@ +import { type AxiosResponse } from 'axios'; + +export interface UploadProps { + //attr + action: string; + defaultFileList?: Array; + header?: { [key: string]: any }; + name?: string; + data?: { [key: string]: any }; + withCredentials?: boolean; + accept?: string; + multiple?: boolean; + drag?: boolean; + // function + onProgress?: (presentNumber: number, file: File) => void; + onSuccess?: (data: AxiosResponse, file: File) => void; + onError?: (err: any, file: File) => void; + beforeUpload?: (file: File) => boolean | Promise; + onChange?: (file: File) => void; + onRemove?: (file: UploadFile) => void; +} +type FileStatus = 'ready' | 'success' | 'uploading' | 'error'; + +export interface UploadFile extends Partial { + uid: string; + size: number; + name: string; + status?: FileStatus; + percent?: number; + raw?: File; + response?: any; + error?: any; +} diff --git a/packages/yike-design/src/index.ts b/packages/yike-design/src/index.ts index 28a6ee3b..f7c62b5d 100644 --- a/packages/yike-design/src/index.ts +++ b/packages/yike-design/src/index.ts @@ -1,2 +1,3 @@ export * from './components/Button'; export * from './components/Space'; +export * from './components/Upload';