/** * @file 身份证上传弹窗组件 * @author luozhengxuan <51071534@qq.com> * */ import React, { useState, useMemo, useCallback } from 'react'; import Axios from 'axios'; import { FormOutlined, DeleteOutlined } from '@ant-design/icons'; import message from 'antd/es/message'; import 'antd/es/message/style/index'; import Modal from 'antd/es/modal'; import 'antd/es/modal/style/index'; import Upload, { RcFile } from 'antd/es/upload'; import 'antd/es/upload/style/index'; import { compressImage } from '@jy-fe/utils'; import modalOpen from '../common/modal-open'; import PNGIdcardPortrait from '../assets/idcard-2.png'; import PNGIdcardEmblem from '../assets/idcard-1.png'; import PNGIdcardCase1 from '../assets/idcard-case-1.png'; import PNGIdcardCase2 from '../assets/idcard-case-2.png'; import PNGIdcardCase3 from '../assets/idcard-case-3.png'; import PNGIdcardCase4 from '../assets/idcard-case-4.png'; import PNGShowcaseSuccess from '../assets/showcase-success.png'; import PNGShowcaseFail from '../assets/showcase-fail.png'; import { OpenConfig, XuiModalIdcardProps } from './xui-modal-idcard.d'; interface FileData { url: string; list: RcFile[]; } export const XuiModalIdcard: React.FC & { open: (c: OpenConfig) => Record; } = ({ name, idcard, uploadURL, uploadExtraConf = {}, success, fail, ...props }) => { const classname = 'xui-ant__modal-idcard'; const imgSize = 5; const accept = useMemo( () => ({ type: ['jpg', 'png', 'jpeg'], mime: ['image/jpeg', 'image/png'], }), [], ); const [filePortrait, setFilePortrait] = useState({ url: '', list: [] }); const [fileEmblem, setFileEmblem] = useState({ url: '', list: [] }); const [loading, setLoading] = useState(false); const internalVerifyFile = (file): boolean => { if (!accept.mime.includes(file.type)) { message.error(`只支持${accept.type.join('、')}格式`); return true; } if (file.size / 1024 / 1024 > imgSize) { message.error(`图片大于${imgSize}M`); return true; } return false; }; const internalBeforeUploadPortrait = file => { if (internalVerifyFile(file)) return false; setFilePortrait({ url: URL.createObjectURL(file), list: [file], }); return false; }; const internalBeforeUploadEmblem = file => { if (internalVerifyFile(file)) return false; setFileEmblem({ url: URL.createObjectURL(file), list: [file], }); return false; }; const handleDeletePortrait = useCallback(() => { setFilePortrait({ url: '', list: [] }); }, []); const handleDeleteEmblem = useCallback(() => { setFileEmblem({ url: '', list: [] }); }, []); // eslint-disable-next-line consistent-return const fetchCreateIdcard = async (e: React.MouseEvent) => { try { if (!filePortrait.list.length) { return message.warn('请上传人像面'); } if (!fileEmblem.list.length) { return message.warn('请上传国徽面'); } const { data: extraData, ...otherExtraConf } = uploadExtraConf; const formData = new FormData(); if (extraData instanceof Object) { Object.entries(extraData).forEach(entry => { formData.append(entry[0], entry[1]); }); } const maxSize = 2000000; let compressFilePortrait; let compressFileEmblem; if (filePortrait.list[0].size > maxSize) { compressFilePortrait = await compressImage(filePortrait.url, 0.5); } if (fileEmblem.list[0].size > maxSize) { compressFileEmblem = await compressImage(fileEmblem.url, 0.5); } const file1 = compressFilePortrait || filePortrait.list[0]; const file2 = compressFileEmblem || fileEmblem.list[0]; formData.append('file1', file1); formData.append('file2', file2); setLoading(true); const { data } = await Axios({ url: uploadURL, method: 'POST', data: formData, ...(otherExtraConf || {}), }); // 这里如果使用 return Promise.reject 会进入到 axios 的捕获里 // TODO: 待优化 if (data.status) throw data; message.success('上传成功'); if (props.onCancel) { props.onCancel(e); } if (success) success(data.data); return data; } catch (err) { if (err.msg) { message.warn(err.msg); } else { message.error('网络异常'); } handleDeletePortrait(); handleDeleteEmblem(); if (fail) fail(err); } finally { setLoading(false); } }; return ( {name && idcard ? (

请上传 "{name}" 身份证号 "{idcard}" 的身份证正反面

) : null}
{filePortrait.list.length ? ( [ ,
  
, ] ) : ( )}
{fileEmblem.list.length ? ( [ ,
  
, ] ) : ( )}
拍摄要求
垂直正面、高清、四角齐全、边缘完整、无反光、{imgSize}M以内的jpg/png/jpeg格式
标准拍摄
边框缺失
照片模糊
拍摄倾斜
); }; XuiModalIdcard.open = (config: OpenConfig) => modalOpen(config, XuiModalIdcard); export default XuiModalIdcard;