Commit 5d02a4f0 by 姜雷

添加登陆和预览

parent fd181f78
import fetch from './fetch';
// login
export const wxAuth = entity =>
fetch({
url: '/login/weChatAuthorization',
params: entity,
});
export const getVcode = entity =>
fetch({
url: '/login/getCode',
params: entity,
});
export const sendMsg = entity =>
fetch({
url: '/login/sendMsg',
params: entity,
});
export const login = entity =>
fetch({
url: '/login/app/login.do',
method: 'post',
data: entity,
});
// base
export const fetchRepairArea = () =>
fetch({
......
import React, { Component } from 'react';
class CodeView extends Component {
constructor(props) {
super(props);
let canDom = document.createElement('canvas');
canDom.id = 'ksCanvas';
canDom.setAttribute('width', '160px');
canDom.setAttribute('height', '64px');
canDom.style = 'display: none';
document.body.appendChild(canDom);
this.canvas = canDom;
}
componentWillUnmount() {
document.body.removeChild(this.canvas);
}
renderImg = () => {
const { value } = this.props;
const ctx = this.canvas.getContext('2d');
ctx.fillStyle = '#F0F0F0';
ctx.fillRect(0, 0, 160, 64);
ctx.font = '26px arial';
// 创建渐变
var gradient = ctx.createLinearGradient(0, 0, 160, 0);
gradient.addColorStop('0', 'magenta');
gradient.addColorStop('0.5', 'blue');
gradient.addColorStop('1.0', 'red');
// 用渐变填色
ctx.strokeStyle = gradient;
ctx.strokeText(value, 50, 40); //画布上添加验证码
return this.canvas.toDataURL();
};
render() {
return <img src={this.renderImg()} alt="" />;
}
}
export default CodeView;
......@@ -52,7 +52,12 @@ class ImagePicker extends Component {
done: true,
}));
if (onChange) {
onChange(filesList);
onChange([
{
filesList,
url: fileUrl,
},
]);
}
};
createObjectURL = blob => {
......
import React, { Component } from 'react';
import { createPortal } from 'react-dom';
// import { createPortal } from 'react-dom';
import styles from './style.css';
import { Carousel } from 'antd-mobile';
import pageIcon from './images/next_pic_btn@2x.png';
class Perview extends Component {
constructor(props) {
......@@ -21,27 +23,36 @@ class Perview extends Component {
}
render() {
const { visibility } = this.props;
return visibility
? createPortal(
<div className={styles}>
<div className={styles.mask} />
const { data, index } = this.props;
return (
<div>
<div className={styles.content}>
<div className={styles.imgBox} />
<div className={styles.imgBox}>
<Carousel selectedIndex={index} dots={false}>
{data.map(
(item, index) =>
item ? <img className={styles.carouselImg} key={index} src={item.url} alt="" /> : null
)}
</Carousel>
</div>
<div className={styles.footer}>
<div className={styles.per}>
<div className={styles.leftIcon} />
<div className={styles.leftIcon}>
<img src={pageIcon} alt="" />
</div>
<div>上一张</div>
</div>
<div className={styles.pagination} />
<div className={styles.pagination}>1/3</div>
<div className={styles.next}>
<div className={styles.rightIcon} />
<div>下一张</div>
<div className={styles.rightIcon}>
<img src={pageIcon} alt="" />
</div>
</div>
</div>
</div>
</div>
</div>,
this.node
)
: null;
);
}
}
......
.mask {
composes: mask from '../Popup/style.css';
}
.content {
}
.imgBox {
margin: 0 auto;
width: 590px;
height: 334px;
}
.carouselImg {
width: 590px;
height: 334px;
}
.footer {
display: flex;
justify-content: center;
height: 76px;
line-height: 76px;
}
.footerItem {
}
.per,
.next {
display: flex;
font-size: 24px;
color: #3695c0;
align-items: center;
}
.footerIcon {
width: 30px;
height: 30px;
margin: 0 18px;
}
.leftIcon {
composes: footerIcon;
}
.rightIcon {
composes: footerIcon;
transform: rotate(180deg);
}
.pagination {
width: 160px;
}
......@@ -4,9 +4,8 @@ import { is_weixn } from '../utils';
import { APP_ID } from '../config';
import UserInfoContext, { defaultUserinfo } from '../context/userinfo-context';
import { Route, Switch } from 'react-router-dom';
import { Route, Switch, Redirect } from 'react-router-dom';
import Home from './Home/Index';
import Report from './report/report';
import Login from './Login/Login';
import PublicCar from './PublicCar/index';
import PublicCarDeal from './PublicCarDeal/index';
......@@ -14,6 +13,9 @@ import Repair from './Repair/index';
import RepairDeal from './RepairDeal/index';
import NoMatch from './NoMatch';
import { wxAuth } from '../api/index';
import { Toast } from 'antd-mobile';
class App extends Component {
constructor(props) {
super(props);
......@@ -61,16 +63,66 @@ class App extends Component {
}
return obj;
};
validateUserinfo = props => {
renderIndex = props => {
console.log(props);
setTimeout(() => {
const { history, location } = props;
let params = this.getParams(location.search);
// history.push('/login');
if (params.code) {
console.log('fetch UserInfo');
console.log('redirect', params, history);
}, 1000);
return <Home />;
wxAuth({
code: params.code,
})
.then(res => {
console.log(res);
const { firstLogin, user } = res.data;
this.updateUserInfo({ ...user, login: true });
if (firstLogin) {
history.replace('/login');
} else {
history.replace('/home');
}
})
.catch(err => {
console.log(err);
Toast.fail(err.msg || '获取授权失败!');
});
} else {
console.log('go in wxAuth');
}
return <div style={{ margin: '60px 24px 0' }}>加载中。。。</div>;
};
goWechatAuth = () => {
let rUrl = encodeURIComponent('');
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APP_ID}&redirect_uri=${rUrl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`;
return <div>授权中。。。</div>;
};
validateUserinfo = (code, Component) => {
const {
userContext: {
userinfo: { login, author },
},
} = this.state;
if (!login) {
return this.goWechatAuth();
}
for (let index = 0; index < author.length; index++) {
const element = author[index];
if (element.code === code) {
if (element.type) {
return <Component />;
} else {
Toast.fail('无权使用该功能');
const { from } = this.props.location.state || {
from: { pathname: '/home' },
};
return <Redirect to={from} />;
}
}
}
return <NoMatch />;
};
updateUserInfo = data => {
this.setState({
......@@ -87,8 +139,8 @@ class App extends Component {
<div className="App">
<UserInfoContext.Provider value={userContext}>
<Switch>
<Route exact path="/" render={this.validateUserinfo} />
<Route path="/report" component={Report} />
<Route exact path="/" render={this.renderIndex} />
<Route path="/home" component={Home} />
<Route path="/login" component={Login} />
<Route path="/publicCar" component={PublicCar} />
<Route path="/publicCarDeal" component={PublicCarDeal} />
......
......@@ -8,7 +8,15 @@ export class Index extends React.Component {
};
render() {
return <div className={styles.LoadPage}>加载中。。。</div>;
return (
<div className={styles.LoadPage}>
<h2>HomePage</h2>
<a href="">功能1</a>
<a href="">功能2</a>
<a href="">功能3</a>
<a href="">功能4</a>
</div>
);
}
}
......
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import styles from './style.css';
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
},
};
import logoIcon from './images/school_logo@2x.png';
import logoWord from './images/school_word_logo@2x.png';
import { Button, Modal, Toast } from 'antd-mobile';
import { getVcode, sendMsg, login } from '../../api/index';
import CodeView from '../../components/CodeView/CodeView';
import UserInfoContext from '../../context/userinfo-context';
class Login extends Component {
state = {
constructor(props) {
super(props);
this.state = {
redirectToReferrer: false,
sending: false,
count: 60,
cellphone: '',
vcodeDialogVisible: false,
vcode: '',
svcode: '',
code: '',
};
}
componentWillUnmount() {
const { sending } = this.state;
if (sending) clearTimeout(this.timer);
}
updateCellphone = e => {
this.setState({
cellphone: e.target.value.replace(/\D/g, ''),
});
};
login = () => {
fakeAuth.authenticate(() => {
getVcodeHandle = () => {
const { sending, cellphone } = this.state;
if (sending) return;
if (!cellphone) {
Toast.fail('请输入手机号');
return;
}
getVcode({ cellphone })
.then(res => {
console.log(res);
this.setState({
svcode: res.data,
vcodeDialogVisible: true,
vcode: '',
});
})
.catch(err => {
Toast.fail(err.msg || '获取验证码失败!');
console.log(err);
});
};
resetDialog = () => {
this.setState({
vcodeDialogVisible: false,
});
};
checkVcode = () => {
const { vcode, svcode } = this.state;
if (vcode === svcode) {
this.sendMsgHandle();
this.resetDialog();
} else {
Toast.fail('请输入正确的验证码!');
}
};
sendMsgHandle = () => {
const { sending, cellphone, vcode } = this.state;
if (sending) return;
sendMsg({
cellphone,
valiCode: vcode,
})
.then(res => {
console.log(res);
Toast.success(res.msg || '发送验证码成功!');
})
.catch(err => {
Toast.fail(err.msg || '发送验证码失败!');
console.log(err);
});
this.setState({
sending: true,
});
this.startCountDown();
};
startCountDown = () => {
const { count } = this.state;
if (count === 0) {
clearTimeout(this.timer);
this.setState(({ count }) => ({
sending: false,
count: 60,
}));
} else {
this.setState(({ count }) => ({
count: --count,
}));
this.timer = setTimeout(() => {
this.startCountDown();
}, 1000);
}
};
loginHandle = () => {
const { updateUserInfo, history } = this.props;
const { code, cellphone } = this.state;
if (!code) {
Toast.fail('请输入短信验证码');
return;
}
const entity = {
cellphone,
code,
};
login(entity)
.then(res => {
const { user, author } = res.data;
updateUserInfo({
...user,
author,
});
this.setState({ redirectToReferrer: true });
console.log(res);
})
.catch(err => {
console.log(err);
});
// fakeAuth.authenticate(() => {
// this.setState({ redirectToReferrer: true });
// });
};
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } };
const { redirectToReferrer } = this.state;
// const { from } = this.props.location.state || { from: { pathname: '/' } };
const {
redirectToReferrer,
sending,
count,
cellphone,
vcodeDialogVisible,
vcode,
svcode,
code,
} = this.state;
if (redirectToReferrer) {
return <Redirect to={from} />;
return <Redirect to={{ pathname: '/home' }} />;
}
return (
<div className={styles.Login}>
<h2>Login</h2>
<button onClick={this.login}>Log in</button>
<div className={styles.loginBox}>
<div className={styles.logo}>
<img src={logoIcon} alt="" />
</div>
<div className={styles.logoWord}>
<img src={logoWord} alt="" />
</div>
<div className={styles.inputWrap}>
<div className={styles.inputBox}>
<input
className={styles.input}
type="tel"
placeholder="请输入手机号"
value={cellphone}
onChange={this.updateCellphone}
maxLength="11"
/>
</div>
<div className={styles.vcodeBox}>
<div className={styles.vInputBox}>
<input
className={styles.input}
type="tel"
placeholder="请输入短信验证码"
value={code}
maxLength="6"
onChange={e =>
this.setState({
code: e.target.value,
})
}
/>
</div>
<div className={styles.vcode} onClick={this.getVcodeHandle}>
{sending ? `${count}s后重新获取` : '获取验证码'}
</div>
</div>
</div>
<div className={styles.btnBox}>
<Button className={styles.okbtn} onClick={this.loginHandle}>
登陆
</Button>
<Button className={styles.canclbtn}>取消</Button>
</div>
<Modal
className={styles.vcodeDialog}
visible={vcodeDialogVisible}
transparent
maskClosable={false}
onClose={this.resetDialog}
title=""
>
<div className={styles.vcodeinputBox}>
<div className={styles.vcodeItem}>
<input
className={styles.input}
type="tel"
value={vcode}
onChange={e => this.setState({ vcode: e.target.value })}
maxLength="6"
/>
</div>
<div className={styles.vcodeItem}>
<CodeView value={svcode} alt="" />
</div>
</div>
<Button className={styles.vcodeOkbtn} onClick={this.checkVcode}>
确认
</Button>
</Modal>
</div>
</div>
);
}
}
export default Login;
export default props => (
<UserInfoContext.Consumer>
{({ userinfo, updateUserInfo }) => (
<Login {...props} updateUserInfo={updateUserInfo} />
)}
</UserInfoContext.Consumer>
);
.Login {
height: 300px;
text-align: center;
background-color: #f0f0f0;
width: 100%;
height: 100%;
overflow: hidden;
}
.loginBox {
width: 560px;
height: 442px;
margin: 158px auto 0;
position: relative;
background-color: #fff;
border-radius: 8px;
}
.logo {
position: absolute;
width: 140px;
height: 140px;
top: -62px;
left: 50%;
transform: translate(-50%, 0);
}
.logoWord {
width: 140px;
height: 40px;
margin: 0 auto 40px;
padding-top: 78px;
}
.inputWrap {
width: 460px;
margin: 0 auto;
line-height: 64px;
padding-bottom: 30px;
}
.inputBox {
height: 64px;
background-color: #f0f0f0;
}
.input {
composes: input from '../Repair/style.css';
box-sizing: border-box;
background-color: #f0f0f0;
text-align: left;
padding-left: 20px;
border-radius: 8px;
}
.vcodeBox {
display: flex;
width: 460px;
margin: 20px auto 0;
}
.vInputBox {
composes: inputBox;
width: 300px;
margin-right: 10px;
}
.vcode {
flex: 1;
font-size: 22px;
color: #3695c0;
}
.btnBox {
display: flex;
height: 64px;
width: 460px;
margin: 0 auto;
justify-content: space-between;
}
.btn {
width: 200px;
height: 64px;
line-height: 64px;
font-size: 30px;
}
.okbtn {
composes: btn;
background-color: #3695c0;
color: #fff;
}
.canclbtn {
composes: btn;
color: #3695c0;
}
.canclbtn::before {
border-color: #3695c0;
}
.vcodeDialog {
}
.vcodeinputBox {
width: 350px;
margin: 15px auto 0;
display: flex;
justify-content: space-between;
}
.vcodeItem {
width: 160px;
height: 64px;
background-color: #f0f0f0;
border-radius: 8px;
}
.vcodeOkbtn {
composes: okbtn;
width: 350px;
margin: 30px auto 0;
}
import React, { Component } from 'react';
import styles from './style.css';
import { Radio, Toast, Button, TextareaItem } from 'antd-mobile';
import { Radio, Toast, Button, TextareaItem, Modal } from 'antd-mobile';
import peopleIcon from './images/repair_people_icon@2x.png';
import phoneIcon from './images/phone_tel_icon@2x.png';
import roleIcon from './images/user_role_icon@2x.png';
......@@ -32,7 +32,7 @@ class ReprtRepair extends Component {
address: '',
uploadImg: [null, null, null],
},
perviewVisibility: true,
perviewVisibility: false,
perviewIndex: 0,
};
}
......@@ -114,7 +114,6 @@ class ReprtRepair extends Component {
}));
};
showViewHandle = index => {
console.log('showViewHandle');
console.log(index);
this.setState({
perviewVisibility: true,
......@@ -189,6 +188,11 @@ class ReprtRepair extends Component {
console.log(err);
});
};
resetDialog = () => {
this.setState({
perviewVisibility: false,
});
};
render() {
const {
applyForm,
......@@ -338,11 +342,16 @@ class ReprtRepair extends Component {
<Button className={styles.applyBtn} onClick={this.startApply}>
提交
</Button>
<Perview
visibility={perviewVisibility}
data={applyForm.uploadImg}
index={perviewIndex}
/>
<Modal
className={styles.perViewDialog}
visible={perviewVisibility}
transparent
maskClosable={true}
onClose={this.resetDialog}
title=""
>
<Perview data={applyForm.uploadImg} index={perviewIndex} />
</Modal>
</div>
);
}
......
......@@ -196,3 +196,7 @@
text-align: center;
padding: 50px 0;
}
.perViewDialog {
width: 100%;
}
import React from 'react';
import { List, InputItem } from 'antd-mobile';
export default () => (
<div>
<List>
<InputItem clear placeholder="报修人">
报修人
</InputItem>
<InputItem clear placeholder="报修电话">
报修电话
</InputItem>
<InputItem clear placeholder="报修人">
报修人
</InputItem>
</List>
</div>
);
import React from 'react';
export const defaultUserinfo = {
openid: '15',
login: false,
userId: '15',
cellphone: '',
name: '',
phone: '',
department: '',
author: [],
};
export const UserContext = React.createContext({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment