daily-share icon indicating copy to clipboard operation
daily-share copied to clipboard

对upload-重新封装实现input上传图片(2020-05-13)

Open yaogengzhu opened this issue 4 years ago • 0 comments

对upload-重新封装实现input上传图片

import React, { ClassAttributes } from 'react'
import { Upload } from 'antd'
import { getQiniuUploadToken } from '@/api/common_api'
import { openMessage, MessageType } from '@/utils/system'
import { qiniuUploadUrl } from '@/config/qiniu'
import { RcFile } from 'antd/lib/upload'
import * as qiniu from 'qiniu-js'
import { ClassDeclaration } from '@babel/types'

type FileType = 'audio' | 'video' | 'image'

export class UploadInstance {
    public file: File | null = null
    public name: string = ""
    public sizeUnit: string = ""
    public filetype: number = 0
    public typename: string = ''
    public progress: number = 0
    public status: 'pending' | 'uploading' | 'error' | 'complete' = 'pending'
    public fileSrc: string = ''
    constructor(props: {
        file: File
    }) {
        this.file = props.file
        this.status = 'pending'
        this.name = this.file.name.split('.')[0] + '.'  // 文件名字
        this.sizeUnit = this.getFileSizeMin(this.file.size)
        this.filetype = this.checkFileType(this.file) // 1 图片, 2 视频
        this.typename = this.file.type && this.file.type.split('/')[1]
        this.fileSrc = '' // 图片
    }

    public onUpload(r: any) {
        this.status = 'uploading'
        // console.log('已上传大小,单位为字节:' + res.total.loaded)
        // console.log(
        //     '本次上传的总量控制信息,单位为字节:' + res.total.size
        // )
        // console.log(
        //     '当前上传进度,范围:0~100:' + res.total.percent
        // )
        // _this.$set(
        //     _this.materialUploadPercentList,
        //     file.file.uid,
        //     res.total.percent.toFixed(0) * 1
        // )
        this.progress = +(r.total.percent).toFixed(2)
    }

    public onError(e: any) {
        this.status = 'error'
    }

    public onComplete(res: any) {
        this.status = 'complete'
        // 判断图片类型
        this.fileSrc = res.key

    }

    // 获取素材的大小
    private getFileSizeMin(val: number) {
        let sizeType = ''
        if (val / (1024 * 1024) > 1) {
            sizeType = 'M'

            return (val / (1024 * 1024)).toFixed(1) + sizeType
        } else {
            sizeType = 'Kb'

            return (val / 1024).toFixed(1) + sizeType
        }
    }

    //  返回文件类型 1 图片 2 视频
    private checkFileType(item: any) {
        let type = -1
        //  注释的视频类型均为七牛不支持类型
        const videoList = [
            // 'flv',
            // 'avi',
            // 'wmv',
            // '3gp',
            // 'm4v',
            // 'ogg',
            // 'rmvb',
            // 'mov',
            // 'x-flv',
            // 'mkv',
            'mp4',
        ]
        const imageList = ['png', 'jpg', 'jpeg']
        const name = item.name
        videoList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(name)) {
                type = 2
            }
        })
        imageList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(name)) {
                type = 1
            }
        })

        return type
    }
}

// tslint:disable-next-line:no-empty-interface
interface IProps {
    className?: ClassDeclaration | any
    beforeUpload?: (file: RcFile, FileList: RcFile[]) => boolean
    onLoad?: (data: UploadInstance) => void // 文件上传
    onChange?: () => void
    onSuccess?: () => void
    camera?: boolean

}

interface IState {
    fileLists: any[]
    materialInfo: any
}
export default class SgUpload extends React.Component<IProps, IState> {
    private qiniuDomain: string = qiniuUploadUrl
    private qiniuToken1: string = ''
    private qiniuToken2: string = ''
    private materialJson: any = {}
    private observer: any = {}
    private Uploadprops: any = {
        action: qiniuUploadUrl,
        multiple: false,
    }

    private staticProps = {
        camera: false
    }
    constructor(props: any) {
        super(props)
        this.state = {
            fileLists: [],
            materialInfo: {}
        }
    }

    public render() {
        return(
            <Upload
                className={ this.props.className }
                // beforeUpload={(file: RcFile, FileList: RcFile[]) => { this.beforeUpload(file, FileList)}}
                customRequest={(file) => { this.qiniuUpload(file) }}
                listType='picture-card'
                fileList={ this.state.fileLists }
                accept={ this.props.camera ? "image/*" : ''}
                capture={this.props.camera ? "camera" : ''}
                {...this.Uploadprops}
            >
                { this.props.children }
            </Upload>
        )
    }


    // 自定义上传方式
    private qiniuUpload(file: any) {
        console.log('file')
        this.beforeUploadCheckout(file.file)
        // tslint:disable-next-line:variable-name
        const _this = this
        const putExtra = {
            fname: file.file.name,
            params: {},
            // mimeType: null,
            //  注释的视频类型均为七牛不支持类型
            mimeType: [
                // 'video/flv',
                // 'video/avi',
                // 'video/3gpp',
                // 'video/wmv',
                // 'video/m4v',
                // 'video/ogg',
                // 'video/rmvb',
                // 'video/mov',
                // 'video/x-flv',
                // 'video/mkv',
                // 'video/quicktime',
                // 'video/x-ms-wmv',
                'video/mp4',
                'image/png',
                'image/jpg',
                'image/jpeg',
            ],
        }
        const config: any = {
            useCdnDomain: true,
            region: null,
            checkByMD5: true,
        }

        if (file.file.type.includes('image')) {
            console.log(file, 'fileInfo---------------')
            // file, key, token, putExtra, config
            this.getQiniuToken(1, () => {
                console.log('ok')
                const observable = qiniu.upload(
                    file.file,
                    file.file.key,
                    this.qiniuToken1,
                    putExtra,
                    config
                )
                const subscription = observable.subscribe(this.observer)
                // this.uploadReq[file.file.uid] = subscription
                // this.setState({
                //     uploadReq: Object.assign({
                //         'file.file.uid': subscription
                //     })
                // })

            })
        } else {
            this.getQiniuToken(2, () => {
                const observable = qiniu.upload(
                    file.file,
                    file.file.key,
                    this.qiniuToken2,
                    putExtra,
                    config
                )
                const subscription = observable.subscribe(this.observer)
                // this.uploadReq[file.file.uid] = subscription
                // this.setState({
                //     uploadReq: Object.assign({
                //         'file.file.uid': subscription
                //     })
                // })
            })
        }
    }

    // 上传文件之前
    private beforeUpload(file: any, fileList: RcFile[]) {
        // console.log(file, 'file')
        if (this.props.beforeUpload) {
            return this.props.beforeUpload(file, fileList)
        } else {
            const fileType = file.type.includes('image') ? 'img' : 'video'
                // 检查大小
            const is100M = file.size / 1024 / 1024 < 100
            const is5M = file.size / 1024 / 1024 < 5
            if (fileType === 'img' && !is5M) {
                openMessage(MessageType.error, '图片大小不能超过5M哦')

                return false
            } else if (fileType === 'video' && !is100M) {
                openMessage(MessageType.error, '图片大小不能超过100M哦')

                return false
            } else if (
                file.name
                    .split('.')
                    .slice(0, -1)
                    .join('.').length > 15
            ) {
                openMessage(MessageType.error, '图片大小不能超过5文件名字不能超过15个字M哦')

                return false
            } else if (!this.isAcceptedFile(file.name)) {
                openMessage(MessageType.error, '不支持上传该类型素材')

                return false
            }
            console.log('test')
            const uploadInstance = new UploadInstance({
                file: file
            })
            this.observer = {
                next: (res: any) => {
                    uploadInstance.onUpload(res)
                    this.props.onChange && this.props.onChange()
                    // _this.props.onChange && _this.props.onChange(res)
                    // console.log('已上传大小,单位为字节:' + res.total.loaded)
                    // console.log(
                    //     '本次上传的总量控制信息,单位为字节:' + res.total.size
                    // )
                    // console.log(
                    //     '当前上传进度,范围:0~100:' + res.total.percent
                    // )
                    // _this.$set(
                    //     _this.materialUploadPercentList,
                    //     file.file.uid,
                    //     res.total.percent.toFixed(0) * 1
                    // )
                },
                error: (err: any) => {
                    // ...
                    console.log(err.code)
                    uploadInstance.onError(err)
                    this.props.onChange && this.props.onChange()
                },
                complete: (res: any) => {
                    // ...
                    console.log(res)
                    uploadInstance.onComplete(res)
                    this.props.onChange && this.props.onChange()
                    // _this.handleSuccess(res, file.file)
                },
                // this.beforeAvatarUpload(file.file)
            }
            this.materialJson = {
                name: file.name.split('.')[0] + '.',  // 文件名字
                size: this.getFileSizeMin(file.size),
                type: this.checkFileType(file),
                typename: file.type && file.type.split('/')[1],
            }
            console.log('Json', this.materialJson)
            this.props.onLoad && this.props.onLoad(uploadInstance)

                // return false

            return true
        }
    }

    private beforeUploadCheckout(file: any) {
        const fileType = file.type.includes('image') ? 'img' : 'video'
                // 检查大小
        const is100M = file.size / 1024 / 1024 < 100
        const is5M = file.size / 1024 / 1024 < 5
        if (fileType === 'img' && !is5M) {
            return openMessage(MessageType.error, '图片大小不能超过5M哦')
        } else if (fileType === 'video' && !is100M) {
            openMessage(MessageType.error, '图片大小不能超过100M哦')

            return false
        } else if (
            file.name
                .split('.')
                .slice(0, -1)
                .join('.').length > 15
        ) {
            openMessage(MessageType.error, '图片大小不能超过5文件名字不能超过15个字M哦')

            return false
        } else if (!this.isAcceptedFile(file.name)) {
            openMessage(MessageType.error, '不支持上传该类型素材')

            return false
        }

        const uploadInstance = new UploadInstance({
            file: file
        })
        this.observer = {
            next: (res: any) => {
                uploadInstance.onUpload(res)
                this.props.onChange && this.props.onChange()
                // _this.props.onChange && _this.props.onChange(res)
                // console.log('已上传大小,单位为字节:' + res.total.loaded)
                // console.log(
                //     '本次上传的总量控制信息,单位为字节:' + res.total.size
                // )
                // console.log(
                //     '当前上传进度,范围:0~100:' + res.total.percent
                // )
                // _this.$set(
                //     _this.materialUploadPercentList,
                //     file.file.uid,
                //     res.total.percent.toFixed(0) * 1
                // )
            },
            error: (err: any) => {
                // ...
                console.log(err.code)
                uploadInstance.onError(err)
                this.props.onChange && this.props.onChange()
            },
            complete: (res: any) => {
                // ...
                console.log(res)
                uploadInstance.onComplete(res)
                this.props.onChange && this.props.onChange()
                // _this.handleSuccess(res, file.file)
            },
            // this.beforeAvatarUpload(file.file)
        }
        // this.materialJson = {
        //     name: file.name.split('.')[0] + '.',  // 文件名字
        //     size: this.getFileSizeMin(file.size),
        //     type: this.checkFileType(file),
        //     typename: file.type && file.type.split('/')[1],
        // }
        // console.log('Json', this.materialJson)
        this.props.onLoad && this.props.onLoad(uploadInstance)
    }

    //  是否处于接受的文件格式类型内
    private isAcceptedFile(fileName: string) {
        //  注释的视频类型均为七牛不支持类型
        const videoList = [
            // 'flv',
            // 'avi',
            // 'wmv',
            // '3gp',
            // 'm4v',
            // 'ogg',
            // 'rmvb',
            // 'mov',
            // 'x-flv',
            // 'mkv',
            'mp4',
        ]
        const imageList = ['png', 'jpg', 'jpeg']
        let flag = false
        videoList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(fileName)) {
                flag = true
            }
        })
        imageList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(fileName)) {
                flag = true
            }
        })

        return flag
    }

        //  返回文件类型 1 图片 2 视频
    private checkFileType(item: any) {
        let type = -1
        //  注释的视频类型均为七牛不支持类型
        const videoList = [
            // 'flv',
            // 'avi',
            // 'wmv',
            // '3gp',
            // 'm4v',
            // 'ogg',
            // 'rmvb',
            // 'mov',
            // 'x-flv',
            // 'mkv',
            'mp4',
        ]
        const imageList = ['png', 'jpg', 'jpeg']
        const name = item.name
        videoList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(name)) {
                type = 2
            }
        })
        imageList.forEach(node => {
            const reg = new RegExp('.' + node + '$', 'i')
            if (reg.test(name)) {
                type = 1
            }
        })

        return type
    }



    // 获取素材的大小
    private getFileSizeMin(val: number) {
        let sizeType = ''
        if (val / (1024 * 1024) > 1) {
            sizeType = 'M'

            return (val / (1024 * 1024)).toFixed(1) + sizeType
        } else {
            sizeType = 'Kb'

            return (val / 1024).toFixed(1) + sizeType
        }
    }

    // 获取七牛的token
    private getQiniuToken(type: number, cb: () => void) {
        getQiniuUploadToken(type).then(data => {
            if (type === 2) {
                // this.qiniuData.token2 = data.token
                // this.qiniuToken1 = data.token
                this.qiniuToken2 = data.token
            } else {
                // this.qiniuData.token = data.token
                // this.qiniuToken2 = data.token
                this.qiniuToken1 = data.token
            }
            cb && cb()
        })
    }
}

yaogengzhu avatar May 13 '20 11:05 yaogengzhu