import React , { ComponentType , useState , useRef , useEffect , CSSProperties , ReactNode , HTMLAttributes } from 'react' ; import { PlusOutlined , DeleteOutlined , EyeOutlined } from '@ant-design/icons' ; import { generate } from 'shortid' ; import classnames from 'classnames' ; import { Modal , Spin , Carousel } from '../index' ; import { ModalHandle } from '../modal/index' ; import { classPrefix } from '../utils' ; import './style/index.less' ; const classNameUpload = `${ classPrefix }-upload` ; interface UploadHandle { showOpenDialog : ( ) => void ; } interface UploadRender { files : FileList | undefined ; upload : UploadHandle ; } interface UploadProps { uploadRender : ( props : UploadRender ) => ReactNode ; onChange ? : ( files : FileList | undefined ) => void ; /**
     * 是否支持多选
     */ multiple ? : boolean ; /**
     * 接收文件类型
     */ accept ? : string ; style ? : CSSProperties ; } /**
 * 上传组件
 */ export const Upload = ( { onChange , uploadRender , multiple , accept , style , } ) => { const [ files , setFiles ] = useState < FileList | undefined > ( undefined ) ; const [ key , setKey ] = useState < string > ( generate ( ) ) ; const uploadRef = useRef < HTMLInputElement > ( null ) ; const upload = { showOpenDialog : ( ) => { uploadRef . current ?. click ( ) ; } } ; return ( < div className = { `${ classNameUpload }-wrapper` } style = { style } > { uploadRender ( { files , upload } ) } < input ref = { uploadRef } key = { key } className = { `${ classNameUpload }-input-file` } multiple = { multiple } accept = { accept } type = "file" onChange = { event => { const { files : targeFiles } = event . target ; setFiles ( targeFiles as FileList | undefined ) ; onChange ?. ( targeFiles as FileList | undefined ) ; setKey ( generate ( ) ) ; } } /> < /div>); } ; export interface UploadImageType { id : string ; url : string ; name : string ; state ? : 'SUCCESS' | 'FAIL' ; } interface ImageRenderProps extends HTMLAttributes < HTMLDivElement > { file : UploadImageType ; } interface UploadPicturesWallProps { onChange ? : ( images : UploadImageType [ ] ) => void ; images ? : UploadImageType [ ] ; onUpload ? : ( file : FileList ) => Promise < UploadImageType [ ] > ; actionRender ? : ComponentType < { className : string ; children : ReactNode ; file : UploadImageType ; } > ; imageRender ? : ComponentType < ImageRenderProps > ; style ? : CSSProperties ; multiple ? : boolean ; onCallbackStateImages ? : ( images : UploadImageType [ ] , setImages : ( uploadImages : UploadImageType [ ] ) => void ) => void ; onSelectKeys : ( keys : string [ ] ) => void ; accept ? : string ; } /**
 * 照片墙上传
 */ export const UploadPicturesWall = ( { onChange , onUpload , onCallbackStateImages , onSelectKeys , imageRender : ImageRender = ( props ) => ( < div { ... props } / > ) , images : imagesProp = [ ] , actionRender : ActionRender = ( { className , children } ) => ( < div className = { className } > { children } < /div>), style, multiple, accept }) => { const uploadRender = ( { files , upload , } ) => { const [ images , setImages ] = useState < UploadImageType [ ] > ( imagesProp ) ; const [ selectKeys , setSelectKey ] = useState < string [ ] > ( [ ] ) ; const modal = useRef < ModalHandle | null > ( null ) ; const [ spinning , setSpinning ] = useState < boolean > ( false ) ; onCallbackStateImages ?. ( images , setImages ) ; const getImgsAsync = ( imgFiles ) => { setSpinning ( true ) ; onUpload ?. ( imgFiles ) . then ( resp => { const tempImages = images . concat ( resp ) ; onChange ?. ( tempImages ) ; setImages ( tempImages ) ; setSpinning ( false ) ; } ) ; } ; useEffect ( ( ) => { if ( files ) { getImgsAsync ( files ) ; } } , [ files ] ) ; useEffect ( ( ) => { setImages ( imagesProp ) ; } , [ imagesProp ] ) ; const carousel = useRef < any | null > ( null ) ; return ( < > { images . map ( ele => ( < ImageRender key = { ele . id } file = { ele } className = { classnames ( { [ `${ classNameUpload }-list-item` ] : true , [ `${ classNameUpload }-list-select-item` ] : selectKeys . includes ( ele . id ) } ) } onClick = { ( ) => { const index = selectKeys . findIndex ( key => ele . id === key ) ; if ( index !== - 1 ) { selectKeys . splice ( index , 1 ) ; } else { selectKeys . push ( ele . id ) ; } onSelectKeys ?. ( selectKeys ) ; setSelectKey ( [ ... selectKeys ] ) ; } } > < img src = { ele . url } alt = { ele . name } / > < ActionRender className = { `${ classNameUpload }-list-item-info` } file = { ele } > < EyeOutlined className = "upload-action-icon" key = 'eye' onClick = { e => { const index = images . findIndex ( img => ele . id === img . id ) ; carousel . current ?. goTo ( index ) ; modal . current ?. show ( ) ; e . stopPropagation ( ) ; } } /> < DeleteOutlined className = "upload-action-icon" key = 'delete' onClick = { e => { const index = images . findIndex ( img => ele . id === img . id ) ; images . splice ( index , 1 ) ; setImages ( [ ... images ] ) ; e . stopPropagation ( ) ; } } /> < /ActionRender> < /ImageRender>))} < Spin spinning = { spinning } > < div className = { `${ classNameUpload }-select-picture-card` } onClick = { ( ) => { upload . showOpenDialog ( ) ; } } > { spinning ? undefined : < PlusOutlined />} < /div> < /Spin> < Modal modal = { modal } footer = { false } width = { 900 } forceRender title = "图片预览" > < div style = { { margin : 20 } } > < Carousel arrows ref = { carousel } > { images . map ( ele => ( < div key = { generate ( ) } > < img src = { ele . url } style = { { width : '100%' } } alt = { ele . name } / > < /div>))} < /Carousel> < /div> < /Modal> < />); } ; return ( < Upload style = { style } multiple = { multiple } accept = { accept } uploadRender = { uploadRender } / > ) ; } ;