import { ModalForm } from '@ant-design/pro-components'; import { Form, Modal, Upload, UploadFile, UploadProps, message } from 'antd'; import { RcFile } from 'antd/lib/upload'; import { cloneDeep } from 'lodash'; import { useEffect, useRef, useState } from 'react'; import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../constant'; import { PlusOutlined } from '@ant-design/icons'; import { transImageFile } from '@/utils'; import { postServiceOrderFileProcess, postServiceOrderUploadPaymentReceipt } from '@/services'; import { RESPONSE_CODE } from '@/constants/enum'; // import { cloneDeep } from 'lodash'; export default ({ setVisible, subOrders, mainOrder, onClose }) => { const [form] = Form.useForm(); const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [previewTitle, setPreviewTitle] = useState(''); const handleCancel = () => setPreviewOpen(false); const [fileList, setFileList] = useState<UploadFile[]>([]); const getBase64 = (file: RcFile): Promise<string> => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = (error) => reject(error); }); const subOrderIds = subOrders?.map((item: any) => { return item.id }); const fileListObj = useRef<UploadFile[]>([]); //使用引用类型,使得在useEffect里面设置监听事件后,不用更新监听事件也能保持obj与外界一致 const handleBeforeUpload = (file: any) => { setFileList([...fileList, file]); return false; }; const uploadButton = ( <div> <PlusOutlined /> <div style={{ marginTop: 8 }}>上传凭证</div> </div> ); /** 粘贴快捷键的回调 */ const onPaste = async (e: any) => { /** 获取剪切板的数据clipboardData */ let clipboardData = e.clipboardData, i = 0, items, item, types; /** 为空判断 */ if (clipboardData) { items = clipboardData.items; if (!items) { message.info('您的剪贴板中没有照片'); return; } item = items[0]; types = clipboardData.types || []; /** 遍历剪切板的数据 */ for (; i < types.length; i++) { if (types[i] === 'Files') { item = items[i]; break; } } /** 判断文件是否为图片 */ if (item && item.kind === 'file' && item.type.match(/^image\//i)) { const imgItem = item.getAsFile(); const newFileList = cloneDeep(fileListObj.current); let filteredArray = newFileList.filter( (obj) => obj.status !== 'removed', ); //过滤掉状态为已删除的照片 const listItem = { ...imgItem, status: 'done', url: await getBase64(imgItem), originFileObj: imgItem, }; if (filteredArray.length >= COMFIR_RECEIPT_IMAGES_NUMBER) { message.info('发货照片数量不能超过3'); return; } fileListObj.current = filteredArray; filteredArray.push(listItem); setFileList(filteredArray); return; } } message.info('您的剪贴板中没有照片'); }; const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => { //fileListObj得在change里变化,change的参数是已经处理过的file数组 //beforeUpload中的参数file是未处理过,还需要Base64拿到文件数据处理 fileListObj.current = newFileList; setFileList(newFileList); }; const handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj as RcFile); } setPreviewImage(file.url || (file.preview as string)); setPreviewOpen(true); setPreviewTitle( file.name || file.originFileObj?.name || file.url!.substring(file.url!.lastIndexOf('/') + 1), ); }; const props: UploadProps = { onRemove: (file) => { const index = fileList.indexOf(file); const newFileList = fileList.slice(); newFileList.splice(index, 1); setFileList(newFileList); }, beforeUpload: handleBeforeUpload, listType: 'picture-card', onPreview: handlePreview, fileList, onChange: handleChange, accept: 'image/png, image/jpeg, image/png', // action: '/api/service/order/fileProcess', name: 'files', headers: { Authorization: localStorage.getItem('token') }, }; useEffect(() => { document.addEventListener('paste', onPaste); return () => { document.removeEventListener('paste', onPaste); }; }, []); return ( <> <ModalForm<{ filePaths: any; }> width={500} open title="回款凭证上传" form={form} autoFocusFirstInput modalProps={{ okText: '提交', cancelText: '取消', destroyOnClose: true, onCancel: () => { setVisible(false); }, }} onFinish={async () => { if (fileList.length <= 0) { message.error('请上传至少一张凭证'); return; } message.open({ type: 'loading', content: '正在上传凭证...', duration: 0, }); //附件处理 let formData = new FormData(); //附件处理 for (let file of fileList) { if (file.originFileObj) { formData.append('files', file.originFileObj as RcFile); } else { //有url的话取url(源文件),没url取thumbUrl。有url的时候thumbUrl是略缩图 if (file?.url === undefined || file?.url === null) { formData.append( 'files', transImageFile(file?.thumbUrl), file?.originFileObj?.name, ); } else { formData.append( 'files', transImageFile(file?.url), file?.originFileObj?.name, ); } } } let res = await postServiceOrderFileProcess({ data: formData, }); message.destroy(); if (res.result === RESPONSE_CODE.SUCCESS) { let fileUrls = res?.data?.map((item) => { return { url: item }; }); //财务审核 const data = await postServiceOrderUploadPaymentReceipt({ data: { subOrderIds: subOrderIds, filePaths: fileUrls, }, }); if (data.result === RESPONSE_CODE.SUCCESS) { message.success(data.message); onClose(); } } else { message.success('上传失败'); } onClose(); }} onOpenChange={setVisible} > <div className="pb-4 text-xs decoration-gray-50"> 可复制照片粘贴 </div> <Upload {...props}> {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER ? uploadButton : ''} </Upload> </ModalForm> <Modal open={previewOpen} title={previewTitle} footer={null} onCancel={handleCancel} > <img alt="图片预览" style={{ width: '100%' }} src={previewImage} /> </Modal> </> ); };