blob: 83d0bcf1b7719c538d2dd597de128401503e5f59 [file] [log] [blame]
Jiarenxiang38dcb052025-03-13 16:40:09 +08001import React, { useEffect, useRef, useState } from 'react';
2import { Modal, Row, Col, Button, Space, Upload, message } from 'antd';
3import { useIntl } from '@umijs/max';
4import { uploadAvatar } from '@/services/system/user';
5import { Cropper } from 'react-cropper';
6import './cropper.css';
7import styles from './index.less';
8import {
9 MinusOutlined,
10 PlusOutlined,
11 RedoOutlined,
12 UndoOutlined,
13 UploadOutlined,
14} from '@ant-design/icons';
15
16/* *
17 *
18 * @author whiteshader@163.com
19 * @datetime 2022/02/24
20 *
21 * */
22
23export type AvatarCropperProps = {
24 onFinished: (isSuccess: boolean) => void;
25 open: boolean;
26 data: any;
27};
28
29const AvatarCropperForm: React.FC<AvatarCropperProps> = (props) => {
30 const cropperRef = useRef<HTMLImageElement>(null);
31 const [avatarData, setAvatarData] = useState<any>();
32 const [previewData, setPreviewData] = useState();
33
34 useEffect(() => {
35 setAvatarData(props.data);
36 }, [props]);
37
38 const intl = useIntl();
39 const handleOk = () => {
40 const imageElement: any = cropperRef?.current;
41 const cropper: any = imageElement?.cropper;
42 cropper.getCroppedCanvas().toBlob((blob: Blob) => {
43 const formData = new FormData();
44 formData.append('avatarfile', blob);
45 uploadAvatar(formData).then((res) => {
46 if (res.code === 200) {
47 message.success(res.msg);
48 props.onFinished(true);
49 } else {
50 message.warning(res.msg);
51 }
52 });
53 }, 'image/png');
54 };
55 const handleCancel = () => {
56 props.onFinished(false);
57 };
58 const onCrop = () => {
59 const imageElement: any = cropperRef?.current;
60 const cropper: any = imageElement?.cropper;
61 setPreviewData(cropper.getCroppedCanvas().toDataURL());
62 };
63 const onRotateRight = () => {
64 const imageElement: any = cropperRef?.current;
65 const cropper: any = imageElement?.cropper;
66 cropper.rotate(90);
67 };
68 const onRotateLeft = () => {
69 const imageElement: any = cropperRef?.current;
70 const cropper: any = imageElement?.cropper;
71 cropper.rotate(-90);
72 };
73 const onZoomIn = () => {
74 const imageElement: any = cropperRef?.current;
75 const cropper: any = imageElement?.cropper;
76 cropper.zoom(0.1);
77 };
78 const onZoomOut = () => {
79 const imageElement: any = cropperRef?.current;
80 const cropper: any = imageElement?.cropper;
81 cropper.zoom(-0.1);
82 };
83 const beforeUpload = (file: any) => {
84 const reader = new FileReader();
85 reader.readAsDataURL(file);
86 reader.onload = () => {
87 setAvatarData(reader.result);
88 };
89 };
90 return (
91 <Modal
92 width={800}
93 title={intl.formatMessage({
94 id: 'system.user.modify_avatar',
95 defaultMessage: '修改头像',
96 })}
97 open={props.open}
98 destroyOnClose
99 onOk={handleOk}
100 onCancel={handleCancel}
101 >
102 <Row gutter={[16, 16]}>
103 <Col span={12} order={1}>
104 <Cropper
105 ref={cropperRef}
106 src={avatarData}
107 style={{ height: 350, width: '100%', marginBottom: '16px' }}
108 initialAspectRatio={1}
109 guides={false}
110 crop={onCrop}
111 zoomable={true}
112 zoomOnWheel={true}
113 rotatable={true}
114 />
115 </Col>
116 <Col span={12} order={2}>
117 <div className={styles.avatarPreview}>
118 <img src={previewData} style={{ height: '100%', width: '100%' }} />
119 </div>
120 </Col>
121 </Row>
122 <Row gutter={[16, 16]}>
123 <Col span={6}>
124 <Upload beforeUpload={beforeUpload} maxCount={1}>
125 <Button>
126 <UploadOutlined />
127 上传
128 </Button>
129 </Upload>
130 </Col>
131 <Col>
132 <Space>
133 <Button icon={<RedoOutlined />} onClick={onRotateRight} />
134 <Button icon={<UndoOutlined />} onClick={onRotateLeft} />
135 <Button icon={<PlusOutlined />} onClick={onZoomIn} />
136 <Button icon={<MinusOutlined />} onClick={onZoomOut} />
137 </Space>
138 </Col>
139 </Row>
140 </Modal>
141 );
142};
143
144export default AvatarCropperForm;