import { FC, useMemo, useRef, useState, useEffect } from 'react' import { useSearchParams } from 'react-router-dom' import { ForbidFill } from 'antd-mobile-icons' import { Toast } from 'antd-mobile' import { isAlipayIDE } from '@/utils' import { ChooseVideoAction, BasicFileValueType } from '@/types' import { Upload, UploadFile, Spin } from 'antd' import emptyFileImg from '@/images/form/empty-file.png' import fileImg from '@/images/form/file.png' import moment from 'moment' import { flowApi } from '@/services/flow' import { useAppDispatch } from '@/store/storeHooks' import { AddOutline } from 'antd-mobile-icons' import styled from 'styled-components' const ossHost = import.meta.env.VITE_OSS_HOST interface FileFieldProps { value?: BasicFileValueType required: boolean maxCount?: number maxSize?: number hostUrl?: string actionUrl?: string platform?: string canDownload?: boolean onChange?: (value: BasicFileValueType) => void accept?: string } interface FileItem { name: string url: string percent?: number uid: string } const FileField: FC = ({ maxCount = 20, maxSize = 30, onChange, value = [], accept = '', actionUrl = '/qy/common/uploadWorkOrderImg/noLogin' }) => { const [searchParams] = useSearchParams() const companyKey = searchParams.get('companyKey') || '' const shopUniqueKey = searchParams.get('shopUniqueKey') || '' const storeDispatch = useAppDispatch() const uploadCount = useRef(0) const [uploading, setUploading] = useState(false) const valueRef = useRef(value) const FileList = value.map((file, index) => { return (
handleDelFile(index)} />
{file.name}
) }) useEffect(() => { valueRef.current = value }, [value]) const triggerValue = (changedValue: BasicFileValueType) => { onChange?.(changedValue) } const onValueChange = (value: BasicFileValueType) => { triggerValue(value) } // 点击上传图片 通知小程序 const handleUploadFile = () => { if (window?.my && !isAlipayIDE) { my.postMessage({ action: 'chooseVideo', option: { maxSize, count: maxCount - value.length } }) my.onMessage = (e: ChooseVideoAction) => { const { action, data } = e if (action === 'chooseVideo') { data.url = `${ossHost}/${data.url}` onValueChange([...value.slice(), data]) } } } } // 删除图片 const handleDelFile = (index: number) => { const tempList = value.slice() tempList.splice(index, 1) onValueChange(tempList) } const isUpLimit = useMemo(() => { return value.length - maxCount >= 0 }, [value, maxCount]) const fileList: FileItem[] = useMemo(() => { return ( value.map((t, i) => { return { ...t, percent: 100, uid: i.toString() } }) || [] ) }, [value]) const asyncUpload = async (file: File) => { setUploading(true) uploadCount.current++ const formData = new FormData() formData.append('file', file) const fileName = `${moment(new Date().getTime()).format( 'YYYY-MM-DD hh:mm:ss' )}_${file.name}` formData.append('fileName', fileName) try { const res = await storeDispatch( flowApi.endpoints.uploadFile.initiate({ url: `${actionUrl}?companyKey=${companyKey}&shopUniqueKey=${shopUniqueKey}`, formData }) ) const { data } = res as { data: string } if ('error' in res && res.error) { throw res.error } else if (data) { valueRef.current = [ ...valueRef.current, { url: `${ossHost}/${data}`, name: file.name } ] onValueChange([...valueRef.current]) } } catch (e) { Toast.show('文件上传失败') } finally { uploadCount.current-- if (uploadCount.current < 1) { setUploading(false) } } } // 手动上传模式, 一直返回false const beforeUpload = async (file: File, fileList: UploadFile[]) => { const size = file.size / 1024 / 1024 < maxSize // TODO: 批量提交的时候 if (fileList?.length + value.length > maxCount) { Toast.show(`最多添加${maxCount}个文件!`) return Upload.LIST_IGNORE } if (!size) { Toast.show(`文件不能大于${maxSize}MB`) return Upload.LIST_IGNORE } await asyncUpload(file) return Upload.LIST_IGNORE } const onRemove = (file: UploadFile) => { const newValue = value.filter(item => item.url !== file.url) onValueChange(newValue) } const onPreview = (file: UploadFile) => { window.open(file?.url) } const UploadBtn = () => ( ) return ( <>
{window?.my && !isAlipayIDE ? ( <> {FileList} {!isUpLimit && (
上传文件
)} ) : ( )}

最多添加{maxCount}个文件,每个最大30Mb

) } const UploadFileBox = styled.div` width: 80px; height: 80px; line-height: 80px; display: flex; align-items: center; justify-content: center; border: 1px dashed #cccccc; border-radius: 4px; ` export default FileField