Skip to content

Commit

Permalink
修改版本
Browse files Browse the repository at this point in the history
  • Loading branch information
zhipenglin committed Jul 24, 2023
1 parent 4977056 commit 837204a
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 7 deletions.
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"name": "@kne/react-form-antd",
"version": "3.0.30",
"type": "module",
"version": "3.0.31",
"syntax": {
"esmodules": true
},
"description": "把 @kne/react-form 表单校验逻辑应用到antd",
"main": "dist/index.cjs",
"main": "dist/index.js",
"module": "dist/index.modern.js",
"source": "src/index.js",
"scripts": {
"init": "npm install --legacy-peer-deps && cd example && npm install --legacy-peer-deps",
"create-fields": "node ./scripts/createIndex.js",
"create-fields": "node ./scripts/createIndex.mjs",
"start": "run-p start:lib start:example",
"build": "run-s create-fields build:lib build:example",
"build:lib": "microbundle --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment",
Expand Down Expand Up @@ -65,6 +67,7 @@
"@kne/react-form-helper": "^1.0.36",
"@kne/use-control-value": "^0.1.1",
"@kne/use-event": "^0.1.3",
"@kne/with-layer": "^0.1.5",
"classnames": "^2.2.6",
"dayjs": "^1.11.7",
"lodash": "^4.17.15"
Expand Down
File renamed without changes.
232 changes: 232 additions & 0 deletions src/fields/Avatar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import React, {useState, useRef, useEffect, forwardRef} from "react";
import {Upload, message, Modal, Slider, Row, Col, Tooltip, App} from "antd";
import withLayer from '@kne/with-layer';
import {globalParams} from "../preset";
import classnames from "classnames";
import {
PlusOutlined, LoadingOutlined
} from "@ant-design/icons";
import AvatarEditor from "react-avatar-editor";
import {hooks} from "@kne/react-form-helper";
import {merge, omit} from 'lodash';
import Rotate from '../assets/rotate';
import Full from '../assets/full';
import getPopupContainer from '../common/getPopupContainer';

const {useOnChange} = hooks;
const avatarParams = globalParams.field.avatar;

const createAvatarEditor = withLayer(({close, file, editor, onComplete, ...props}) => {
const editorRef = useRef(null);
const [rotate, setRotate] = useState(0);
const [scale, setScale] = useState(() => {
if (editor.width === editor.height) {
return 1;
}
return 0.35;
});
const {modal} = App.useApp();

return <Modal {...props} className={editor.className} centered onOk={() => {
onComplete && onComplete(editorRef.current.getImage().toDataURL());
close();
}}>
{editor.tips ? <div className="react-form-avatar-tips">{editor.tips}</div> : null}
<div style={{
"width": editor.width, "margin": "auto"
}}>
<AvatarEditor
ref={editorRef}
image={file}
width={editor.width}
height={editor.height}
border={1}
borderRadius={editor.borderRadius}
color={[24, 144, 255, 1]} // RGBA
scale={scale}
rotate={rotate}
/>
<Row gutter={4} align="middle">
<Col span={4}><Tooltip title="旋转" placement="bottom" getPopupContainer={getPopupContainer}><Rotate
className="react-form-avatar-btn" onClick={() => {
setRotate((rotate) => {
return (rotate - 90) % 360;
});
}}/></Tooltip></Col>
<Col span={4}><Tooltip title="还原" placement="bottom" getPopupContainer={getPopupContainer}><Full
className="react-form-avatar-btn" onClick={() => {
setScale(1);
}}/></Tooltip></Col>
<Col flex={1}>
<Slider className="react-form-avatar-slider" tooltip={{
placement: "bottom", formatter: () => '大小', getPopupContainer
}} value={scale} step={0.05} min={0.2} max={3} onChange={setScale}/>
</Col>
</Row>
</div>
</Modal>
});


const _Avatar = ({
className,
value: imageUrl,
onChange: propsChange,
beforeUpload: onBeforeUpload,
transformResponse,
action,
imageType,
fileSize: size,
children,
extraRender,
onError,
openEditor,
editorTips,
editor: targetEditor,
previewImg,
previewRender
}) => {
const [loading, setLoading] = useState(false);
const [showImageUrl, setImageUrl] = useState(imageUrl);
const editorRef = useRef();

const defaultEditor = {
open: false,
width: 250,
height: 250,
borderRadius: 1,
text: "确定",
cancelText: '取消',
title: "裁剪图片",
tips: null
};
const editor = merge({}, defaultEditor, {open: openEditor, tips: editorTips}, targetEditor);

useEffect(() => {
setImageUrl(imageUrl);
}, [imageUrl]);

/* base64转blob */
const dataURLtoBlob = (dataurl) => {
let arr = dataurl.split(",");
// 注意base64的最后面中括号和引号是不转译的
let _arr = arr[1].substring(0, arr[1].length - 2);
let mime = arr[0].match(/:(.*?);/)[1], bstr = atob(_arr), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {
type: mime
});
};

const uploadButton = (<div>
{loading ? <LoadingOutlined/> : <PlusOutlined/>}
{children}
</div>);

const beforeUpload = async (file) => {
return new Promise((resolve, reject) => {
const isJpgOrPng = imageType.indexOf(file.type) > -1;
if (!isJpgOrPng) {
onError(`只支持${imageType.map((str) => str.replace("image/", "")).join("/")}格式图片!`, "typeError", {
type: imageType, fileType: file.type
});
reject();
return false;
}
const isLt = file.size / 1024 / 1024 < size;
if (!isLt) {
onError(`图片不能超过${size}MB!`, "sizeError", {size, fileSize: file.size});
reject();
return false;
}

/*剪切图像*/
// editor:{open:false,width:250,height:250,borderRadius:0-100,text:'剪切'}
if (editor.open) {
createAvatarEditor({
editor,
file,
title: editor.title,
icon: "",
width: editor.width * 2,
cancelText: editor.cancelText,
okText: editor.text,
onComplete: (base64) => {
setImageUrl(base64);
let blob = dataURLtoBlob(base64);
const files = new window.File([blob], file.name, {type: file.type});
onBeforeUpload && onBeforeUpload(files);
resolve(files);
}
});
} else {
onBeforeUpload && onBeforeUpload(file);
resolve(file);
}
});

};

const onChange = (info) => {
if (info.file.status === "uploading") {
setLoading(true);
return;
}
if (info.file.status === "done") {
setLoading(false);
const response = (transformResponse || avatarParams.transformResponse)(info.file.response);
if (response.code === 200) {
propsChange(response.results);
} else {
onError(response.msg, "xhrError", response);
}
}
};

const headers = Object.assign({}, avatarParams.headers);

if (typeof avatarParams.getHeaders === 'function') {
Object.assign(headers, avatarParams.getHeaders())
}

return (<>
<Upload {...omit(avatarParams, ['action', 'transformResponse', 'headers', 'getHeaders'])}
headers={headers}
className={classnames(className, "react-form-avatar")} listType="picture-card"
showUploadList={false}
action={action || avatarParams.action}
beforeUpload={beforeUpload} onChange={onChange}>
<div className="react-form-avatar-inner">
{previewImg && showImageUrl ? previewRender ? previewRender(showImageUrl) :
<div className="preview"><img src={showImageUrl} alt="avatar"/></div> : uploadButton}
{extraRender ? extraRender(showImageUrl) : ''}
</div>
</Upload>
</>);
};

_Avatar.defaultProps = {
imageType: ["image/jpeg", "image/png"],
fileSize: 2, // 单位MB
children: <div className="ant-upload-text">点击上传</div>,
extraRender: null,
onError: (info) => message.error(info),
previewImg: true,
previewRender: null,
openEditor: false
};

const AvatarInput = (props) => {
const render = useOnChange(props);
return render(_Avatar);
};

AvatarInput.defaultProps = {
fieldName: 'avatar'
};

AvatarInput.field = _Avatar;

export default AvatarInput;
3 changes: 2 additions & 1 deletion src/fields/Upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import {get, groupBy, uniqueId, omit} from 'lodash';
import {hooks} from '@kne/react-form-helper';
import {globalParams} from "../preset";
import AvatarInput from "./Avatar.js";

const {useOnChange} = hooks;

Expand Down Expand Up @@ -167,6 +168,6 @@ UploadInput.defaultProps = {
};


UploadInput.field = _Upload;
UploadInput.field = AvatarInput.Field = _Upload;

export default UploadInput;
5 changes: 3 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import DatePicker from './fields/DatePicker';
import CheckboxGroup from './fields/CheckboxGroup';
import Checkbox from './fields/Checkbox';
import Cascader from './fields/Cascader';
import Avatar from './fields/Avatar';

export * from './Form';
export default Form;
Expand All @@ -22,6 +23,6 @@ export {default as preset} from './preset';
export {default as ResetButton} from './ResetButton';
export {default as SubmitButton} from './SubmitButton';
export {default as CancelButton} from './CancelButton';
export {Upload, TreeSelect, TimePicker, TextArea, Switch, Select, RadioGroup, InputNumber, Input, DatePickerToday, DatePicker, CheckboxGroup, Checkbox, Cascader};
export {Upload, TreeSelect, TimePicker, TextArea, Switch, Select, RadioGroup, InputNumber, Input, DatePickerToday, DatePicker, CheckboxGroup, Checkbox, Cascader, Avatar};

export const fields = { Upload, TreeSelect, TimePicker, TextArea, Switch, Select, RadioGroup, InputNumber, Input, DatePickerToday, DatePicker, CheckboxGroup, Checkbox, Cascader };
export const fields = { Upload, TreeSelect, TimePicker, TextArea, Switch, Select, RadioGroup, InputNumber, Input, DatePickerToday, DatePicker, CheckboxGroup, Checkbox, Cascader, Avatar };

0 comments on commit 837204a

Please sign in to comment.