import React, { Component } from 'react'; import Cropper from 'react-cropper'; import 'cropperjs/dist/cropper.css'; import './index.less'; import FileUpload from '@src/components/FileUpload'; import Assets from '@src/components/Assets'; import scale from '@src/services/Scale'; import { asyncSMessage } from '@src/services/AsyncTools'; import { SelectInput, VerificationInput, Input } from '../Login'; import { MobileArea } from '../../../Constant'; import Invite from '../Invite'; import Modal from '../Modal'; import { Common } from '../../stores/common'; import { User } from '../../stores/user'; import { My } from '../../stores/my'; export class BindPhone extends Component { constructor(props) { super(props); this.props.data = this.props.data || {}; this.state = Object.assign({ step: 0, data: {} }, this.initState(this.props)); this.stepProp = { 0: { title: '绑定手机', onConfirm: props.onConfirm, }, 1: { title: '绑定手机', onConfirm: () => { this.submit(); }, onCancel: props.onCancel, confirmText: '提交', }, }; } initState(props) { if (!props.show || this.props.show) return {}; const data = Object.assign({}, props.data); if (!data.area) data.area = MobileArea[0].value; return { step: props.data.mobile ? 0 : 1, data }; } componentWillReceiveProps(nextProps) { this.setState(this.initState(nextProps)); } onNext() { this.setState({ step: 1 }); } changeData(field, value) { let { data } = this.state; data = data || {}; data[field] = value; this.setState({ data, error: null }); } validMobile() { const { data } = this.state; const { area, mobile } = data; if (!area || !mobile) return; this.validNumber += 1; const number = this.validNumber; User.validMobile(area, mobile) .then(result => { if (number !== this.validNumber) return Promise.resolve(); return result ? Promise.resolve() : Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码')); }) .catch(err => { this.setState({ mobileError: err.message }); }); } sendValid() { const { data, error } = this.state; const { area, mobile } = data; if (!area || !mobile || error) return Promise.reject(); return Common.sendSms(area, mobile) .then(result => { if (result) { asyncSMessage('发送成功'); this.setState({ error: '', validError: '' }); } else { throw new Error('发送失败'); } }) .catch(err => { this.setState({ error: err.message }); throw err; }); } submit() { const { data, error } = this.state; if (!data.mobile || !data.area || error) return; const { area, mobile } = data; My.bindMobile(area, mobile) .then(() => { asyncSMessage('操作成功'); this.setState({ step: 0 }); User.infoHandle(Object.assign(this.props.data, { area, mobile })); this.props.onConfirm(); }) .catch(e => { this.setState({ error: e.message }); }); } render() { const { show } = this.props; const { step = 0 } = this.state; return ( <Modal className="bind-phone-modal" show={show} width={630} {...this.stepProp[step]}> <div className="bind-phone-modal-wrapper">{this[`renderStep${step}`]()}</div> </Modal> ); } renderStep0() { const { data } = this.state; return ( <div className="step-0-layout"> 已绑定手机 {data.mobile} <a onClick={() => this.onNext()}>修改</a> </div> ); } renderStep1() { return ( <div className="step-1-layout"> <div className="label">手机号</div> <div className="input-layout"> <SelectInput placeholder="请输入手机号" selectValue={this.state.data.area} select={MobileArea} value={this.state.data.mobile} error={this.state.error} onSelect={value => { this.changeData('area', value); this.validMobile(); }} onChange={e => { this.changeData('mobile', e.target.value); this.validMobile(); }} /> <VerificationInput placeholder="请输入验证码" value={this.state.data.mobileVerifyCode} error={this.state.validError} onSend={() => { return this.sendValid(); }} onChange={e => { this.changeData('mobileVerifyCode', e.target.value); }} /> </div> </div> ); } } export class BindEmail extends Component { constructor(props) { super(props); this.props.data = this.props.data || {}; this.state = Object.assign({ step: 0, data: {} }, this.initState(this.props)); this.stepProp = { 0: { title: '绑定邮箱', onConfirm: props.onConfirm, }, 1: { title: '绑定邮箱', onConfirm: () => { this.submit(); }, onCancel: props.onCancel, confirmText: '提交', }, }; } initState(props) { if (!props.show || this.props.show) return {}; return { step: props.data.email ? 0 : 1, data: Object.assign({}, props.data) }; } componentWillReceiveProps(nextProps) { this.setState(this.initState(nextProps)); } onNext() { this.setState({ step: 1 }); } changeData(field, value) { let { data } = this.state; data = data || {}; data[field] = value; this.setState({ data, error: null }); } submit() { const { data, error } = this.state; if (!data.email || error) return; const { email } = data; My.bindEmail(email) .then(() => { asyncSMessage('操作成功'); this.setState({ step: 0 }); User.infoHandle(Object.assign(this.props.data, { email })); this.props.onConfirm(); }) .catch(e => { this.setState({ error: e.message }); }); } render() { const { show } = this.props; const { step = 0 } = this.state; return ( <Modal className="bind-email-modal" show={show} width={630} {...this.stepProp[step]}> <div className="bind-email-modal-wrapper">{this[`renderStep${step}`]()}</div> </Modal> ); } renderStep0() { const { data } = this.state; return ( <div className="step-0-layout"> 已绑定邮箱 {data.email} <a onClick={() => this.onNext()}>修改</a> </div> ); } renderStep1() { return ( <div className="step-1-layout"> <div className="label">邮箱地址</div> <div className="input-layout"> <Input placeholder="请输入邮箱" value={this.state.data.email} error={this.state.error} onChange={e => { this.changeData('email', e.target.value); }} /> </div> </div> ); } } export class EditInfo extends Component { constructor(props) { super(props); this.props.data = this.props.data || {}; this.state = Object.assign({ data: {} }, this.initState(this.props)); } initState(props) { if (props.image && this.waitImage) { const { state } = this; Common.upload(props.image).then(result => { const { data } = this.state; data.avatar = result.url; this.setState({ data, uploading: false }); }).catch((e) => { this.setState({ imageError: e.message }); }); state.uploading = true; this.waitImage = false; return state; } if (!props.show || this.props.show) return {}; return { data: Object.assign({}, props.data) }; } componentWillReceiveProps(nextProps) { this.setState(this.initState(nextProps)); } changeData(field, value) { let { data } = this.state; data = data || {}; data[field] = value; this.setState({ data, error: null }); } submit() { const { data, error } = this.state; if (!data.nickname || error) return; const { nickname, avatar } = data; My.editInfo({ nickname, avatar }) .then(() => { asyncSMessage('操作成功'); User.infoHandle(Object.assign(this.props.data, { nickname, avatar })); this.props.onConfirm(); }) .catch(e => { this.setState({ error: e.message }); }); } render() { const { show, onCancel, onSelectImage } = this.props; return ( <Modal className="edit-info-modal" show={show} width={630} title="修改资料" confirmText="保存" onCancel={onCancel} onConfirm={() => { this.submit(); }} > <div className="edit-info-modal-wrapper"> <div className="edit-info-modal-block"> <div className="label">昵称</div> <div className="input-layout"> <Input placeholder="2-20位,不可使用特殊字符。" value={this.state.data.nickname || ''} error={this.state.error} onChange={e => { this.changeData('nickname', e.target.value); }} /> </div> </div> <div className="edit-info-modal-block"> <div className="label">头像</div> <div className="input-layout"> <FileUpload uploading={this.state.uploading} value={this.state.data.avatar} onUpload={({ file }) => { this.waitImage = true; onSelectImage(file); return Promise.reject(); }} /> {this.state.imageError || ''} </div> </div> </div> </Modal> ); } } export class RealAuth extends Component { constructor(props) { super(props); this.state = { data: {} }; } render() { const { show, onConfirm } = this.props; return ( <Modal className="real-auth-modal" show={show} width={630} title="实名认证" confirmText="好的,知道了" btnAlign="center" onConfirm={onConfirm} > <div className="real-auth-modal-wrapper"> <div className="real-auth-text"> <div className="t1">完成实名认证即可领取:</div> <div className="t2">6个月VIP权限 和 5折机经优惠劵。</div> <div className="t3">扫码关注公众号,点击“我的-实名认证”</div> </div> <div className="real-auth-qrcode"> <Assets name="qrcode" /> </div> </div> </Modal> ); } } export class EditAvatar extends Component { constructor(props) { super(props); this.state = Object.assign({ data: {} }, this.initState(this.props)); } initState(props) { if (props.image) this.loadImage(props.image); if (!props.show || this.props.show) return {}; return { data: {} }; } componentWillReceiveProps(nextProps) { this.setState(this.initState(nextProps)); } loadImage(file) { this.defaultZoomValue = 1; if (window.FileReader) { const reader = new FileReader(); reader.readAsDataURL(file); // 渲染文件 reader.onload = (arg) => { this.setState({ image: arg.target.result, fileName: file.name, zoomValue: 1 }); }; } else { const img = new Image(); img.onload = function () { const canvas = document.createElement('canvas'); canvas.height = img.height; canvas.width = img.width; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); this.setState({ image: canvas.toDataURL() }); }; img.src = '1.gif'; } } computerZoom() { const data = this.cropRef.getImageData(); this.defaultZoomValue = 200 / parseFloat(Math.max(data.naturalWidth, data.naturalHeight)); } crop() { // image in dataUrl // console.log(this.cropRef.getCroppedCanvas().toDataURL()) // const canvas = this.cropRef.getCroppedCanvas(); // const avatar = scale(this.props.crop, canvas, 'png-src'); // let scaleCanvas = this.cropRef.getCroppedCanvas(this.props.crop) // this.setState({ avatar }); } select() { const { fileName } = this.state; const { onConfirm } = this.props; const canvas = this.cropRef.getCroppedCanvas(); const scaleCanvas = scale(this.props.crop, canvas); // let scaleCanvas = this.cropRef.getCroppedCanvas(this.props.crop) scaleCanvas.toBlob((blob) => { const file = new File([blob], fileName); onConfirm(file); }); } render() { const { show, onCancel } = this.props; const { image } = this.state; return ( <Modal className="edit-avatar-modal" show={show} width={630} title="调整头像" confirmText="保存头像" onConfirm={() => { this.select(); }} onCancel={onCancel} > <div className="edit-avatar-modal-wrapper"> <div className="edit-avatar-o"> <Cropper ref={(ref) => { this.cropRef = ref; }} src={image} ready={() => { this.computerZoom(); }} style={{ height: 360, width: 360 }} // Cropper.js options aspectRatio={1} viewMode={0} // autoCropArea={0.8} preview=".img-preview" // dragMode='move' guides={false} movable={false} rotatable={false} scalable={false} // zoom={(value) => { // console.log('zoom', value); // const zoomValue = value * this.defaultZoomValue / 50; // this.cropRef.zoomTo(zoomValue); // }} cropmove={() => { this.crop(); }} toggleDragModeOnDblclick={false} cropBoxResizable /> </div> <div className="edit-avatar-r"> <div className="text">头像预览</div> <div className="img-preview" style={{ width: 100, height: 100, overflow: 'hidden' }} /> </div> </div> </Modal> ); } } export class InviteModal extends Component { constructor(props) { super(props); this.state = { data: {} }; } render() { const { show, onClose, data } = this.props; return ( <Modal className="invite-modal" show={show} width={630} title="邀请好友" onClose={onClose}> <div className="invite-modal-wrapper"> <div className="tip">每邀请一位小伙伴加入“千行GMAT”, 您的VIP权限会延长7天,可累加 无上限!赶紧行动吧~</div> <Invite data={data} /> </div> </Modal> ); } }