import { RESPONSE_CODE } from '@/constants/enum'; import { postCanrdApiUserList, postPrepaidCreate, postPrepaidUpdate, postServiceOrderFileProcess, postServiceOrderQuerySalesCode, } from '@/services'; import { transImageFile } from '@/utils'; import { PlusOutlined } from '@ant-design/icons'; import { ModalForm, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea, } from '@ant-design/pro-components'; import { Form, Modal, Upload, UploadFile, UploadProps, message } from 'antd'; import { RcFile } from 'antd/es/upload'; import { cloneDeep } from 'lodash'; import { useEffect, useRef, useState } from 'react'; // import { cloneDeep } from 'lodash'; export default ({ setVisible, prepaymentObject, onClose }) => { const [form] = Form.useForm<{ proofImages: any; id: number; customerName: string; contactPerson: string; salesCode: string; rechargeAmount: number; notes: string; }>(); const [salesCodeOptions, setSalesCodeOptions] = useState([]); const [isCreate, setIsCreate] = useState(true); const [fileList, setFileList] = useState<UploadFile[]>([]); const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [previewTitle, setPreviewTitle] = useState(''); const [messageApi, contextHolder] = message.useMessage(); const fileListObj = useRef<UploadFile[]>([]); //使用引用类型,使得在useEffect里面设置监听事件后,不用更新监听事件也能保持obj与外界一致 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 handleCancel = () => setPreviewOpen(false); /** 粘贴快捷键的回调 */ 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 >= 3) { message.info('发货照片数量不能超过3'); return; } fileListObj.current = filteredArray; filteredArray.push(listItem); setFileList(filteredArray); return; } } message.info('您的剪贴板中没有照片'); }; 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 handleBeforeUpload = (file: any) => { setFileList([...fileList, file]); return false; }; const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => { //fileListObj得在change里变化,change的参数是已经处理过的file数组 //beforeUpload中的参数file是未处理过,还需要Base64拿到文件数据处理 fileListObj.current = newFileList; setFileList(newFileList); }; 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') }, }; const uploadButton = ( <div> <PlusOutlined /> <div style={{ marginTop: 8 }}>上传凭证</div> </div> ); /** * 获取销售代码枚举,在复制和编辑的时候判断是否为旧的代码 */ const getSalesCodeOptions = async () => { const res = await postServiceOrderQuerySalesCode(); let options = res.data?.map((item) => { return { label: item.userName, value: item.userName, number: item.number, }; }); setSalesCodeOptions(options); }; // 自定义校验规则 const validateRechargeAmount = async (rule: any, value: number) => { if (value <= 0) { throw new Error('充值金额必须大于0'); } }; //自动填充客户信息 const autoFillCustomerContactSelectOptions = (option: any) => { console.log(option); //新增 if (option.value === 3.1415926) { form.setFieldValue('customerNameString', option.name); } else { form.setFieldValue('phone', option.phone); form.setFieldValue('contactPerson', option.realName); form.setFieldValue('customerNameString', option.institution); } }; useEffect(() => { getSalesCodeOptions(); //修改,信息回显 if (prepaymentObject !== null) { setIsCreate(false); let values = form.getFieldsValue(); let keys = Object.keys(values); for (let key of keys) { form.setFieldValue(key, prepaymentObject[key]); } //客户select回显 form.setFieldValue('customerName', prepaymentObject.customerName); //凭证回显 let images = prepaymentObject.proofImages; if (images !== null && images !== undefined) { let files = images?.map((item) => { return { url: item, status: 'done', isOld: true, }; }); setFileList(files); } } }, []); useEffect(() => { document.addEventListener('paste', onPaste); return () => { document.removeEventListener('paste', onPaste); }; }, []); return ( <> <ModalForm width={500} open title={(isCreate ? '新增' : '修改') + '预存记录'} form={form} autoFocusFirstInput modalProps={{ okText: '保存', cancelText: '取消', destroyOnClose: true, onCancel: () => { setVisible(false); }, }} onFinish={async (values) => { if (fileList.length <= 0) { message.error('凭证不能为空'); return; } messageApi.open({ type: 'loading', content: '正在上传图片...', duration: 0, }); //附件处理 let formData = new FormData(); //附件处理 console.log(fileList); for (let file of fileList) { if (file.isOld === undefined) { 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, }); if (res.result === RESPONSE_CODE.SUCCESS) { message.success('上传成功!'); let fileUrls = res?.data?.map((item) => { return item; }); //旧的凭证也要加上去 fileList.forEach((item) => { if (item.isOld !== undefined) { fileUrls.unshift(item.url); } }); values.proofImages = fileUrls; if (isCreate) { res = await postPrepaidCreate({ data: { ...values, customerName: form.getFieldValue('customerNameString'), }, }); } else { let customerNameString = form.getFieldValue('customerNameString'); let body = { ...values }; if (customerNameString) { //customerNameString不为空说明是有重新选择客户,customerName要取这个值 body.customerName = customerNameString; } res = await postPrepaidUpdate({ data: body, }); } if (res && res.result === RESPONSE_CODE.SUCCESS) { message.success(res.message); onClose(); } } }} onOpenChange={setVisible} > <ProFormText name="id" label="编号" disabled /> <ProFormSelect name="customerName" key="customerName" width="lg" showSearch label="客户名称" placeholder="请选择客户" onChange={(_, option) => { autoFillCustomerContactSelectOptions(option); }} fieldProps={{ filterOption() { return true; }, optionItemRender(item) { if (item.type === 'add') { return ( <div title={item.name + '(新增客户)'}> <span style={{ color: '#333333' }}>{item.name}</span> {' | '} <span style={{ color: 'orange' }}>自定义</span> </div> ); } let name = item.label + ' | ' + item.institution + ' | ' + item.nowMoney + '¥' + ' | ' + item.phone; return ( <div title={name}> <span style={{ color: '#333333' }}>{name}</span> </div> ); }, }} debounceTime={1000} request={async (value, {}) => { const keywords = value.keyWords; const res = await postCanrdApiUserList({ data: { keywords: keywords, pageSize: 1000000 }, }); let options = res?.data?.data?.map((c: any) => { return { ...c, label: c.realName, value: c.uid, key: c.uid, }; }); //第一个默认为要新增客户 if (keywords.trim() !== '') { options.unshift({ name: keywords, type: 'add', label: keywords, value: 3.1415926, key: keywords, }); } return options; }} /> <ProFormText name="contactPerson" label="联系人" rules={[{ required: true, message: '请输入联系人' }]} /> <ProFormText name="phone" label="手机号" rules={[{ required: true, message: '请输入手机号' }]} normalize={(value) => value && value.trim()} /> <ProFormSelect name="salesCode" key="salesCode" width="lg" showSearch label="销售代表" placeholder="请输入销售代表" rules={[{ required: true, message: '销售代表必填' }]} options={salesCodeOptions} /> <ProFormDigit name="rechargeAmount" label="充值金额(¥)" rules={[ { required: true, message: '请输入充值金额' }, { validator: validateRechargeAmount }, ]} /> <> <div className="pb-4 text-xs decoration-gray-50">可复制照片粘贴</div> <Upload {...props}>{fileList.length < 3 ? uploadButton : ''}</Upload> </> <ProFormTextArea name="notes" label="备注" /> </ModalForm> <Modal open={previewOpen} title={previewTitle} footer={null} onCancel={handleCancel} > <img alt="图片预览" style={{ width: '100%' }} src={previewImage} /> </Modal> {contextHolder} </> ); };