joywok-material-components
Version:
<h1 align="center"> Joywok Material Components </h1>
371 lines (359 loc) • 16.1 kB
JavaScript
/**
*
* @api {} EditImage
* @apiName EditImage - 图片上传裁切组件
* @apiGroup 组件使用
*
* @apiParam {Number } cutHeight 裁切后的图片高度 (推荐尺寸的 height 值)
* @apiParam {Number } cutWidth 裁切后的图片宽度 (推荐尺寸的 width 值)
* @apiParam {Number } height 裁切蒙版的高度(最大设为裁剪可视区的像素高度,宽高比保持跟裁切后的宽高比一致,预览效果才是准确的)
* @apiParam {Number } width 裁切蒙版的宽度(最大设为裁剪可视区的像素宽度,宽高比保持跟裁切后的宽高比一致,预览效果才是准确的)
* @apiParam {Number|Number[] } border 定制裁切蒙版的边框,在裁切时可以在边框里看到图片,但实际裁切时,只裁切蒙版内的图片内容。可不传,或直接设置为0,当传数组时,会当成水平边框和垂直边框
* @apiParam {Number } zoom 缩放比例,推荐尺寸/裁切蒙版尺寸的比值,即 cutWidth/width 或 cutHeight/height
* @apiParam {String } cutfileUrl 固定的接口地址,图片裁切接口 URL
* @apiParam {String } uploadUrl 固定的接口地址,图片保存接口 URL
* @apiParam {String } title 弹框显示的标题
* @apiParam {String } desc 推荐尺寸描述等
* @apiParam {String } colorSystem 色系,gray 灰色;默认为绿色
*/
import React , {Component} from 'react';
import {connect} from 'dva';
import AvatarEditor from 'react-avatar-editor'
import { Base64 } from 'js-base64';
import Upload from 'antd/lib/upload';
import Progress from 'antd/lib/progress/progress';
import { AloneTip, Button } from 'joywok-material-components';
import request from '../utils/request';
import { COMPONENT_DICT } from '../constants';
require('./style/index.css');
require('./style/form.css');
const Dragger = Upload.Dragger;
class EditImage extends React.Component{
constructor(props) {
super(props);
let self = this;
console.log(props,'zzzzzzzz');
this.state = {
image: this.props.image ? this.props.image : "",
position_x: 0.5,
position_y: 0.5,
top: 0.5,
left: 0.5,
mouseFlag: 5,
desc: this.props.desc ? this.props.desc : COMPONENT_DICT('label.business.suggested.size')+this.props.cutWidth+"*"+this.props.cutHeight+ ' px',
title: this.props.title ? this.props.title : COMPONENT_DICT('label.business.edit.logo'),
disabled: true,
saveing: false,
loading: false,
id:this.props.id?this.props.id:'',
border: this.props.border ? this.props.border : 0,
height: this.props.height ? this.props.height : 0,
width: this.props.width ? this.props.width : 0,
cutHeight: this.props.cutHeight ? this.props.cutHeight/this.props.zoom : 80,
zoom: this.props.zoom,
scale: 1,
cutWidth: this.props.cutWidth ? this.props.cutWidth/this.props.zoom : 200,
cutfileUrl: this.props.cutfileUrl,
colorSystem: props.colorSystem || 'green',
files: {
name: 'jwfile',
action: this.props.uploadUrl,
accept: props.fileAccept || "image/*,.png,.jpg,.jpeg,.gif",
headers: {
authorization: 'authorization-text',
"Access-Token":window.AccessToken,
"Domain-Id": window.DomainId
},
beforeUpload(){
self.setState({
percent: 0,
})
setTimeout(function(){
self.setState({
show: true,
})
},100)
let a = AloneTip({ type: 'warning', duration: 1000, hasclose: false, autoHideDuration: 1000, message: COMPONENT_DICT('label.business.uploading') })
// message.loading('上传中…', 0);
},
onProgress(){
setTimeout(function(){
self.setState({
percent: 50
})
},200)
},
onChange(info) {
if (info.file.status !== 'uploading') {
self.setState({
loading: true
})
}
if (info.file.status === 'done') {
// message.destroy()
if(info.file.response.data && info.file.response.data.data && info.file.response.data.data.errmemo){
// message.error(`${info.file.name} 上传失败`);
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message: `${info.file.name} ` + COMPONENT_DICT('label.business.failed.upload') })
}else{
if(info.file.response.JMStatus && info.file.response.JMStatus.errmemo){
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message: `${info.file.response.JMStatus.errmemo}` })
// message.error();
}else{
console.log('!!!!!! info: ', info);
self.state.image = info.file.response.JMTmpfile.link;
self.state.height = info.file.response.JMTmpfile.height;
self.state.width = info.file.response.JMTmpfile.width;
self.state.id = info.file.response.JMTmpfile.fid;
self.state.disabled = false;
self.state.saveing = false;
self.setState({
state: self.state
})
// message.success(`${info.file.name} 上传成功`);
let a = AloneTip({ type: 'success', duration: 1000, hasclose: false, autoHideDuration: 1000, message: `${info.file.name} ` + COMPONENT_DICT('label.business.success.upload') })
setTimeout(function(){
self.setState({
percent: 100
})
},300)
setTimeout(function(){
self.setState({
show: false,
})
},2000)
}
}
} else if (info.file.status === 'error') {
// message.error(`${info.file.name} file upload failed.`);
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message: `${info.file.name} file upload failed.` })
}
},
},
percent:0,
show:false,
noCut:this.props.noCut || 'undefined'
}
}
save(){
let self = this;
let data = {
"type": this.props.type ? this.props.type : "maker"
}
self.setState({
disabled: true
})
data.id = self.state.id
if(this.state.noCut!='undefined'){
data.scale = 0;
data.height = self.state.height;
data.width = self.state.width;
data.zoom = 1;
data.top = 0;
data.left = 0;
}else{
data.height = self.props.cutHeight
data.width = self.props.cutWidth
data.zoom = self.props.zoom
let zoom = Math.abs(self.state.scale);
if(self.state.height/self.state.cutHeight < self.state.width/self.state.cutWidth){
let height = zoom * self.state.cutHeight;
data.scale = height/self.state.height
data.top = self.state.top * self.state.cutHeight * zoom - self.state.cutHeight/2
data.left = self.state.left * self.state.cutHeight * zoom * self.state.width / self.state.height - self.state.cutWidth/2
}else{
let width = zoom * self.state.cutWidth;
data.scale = width/self.state.width
data.left = self.state.left * self.state.cutWidth*zoom - self.state.cutWidth/2
data.top = self.state.top * self.state.cutWidth*zoom * self.state.height / self.state.width - self.state.cutHeight/2
}
}
let url = self.state.cutfileUrl.replace(":id", data.id)
request(url,{
method:"POST",
body: JSON.stringify(data)
})
.then(function(resp){
if(resp.data.errmemo){
self.setState({
saveing: false
})
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message:COMPONENT_DICT('label.business.err.info')+ resp.data.errmemo })
// message.error("保存失败,错误信息:"+ resp.data.errmemo );
}else{
if(resp.data.JMStatus && resp.data.JMStatus.errmemo){
// message.error("保存失败,错误信息:"+ resp.data.errmemo );
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message:COMPONENT_DICT('label.business.err.info')+ resp.data.errmemo })
self.setState({
saveing: false
})
}else{
if(resp.data && resp.data.data && resp.data.data.errmemo){
// message.error("保存失败,错误信息:"+ resp.data.errmemo );
let a = AloneTip({ type: 'error', duration: 1000, hasclose: false, autoHideDuration: 1000, message:COMPONENT_DICT('label.business.err.info')+ resp.data.errmemo })
self.setState({
saveing: false
})
}else{
let a = AloneTip({ type: 'success', duration: 1000, hasclose: false, autoHideDuration: 1000, message: COMPONENT_DICT('label.business.saved.success') })
// message.success("保存成功");
self.setState({
disabled: true
})
self.props.callback(resp.data)
$("body").removeClass('overflowhidden')
}
}
}
})
}
handleClickClose = () => {
this.props.close && this.props.close();
$("body").removeClass('overflowhidden');
}
onPositionChange(position){
let self = this;
self.setState({
position_x: position.x,
position_y: position.y,
top: position.y,
left: position.x
})
}
onChange(e,a){
$('.submit').click()
}
handleScroll(e){
let self = this;
if(e.deltaY < 0 && e.deltaY < self.state.mouseFlag*-1){
self.state.scale = (self.state.scale*10-1)/10 == 0 ? (self.state.scale*10-2)/10 : (self.state.scale*10-1)/10
self.setState({
scale: self.state.scale
})
}else if(e.deltaY < 0 && e.deltaY > self.state.mouseFlag*-1){
self.state.scale = (self.state.scale*10-1)/10 == 0 ? (self.state.scale*10-2)/10 : (self.state.scale*10-1)/10
self.setState({
scale: self.state.scale
})
}else if(e.deltaY > 0 && e.deltaY > self.state.mouseFlag){
self.state.scale = (self.state.scale*10+1)/10 == 0 ? (self.state.scale*10+2)/10 : (self.state.scale*10+1)/10
self.setState({
scale: self.state.scale
})
}else if(e.deltaY > 0 && e.deltaY < self.state.mouseFlag){
self.state.scale = (self.state.scale*10+1)/10 == 0 ? (self.state.scale*10+2)/10 : (self.state.scale*10+1)/10
self.setState({
scale: self.state.scale
})
}
}
onDrop(e){
e.preventDefault()
}
onDragEnter(e){
e.preventDefault()
}
onDragLeave(e){
e.preventDefault()
}
componentDidMount(){
$("body").addClass('overflowhidden')
}
render(){
var self=this;
let zoom = 0;
if(self.state.height/self.state.cutHeight < self.state.width/self.state.cutWidth){
zoom = self.state.height/self.state.cutHeight
}else{
zoom = self.state.width/self.state.cutWidth
}
let style = {
"background-image": "url("+this.state.image+")",
"background-size": (self.state.width/2/zoom) + "px " +(self.state.height/2/zoom)+ "px",
"background-position": self.state.position_x+" "+self.state.position_y,
"width": self.state.cutWidth/2 + "px",
"height": self.state.cutHeight/2 + "px"
}
// {this.state.show?<Progress percent={this.state.percent} showInfo={false} />:''}
let colorSystemClass = this.state.colorSystem=='gray'? 'jw-upload-button-gray' : '';
let colorSystemButton = this.state.colorSystem=='gray'? 'jw-button-gray' : '';
return(
<div className="jw-img-editor">
<div className="jw-img-editor-bg"> </div>
<div className="jw-img-editor-content">
<div className="jw-img-content-title">{self.state.title}<div onClick={self.props.close} className="close"><i className="icon-dialog-close"></i></div></div>
<div className="jw-img-content-left">
{this.state.show?<Progress percent={this.state.percent} showInfo={false} />:''}
<div className="jw-img-content" onWheel={self.handleScroll.bind(self)}>
{self.state.image == "" ? "" : <div className="jw-img-content-left-bg"> </div>}
{self.state.image == "" ?
<Dragger className="jw-upload-drop" {...this.state.files}>
<div className="drop-1">{COMPONENT_DICT('label.business.drag.img')}</div>
<div className="drop-2">{COMPONENT_DICT('label.business.or-by')}</div>
<div className={"jw-upload-button "+colorSystemClass}>
<Button variant="contained">{COMPONENT_DICT('label.business.choose.from.comp')}</Button>
</div>
</Dragger> :
(this.state.noCut!='undefined'
?
<div className={"jw-img-content-nocut-c"}><div className={"jw-img-content-nocut"}> <img src={this.state.image}/></div></div>
:
<AvatarEditor
style={{left: ((440-self.state.cutWidth)/2-self.state.border), top: ((330-self.state.cutHeight)/2-self.state.border)}}
image={this.state.image}
width={this.state.cutWidth}
height={this.state.cutHeight}
border={this.state.border}
color={[0, 0, 0, 0.3]}
scale={Math.abs(self.state.scale)}
rotate={0}
onPositionChange={this.onPositionChange.bind(this)}
/>
)
}
</div>
{
this.state.noCut!='undefined'?"":<div className="jw-img-desc">{self.state.desc}</div>
}
</div>
{self.state.image == "" ? "" :
<div className="jw-img-content-right">
<div className="jw-img-preview">
<div className="preview-title">{COMPONENT_DICT('label.business.preview')}</div>
{(this.state.noCut!='undefined'
?
<img src={this.state.image}/>
:
<AvatarEditor
image={this.state.image}
width={this.state.cutWidth/2}
height={this.state.cutHeight/2}
border={0}
color={[0, 0, 0, 0.3]}
scale={Math.abs(self.state.scale)}
rotate={0}
position={{x: this.state.position_x , y: this.state.position_y}}
onPositionChange={this.onPositionChange.bind(this)}
/>
)}
{ //<div className="preview-img" style={style}></div>
}
</div>
<div className={"jw-upload-button " + colorSystemClass}>
<Upload {...this.state.files}>
<Button className="jw-img-upload-reset">
{this.state.image ? COMPONENT_DICT('label.business.reset.upload') : COMPONENT_DICT('label.business.select.file')}
</Button>
</Upload>
</div>
</div>
}
<div className={"jw-img-editor-options " + colorSystemButton}>
{self.state.disabled ? <Button className="editor-save disabled" disabled>{COMPONENT_DICT('label.business.save')}</Button> : (self.state.saveing ? <Button className="editor-save saving">{COMPONENT_DICT('label.business.saving')}</Button> : <Button className="editor-save" onClick={self.save.bind(self)}>{COMPONENT_DICT('label.business.save')}</Button>)}
<Button className="editor-cancel" onClick={this.handleClickClose} >{COMPONENT_DICT('label.business.cancel')}</Button>
</div>
</div>
</div>
)
}
}
export default connect()(EditImage);