新增Signature签字组件
parent
7485d77973
commit
a4e026b838
|
|
@ -59,12 +59,12 @@ const FormBuilder = (props) => {
|
|||
{submitButtonText}
|
||||
</Button>
|
||||
)}
|
||||
{extraActionButtons}
|
||||
{showCancelButton && (
|
||||
<Button onClick={handleCancel}>
|
||||
{cancelButtonText}
|
||||
</Button>
|
||||
)}
|
||||
{extraActionButtons}
|
||||
</Space>
|
||||
)}
|
||||
</Col>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import type { FC } from "react";
|
||||
|
||||
export interface SignatureValue {
|
||||
/** 签字时间,YYYY-MM-DD HH:mm:ss */
|
||||
time: string;
|
||||
/** 签字图片的base64编码 */
|
||||
base64: string;
|
||||
}
|
||||
|
||||
export interface SignatureProps {
|
||||
/** 确认签字回调 */
|
||||
onConfirm: (value: SignatureValue) => void;
|
||||
/** 签字区域宽度,默认为 752 */
|
||||
width?: number;
|
||||
/** 签字区域高度,默认为 300 */
|
||||
height?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 签字组件
|
||||
*/
|
||||
declare const Signature: FC<SignatureProps>;
|
||||
|
||||
export default Signature;
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import { Button, Image, message, Modal } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import { useRef, useState } from "react";
|
||||
import SignatureCanvas from "react-signature-canvas";
|
||||
import { base642File } from "../../utils";
|
||||
|
||||
/**
|
||||
* 签字组件
|
||||
*/
|
||||
function Signature(props) {
|
||||
const {
|
||||
onConfirm,
|
||||
width = 752,
|
||||
height = 300,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const [signatureModalOpen, setSignatureModalOpen] = useState(false);
|
||||
const signatureCanvas = useRef(null);
|
||||
const [base64, setBase64] = useState("");
|
||||
|
||||
const onOk = () => {
|
||||
if (signatureCanvas.current.isEmpty()) {
|
||||
message.warning("请签名");
|
||||
return;
|
||||
}
|
||||
const base64 = signatureCanvas.current.toDataURL();
|
||||
setBase64(base64);
|
||||
onConfirm({
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
base64,
|
||||
file: base642File(base64),
|
||||
});
|
||||
signatureCanvas.current.clear();
|
||||
setSignatureModalOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
setSignatureModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{base64 ? "重新签字" : "手写签字"}
|
||||
</Button>
|
||||
</div>
|
||||
{base64 && (
|
||||
<div style={{ border: "1px dashed #d9d9d9", width, height, marginTop: 16 }}>
|
||||
<Image src={base64} />
|
||||
</div>
|
||||
)}
|
||||
<Modal
|
||||
title="签字"
|
||||
width={800}
|
||||
open={signatureModalOpen}
|
||||
onCancel={() => setSignatureModalOpen(false)}
|
||||
footer={[
|
||||
<Button key="clear" onClick={() => signatureCanvas.current.clear()}>重签</Button>,
|
||||
<Button
|
||||
key="cancel"
|
||||
onClick={() => {
|
||||
setSignatureModalOpen(false);
|
||||
signatureCanvas.current.clear();
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Button>,
|
||||
<Button key="ok" type="primary" onClick={onOk}>确定</Button>,
|
||||
]}
|
||||
>
|
||||
<div style={{ border: "1px dashed #d9d9d9" }}>
|
||||
<SignatureCanvas
|
||||
ref={signatureCanvas}
|
||||
penColor="black"
|
||||
canvasProps={{ width, height }}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Signature;
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
"dayjs": "^1.11.18",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^18.3.1",
|
||||
"react-pdf": "^10.2.0"
|
||||
"react-pdf": "^10.2.0",
|
||||
"react-signature-canvas": "^1.1.0-alpha.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,6 +261,11 @@ export function getIndexColumn(pagination: false | BasePaginationConfig): {
|
|||
*/
|
||||
export function getFileUrl(): string;
|
||||
|
||||
/**
|
||||
* base64转File对象
|
||||
*/
|
||||
export function base642File(base64: string, filename?: string): File;
|
||||
|
||||
/**
|
||||
* 获取树形节点路径
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -61,6 +61,23 @@ export function image2Base642(file) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
base64转File对象
|
||||
*/
|
||||
export function base642File(base64, filename = "file") {
|
||||
const arr = base64.split(",");
|
||||
const mime = arr[0].match(/:(.*?);/)[1];
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
|
||||
return new File([u8arr], filename, { type: mime });
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断图片是否可访问成功
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue